vislearnlabpy 0.0.2.3__tar.gz → 0.0.2.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {vislearnlabpy-0.0.2.3/src/vislearnlabpy.egg-info → vislearnlabpy-0.0.2.4}/PKG-INFO +1 -1
- {vislearnlabpy-0.0.2.3 → vislearnlabpy-0.0.2.4}/pyproject.toml +1 -1
- {vislearnlabpy-0.0.2.3 → vislearnlabpy-0.0.2.4}/src/vislearnlabpy/embeddings/stimuli_loader.py +137 -38
- vislearnlabpy-0.0.2.4/src/vislearnlabpy/models/dinov3_model.py +20 -0
- {vislearnlabpy-0.0.2.3 → vislearnlabpy-0.0.2.4}/src/vislearnlabpy/models/multimodal_model.py +0 -39
- vislearnlabpy-0.0.2.4/src/vislearnlabpy/models/vision_model.py +54 -0
- {vislearnlabpy-0.0.2.3 → vislearnlabpy-0.0.2.4/src/vislearnlabpy.egg-info}/PKG-INFO +1 -1
- {vislearnlabpy-0.0.2.3 → vislearnlabpy-0.0.2.4}/src/vislearnlabpy.egg-info/SOURCES.txt +3 -1
- {vislearnlabpy-0.0.2.3 → vislearnlabpy-0.0.2.4}/LICENSE +0 -0
- {vislearnlabpy-0.0.2.3 → vislearnlabpy-0.0.2.4}/README.md +0 -0
- {vislearnlabpy-0.0.2.3 → vislearnlabpy-0.0.2.4}/setup.cfg +0 -0
- {vislearnlabpy-0.0.2.3 → vislearnlabpy-0.0.2.4}/src/vislearnlabpy/__init__.py +0 -0
- {vislearnlabpy-0.0.2.3 → vislearnlabpy-0.0.2.4}/src/vislearnlabpy/drawings/drawing.py +0 -0
- {vislearnlabpy-0.0.2.3 → vislearnlabpy-0.0.2.4}/src/vislearnlabpy/drawings/svg_render_helpers.py +0 -0
- {vislearnlabpy-0.0.2.3 → vislearnlabpy-0.0.2.4}/src/vislearnlabpy/embeddings/embedding_store.py +0 -0
- {vislearnlabpy-0.0.2.3 → vislearnlabpy-0.0.2.4}/src/vislearnlabpy/embeddings/generate_embeddings.py +0 -0
- {vislearnlabpy-0.0.2.3 → vislearnlabpy-0.0.2.4}/src/vislearnlabpy/embeddings/similarity_generator.py +0 -0
- {vislearnlabpy-0.0.2.3 → vislearnlabpy-0.0.2.4}/src/vislearnlabpy/embeddings/similarity_utils.py +0 -0
- {vislearnlabpy-0.0.2.3 → vislearnlabpy-0.0.2.4}/src/vislearnlabpy/embeddings/utils.py +0 -0
- {vislearnlabpy-0.0.2.3 → vislearnlabpy-0.0.2.4}/src/vislearnlabpy/extractions/drawingtask_extractor.py +0 -0
- {vislearnlabpy-0.0.2.3 → vislearnlabpy-0.0.2.4}/src/vislearnlabpy/extractions/mongo_extractor.py +0 -0
- {vislearnlabpy-0.0.2.3 → vislearnlabpy-0.0.2.4}/src/vislearnlabpy/models/clip_model.py +0 -0
- {vislearnlabpy-0.0.2.3 → vislearnlabpy-0.0.2.4}/src/vislearnlabpy/models/feature_generator.py +0 -0
- {vislearnlabpy-0.0.2.3 → vislearnlabpy-0.0.2.4}/src/vislearnlabpy.egg-info/dependency_links.txt +0 -0
- {vislearnlabpy-0.0.2.3 → vislearnlabpy-0.0.2.4}/src/vislearnlabpy.egg-info/requires.txt +0 -0
- {vislearnlabpy-0.0.2.3 → vislearnlabpy-0.0.2.4}/src/vislearnlabpy.egg-info/top_level.txt +0 -0
{vislearnlabpy-0.0.2.3 → vislearnlabpy-0.0.2.4}/src/vislearnlabpy/embeddings/stimuli_loader.py
RENAMED
|
@@ -10,6 +10,9 @@ from typing import Callable, Any
|
|
|
10
10
|
import warnings
|
|
11
11
|
from torchvision import transforms
|
|
12
12
|
import numpy as np
|
|
13
|
+
from scipy import ndimage
|
|
14
|
+
from skimage.morphology import skeletonize, binary_dilation, disk
|
|
15
|
+
from skimage import img_as_bool
|
|
13
16
|
|
|
14
17
|
random.seed(2)
|
|
15
18
|
|
|
@@ -24,7 +27,12 @@ class ImgExtractionSettings:
|
|
|
24
27
|
change_stroke_color: bool = False
|
|
25
28
|
stroke_color: tuple = (0, 0, 0)
|
|
26
29
|
stroke_threshold: int = 200
|
|
27
|
-
|
|
30
|
+
bg_threshold: int = 200 # threshold to consider a pixel as background (0-255)
|
|
31
|
+
bg_component_size: int = 10 # minimum size of connected components to keep (in pixels)
|
|
32
|
+
filter_edge_artifacts: bool = False # whether to filter out edge artifacts during cropping
|
|
33
|
+
normalize_stroke_thickness: bool = False
|
|
34
|
+
stroke_target_thickness: int = 2 # target thickness for stroke normalization
|
|
35
|
+
double_resize: bool = False # whether to resize twice (once with thumbnail, once after with resize func)
|
|
28
36
|
|
|
29
37
|
class ImageExtractor:
|
|
30
38
|
@staticmethod
|
|
@@ -87,27 +95,115 @@ class ImageExtractor:
|
|
|
87
95
|
result[stroke_mask, 2] = target_color[2] # B
|
|
88
96
|
|
|
89
97
|
return Image.fromarray(result)
|
|
98
|
+
|
|
99
|
+
def normalize_stroke_thickness(img, target_thickness=2):
|
|
100
|
+
# Binarize
|
|
101
|
+
arr = np.array(img.convert('L'))
|
|
102
|
+
binary = arr < 128 # assuming dark strokes on light background
|
|
103
|
+
|
|
104
|
+
# Skeletonize to 1-pixel lines
|
|
105
|
+
skeleton = skeletonize(binary)
|
|
106
|
+
|
|
107
|
+
# Dilate to consistent thickness
|
|
108
|
+
if target_thickness > 1:
|
|
109
|
+
skeleton = binary_dilation(skeleton, disk(target_thickness//2))
|
|
110
|
+
|
|
111
|
+
# Convert back to image (white background, black strokes)
|
|
112
|
+
result = (~skeleton * 255).astype(np.uint8)
|
|
113
|
+
return Image.fromarray(result)
|
|
114
|
+
|
|
115
|
+
@staticmethod
|
|
116
|
+
def _filter_edge_artifacts(large_components, labeled, component_sizes, img_width, img_height):
|
|
117
|
+
for comp_id in range(1, len(component_sizes)):
|
|
118
|
+
if large_components[comp_id]:
|
|
119
|
+
comp_mask = (labeled == comp_id)
|
|
120
|
+
rows, cols = np.where(comp_mask)
|
|
121
|
+
|
|
122
|
+
if len(rows) > 0 or len(cols) > 0:
|
|
123
|
+
ylb, yub = min(rows), max(rows)
|
|
124
|
+
xlb, xub = min(cols), max(cols)
|
|
125
|
+
width = xub - xlb + 1
|
|
126
|
+
height = yub - ylb + 1
|
|
127
|
+
x_tolerance = 10
|
|
128
|
+
y_tolerance = 100
|
|
129
|
+
touches_top = ylb <= y_tolerance
|
|
130
|
+
touches_bottom = yub >= img_height - 1 - y_tolerance
|
|
131
|
+
touches_left = xlb <= x_tolerance
|
|
132
|
+
touches_right = xub >= img_width - 1 - x_tolerance
|
|
133
|
+
# Check if it's a thin strip spanning nearly the entire edge
|
|
134
|
+
# vertical strip is more likely to not be image artifact
|
|
135
|
+
is_thin_vertical_strip = (touches_top or touches_bottom and width < img_width * 0.2)
|
|
136
|
+
is_thin_horizontal_strip = (touches_left and touches_right and height < img_height * 0.2)
|
|
137
|
+
if is_thin_vertical_strip or is_thin_horizontal_strip or (width / height >= 10) or (height / width >= 10):
|
|
138
|
+
large_components[comp_id] = False
|
|
139
|
+
return large_components
|
|
90
140
|
|
|
91
141
|
@staticmethod
|
|
92
|
-
def crop_to_content(img, apply_content_crop):
|
|
93
|
-
"""Crop image to remove white space around content."""
|
|
142
|
+
def crop_to_content(img, apply_content_crop, stroke_threshold=200, min_component_size=10, filter_edge_artifacts=False):
|
|
143
|
+
"""Crop image to remove white space around content, ignoring small artifacts."""
|
|
94
144
|
if not apply_content_crop:
|
|
95
145
|
return img
|
|
96
146
|
|
|
97
147
|
arr = np.asarray(img)
|
|
98
|
-
|
|
148
|
+
img_width, img_height = img.size
|
|
149
|
+
# Create binary mask of non-white pixels
|
|
150
|
+
mask = np.all(arr < stroke_threshold, axis=2) if arr.ndim == 3 else arr < stroke_threshold
|
|
99
151
|
|
|
152
|
+
# Label connected components
|
|
153
|
+
labeled, num_features = ndimage.label(mask)
|
|
154
|
+
|
|
155
|
+
# Find component sizes
|
|
156
|
+
component_sizes = np.bincount(labeled.ravel())
|
|
157
|
+
# Component 0 is background, so start from 1
|
|
158
|
+
large_components = component_sizes >= min_component_size
|
|
159
|
+
large_components[0] = False # Don't include background
|
|
160
|
+
# Filter out edge artifacts (components that span entire width or height)
|
|
161
|
+
if filter_edge_artifacts:
|
|
162
|
+
large_components = ImageExtractor._filter_edge_artifacts(large_components, labeled, component_sizes, img_width, img_height)
|
|
163
|
+
|
|
164
|
+
# Create cleaned mask with only large components
|
|
165
|
+
cleaned_mask = large_components[labeled]
|
|
166
|
+
if arr.ndim == 3:
|
|
167
|
+
white_img = np.ones_like(arr) * 255
|
|
168
|
+
else:
|
|
169
|
+
white_img = np.ones_like(arr) * 255
|
|
170
|
+
|
|
171
|
+
# Copy only the content pixels (keep background white)
|
|
172
|
+
white_img[cleaned_mask] = arr[cleaned_mask]
|
|
173
|
+
img = Image.fromarray(white_img.astype(np.uint8))
|
|
100
174
|
try:
|
|
101
|
-
|
|
102
|
-
xub = max(cols) # right bound
|
|
175
|
+
rows, cols = np.where(cleaned_mask)
|
|
103
176
|
ylb = min(rows) # top bound
|
|
104
177
|
yub = max(rows) # bottom bound
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
178
|
+
xlb = min(cols) # left bound
|
|
179
|
+
xub = max(cols) # right bound
|
|
180
|
+
width = xub - xlb
|
|
181
|
+
height = yub - ylb
|
|
182
|
+
max_dim = max(width, height)
|
|
183
|
+
|
|
184
|
+
x_center = (xlb + xub) // 2
|
|
185
|
+
y_center = (ylb + yub) // 2
|
|
186
|
+
|
|
187
|
+
lb_x = x_center - max_dim // 2
|
|
188
|
+
ub_x = x_center + max_dim // 2
|
|
189
|
+
lb_y = y_center - max_dim // 2
|
|
190
|
+
ub_y = y_center + max_dim // 2
|
|
191
|
+
|
|
192
|
+
# Shift if out of bounds (to maintain square)
|
|
193
|
+
if lb_x < 0:
|
|
194
|
+
ub_x -= lb_x
|
|
195
|
+
lb_x = 0
|
|
196
|
+
if lb_y < 0:
|
|
197
|
+
ub_y -= lb_y
|
|
198
|
+
lb_y = 0
|
|
199
|
+
if ub_x > img.size[0]:
|
|
200
|
+
lb_x -= (ub_x - img.size[0])
|
|
201
|
+
ub_x = img.size[0]
|
|
202
|
+
if ub_y > img.size[1]:
|
|
203
|
+
lb_y -= (ub_y - img.size[1])
|
|
204
|
+
ub_y = img.size[1]
|
|
205
|
+
|
|
206
|
+
img = img.crop((lb_x, lb_y, ub_x, ub_y))
|
|
111
207
|
except ValueError:
|
|
112
208
|
print('Blank image - skipping crop')
|
|
113
209
|
return img
|
|
@@ -124,35 +220,38 @@ class ImageExtractor:
|
|
|
124
220
|
# Step 1: Apply thumbnail resizing if requested
|
|
125
221
|
if settings.use_thumbnail:
|
|
126
222
|
image.thumbnail((settings.resize_dim, settings.resize_dim), Image.Resampling.LANCZOS)
|
|
223
|
+
image.thumbnail((settings.crop_dim, settings.crop_dim), Image.Resampling.LANCZOS)
|
|
224
|
+
# Step 2: Convert RGBA to RGB
|
|
225
|
+
img_rgb = ImageExtractor.RGBA2RGB(image)
|
|
127
226
|
|
|
128
|
-
# Step
|
|
227
|
+
# Step 3: Normalize stroke thickness if enabled
|
|
228
|
+
if settings.normalize_stroke_thickness:
|
|
229
|
+
img_rgb = ImageExtractor.normalize_stroke_thickness(
|
|
230
|
+
img_rgb,
|
|
231
|
+
settings.stroke_target_thickness
|
|
232
|
+
)
|
|
233
|
+
# change stroke color if enabled
|
|
129
234
|
if settings.change_stroke_color:
|
|
130
|
-
|
|
131
|
-
|
|
235
|
+
img_rgb = ImageExtractor.change_stroke_color(
|
|
236
|
+
img_rgb,
|
|
132
237
|
settings.stroke_color,
|
|
133
238
|
settings.stroke_threshold
|
|
134
239
|
)
|
|
135
|
-
|
|
136
|
-
# Step 3: Convert RGBA to RGB
|
|
137
|
-
img_rgb = ImageExtractor.RGBA2RGB(image)
|
|
138
|
-
|
|
139
240
|
# Step 4: Crop to content (remove whitespace) if enabled
|
|
140
|
-
img_cropped = ImageExtractor.crop_to_content(img_rgb, settings.apply_content_crop)
|
|
241
|
+
img_cropped = ImageExtractor.crop_to_content(img_rgb, settings.apply_content_crop, settings.bg_threshold, settings.bg_component_size, settings.filter_edge_artifacts)
|
|
141
242
|
return img_cropped
|
|
142
243
|
|
|
143
244
|
# Build transformation pipeline
|
|
144
245
|
transform_list = []
|
|
145
|
-
|
|
246
|
+
if settings.apply_center_crop:
|
|
247
|
+
transform_list.append(transforms.CenterCrop(settings.crop_dim))
|
|
248
|
+
transform_list.append(transforms.Lambda(combined_transform))
|
|
249
|
+
|
|
146
250
|
# Only add regular resize if not using thumbnail
|
|
147
|
-
if not settings.use_thumbnail:
|
|
148
|
-
# resize
|
|
251
|
+
if not settings.use_thumbnail or settings.double_resize:
|
|
252
|
+
# resize last to ensure highest res
|
|
149
253
|
transform_list.append(transforms.Resize(settings.resize_dim))
|
|
150
254
|
|
|
151
|
-
transform_list.append(transforms.Lambda(combined_transform))
|
|
152
|
-
|
|
153
|
-
if settings.apply_center_crop:
|
|
154
|
-
transform_list.append(transforms.CenterCrop(settings.crop_dim))
|
|
155
|
-
|
|
156
255
|
# Add any additional transforms you might need
|
|
157
256
|
#transform_list.extend([
|
|
158
257
|
#transforms.ToTensor(),
|
|
@@ -210,17 +309,17 @@ class StimuliDataset(Dataset):
|
|
|
210
309
|
else:
|
|
211
310
|
with Image.open(image_path) as img:
|
|
212
311
|
img_copy = img.copy() # Copy the image data to memory
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
312
|
+
try:
|
|
313
|
+
if self.transform is not None:
|
|
314
|
+
img_copy = self.transform(img_copy)
|
|
315
|
+
else:
|
|
316
|
+
img_copy = img_copy.convert('RGB')
|
|
317
|
+
except Exception as e:
|
|
318
|
+
print(f"Warning: failed to process image {idx} ({e}); skipping transform.")
|
|
219
319
|
img_copy = img_copy.convert('RGB')
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
320
|
+
full_image_paths.append(image_path)
|
|
321
|
+
images.append(img_copy)
|
|
322
|
+
|
|
224
323
|
# just assuming the image path as an item id for now if there is more than one item per row.
|
|
225
324
|
# TODO: allow for the provision of both item ids and row ids
|
|
226
325
|
row_id = [row[self.id_column] if self.id_column is not None else random.randint(0, 1000000)]
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from transformers import pipeline
|
|
2
|
+
from vislearnlabpy.models.vision_model import VisionModel
|
|
3
|
+
from transformers import AutoImageProcessor, AutoModel
|
|
4
|
+
import torch
|
|
5
|
+
|
|
6
|
+
class DinoV3Generator(VisionModel):
|
|
7
|
+
def __init__(self, dataloader=None, device=None, text_prompt="a photo of a "):
|
|
8
|
+
self.pipe = pipeline(
|
|
9
|
+
task="image-feature-extraction",
|
|
10
|
+
model="facebook/dinov3-vits16-pretrain-lvd1689m",
|
|
11
|
+
dtype=torch.bfloat16,
|
|
12
|
+
)
|
|
13
|
+
self.model, self.preprocess = self.pipe.model, self.pipe.feature_extractor
|
|
14
|
+
super().__init__(self.model, self.preprocess, dataloader, device)
|
|
15
|
+
self.name = "dinov3"
|
|
16
|
+
|
|
17
|
+
def image_embeddings(self):
|
|
18
|
+
#
|
|
19
|
+
return
|
|
20
|
+
|
{vislearnlabpy-0.0.2.3 → vislearnlabpy-0.0.2.4}/src/vislearnlabpy/models/multimodal_model.py
RENAMED
|
@@ -75,42 +75,3 @@ class MultimodalModel(FeatureGenerator):
|
|
|
75
75
|
luce = distractor_similarity / (distractor_similarity + target_similarity)
|
|
76
76
|
return luce
|
|
77
77
|
|
|
78
|
-
def similarities(self, word1, word2, images):
|
|
79
|
-
valid_images = [img for img in images if img is not None]
|
|
80
|
-
similarity_scores = []
|
|
81
|
-
# TODO: this only returns the similarity scores for the first pair of images: need to separate out, indexing is weird
|
|
82
|
-
for image1, image2 in itertools.combinations(valid_images, 2):
|
|
83
|
-
curr_image_embeddings = self.image_embeddings([image1, image2])
|
|
84
|
-
curr_text_embeddings = self.text_embeddings([word1, word2])
|
|
85
|
-
# TODO: need to fix how each row is labeled in lookit_similarities,
|
|
86
|
-
similarity_scores.append({
|
|
87
|
-
'image_similarity': self.similarity(curr_image_embeddings[0], curr_image_embeddings[1]),
|
|
88
|
-
'text_similarity': self.similarity(curr_text_embeddings[0], curr_text_embeddings[1]),
|
|
89
|
-
# finding distractor image to target word similarity
|
|
90
|
-
'multimodal_similarity': self.text_to_images_similarity(curr_image_embeddings, curr_text_embeddings[0], logit_scale=10),
|
|
91
|
-
})
|
|
92
|
-
if similarity_scores == []:
|
|
93
|
-
print(f"skipping {word1} and {word2} since they do not have valid images")
|
|
94
|
-
return [{
|
|
95
|
-
'image_similarity': None,
|
|
96
|
-
'text_similarity': None,
|
|
97
|
-
'multimodal_similarity': None
|
|
98
|
-
}]
|
|
99
|
-
else:
|
|
100
|
-
return similarity_scores
|
|
101
|
-
|
|
102
|
-
# TODO: probably move this to the dataloader row level instead of to a pair of words within a dataloader row
|
|
103
|
-
# TODO: words or texts? what is my parameter
|
|
104
|
-
def embeddings(self, word1, word2, dataloader_row):
|
|
105
|
-
valid_images = [img for img in dataloader_row['images'] if img is not None]
|
|
106
|
-
output_embeddings = []
|
|
107
|
-
for image1, image2 in itertools.combinations(valid_images, 2):
|
|
108
|
-
curr_image_embeddings = self.image_embeddings([image1, image2])
|
|
109
|
-
curr_text_embeddings = self.text_embeddings([word1, word2])
|
|
110
|
-
output_embeddings.append({
|
|
111
|
-
'image_embeddings': curr_image_embeddings,
|
|
112
|
-
'text_embeddings': curr_text_embeddings,
|
|
113
|
-
'multimodal_embeddings': self.multimodal_embeddings(curr_image_embeddings, curr_text_embeddings)
|
|
114
|
-
})
|
|
115
|
-
return output_embeddings
|
|
116
|
-
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import itertools
|
|
2
|
+
from vislearnlabpy.models.feature_generator import FeatureGenerator
|
|
3
|
+
from vislearnlabpy.embeddings import utils
|
|
4
|
+
from torchvision import transforms
|
|
5
|
+
import torch
|
|
6
|
+
|
|
7
|
+
class VisionModel(FeatureGenerator):
|
|
8
|
+
"""Abstract base class for multimodal models like CLIP and CVCL that extends FeatureGenerator"""
|
|
9
|
+
|
|
10
|
+
def __init__(self, model, preprocess, dataloader=None, device=None):
|
|
11
|
+
super().__init__(model, preprocess, dataloader, device)
|
|
12
|
+
self.image_word_alignment = lambda **x: self.model(**x).logits_per_image.softmax(dim=-1).detach().cpu().numpy()
|
|
13
|
+
|
|
14
|
+
# Load and preprocess images
|
|
15
|
+
def preprocess_image(self, image):
|
|
16
|
+
if isinstance(image, torch.Tensor):
|
|
17
|
+
transform = transforms.ToPILImage()
|
|
18
|
+
image = transform(image)
|
|
19
|
+
return self.preprocess(image).unsqueeze(0).to(self.device)
|
|
20
|
+
|
|
21
|
+
def encode_image(self, image):
|
|
22
|
+
return self.model.encode_image(image)
|
|
23
|
+
|
|
24
|
+
def image_embeddings(self, images, normalize_embeddings=False):
|
|
25
|
+
"""Get image embeddings (batched for speed)"""
|
|
26
|
+
# Handle single image case
|
|
27
|
+
if not isinstance(images, list):
|
|
28
|
+
return self.image_embeddings([images], normalize_embeddings)[0]
|
|
29
|
+
# Preprocess all images → batch
|
|
30
|
+
preprocessed_images = [self.preprocess_image(image) for image in images]
|
|
31
|
+
preprocessed_images = [image.squeeze(0) if image.dim() == 4 else image for image in preprocessed_images]
|
|
32
|
+
# Stack into a single tensor batch (assuming tensors are returned)
|
|
33
|
+
image_batch = torch.stack(preprocessed_images).to(self.device)
|
|
34
|
+
with torch.no_grad():
|
|
35
|
+
embeddings = self.encode_image(image_batch) # model handles batch
|
|
36
|
+
if normalize_embeddings:
|
|
37
|
+
embeddings = utils.normalize_embeddings(embeddings)
|
|
38
|
+
return embeddings
|
|
39
|
+
|
|
40
|
+
# TODO: probably move this to the dataloader row level instead of to a pair of words within a dataloader row
|
|
41
|
+
# TODO: words or texts? what is my parameter
|
|
42
|
+
def embeddings(self, word1, word2, dataloader_row):
|
|
43
|
+
valid_images = [img for img in dataloader_row['images'] if img is not None]
|
|
44
|
+
output_embeddings = []
|
|
45
|
+
for image1, image2 in itertools.combinations(valid_images, 2):
|
|
46
|
+
curr_image_embeddings = self.image_embeddings([image1, image2])
|
|
47
|
+
curr_text_embeddings = self.text_embeddings([word1, word2])
|
|
48
|
+
output_embeddings.append({
|
|
49
|
+
'image_embeddings': curr_image_embeddings,
|
|
50
|
+
'text_embeddings': curr_text_embeddings,
|
|
51
|
+
'multimodal_embeddings': self.multimodal_embeddings(curr_image_embeddings, curr_text_embeddings)
|
|
52
|
+
})
|
|
53
|
+
return output_embeddings
|
|
54
|
+
|
|
@@ -18,5 +18,7 @@ src/vislearnlabpy/embeddings/utils.py
|
|
|
18
18
|
src/vislearnlabpy/extractions/drawingtask_extractor.py
|
|
19
19
|
src/vislearnlabpy/extractions/mongo_extractor.py
|
|
20
20
|
src/vislearnlabpy/models/clip_model.py
|
|
21
|
+
src/vislearnlabpy/models/dinov3_model.py
|
|
21
22
|
src/vislearnlabpy/models/feature_generator.py
|
|
22
|
-
src/vislearnlabpy/models/multimodal_model.py
|
|
23
|
+
src/vislearnlabpy/models/multimodal_model.py
|
|
24
|
+
src/vislearnlabpy/models/vision_model.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vislearnlabpy-0.0.2.3 → vislearnlabpy-0.0.2.4}/src/vislearnlabpy/drawings/svg_render_helpers.py
RENAMED
|
File without changes
|
{vislearnlabpy-0.0.2.3 → vislearnlabpy-0.0.2.4}/src/vislearnlabpy/embeddings/embedding_store.py
RENAMED
|
File without changes
|
{vislearnlabpy-0.0.2.3 → vislearnlabpy-0.0.2.4}/src/vislearnlabpy/embeddings/generate_embeddings.py
RENAMED
|
File without changes
|
{vislearnlabpy-0.0.2.3 → vislearnlabpy-0.0.2.4}/src/vislearnlabpy/embeddings/similarity_generator.py
RENAMED
|
File without changes
|
{vislearnlabpy-0.0.2.3 → vislearnlabpy-0.0.2.4}/src/vislearnlabpy/embeddings/similarity_utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vislearnlabpy-0.0.2.3 → vislearnlabpy-0.0.2.4}/src/vislearnlabpy/extractions/mongo_extractor.py
RENAMED
|
File without changes
|
|
File without changes
|
{vislearnlabpy-0.0.2.3 → vislearnlabpy-0.0.2.4}/src/vislearnlabpy/models/feature_generator.py
RENAMED
|
File without changes
|
{vislearnlabpy-0.0.2.3 → vislearnlabpy-0.0.2.4}/src/vislearnlabpy.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|