Aalpk commited on
Commit
3f2ab17
·
verified ·
1 Parent(s): f222085

Publish Trendyol DinoV2.1 ecommerce 256d (GeM run_12 epoch=09)

Browse files
LICENSE ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2025 Trendyol
2
+
3
+ This work, including the model weights and code, is licensed under the
4
+ Creative Commons Attribution-ShareAlike 4.0 International License.
5
+ A copy of the license is available at:
6
+ http://creativecommons.org/licenses/by-sa/4.0/
7
+ ================================================================================
8
+
9
+ ---
10
+
11
+ ### Human-Readable Summary of the License:
12
+
13
+ ---
14
+
15
+ This is a summary of the CC BY-SA 4.0 license and not a substitute for the full license text.
16
+ **You are free to:**
17
+
18
+ - **Share** — copy and redistribute the material in any medium or format for any purpose, even commercially.
19
+ - **Adapt** — remix, transform, and build upon the material for any purpose, even commercially.
20
+ The licensor cannot revoke these freedoms as long as you follow the license terms.
21
+ **Under the following terms:**
22
+ - **Attribution (BY)** — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
23
+ - **ShareAlike (SA)** — If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original.
24
+ - **No additional restrictions** — You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits.
25
+
26
+ ---
27
+
28
+ ### Attribution Requirements
29
+
30
+ ---
31
+
32
+ If you use this model or its derivatives, you must provide proper attribution. Please cite our work as follows:
33
+ "Trendyol DinoV2 Image Similarity Model, licensed under CC BY-SA 4.0. Available at: https://huggingface.co/Trendyol/trendyol-dino-v2-ecommerce-256d"
34
+
35
+ ---
36
+
37
+ ### Disclaimer of Warranty
38
+
39
+ ---
40
+
41
+ Unless required by applicable law or agreed to in writing, the Work is provided on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with your exercise of permissions under this License.
README.md ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ language:
3
+ - en
4
+ license: cc-by-sa-4.0
5
+ library_name: transformers
6
+ tags:
7
+ - image-similarity
8
+ - image-retrieval
9
+ - computer-vision
10
+ - e-commerce
11
+ - dinov2
12
+ - gem-pooling
13
+ - pytorch
14
+ - safetensors
15
+ datasets:
16
+ - e-commerce-product-images
17
+ pipeline_tag: feature-extraction
18
+ base_model: Trendyol/trendyol-dino-v2-ecommerce-256d
19
+ ---
20
+
21
+ # Trendyol DinoV2.1 Image Similarity Model
22
+
23
+ Fine-tuned DinoV2 (ViT-B/14) with **GeM pooling** for e-commerce product image retrieval.
24
+ This is the successor to [`Trendyol/trendyol-dino-v2-ecommerce-256d`](https://huggingface.co/Trendyol/trendyol-dino-v2-ecommerce-256d).
25
+
26
+ ## Model Details
27
+
28
+ - **Model Type**: Image Similarity / Retrieval
29
+ - **Architecture**: DinoV2 ViT-B/14 + GeM pooling + linear projection (ArcFace-trained)
30
+ - **Embedding Dimension**: 256
31
+ - **Input Size**: 224×224
32
+ - **Checkpoint**: `ray-dinov2-full_catalog_1000_20-pfc-gem-mlp-run_12` epoch **09**
33
+ - **Framework**: PyTorch / SafeTensors
34
+
35
+ ## What's new vs v2
36
+
37
+ | | v2 | **v2.1** |
38
+ |---|---|---|
39
+ | Pooling / head | Flatten spatial tokens → Linear(196608→256) | **GeM** → Linear(768→256) |
40
+ | Training data | full_catalog_300_20 style | **full_catalog_1000_20** |
41
+ | Preprocess | Lanczos/JPEG/332 pad pipeline | Scale+pad to 224 (training inference preprocess) |
42
+
43
+ ## Quick Start
44
+
45
+ ```python
46
+ import torch
47
+ from PIL import Image
48
+ from transformers import AutoModel, AutoImageProcessor
49
+
50
+ device = "cuda" if torch.cuda.is_available() else "cpu"
51
+ repo = "Trendyol/trendyol-dino-v2.1-ecommerce-256d"
52
+
53
+ processor = AutoImageProcessor.from_pretrained(repo, trust_remote_code=True)
54
+ model = AutoModel.from_pretrained(repo, trust_remote_code=True).to(device).eval()
55
+
56
+ image = Image.open("your_image.jpg").convert("RGB")
57
+ inputs = processor(images=image, return_tensors="pt")
58
+ inputs = {k: v.to(device) for k, v in inputs.items()}
59
+
60
+ with torch.no_grad():
61
+ embeddings = model(**inputs).last_hidden_state # [1, 256]
62
+
63
+ print(embeddings.shape)
64
+ ```
65
+
66
+ ## Preprocessing Pipeline
67
+
68
+ 1. **ScaleImage**: resize so max side = 224 (keep aspect ratio)
69
+ 2. **PadToSquare**: pad with color 255
70
+ 3. **Resize**: 224×224
71
+ 4. **ToTensor** + **ImageNet Normalize** (mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
72
+
73
+ ## Installation
74
+
75
+ ```bash
76
+ pip install transformers torch torchvision safetensors pillow numpy
77
+ ```
78
+
79
+ ## Intended Use
80
+
81
+ - Product image similarity search
82
+ - Visual recommendations / duplicate detection
83
+ - Content-based retrieval in e-commerce
84
+
85
+ ## Limitations
86
+
87
+ - Optimized for product / e-commerce images
88
+ - Requires `trust_remote_code=True`
89
+ - Classification heads from training are **not** included in this Hub export (embeddings only)
90
+
91
+ ## License
92
+
93
+ See [LICENSE](LICENSE). Same terms as the v2 release: source-available; commercial use requires attribution and prior notification to Trendyol (`scr.datascience@trendyol.com`).
94
+
95
+ ## Citation
96
+
97
+ ```
98
+ @misc{trendyol-dinov2-ecommerce-v21,
99
+ title={Trendyol DinoV2.1 E-commerce Image Similarity Model},
100
+ author={Trendyol Data Science Team},
101
+ year={2026},
102
+ url={https://huggingface.co/Trendyol/trendyol-dino-v2.1-ecommerce-256d}
103
+ }
104
+ ```
__init__.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Trendyol DinoV2.1 Image Similarity Model (GeM)
3
+
4
+ Hugging Face transformers-compatible package.
5
+ """
6
+
7
+ from transformers import AutoConfig, AutoImageProcessor, AutoModel
8
+
9
+ from .image_processing_trendyol_dinov2_v21 import TrendyolDinoV21ImageProcessor
10
+ from .modeling_trendyol_dinov2_v21 import TrendyolDinoV21Config, TrendyolDinoV21Model
11
+
12
+ AutoConfig.register("trendyol_dinov2_v21", TrendyolDinoV21Config)
13
+ AutoModel.register(TrendyolDinoV21Config, TrendyolDinoV21Model)
14
+ AutoImageProcessor.register(TrendyolDinoV21Config, TrendyolDinoV21ImageProcessor)
15
+
16
+ __version__ = "2.1.0"
17
+ __all__ = [
18
+ "TrendyolDinoV21Model",
19
+ "TrendyolDinoV21Config",
20
+ "TrendyolDinoV21ImageProcessor",
21
+ ]
config.json ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model_type": "trendyol_dinov2_v21",
3
+ "architectures": [
4
+ "TrendyolDinoV21Model"
5
+ ],
6
+ "auto_map": {
7
+ "AutoConfig": "modeling_trendyol_dinov2_v21.TrendyolDinoV21Config",
8
+ "AutoModel": "modeling_trendyol_dinov2_v21.TrendyolDinoV21Model",
9
+ "AutoImageProcessor": "image_processing_trendyol_dinov2_v21.TrendyolDinoV21ImageProcessor"
10
+ },
11
+ "backbone_name": "dinov2_vitb14",
12
+ "embedding_dim": 256,
13
+ "hidden_size": 256,
14
+ "in_features": 768,
15
+ "gem_p": 2.9,
16
+ "dropout": 0.3,
17
+ "input_size": 224,
18
+ "pad_color": 255,
19
+ "pooling": "GeM",
20
+ "normalization": {
21
+ "mean": [0.485, 0.456, 0.406],
22
+ "std": [0.229, 0.224, 0.225]
23
+ },
24
+ "preprocessing": {
25
+ "input_size": 224,
26
+ "pad_color": 255,
27
+ "transforms": [
28
+ "ScaleImage",
29
+ "PadToSquare",
30
+ "Resize",
31
+ "ToTensor",
32
+ "Normalize"
33
+ ]
34
+ },
35
+ "task_type": "image-retrieval",
36
+ "training_info": {
37
+ "experiment": "ray-dinov2-full_catalog_1000_20-pfc-gem-mlp-run_12",
38
+ "epoch": "9",
39
+ "dataset": "full_catalog_1000_20",
40
+ "torch_version": "2.8.0"
41
+ },
42
+ "torch_dtype": "float32",
43
+ "transformers_version": "4.20.0"
44
+ }
image_processing_trendyol_dinov2_v21.py ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Hugging Face image processor for Trendyol DinoV2.1 (GeM).
3
+
4
+ Matches training/inference preprocess used by SimilarityInferenceModel /
5
+ dino_v2_gem.Preprocessor: scale-to-max(224), pad-to-square(255), resize 224,
6
+ ImageNet normalize. (No JPEG / 332 downscale stage.)
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from typing import List, Optional, Union
12
+
13
+ import numpy as np
14
+ import torch
15
+ from PIL import Image
16
+ from torchvision import transforms
17
+ from torchvision.transforms import functional as TF
18
+ from transformers import BatchFeature, ImageProcessingMixin
19
+ from transformers.utils import TensorType
20
+
21
+
22
+ def resize_keep_ratio(img: Image.Image, size: int) -> Image.Image:
23
+ w, h = img.size
24
+ max_size = max(h, w)
25
+ scale = size / max_size
26
+ new_size = int(w * scale), int(h * scale)
27
+ return img.resize(new_size, Image.BILINEAR)
28
+
29
+
30
+ class ScaleImage:
31
+ def __init__(self, target_size: int):
32
+ self.target_size = target_size
33
+
34
+ def __call__(self, img: Image.Image) -> Image.Image:
35
+ return resize_keep_ratio(img, self.target_size)
36
+
37
+
38
+ class PadToSquare:
39
+ def __init__(self, color: int = 255):
40
+ self.color = color
41
+
42
+ def __call__(self, img: Image.Image) -> Image.Image:
43
+ width, height = img.size
44
+ padding = abs(width - height) // 2
45
+ if width < height:
46
+ return TF.pad(
47
+ img,
48
+ (padding, 0, padding + (height - width) % 2, 0),
49
+ fill=self.color,
50
+ padding_mode="constant",
51
+ )
52
+ if width > height:
53
+ return TF.pad(
54
+ img,
55
+ (0, padding, 0, padding + (width - height) % 2),
56
+ fill=self.color,
57
+ padding_mode="constant",
58
+ )
59
+ return img
60
+
61
+
62
+ class TrendyolDinoV21ImageProcessor(ImageProcessingMixin):
63
+ model_input_names = ["pixel_values"]
64
+
65
+ def __init__(
66
+ self,
67
+ input_size: int = 224,
68
+ pad_color: int = 255,
69
+ do_normalize: bool = True,
70
+ image_mean=(0.485, 0.456, 0.406),
71
+ image_std=(0.229, 0.224, 0.225),
72
+ **kwargs,
73
+ ):
74
+ super().__init__(**kwargs)
75
+ self.input_size = input_size
76
+ self.pad_color = pad_color
77
+ self.do_normalize = do_normalize
78
+ self.image_mean = list(image_mean)
79
+ self.image_std = list(image_std)
80
+
81
+ def _get_preprocess_fn(self):
82
+ steps = [
83
+ ScaleImage(self.input_size),
84
+ PadToSquare(self.pad_color),
85
+ transforms.Resize((self.input_size, self.input_size)),
86
+ transforms.ToTensor(),
87
+ ]
88
+ if self.do_normalize:
89
+ steps.append(transforms.Normalize(self.image_mean, self.image_std))
90
+ return transforms.Compose(steps)
91
+
92
+ def __call__(
93
+ self,
94
+ images: Union[Image.Image, np.ndarray, List],
95
+ return_tensors: Optional[Union[str, TensorType]] = None,
96
+ **kwargs,
97
+ ) -> BatchFeature:
98
+ if not isinstance(images, list):
99
+ images = [images]
100
+ preprocess_fn = self._get_preprocess_fn()
101
+ processed = []
102
+ for image in images:
103
+ if isinstance(image, str):
104
+ image = Image.open(image).convert("RGB")
105
+ elif isinstance(image, np.ndarray):
106
+ image = Image.fromarray(image).convert("RGB")
107
+ elif not isinstance(image, Image.Image):
108
+ raise ValueError(f"Unsupported image type: {type(image)}")
109
+ else:
110
+ image = image.convert("RGB")
111
+ processed.append(preprocess_fn(image))
112
+ data = {"pixel_values": torch.stack(processed)}
113
+ return BatchFeature(data=data, tensor_type=return_tensors)
114
+
115
+
116
+ TrendyolDinoV21ImageProcessor.register_for_auto_class("AutoImageProcessor")
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5ba54402e876cd9b0461f8d203771ae8b576123e9501f2165ff7b73ab69e81ce
3
+ size 347132884
modeling_trendyol_dinov2_v21.py ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Hugging Face compatible model for Trendyol DinoV2.1 (GeM pooling).
3
+
4
+ Checkpoint source:
5
+ ray-dinov2-full_catalog_1000_20-pfc-gem-mlp-run_12 / epoch=09
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from typing import Optional
11
+
12
+ import torch
13
+ import torch.nn as nn
14
+ import torch.nn.functional as F
15
+ from transformers import PretrainedConfig, PreTrainedModel
16
+ from transformers.modeling_outputs import BaseModelOutput
17
+
18
+
19
+ class TrendyolDinoV21Config(PretrainedConfig):
20
+ model_type = "trendyol_dinov2_v21"
21
+
22
+ def __init__(
23
+ self,
24
+ embedding_dim: int = 256,
25
+ input_size: int = 224,
26
+ backbone_name: str = "dinov2_vitb14",
27
+ in_features: int = 768,
28
+ gem_p: float = 2.9,
29
+ dropout: float = 0.3,
30
+ pad_color: int = 255,
31
+ **kwargs,
32
+ ):
33
+ super().__init__(**kwargs)
34
+ self.embedding_dim = embedding_dim
35
+ self.input_size = input_size
36
+ self.backbone_name = backbone_name
37
+ self.in_features = in_features
38
+ self.gem_p = gem_p
39
+ self.dropout = dropout
40
+ self.pad_color = pad_color
41
+ self.hidden_size = embedding_dim
42
+
43
+
44
+ class GeM(nn.Module):
45
+ def __init__(self, p: float = 2.9, eps: float = 1e-6):
46
+ super().__init__()
47
+ self.register_buffer("p", torch.tensor(float(p)))
48
+ self.eps = eps
49
+
50
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
51
+ x = x.clamp(min=self.eps).pow(self.p)
52
+ x = F.adaptive_avg_pool2d(x, (1, 1))
53
+ x = x.pow(1.0 / self.p)
54
+ return x.squeeze(-1).squeeze(-1)
55
+
56
+
57
+ class DinoV2Backbone(nn.Module):
58
+ """Matches training ``Backbone`` wrapper: ``self.model = hub dinov2``."""
59
+
60
+ def __init__(self, backbone_name: str = "dinov2_vitb14"):
61
+ super().__init__()
62
+ try:
63
+ self.model = torch.hub.load("facebookresearch/dinov2", backbone_name)
64
+ except Exception as exc: # noqa: BLE001
65
+ raise RuntimeError(f"Failed to load DinoV2 backbone: {exc}") from exc
66
+ self.model.requires_grad_(False)
67
+
68
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
69
+ features = self.model.get_intermediate_layers(
70
+ x, return_class_token=True, reshape=True
71
+ )
72
+ return features[0][0]
73
+
74
+
75
+ class TYGeMDinoV2(nn.Module):
76
+ """Core GeM retrieval trunk used in run_12 (embeddings only)."""
77
+
78
+ def __init__(self, config: TrendyolDinoV21Config):
79
+ super().__init__()
80
+ self.config = config
81
+ self.backbone = DinoV2Backbone(config.backbone_name)
82
+ self.pooling = GeM(p=config.gem_p)
83
+ self.feature = nn.Sequential(
84
+ nn.Linear(config.in_features, config.embedding_dim, bias=False),
85
+ nn.BatchNorm1d(config.embedding_dim),
86
+ nn.Dropout(config.dropout),
87
+ )
88
+
89
+ def forward(self, pixel_values: torch.Tensor) -> torch.Tensor:
90
+ feats = self.backbone(pixel_values)
91
+ feats = self.pooling(feats)
92
+ feats = self.feature(feats)
93
+ return F.normalize(feats, p=2, dim=1)
94
+
95
+
96
+ class TrendyolDinoV21Model(PreTrainedModel):
97
+ config_class = TrendyolDinoV21Config
98
+ base_model_prefix = "model"
99
+
100
+ def __init__(self, config: TrendyolDinoV21Config):
101
+ super().__init__(config)
102
+ self.model = TYGeMDinoV2(config)
103
+ self.post_init()
104
+
105
+ @classmethod
106
+ def from_pretrained(cls, pretrained_model_name_or_path, *model_args, **kwargs):
107
+ # torch.hub DinoV2 backbone is incompatible with meta-device init.
108
+ kwargs.setdefault("low_cpu_mem_usage", False)
109
+ return super().from_pretrained(pretrained_model_name_or_path, *model_args, **kwargs)
110
+
111
+ def forward(
112
+ self,
113
+ pixel_values: Optional[torch.Tensor] = None,
114
+ return_dict: Optional[bool] = None,
115
+ **kwargs,
116
+ ):
117
+ return_dict = return_dict if return_dict is not None else self.config.use_return_dict
118
+ if pixel_values is None:
119
+ raise ValueError("pixel_values cannot be None")
120
+
121
+ embeddings = self.model(pixel_values)
122
+ if not return_dict:
123
+ return (embeddings,)
124
+ return BaseModelOutput(
125
+ last_hidden_state=embeddings,
126
+ hidden_states=None,
127
+ attentions=None,
128
+ )
129
+
130
+ def get_embeddings(self, pixel_values: torch.Tensor) -> torch.Tensor:
131
+ with torch.no_grad():
132
+ return self.forward(pixel_values, return_dict=True).last_hidden_state
133
+
134
+
135
+ TrendyolDinoV21Config.register_for_auto_class()
136
+ TrendyolDinoV21Model.register_for_auto_class("AutoModel")
preprocessor_config.json ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "image_processor_type": "TrendyolDinoV21ImageProcessor",
3
+ "processor_class": "TrendyolDinoV21ImageProcessor",
4
+ "auto_map": {
5
+ "AutoImageProcessor": "image_processing_trendyol_dinov2_v21.TrendyolDinoV21ImageProcessor"
6
+ },
7
+ "input_size": 224,
8
+ "pad_color": 255,
9
+ "do_normalize": true,
10
+ "image_mean": [0.485, 0.456, 0.406],
11
+ "image_std": [0.229, 0.224, 0.225],
12
+ "do_resize": true,
13
+ "size": {"height": 224, "width": 224},
14
+ "do_convert_rgb": true,
15
+ "transforms": [
16
+ "ScaleImage",
17
+ "PadToSquare",
18
+ "Resize",
19
+ "ToTensor",
20
+ "Normalize"
21
+ ]
22
+ }
pytorch_model.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:aa2daa2b961dbb6bdb3825b38deb43bfbbf8429b51cae0bf078d3bc7552eda4f
3
+ size 347171771
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ torch>=1.9.0
2
+ torchvision>=0.10.0
3
+ safetensors>=0.3.0
4
+ Pillow>=8.0.0
5
+ numpy>=1.20.0
6
+ opencv-python>=4.5.0
7
+ transformers>=4.20.0