louis JULIEN commited on
Commit
26cab2b
·
1 Parent(s): 1da1e59

model and first documentation

Browse files
.gitattributes CHANGED
@@ -23,6 +23,7 @@
23
  *.pth filter=lfs diff=lfs merge=lfs -text
24
  *.rar filter=lfs diff=lfs merge=lfs -text
25
  *.safetensors filter=lfs diff=lfs merge=lfs -text
 
26
  saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
  *.tar.* filter=lfs diff=lfs merge=lfs -text
28
  *.tar filter=lfs diff=lfs merge=lfs -text
@@ -33,3 +34,6 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
23
  *.pth filter=lfs diff=lfs merge=lfs -text
24
  *.rar filter=lfs diff=lfs merge=lfs -text
25
  *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ *.pt filter=lfs diff=lfs merge=lfs -text
27
  saved_model/**/* filter=lfs diff=lfs merge=lfs -text
28
  *.tar.* filter=lfs diff=lfs merge=lfs -text
29
  *.tar filter=lfs diff=lfs merge=lfs -text
 
34
  *.zip filter=lfs diff=lfs merge=lfs -text
35
  *.zst filter=lfs diff=lfs merge=lfs -text
36
  *tfevents* filter=lfs diff=lfs merge=lfs -text
37
+ src/shared/model_scripted.pt filter=lfs diff=lfs merge=lfs -text
38
+ images/** filter=lfs diff=lfs merge=lfs -text
39
+ src/assets/** filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ dataset
2
+ venv
3
+ .env
4
+ savepoints
README.md CHANGED
@@ -1,3 +1,34 @@
1
- ---
2
- license: mit
3
- ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## Purpose
2
+ This very lightweight model recognizes clothes pictures stance.
3
+
4
+ ![result-first-hand.png](images/result-first-hand.png)
5
+ ![result-second-hand-1.png](images/result-second-hand-1.png)
6
+ ![result-second-hand-2.png](images/result-second-hand-2.png)
7
+
8
+ This model classifies clothes picture based on their stance. It can recognize picture of the front, back, label, close up and
9
+ more. It is not perfectly accurate on the recognized stance but is perfect to sort pictures consistently e.g. front first,
10
+ back second, third closeup and label last.
11
+
12
+ It has been trained on a dataset made up of 50% commercial studio pictures (from Fashionpedia) and 50% second hand (
13
+ =amateur) pictures.
14
+
15
+ The base model is `nvidia_efficientnet_b0` that has been retrained using pytorch. You can see the training
16
+ parameters [here](src/neural-network-transfer-learning.ipynb).
17
+
18
+ As the base model is super small (5.2M parameters), it runs fast on CPU and with a very small memory footprint. It also
19
+ runs blazing fast on GPU. CUDA is not required to run the model.
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ pip install -r requirements.txt
25
+ ```
26
+
27
+ ## Usage
28
+
29
+ See [use-example.ipynb](src/use-example.ipynb)
30
+
31
+ # Dataset
32
+
33
+ The dataset has been curated by hand. For any enquiry about the training
34
+ dataset, [contact me](https://www.linkedin.com/in/louisjulien95).
images/confusion-matrix.png ADDED

Git LFS Details

  • SHA256: c7347091f8671b1b3c2a49474e72e0aab22b27d00f465e0610f76d0892b72412
  • Pointer size: 130 Bytes
  • Size of remote file: 37.9 kB
images/dataset.png ADDED

Git LFS Details

  • SHA256: f5dcb8b44ffe5aa8202729baa6b03175e93dbee6d94fb67854a64ceeffa0c6e6
  • Pointer size: 130 Bytes
  • Size of remote file: 12.1 kB
images/result-first-hand.png ADDED

Git LFS Details

  • SHA256: 3ca80a0184691d5b2efbe40f8eeb96a392e02daf368a8bf305eca13b27e1a821
  • Pointer size: 131 Bytes
  • Size of remote file: 296 kB
images/result-second-hand-1.png ADDED

Git LFS Details

  • SHA256: d5d57ebc83469e9b8e81f913173771e1ea3607b6aadcd2a343bdc08adca9c0b5
  • Pointer size: 131 Bytes
  • Size of remote file: 420 kB
images/result-second-hand-2.png ADDED

Git LFS Details

  • SHA256: f659059979f41a5673cae87fdd696a889514c0f2d85a63c38c737e4d23aa2e33
  • Pointer size: 131 Bytes
  • Size of remote file: 482 kB
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ numpy==1.26.4
2
+ requests==2.31.0
3
+ matplotlib==3.8.2
4
+ Pillow==10.3.0
5
+ torchvision==0.18.1
6
+ torch==2.3.1
7
+
8
+ scipy==1.16.3
9
+ notebook==7.4.7
src/assets/dress-drm-free/1.jpeg ADDED

Git LFS Details

  • SHA256: a8d374bac2f4dd14a0594fb25f690bb1d876a7b57d8472f625c784606e03cd8c
  • Pointer size: 131 Bytes
  • Size of remote file: 231 kB
src/assets/dress-drm-free/2.jpeg ADDED

Git LFS Details

  • SHA256: 7a5fefc4c98842d7782c2579002612282e6b59cf3d32f71484d573ecc4a47da7
  • Pointer size: 131 Bytes
  • Size of remote file: 211 kB
src/assets/dress-drm-free/3.jpeg ADDED

Git LFS Details

  • SHA256: 4613b0f0caad286f1329fb5fbdeebc2b910dcbf6846cdd8d7dda4810ed3bd75c
  • Pointer size: 131 Bytes
  • Size of remote file: 200 kB
src/assets/dress-drm-free/4.jpeg ADDED

Git LFS Details

  • SHA256: ea37e38eef705def3f4be55f01968e0ac87ee511568572dcdae9d1ee8992223c
  • Pointer size: 131 Bytes
  • Size of remote file: 394 kB
src/assets/label-difficult/1.jpeg ADDED

Git LFS Details

  • SHA256: ffab375cdd6599b27a467a6fa2a0cc5ff85983967631e9f3f0ea8fd427d7afdf
  • Pointer size: 131 Bytes
  • Size of remote file: 136 kB
src/assets/label-difficult/2.jpeg ADDED

Git LFS Details

  • SHA256: 48e8be11ea5a28395b3f1d756c045796096b8bd2eee6495409c83d2800acd70d
  • Pointer size: 131 Bytes
  • Size of remote file: 142 kB
src/assets/label-difficult/3.jpeg ADDED

Git LFS Details

  • SHA256: 41b5b2db833f711c6259bb75a30e6b19a103dc5705b149ceef26db0c4339df66
  • Pointer size: 131 Bytes
  • Size of remote file: 176 kB
src/assets/label-difficult/4.jpeg ADDED

Git LFS Details

  • SHA256: b32674f692f698747d8401280c883ebf4c31f8b73968cdcb81d70b48394d02bd
  • Pointer size: 131 Bytes
  • Size of remote file: 131 kB
src/assets/label-difficult/5.jpeg ADDED

Git LFS Details

  • SHA256: f301477871db384c527b6b9416e023b4d97ab05a2ff31864a13d2def6a0a0555
  • Pointer size: 131 Bytes
  • Size of remote file: 143 kB
src/assets/saint-james-coat/1.jpeg ADDED

Git LFS Details

  • SHA256: 40010063fac2563e501ffcb7feeec214b10903d6932999fe7cdc3eaa658389ab
  • Pointer size: 132 Bytes
  • Size of remote file: 1.35 MB
src/assets/saint-james-coat/2.jpeg ADDED

Git LFS Details

  • SHA256: f5825890c32e9b3028161b125e4d1420562838474abd7bd9c39edbbdeed3d35e
  • Pointer size: 132 Bytes
  • Size of remote file: 1.4 MB
src/assets/saint-james-coat/3.jpeg ADDED

Git LFS Details

  • SHA256: 67d4e30ebb9ee2d4ec73e8feb8bdfd54fb8d3b3ac6ff57ffad5c72ac346f0c58
  • Pointer size: 132 Bytes
  • Size of remote file: 4.48 MB
src/assets/saint-james-coat/4.jpeg ADDED

Git LFS Details

  • SHA256: 5b1887374be5478aa1c5857b9267bd19b9be902024e3f36d634185d5acfd5caf
  • Pointer size: 132 Bytes
  • Size of remote file: 3.28 MB
src/assets/saint-james-coat/5.jpeg ADDED

Git LFS Details

  • SHA256: 623732a5d03c1fb1d81db2d63b8e3c0705eb0e14eccff140b950c6f5170a7a33
  • Pointer size: 132 Bytes
  • Size of remote file: 1.06 MB
src/neural-network-transfer-learning.ipynb ADDED
@@ -0,0 +1,448 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "outputs": [],
6
+ "source": [
7
+ "import json\n",
8
+ "\n",
9
+ "import torch\n",
10
+ "import torch.nn as nn\n",
11
+ "from torchvision import datasets, transforms\n",
12
+ "from torchvision.transforms import v2\n",
13
+ "from torch.utils.data import DataLoader\n",
14
+ "from matplotlib import colors\n",
15
+ "import numpy as np\n",
16
+ "import matplotlib.pyplot as plt\n",
17
+ "\n",
18
+ "# Define transformation for both training and validation data\n",
19
+ "transform = transforms.Compose([\n",
20
+ " transforms.Resize((256, 256)),\n",
21
+ " transforms.ToTensor(),\n",
22
+ " v2.RandomHorizontalFlip(p=0.5),\n",
23
+ " v2.ColorJitter(brightness=.4, hue=.1),\n",
24
+ " v2.RandomPerspective(distortion_scale=0.05, p=1.0),\n",
25
+ " v2.RandomRotation(degrees=(-5, 5)),\n",
26
+ " v2.GaussianBlur(kernel_size=(5, 9), sigma=(0.1, 3.)),\n",
27
+ " transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),\n",
28
+ "])\n",
29
+ "\n",
30
+ "# Load the dataset\n",
31
+ "full_dataset = datasets.ImageFolder(\n",
32
+ " './dataset/dataset-clothes-pictures-stance-v3-labeled-80k',\n",
33
+ " transform=transform)\n",
34
+ "\n",
35
+ "random_generator = torch.Generator().manual_seed(12)\n",
36
+ "train_data, validation_data = torch.utils.data.random_split(full_dataset, [0.9, 0.1], generator=random_generator)\n",
37
+ "\n",
38
+ "# Create data loaders\n",
39
+ "train_loader = DataLoader(train_data, batch_size=32, shuffle=True, num_workers=12, pin_memory=True)\n",
40
+ "validation_loader = DataLoader(validation_data, batch_size=320, shuffle=False, num_workers=12, pin_memory=True)"
41
+ ],
42
+ "metadata": {
43
+ "collapsed": false,
44
+ "ExecuteTime": {
45
+ "end_time": "2024-03-30T13:58:01.023179Z",
46
+ "start_time": "2024-03-30T13:57:58.929471Z"
47
+ }
48
+ },
49
+ "id": "15c69cabd27e8626",
50
+ "execution_count": 1
51
+ },
52
+ {
53
+ "cell_type": "code",
54
+ "outputs": [
55
+ {
56
+ "data": {
57
+ "text/plain": "['back',\n 'closeup',\n 'front',\n 'inside',\n 'label',\n 'others',\n 'side_view',\n 'three_fourth']"
58
+ },
59
+ "execution_count": 2,
60
+ "metadata": {},
61
+ "output_type": "execute_result"
62
+ }
63
+ ],
64
+ "source": [
65
+ "full_dataset.classes"
66
+ ],
67
+ "metadata": {
68
+ "collapsed": false,
69
+ "ExecuteTime": {
70
+ "end_time": "2024-03-30T13:58:01.026979Z",
71
+ "start_time": "2024-03-30T13:58:01.024125Z"
72
+ }
73
+ },
74
+ "id": "bd76ca75c01f278b",
75
+ "execution_count": 2
76
+ },
77
+ {
78
+ "metadata": {},
79
+ "cell_type": "markdown",
80
+ "source": [
81
+ "# Dataset\n",
82
+ "**Number of image per label**<br/>\n",
83
+ "back: 19587<br/>\n",
84
+ "closeup: 8292<br/>\n",
85
+ "front: 35042<br/>\n",
86
+ "inside: 245<br/>\n",
87
+ "label: 6869<br/>\n",
88
+ "others: 231<br/>\n",
89
+ "side_view: 9000<br/>\n",
90
+ "three_fourth: 3002<br/>"
91
+ ],
92
+ "id": "9be4e2d2cef9ffd2"
93
+ },
94
+ {
95
+ "cell_type": "code",
96
+ "outputs": [
97
+ {
98
+ "data": {
99
+ "text/plain": "Counter({'front': 31530,\n 'back': 17592,\n 'side_view': 8116,\n 'closeup': 7456,\n 'label': 6196,\n 'three_fourth': 2700,\n 'inside': 221,\n 'others': 205})"
100
+ },
101
+ "execution_count": 3,
102
+ "metadata": {},
103
+ "output_type": "execute_result"
104
+ }
105
+ ],
106
+ "source": [
107
+ "from collections import Counter\n",
108
+ "\n",
109
+ "train_classes = [full_dataset.classes[full_dataset.targets[i]] for i in train_data.indices]\n",
110
+ "Counter(train_classes)"
111
+ ],
112
+ "metadata": {
113
+ "collapsed": false,
114
+ "ExecuteTime": {
115
+ "end_time": "2024-03-30T13:58:03.288969Z",
116
+ "start_time": "2024-03-30T13:58:03.282046Z"
117
+ }
118
+ },
119
+ "id": "b03df8d708a8de9c",
120
+ "execution_count": 3
121
+ },
122
+ {
123
+ "cell_type": "code",
124
+ "outputs": [],
125
+ "source": [
126
+ "neural_network_model = torch.hub.load('NVIDIA/DeepLearningExamples:torchhub', 'nvidia_efficientnet_b0', pretrained=True)\n",
127
+ "\n",
128
+ "for param in neural_network_model.parameters():\n",
129
+ " param.requires_grad = False\n",
130
+ "\n",
131
+ "# Modify the fully connected layer to match the number of classes in your dataset\n",
132
+ "num_classes = len(full_dataset.classes)\n",
133
+ "num_ftrs = neural_network_model.classifier.fc.in_features\n",
134
+ "\n",
135
+ "neural_network_model.classifier.fc = nn.Sequential(\n",
136
+ " nn.Linear(num_ftrs, num_classes),\n",
137
+ " nn.Linear(num_classes, num_classes)\n",
138
+ ")\n",
139
+ "initial_model_hash = hash(neural_network_model)\n",
140
+ "print(f'{initial_model_hash=}')"
141
+ ],
142
+ "metadata": {
143
+ "collapsed": false
144
+ },
145
+ "id": "92566906437e3e85",
146
+ "execution_count": null
147
+ },
148
+ {
149
+ "cell_type": "code",
150
+ "outputs": [],
151
+ "source": [
152
+ "cross_entropy_criterion = nn.CrossEntropyLoss()\n",
153
+ "fine_tuning_optimizer = torch.optim.RMSprop(filter(lambda p: p.requires_grad, neural_network_model.parameters()), lr=0.001)"
154
+ ],
155
+ "metadata": {
156
+ "collapsed": false,
157
+ "ExecuteTime": {
158
+ "end_time": "2024-03-30T13:58:18.635149Z",
159
+ "start_time": "2024-03-30T13:58:18.632188Z"
160
+ }
161
+ },
162
+ "id": "3f67806429de0fd2",
163
+ "execution_count": 6
164
+ },
165
+ {
166
+ "cell_type": "code",
167
+ "outputs": [],
168
+ "source": [
169
+ "for param in neural_network_model.parameters():\n",
170
+ " param.requires_grad = True\n",
171
+ "initial_model_hash = str(hash(neural_network_model)) + '_finetunning'"
172
+ ],
173
+ "metadata": {
174
+ "collapsed": false,
175
+ "ExecuteTime": {
176
+ "end_time": "2024-03-30T13:58:20.386435Z",
177
+ "start_time": "2024-03-30T13:58:20.383879Z"
178
+ }
179
+ },
180
+ "id": "7afd92b44f465364",
181
+ "execution_count": 7
182
+ },
183
+ {
184
+ "cell_type": "code",
185
+ "outputs": [],
186
+ "source": [
187
+ "def train_model(model, criterion, optimizer, num_epochs=10):\n",
188
+ " for epoch in range(num_epochs):\n",
189
+ " model.train()\n",
190
+ " running_loss = 0.0\n",
191
+ " for inputs, labels in train_loader:\n",
192
+ " inputs, labels = inputs.cuda(), labels.cuda()\n",
193
+ " optimizer.zero_grad()\n",
194
+ " outputs = model(inputs)\n",
195
+ " loss = criterion(outputs, labels)\n",
196
+ " loss.backward()\n",
197
+ " optimizer.step()\n",
198
+ " running_loss += loss.item() * inputs.size(0)\n",
199
+ "\n",
200
+ " epoch_loss = running_loss / len(train_loader.dataset)\n",
201
+ " print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {epoch_loss:.5f}')\n",
202
+ " model_scripted = torch.jit.script(neural_network_model.cpu())\n",
203
+ " model_scripted.save(f'savepoints/{initial_model_hash}-{epoch}-{epoch_loss:.5f}.pt')\n",
204
+ " neural_network_model.cuda()\n",
205
+ "\n",
206
+ "\n",
207
+ "neural_network_model = neural_network_model.cuda() # Move model to GPU if available "
208
+ ],
209
+ "metadata": {
210
+ "collapsed": false,
211
+ "ExecuteTime": {
212
+ "end_time": "2024-03-30T15:19:23.709405Z",
213
+ "start_time": "2024-03-30T15:19:23.689408Z"
214
+ }
215
+ },
216
+ "id": "36df57cc9e0ec04c",
217
+ "execution_count": 13
218
+ },
219
+ {
220
+ "cell_type": "code",
221
+ "outputs": [
222
+ {
223
+ "name": "stdout",
224
+ "output_type": "stream",
225
+ "text": [
226
+ "Epoch [1/20], Loss: 0.10386\n",
227
+ "Epoch [2/20], Loss: 0.09937\n",
228
+ "Epoch [3/20], Loss: 0.09417\n",
229
+ "Epoch [4/20], Loss: 0.09078\n",
230
+ "Epoch [5/20], Loss: 0.08554\n",
231
+ "Epoch [6/20], Loss: 0.08409\n",
232
+ "Epoch [7/20], Loss: 0.07838\n",
233
+ "Epoch [8/20], Loss: 0.07729\n",
234
+ "Epoch [9/20], Loss: 0.07616\n",
235
+ "Epoch [10/20], Loss: 0.07047\n",
236
+ "Epoch [11/20], Loss: 0.06827\n",
237
+ "Epoch [12/20], Loss: 0.06546\n",
238
+ "Epoch [13/20], Loss: 0.06497\n",
239
+ "Epoch [14/20], Loss: 0.06133\n",
240
+ "Epoch [15/20], Loss: 0.06110\n",
241
+ "Epoch [16/20], Loss: 0.05928\n",
242
+ "Epoch [17/20], Loss: 0.05884\n",
243
+ "Epoch [18/20], Loss: 0.05555\n",
244
+ "Epoch [19/20], Loss: 0.05389\n",
245
+ "Epoch [20/20], Loss: 0.05302\n"
246
+ ]
247
+ }
248
+ ],
249
+ "source": [
250
+ "train_model(neural_network_model, cross_entropy_criterion, fine_tuning_optimizer, num_epochs=20)"
251
+ ],
252
+ "metadata": {
253
+ "collapsed": false,
254
+ "ExecuteTime": {
255
+ "end_time": "2024-03-30T16:33:36.897968Z",
256
+ "start_time": "2024-03-30T15:19:24.153863Z"
257
+ }
258
+ },
259
+ "id": "c4b2fd744c1d5b94",
260
+ "execution_count": 14
261
+ },
262
+ {
263
+ "cell_type": "code",
264
+ "outputs": [],
265
+ "source": [],
266
+ "metadata": {
267
+ "collapsed": false,
268
+ "ExecuteTime": {
269
+ "end_time": "2024-02-22T09:00:00.332964Z",
270
+ "start_time": "2024-02-22T09:00:00.332331Z"
271
+ }
272
+ },
273
+ "id": "a5951b3a238c03b1",
274
+ "execution_count": null
275
+ },
276
+ {
277
+ "cell_type": "code",
278
+ "outputs": [
279
+ {
280
+ "name": "stdout",
281
+ "output_type": "stream",
282
+ "text": [
283
+ "Total Validation Accuracy: 0.8943 (7355 / 8224)\n"
284
+ ]
285
+ },
286
+ {
287
+ "data": {
288
+ "text/plain": "<Figure size 640x480 with 1 Axes>",
289
+ "image/png": "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"
290
+ },
291
+ "metadata": {},
292
+ "output_type": "display_data"
293
+ }
294
+ ],
295
+ "source": [
296
+ "# Evaluate the model\n",
297
+ "neural_network_model.eval()\n",
298
+ "labels_to_index = {v: k for k, v in full_dataset.class_to_idx.items()}\n",
299
+ "all_labels = {k: 0 for k in full_dataset.classes}\n",
300
+ "actual_to_predicted_label = {}\n",
301
+ "\n",
302
+ "correct = 0\n",
303
+ "total = 0\n",
304
+ "\n",
305
+ "for a_label in all_labels.keys():\n",
306
+ " actual_to_predicted_label[a_label] = all_labels.copy()\n",
307
+ "\n",
308
+ "with torch.no_grad():\n",
309
+ " for inputs_, labels_ in validation_loader:\n",
310
+ " inputs_, labels_ = inputs_.cuda(), labels_.cuda()\n",
311
+ " outputs_ = neural_network_model(inputs_)\n",
312
+ " _, predicted = torch.max(outputs_.data, 1)\n",
313
+ "\n",
314
+ " for one_prediction, one_label in zip(predicted, labels_):\n",
315
+ " one_prediction_label_name = labels_to_index[one_prediction.tolist()]\n",
316
+ " one_label_name = labels_to_index[one_label.tolist()]\n",
317
+ " actual_to_predicted_label[one_label_name][one_prediction_label_name] += 1\n",
318
+ " total += labels_.size(0)\n",
319
+ " correct += (predicted == labels_).sum().item()\n",
320
+ "\n",
321
+ "accuracy = correct / total\n",
322
+ "print(f'Total Validation Accuracy: {accuracy:.4f} ({correct} / {total})')\n",
323
+ "\n",
324
+ "result_matrix = [[y for y in x.values()] for x in actual_to_predicted_label.values()]\n",
325
+ "max_value = max(*[max(y) for y in result_matrix])\n",
326
+ "axis_labels = list(actual_to_predicted_label.keys())\n",
327
+ "\n",
328
+ "fig = plt.figure()\n",
329
+ "ax = fig.add_subplot(111)\n",
330
+ "ax.matshow(result_matrix, norm=colors.LogNorm(vmin=0, vmax=max_value))\n",
331
+ "\n",
332
+ "for (i, j), z in np.ndenumerate(result_matrix):\n",
333
+ " ax.text(j, i, z, ha='center', va='center')\n",
334
+ "\n",
335
+ "ax.set_xlabel('Actual label')\n",
336
+ "ax.set_ylabel('Predicted label')\n",
337
+ "plt.xticks(ticks=range(len(axis_labels)), labels=axis_labels)\n",
338
+ "plt.yticks(ticks=range(len(axis_labels)), labels=axis_labels)\n",
339
+ "\n",
340
+ "plt.show()"
341
+ ],
342
+ "metadata": {
343
+ "collapsed": false,
344
+ "ExecuteTime": {
345
+ "end_time": "2024-03-30T16:34:01.929118Z",
346
+ "start_time": "2024-03-30T16:33:36.904651Z"
347
+ }
348
+ },
349
+ "id": "3ce3444ebf880a3",
350
+ "execution_count": 15
351
+ },
352
+ {
353
+ "cell_type": "code",
354
+ "outputs": [],
355
+ "source": [],
356
+ "metadata": {
357
+ "collapsed": false
358
+ },
359
+ "id": "c764a1ac6b5aa8ba",
360
+ "execution_count": null
361
+ },
362
+ {
363
+ "cell_type": "code",
364
+ "outputs": [],
365
+ "source": [
366
+ "neural_network_model.eval()\n",
367
+ "neural_network_model.cpu()\n",
368
+ "model_scripted = torch.jit.script(neural_network_model)\n",
369
+ "model_scripted.save('shared/model_scripted.pt')\n",
370
+ "neural_network_model.cuda()\n",
371
+ "\n",
372
+ "with open(f\"shared/labels_to_output_index.json\", \"w\") as json_file:\n",
373
+ " json.dump(full_dataset.classes, json_file)"
374
+ ],
375
+ "metadata": {
376
+ "collapsed": false,
377
+ "ExecuteTime": {
378
+ "end_time": "2024-03-30T16:34:35.966119Z",
379
+ "start_time": "2024-03-30T16:34:35.878966Z"
380
+ }
381
+ },
382
+ "id": "8b92d61aad8b2ce8",
383
+ "execution_count": 16
384
+ },
385
+ {
386
+ "cell_type": "code",
387
+ "outputs": [],
388
+ "source": [],
389
+ "metadata": {
390
+ "collapsed": false
391
+ },
392
+ "id": "2a04a4db365d9db4",
393
+ "execution_count": null
394
+ },
395
+ {
396
+ "metadata": {},
397
+ "cell_type": "code",
398
+ "outputs": [],
399
+ "execution_count": null,
400
+ "source": "",
401
+ "id": "42548abda9c8370f"
402
+ },
403
+ {
404
+ "cell_type": "code",
405
+ "source": [
406
+ "# Load model from file\n",
407
+ "neural_network_model = torch.jit.load('shared/model_scripted.pt')"
408
+ ],
409
+ "metadata": {
410
+ "collapsed": false
411
+ },
412
+ "id": "f1cffed5763919d5",
413
+ "outputs": [],
414
+ "execution_count": null
415
+ },
416
+ {
417
+ "cell_type": "code",
418
+ "outputs": [],
419
+ "source": [],
420
+ "metadata": {
421
+ "collapsed": false
422
+ },
423
+ "id": "41d6a1305c8f992b",
424
+ "execution_count": null
425
+ }
426
+ ],
427
+ "metadata": {
428
+ "kernelspec": {
429
+ "display_name": "Python 3",
430
+ "language": "python",
431
+ "name": "python3"
432
+ },
433
+ "language_info": {
434
+ "codemirror_mode": {
435
+ "name": "ipython",
436
+ "version": 2
437
+ },
438
+ "file_extension": ".py",
439
+ "mimetype": "text/x-python",
440
+ "name": "python",
441
+ "nbconvert_exporter": "python",
442
+ "pygments_lexer": "ipython2",
443
+ "version": "2.7.6"
444
+ }
445
+ },
446
+ "nbformat": 4,
447
+ "nbformat_minor": 5
448
+ }
src/shared/labels_to_output_index.json ADDED
@@ -0,0 +1 @@
 
 
1
+ ["back", "closeup", "front", "inside", "label", "others", "side_view", "three_fourth"]
src/shared/model_scripted.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:bfd8ed5a39969daf63bc67f6a4f0c99aa989683b9c2762a738df23ac61379668
3
+ size 16556362
src/shared/stance_recognize.py ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import List
2
+
3
+ import numpy as np
4
+ import torch
5
+ from PIL.Image import Image
6
+ from scipy.special import softmax
7
+ from torch import Tensor
8
+ from torch.jit import RecursiveScriptModule
9
+ from torchvision import transforms
10
+
11
+
12
+ def normalize_neural_network_output(neural_network_output: np.ndarray) -> List[float]:
13
+ return softmax(neural_network_output).tolist()
14
+
15
+
16
+ def predict(pil_images: List[Image],
17
+ labels_to_output_index: list,
18
+ neural_network_model: RecursiveScriptModule
19
+ ) -> List[dict]:
20
+ neural_network_input = format_pils_images(pil_images)
21
+ neural_network_output = predict_neural_network(neural_network_input, neural_network_model)
22
+ return format_output(neural_network_output, labels_to_output_index)
23
+
24
+
25
+ def predict_neural_network(neural_network_input: Tensor, neural_network_model: RecursiveScriptModule) -> List[
26
+ List[float]]:
27
+ with torch.no_grad():
28
+ all_outputs = neural_network_model(neural_network_input).tolist()
29
+
30
+ normalized_neural_network_output = list(map(normalize_neural_network_output, all_outputs))
31
+ return normalized_neural_network_output
32
+
33
+
34
+ def format_output(neural_network_output: list, labels_to_output_index: list) -> List[dict]:
35
+ results = []
36
+ for i, a_nn_output in enumerate(neural_network_output):
37
+ results.append(
38
+ {
39
+ 'probabilities_neural_network': {
40
+ labels_to_output_index[j]: p for j, p in enumerate(a_nn_output)
41
+ },
42
+ })
43
+ return results
44
+
45
+
46
+ def format_pils_images(pil_images: List[Image]) -> Tensor:
47
+ pil_images_transformed = []
48
+
49
+ transform = transforms.Compose([
50
+ transforms.Resize((256, 256)),
51
+ transforms.ToTensor(),
52
+ transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
53
+ ])
54
+
55
+ for a_pil_image in pil_images:
56
+ a_pil_image = transform(a_pil_image)
57
+ pil_images_transformed.append(a_pil_image.unsqueeze(0))
58
+
59
+ return torch.cat(pil_images_transformed, dim=0)
src/use-example.ipynb ADDED
@@ -0,0 +1,412 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "source": [
6
+ "import json\n",
7
+ "\n",
8
+ "from enum import StrEnum\n",
9
+ "\n",
10
+ "import numpy as np\n",
11
+ "from PIL import Image\n",
12
+ "from scipy.special import softmax\n",
13
+ "from torch import Tensor\n",
14
+ "from torch.jit import RecursiveScriptModule\n",
15
+ "from torchvision import transforms\n",
16
+ "\n",
17
+ "from IPython.display import display, HTML\n",
18
+ "\n",
19
+ "import torch"
20
+ ],
21
+ "metadata": {
22
+ "collapsed": false,
23
+ "ExecuteTime": {
24
+ "end_time": "2025-11-10T21:15:01.207611Z",
25
+ "start_time": "2025-11-10T21:15:01.205436Z"
26
+ }
27
+ },
28
+ "id": "15c69cabd27e8626",
29
+ "outputs": [],
30
+ "execution_count": 10
31
+ },
32
+ {
33
+ "cell_type": "code",
34
+ "source": [
35
+ "class PHOTO_FRAMING(StrEnum):\n",
36
+ " FRONT = \"front\"\n",
37
+ " BACK = \"back\"\n",
38
+ " SIDE_VIEW = \"side_view\"\n",
39
+ " THREE_FOURTH = \"three_fourth\"\n",
40
+ " INSIDE = \"inside\"\n",
41
+ " CLOSEUP = \"closeup\"\n",
42
+ " LABEL = \"label\"\n",
43
+ " OTHERS = \"others\"\n",
44
+ "\n",
45
+ "\n",
46
+ "AiPredictionByFraming = list[dict[PHOTO_FRAMING, float]]"
47
+ ],
48
+ "metadata": {
49
+ "collapsed": false,
50
+ "ExecuteTime": {
51
+ "end_time": "2025-11-10T21:15:01.265847Z",
52
+ "start_time": "2025-11-10T21:15:01.263362Z"
53
+ }
54
+ },
55
+ "id": "f1cffed5763919d5",
56
+ "outputs": [],
57
+ "execution_count": 12
58
+ },
59
+ {
60
+ "metadata": {
61
+ "ExecuteTime": {
62
+ "end_time": "2025-11-10T21:15:01.312581Z",
63
+ "start_time": "2025-11-10T21:15:01.308237Z"
64
+ }
65
+ },
66
+ "cell_type": "code",
67
+ "source": [
68
+ "def normalize_neural_network_output(neural_network_output: np.ndarray) -> list[float]:\n",
69
+ " return softmax(neural_network_output).tolist()\n",
70
+ "\n",
71
+ "\n",
72
+ "def predict_neural_network(neural_network_input: Tensor, neural_network_model: RecursiveScriptModule) -> list[\n",
73
+ " list[float]]:\n",
74
+ " with torch.no_grad():\n",
75
+ " all_outputs = neural_network_model(neural_network_input).tolist()\n",
76
+ "\n",
77
+ " normalized_neural_network_output = list(map(normalize_neural_network_output, all_outputs))\n",
78
+ " return normalized_neural_network_output\n",
79
+ "\n",
80
+ "\n",
81
+ "def format_output(neural_network_output: list, labels_to_output_index: list) -> list[dict]:\n",
82
+ " results = []\n",
83
+ " for i, a_nn_output in enumerate(neural_network_output):\n",
84
+ " results.append(\n",
85
+ " {\n",
86
+ " 'probabilities_neural_network': {\n",
87
+ " labels_to_output_index[j]: p for j, p in enumerate(a_nn_output)\n",
88
+ " },\n",
89
+ " })\n",
90
+ " return results\n",
91
+ "\n",
92
+ "\n",
93
+ "def format_pils_images(pil_images: list[Image.Image]) -> Tensor:\n",
94
+ " pil_images_transformed = []\n",
95
+ "\n",
96
+ " transform = transforms.Compose([\n",
97
+ " transforms.Resize((256, 256)),\n",
98
+ " transforms.ToTensor(),\n",
99
+ " transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),\n",
100
+ " ])\n",
101
+ "\n",
102
+ " for a_pil_image in pil_images:\n",
103
+ " a_pil_image = transform(a_pil_image)\n",
104
+ " pil_images_transformed.append(a_pil_image.unsqueeze(0))\n",
105
+ "\n",
106
+ " return torch.cat(pil_images_transformed, dim=0)\n",
107
+ "\n",
108
+ "\n",
109
+ "def predict(pil_images: list[Image.Image],\n",
110
+ " labels_to_output_index: list,\n",
111
+ " neural_network_model: RecursiveScriptModule\n",
112
+ ") -> list[dict]:\n",
113
+ " neural_network_input = format_pils_images(pil_images)\n",
114
+ " neural_network_output = predict_neural_network(neural_network_input, neural_network_model)\n",
115
+ " return format_output(neural_network_output, labels_to_output_index)\n"
116
+ ],
117
+ "id": "7a05d1015a88e18c",
118
+ "outputs": [],
119
+ "execution_count": 13
120
+ },
121
+ {
122
+ "cell_type": "code",
123
+ "source": [
124
+ "neural_network_model = torch.jit.load('shared/model_scripted.pt')\n",
125
+ "\n",
126
+ "with open('shared/labels_to_output_index.json', 'r') as fp:\n",
127
+ " labels_to_output_index = json.load(fp)\n",
128
+ "\n",
129
+ "\n",
130
+ "def get_picture_framing_prediction(images_pil: list[Image.Image]) -> AiPredictionByFraming:\n",
131
+ " ai_prediction_scores = predict(images_pil,\n",
132
+ " labels_to_output_index,\n",
133
+ " neural_network_model)\n",
134
+ " ai_prediction_by_framing = [p['probabilities_neural_network'] for p in ai_prediction_scores]\n",
135
+ "\n",
136
+ " return ai_prediction_by_framing"
137
+ ],
138
+ "metadata": {
139
+ "collapsed": false,
140
+ "ExecuteTime": {
141
+ "end_time": "2025-11-10T21:15:01.535844Z",
142
+ "start_time": "2025-11-10T21:15:01.355615Z"
143
+ }
144
+ },
145
+ "id": "41d6a1305c8f992b",
146
+ "outputs": [],
147
+ "execution_count": 14
148
+ },
149
+ {
150
+ "metadata": {
151
+ "ExecuteTime": {
152
+ "end_time": "2025-11-10T21:15:01.575230Z",
153
+ "start_time": "2025-11-10T21:15:01.563426Z"
154
+ }
155
+ },
156
+ "cell_type": "code",
157
+ "source": [
158
+ "image_paths = [\"assets/dress-drm-free/1.jpeg\",\n",
159
+ " \"assets/dress-drm-free/2.jpeg\",\n",
160
+ " \"assets/dress-drm-free/3.jpeg\",\n",
161
+ " \"assets/dress-drm-free/4.jpeg\",\n",
162
+ " \"assets/label-difficult/1.jpeg\",\n",
163
+ " \"assets/label-difficult/2.jpeg\",\n",
164
+ " \"assets/label-difficult/3.jpeg\",\n",
165
+ " \"assets/label-difficult/4.jpeg\",\n",
166
+ " \"assets/label-difficult/5.jpeg\",\n",
167
+ " \"assets/saint-james-coat/1.jpeg\",\n",
168
+ " \"assets/saint-james-coat/2.jpeg\",\n",
169
+ " \"assets/saint-james-coat/3.jpeg\",\n",
170
+ " \"assets/saint-james-coat/4.jpeg\",\n",
171
+ " \"assets/saint-james-coat/5.jpeg\"]\n",
172
+ "input_images = [Image.open(one_image_path) for one_image_path in image_paths]"
173
+ ],
174
+ "id": "3f7877aba0b830c9",
175
+ "outputs": [],
176
+ "execution_count": 15
177
+ },
178
+ {
179
+ "metadata": {
180
+ "ExecuteTime": {
181
+ "end_time": "2025-11-10T21:15:02.393613Z",
182
+ "start_time": "2025-11-10T21:15:01.613188Z"
183
+ }
184
+ },
185
+ "cell_type": "code",
186
+ "source": [
187
+ "predictions = get_picture_framing_prediction(input_images)\n",
188
+ "prediction_texts = []\n",
189
+ "\n",
190
+ "for one_image_prediction in predictions:\n",
191
+ " max_key = max(one_image_prediction, key=one_image_prediction.get)\n",
192
+ " max_value = one_image_prediction[max_key]\n",
193
+ "\n",
194
+ " one_image_predictions = []\n",
195
+ " for key, value in one_image_prediction.items():\n",
196
+ " one_image_text = f\"{key}: {value:.3f}\"\n",
197
+ " if key == max_key:\n",
198
+ " one_image_text = f\"<b>{one_image_text}</b>\"\n",
199
+ " one_image_predictions.append(one_image_text)\n",
200
+ "\n",
201
+ " prediction_texts.append(\"<br/>\".join(one_image_predictions))"
202
+ ],
203
+ "id": "cda1d624454cda79",
204
+ "outputs": [],
205
+ "execution_count": 16
206
+ },
207
+ {
208
+ "metadata": {
209
+ "ExecuteTime": {
210
+ "end_time": "2025-11-10T21:15:02.400026Z",
211
+ "start_time": "2025-11-10T21:15:02.396874Z"
212
+ }
213
+ },
214
+ "cell_type": "code",
215
+ "source": [
216
+ "html = \"<div style='display: flex; flex-direction: column;'>\"\n",
217
+ "for img_path, text in zip(image_paths, prediction_texts):\n",
218
+ " html += f\"\"\"\n",
219
+ " <div style='display: flex; align-items: center; margin: 10px;'>\n",
220
+ " <div style='margin-right: 20px;'>\n",
221
+ " <img src='{img_path}' style='max-width: 200px; max-height: 200px;' />\n",
222
+ " </div>\n",
223
+ " <div style='text-align: left;'>\n",
224
+ " <p>{text}</p>\n",
225
+ " </div>\n",
226
+ " </div>\n",
227
+ " \"\"\"\n",
228
+ "html += \"</div>\"\n",
229
+ "display(HTML(html))"
230
+ ],
231
+ "id": "c6a4c569aa8d6213",
232
+ "outputs": [
233
+ {
234
+ "data": {
235
+ "text/plain": [
236
+ "<IPython.core.display.HTML object>"
237
+ ],
238
+ "text/html": [
239
+ "<div style='display: flex; flex-direction: column;'>\n",
240
+ " <div style='display: flex; align-items: center; margin: 10px;'>\n",
241
+ " <div style='margin-right: 20px;'>\n",
242
+ " <img src='assets/dress-drm-free/1.jpeg' style='max-width: 200px; max-height: 200px;' />\n",
243
+ " </div>\n",
244
+ " <div style='text-align: left;'>\n",
245
+ " <p>back: 0.000<br/>closeup: 0.000<br/><b>front: 1.000</b><br/>inside: 0.000<br/>label: 0.000<br/>others: 0.000<br/>side_view: 0.000<br/>three_fourth: 0.000</p>\n",
246
+ " </div>\n",
247
+ " </div>\n",
248
+ " \n",
249
+ " <div style='display: flex; align-items: center; margin: 10px;'>\n",
250
+ " <div style='margin-right: 20px;'>\n",
251
+ " <img src='assets/dress-drm-free/2.jpeg' style='max-width: 200px; max-height: 200px;' />\n",
252
+ " </div>\n",
253
+ " <div style='text-align: left;'>\n",
254
+ " <p>back: 0.001<br/>closeup: 0.000<br/>front: 0.008<br/>inside: 0.000<br/>label: 0.000<br/>others: 0.000<br/><b>side_view: 0.991</b><br/>three_fourth: 0.000</p>\n",
255
+ " </div>\n",
256
+ " </div>\n",
257
+ " \n",
258
+ " <div style='display: flex; align-items: center; margin: 10px;'>\n",
259
+ " <div style='margin-right: 20px;'>\n",
260
+ " <img src='assets/dress-drm-free/3.jpeg' style='max-width: 200px; max-height: 200px;' />\n",
261
+ " </div>\n",
262
+ " <div style='text-align: left;'>\n",
263
+ " <p>back: 0.014<br/>closeup: 0.000<br/>front: 0.000<br/>inside: 0.000<br/>label: 0.000<br/>others: 0.000<br/>side_view: 0.001<br/><b>three_fourth: 0.985</b></p>\n",
264
+ " </div>\n",
265
+ " </div>\n",
266
+ " \n",
267
+ " <div style='display: flex; align-items: center; margin: 10px;'>\n",
268
+ " <div style='margin-right: 20px;'>\n",
269
+ " <img src='assets/dress-drm-free/4.jpeg' style='max-width: 200px; max-height: 200px;' />\n",
270
+ " </div>\n",
271
+ " <div style='text-align: left;'>\n",
272
+ " <p>back: 0.000<br/><b>closeup: 1.000</b><br/>front: 0.000<br/>inside: 0.000<br/>label: 0.000<br/>others: 0.000<br/>side_view: 0.000<br/>three_fourth: 0.000</p>\n",
273
+ " </div>\n",
274
+ " </div>\n",
275
+ " \n",
276
+ " <div style='display: flex; align-items: center; margin: 10px;'>\n",
277
+ " <div style='margin-right: 20px;'>\n",
278
+ " <img src='assets/label-difficult/1.jpeg' style='max-width: 200px; max-height: 200px;' />\n",
279
+ " </div>\n",
280
+ " <div style='text-align: left;'>\n",
281
+ " <p>back: 0.003<br/>closeup: 0.000<br/><b>front: 0.997</b><br/>inside: 0.000<br/>label: 0.000<br/>others: 0.000<br/>side_view: 0.000<br/>three_fourth: 0.000</p>\n",
282
+ " </div>\n",
283
+ " </div>\n",
284
+ " \n",
285
+ " <div style='display: flex; align-items: center; margin: 10px;'>\n",
286
+ " <div style='margin-right: 20px;'>\n",
287
+ " <img src='assets/label-difficult/2.jpeg' style='max-width: 200px; max-height: 200px;' />\n",
288
+ " </div>\n",
289
+ " <div style='text-align: left;'>\n",
290
+ " <p><b>back: 0.943</b><br/>closeup: 0.000<br/>front: 0.057<br/>inside: 0.000<br/>label: 0.000<br/>others: 0.000<br/>side_view: 0.000<br/>three_fourth: 0.000</p>\n",
291
+ " </div>\n",
292
+ " </div>\n",
293
+ " \n",
294
+ " <div style='display: flex; align-items: center; margin: 10px;'>\n",
295
+ " <div style='margin-right: 20px;'>\n",
296
+ " <img src='assets/label-difficult/3.jpeg' style='max-width: 200px; max-height: 200px;' />\n",
297
+ " </div>\n",
298
+ " <div style='text-align: left;'>\n",
299
+ " <p>back: 0.192<br/>closeup: 0.315<br/><b>front: 0.442</b><br/>inside: 0.000<br/>label: 0.048<br/>others: 0.001<br/>side_view: 0.000<br/>three_fourth: 0.002</p>\n",
300
+ " </div>\n",
301
+ " </div>\n",
302
+ " \n",
303
+ " <div style='display: flex; align-items: center; margin: 10px;'>\n",
304
+ " <div style='margin-right: 20px;'>\n",
305
+ " <img src='assets/label-difficult/4.jpeg' style='max-width: 200px; max-height: 200px;' />\n",
306
+ " </div>\n",
307
+ " <div style='text-align: left;'>\n",
308
+ " <p><b>back: 1.000</b><br/>closeup: 0.000<br/>front: 0.000<br/>inside: 0.000<br/>label: 0.000<br/>others: 0.000<br/>side_view: 0.000<br/>three_fourth: 0.000</p>\n",
309
+ " </div>\n",
310
+ " </div>\n",
311
+ " \n",
312
+ " <div style='display: flex; align-items: center; margin: 10px;'>\n",
313
+ " <div style='margin-right: 20px;'>\n",
314
+ " <img src='assets/label-difficult/5.jpeg' style='max-width: 200px; max-height: 200px;' />\n",
315
+ " </div>\n",
316
+ " <div style='text-align: left;'>\n",
317
+ " <p>back: 0.000<br/><b>closeup: 0.971</b><br/>front: 0.000<br/>inside: 0.000<br/>label: 0.028<br/>others: 0.000<br/>side_view: 0.000<br/>three_fourth: 0.000</p>\n",
318
+ " </div>\n",
319
+ " </div>\n",
320
+ " \n",
321
+ " <div style='display: flex; align-items: center; margin: 10px;'>\n",
322
+ " <div style='margin-right: 20px;'>\n",
323
+ " <img src='assets/saint-james-coat/1.jpeg' style='max-width: 200px; max-height: 200px;' />\n",
324
+ " </div>\n",
325
+ " <div style='text-align: left;'>\n",
326
+ " <p>back: 0.000<br/>closeup: 0.000<br/><b>front: 0.932</b><br/>inside: 0.000<br/>label: 0.000<br/>others: 0.065<br/>side_view: 0.002<br/>three_fourth: 0.000</p>\n",
327
+ " </div>\n",
328
+ " </div>\n",
329
+ " \n",
330
+ " <div style='display: flex; align-items: center; margin: 10px;'>\n",
331
+ " <div style='margin-right: 20px;'>\n",
332
+ " <img src='assets/saint-james-coat/2.jpeg' style='max-width: 200px; max-height: 200px;' />\n",
333
+ " </div>\n",
334
+ " <div style='text-align: left;'>\n",
335
+ " <p>back: 0.327<br/>closeup: 0.014<br/><b>front: 0.376</b><br/>inside: 0.001<br/>label: 0.000<br/>others: 0.000<br/>side_view: 0.271<br/>three_fourth: 0.011</p>\n",
336
+ " </div>\n",
337
+ " </div>\n",
338
+ " \n",
339
+ " <div style='display: flex; align-items: center; margin: 10px;'>\n",
340
+ " <div style='margin-right: 20px;'>\n",
341
+ " <img src='assets/saint-james-coat/3.jpeg' style='max-width: 200px; max-height: 200px;' />\n",
342
+ " </div>\n",
343
+ " <div style='text-align: left;'>\n",
344
+ " <p>back: 0.000<br/><b>closeup: 1.000</b><br/>front: 0.000<br/>inside: 0.000<br/>label: 0.000<br/>others: 0.000<br/>side_view: 0.000<br/>three_fourth: 0.000</p>\n",
345
+ " </div>\n",
346
+ " </div>\n",
347
+ " \n",
348
+ " <div style='display: flex; align-items: center; margin: 10px;'>\n",
349
+ " <div style='margin-right: 20px;'>\n",
350
+ " <img src='assets/saint-james-coat/4.jpeg' style='max-width: 200px; max-height: 200px;' />\n",
351
+ " </div>\n",
352
+ " <div style='text-align: left;'>\n",
353
+ " <p>back: 0.000<br/>closeup: 0.266<br/>front: 0.004<br/>inside: 0.000<br/><b>label: 0.729</b><br/>others: 0.000<br/>side_view: 0.000<br/>three_fourth: 0.000</p>\n",
354
+ " </div>\n",
355
+ " </div>\n",
356
+ " \n",
357
+ " <div style='display: flex; align-items: center; margin: 10px;'>\n",
358
+ " <div style='margin-right: 20px;'>\n",
359
+ " <img src='assets/saint-james-coat/5.jpeg' style='max-width: 200px; max-height: 200px;' />\n",
360
+ " </div>\n",
361
+ " <div style='text-align: left;'>\n",
362
+ " <p>back: 0.000<br/>closeup: 0.000<br/>front: 0.000<br/>inside: 0.000<br/><b>label: 1.000</b><br/>others: 0.000<br/>side_view: 0.000<br/>three_fourth: 0.000</p>\n",
363
+ " </div>\n",
364
+ " </div>\n",
365
+ " </div>"
366
+ ]
367
+ },
368
+ "metadata": {},
369
+ "output_type": "display_data",
370
+ "jetTransient": {
371
+ "display_id": null
372
+ }
373
+ }
374
+ ],
375
+ "execution_count": 17
376
+ },
377
+ {
378
+ "metadata": {
379
+ "ExecuteTime": {
380
+ "end_time": "2025-11-10T21:15:02.510927Z",
381
+ "start_time": "2025-11-10T21:15:02.509743Z"
382
+ }
383
+ },
384
+ "cell_type": "code",
385
+ "source": "",
386
+ "id": "9d18593f866478ec",
387
+ "outputs": [],
388
+ "execution_count": null
389
+ }
390
+ ],
391
+ "metadata": {
392
+ "kernelspec": {
393
+ "display_name": "Python 3",
394
+ "language": "python",
395
+ "name": "python3"
396
+ },
397
+ "language_info": {
398
+ "codemirror_mode": {
399
+ "name": "ipython",
400
+ "version": 2
401
+ },
402
+ "file_extension": ".py",
403
+ "mimetype": "text/x-python",
404
+ "name": "python",
405
+ "nbconvert_exporter": "python",
406
+ "pygments_lexer": "ipython2",
407
+ "version": "2.7.6"
408
+ }
409
+ },
410
+ "nbformat": 4,
411
+ "nbformat_minor": 5
412
+ }