paulokewunmi commited on
Commit
a3f0ad9
1 Parent(s): ac58068

Upload 44 files

Browse files
Files changed (44) hide show
  1. data/pinecone.ipynb +409 -0
  2. data/processed/.gitkeep +0 -0
  3. data/processed/jumia_3650/jumia_3650.json +0 -0
  4. data/processed/jumia_3650/test.csv +710 -0
  5. data/processed/jumia_3650/train.csv +0 -0
  6. image_search_engine/__init__.py +0 -0
  7. image_search_engine/artifacts/__init__.py +0 -0
  8. image_search_engine/artifacts/config.json +1 -0
  9. image_search_engine/artifacts/label_encoder/class_encoder_jumia_3650.pkl +3 -0
  10. image_search_engine/artifacts/model_staged/index.pkl +3 -0
  11. image_search_engine/artifacts/model_staged/model.pt +3 -0
  12. image_search_engine/artifacts/weights/Loss0.6555_epoch3.bin +3 -0
  13. image_search_engine/data/__init__.py +1 -0
  14. image_search_engine/data/base_data_module.py +39 -0
  15. image_search_engine/data/jumia_3650_dataset.py +60 -0
  16. image_search_engine/data/utils.py +16 -0
  17. image_search_engine/evaluation/__init__.py +0 -0
  18. image_search_engine/image_search_engine.egg-info/PKG-INFO +5 -0
  19. image_search_engine/image_search_engine.egg-info/SOURCES.txt +20 -0
  20. image_search_engine/image_search_engine.egg-info/dependency_links.txt +1 -0
  21. image_search_engine/image_search_engine.egg-info/top_level.txt +6 -0
  22. image_search_engine/metadata/__init__.py +1 -0
  23. image_search_engine/metadata/jumia_3650.py +19 -0
  24. image_search_engine/metadata/shared.py +4 -0
  25. image_search_engine/models/__init__.py +3 -0
  26. image_search_engine/models/arc_margin_product.py +60 -0
  27. image_search_engine/models/base.py +200 -0
  28. image_search_engine/models/efficientnet_ns.py +48 -0
  29. image_search_engine/models/gem_pooling.py +30 -0
  30. image_search_engine/product_image_search.py +64 -0
  31. image_search_engine/tests/__init__.py +0 -0
  32. image_search_engine/tests/test_img/1.jpg +0 -0
  33. image_search_engine/tests/test_img/2.jpg +0 -0
  34. image_search_engine/tests/test_img/3.jpg +0 -0
  35. image_search_engine/tests/test_img/4.jpg +0 -0
  36. image_search_engine/tests/test_img/5.jpg +0 -0
  37. image_search_engine/tests/test_img/6.jpg +0 -0
  38. image_search_engine/tests/test_img/7.jpg +0 -0
  39. image_search_engine/tests/test_img/8.jpg +0 -0
  40. image_search_engine/tests/test_img/Shark2.jpg +0 -0
  41. image_search_engine/tests/test_img/smart_band.jpg +0 -0
  42. image_search_engine/tests/test_img/smart_band_2.jpg +0 -0
  43. image_search_engine/tests/test_img/sony.png +0 -0
  44. image_search_engine/utils.py +48 -0
data/pinecone.ipynb ADDED
@@ -0,0 +1,409 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": 1,
6
+ "id": "small-delaware",
7
+ "metadata": {},
8
+ "outputs": [
9
+ {
10
+ "name": "stdout",
11
+ "output_type": "stream",
12
+ "text": [
13
+ "\u001b[31mERROR: After October 2020 you may experience errors when installing or updating packages. This is because pip will change the way that it resolves dependency conflicts.\n",
14
+ "\n",
15
+ "We recommend you use --use-feature=2020-resolver to test your packages with the new resolver before it becomes the default.\n",
16
+ "\n",
17
+ "mediapipe 0.8.1 requires opencv-python, which is not installed.\n",
18
+ "djitellopy 2.4.0 requires opencv-python, which is not installed.\n",
19
+ "umojahack2023 0.1 requires numpy==1.23.5, but you'll have numpy 1.24.4 which is incompatible.\n",
20
+ "tensorflow 2.11.0 requires gast<=0.4.0,>=0.2.1, but you'll have gast 0.5.3 which is incompatible.\n",
21
+ "streamlit 1.3.1 requires click<8.0,>=7.0, but you'll have click 8.1.3 which is incompatible.\n",
22
+ "pandas-profiling 3.2.0 requires joblib~=1.1.0, but you'll have joblib 1.2.0 which is incompatible.\n",
23
+ "pandas-profiling 3.2.0 requires markupsafe~=2.1.1, but you'll have markupsafe 2.0.1 which is incompatible.\n",
24
+ "mediapipe 0.8.1 requires numpy==1.19.3, but you'll have numpy 1.24.4 which is incompatible.\n",
25
+ "huggingface-hub 0.14.1 requires packaging>=20.9, but you'll have packaging 20.8 which is incompatible.\n",
26
+ "google-api-core 2.11.0 requires protobuf!=3.20.0,!=3.20.1,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5,<5.0.0dev,>=3.19.5, but you'll have protobuf 3.19.3 which is incompatible.\u001b[0m\n"
27
+ ]
28
+ }
29
+ ],
30
+ "source": [
31
+ "!pip install -qU pinecone-client \\\n",
32
+ " tqdm \\\n",
33
+ " httpimport \\\n",
34
+ " requests"
35
+ ]
36
+ },
37
+ {
38
+ "cell_type": "code",
39
+ "execution_count": 2,
40
+ "id": "legal-course",
41
+ "metadata": {},
42
+ "outputs": [
43
+ {
44
+ "name": "stderr",
45
+ "output_type": "stream",
46
+ "text": [
47
+ "/Users/paul/miniconda3/lib/python3.8/site-packages/pinecone/index.py:4: TqdmExperimentalWarning: Using `tqdm.autonotebook.tqdm` in notebook mode. Use `tqdm.tqdm` instead to force console mode (e.g. in jupyter console)\n",
48
+ " from tqdm.autonotebook import tqdm\n"
49
+ ]
50
+ }
51
+ ],
52
+ "source": [
53
+ "import os\n",
54
+ "import requests\n",
55
+ "\n",
56
+ "import tqdm\n",
57
+ "import httpimport\n",
58
+ "import pinecone\n",
59
+ "import numpy as np\n",
60
+ "from PIL import Image\n",
61
+ "\n",
62
+ "DATA_DIRECTORY = 'tmp'\n",
63
+ "INDEX_NAME = 'jumia-product-search'\n",
64
+ "INDEX_DIMENSION = 512\n",
65
+ "BATCH_SIZE=200"
66
+ ]
67
+ },
68
+ {
69
+ "cell_type": "code",
70
+ "execution_count": 3,
71
+ "id": "political-robertson",
72
+ "metadata": {},
73
+ "outputs": [],
74
+ "source": [
75
+ "PINECONE_API_KEY = \"22e8b95b-18a6-42b4-8824-dc65f08a60e1\"\n",
76
+ "PINECONE_ENV = \"us-west1-gcp-free\""
77
+ ]
78
+ },
79
+ {
80
+ "cell_type": "code",
81
+ "execution_count": 4,
82
+ "id": "contained-financing",
83
+ "metadata": {},
84
+ "outputs": [],
85
+ "source": [
86
+ "pinecone.init(api_key= PINECONE_API_KEY,\n",
87
+ " environment=PINECONE_ENV)\n"
88
+ ]
89
+ },
90
+ {
91
+ "cell_type": "code",
92
+ "execution_count": 7,
93
+ "id": "biblical-decision",
94
+ "metadata": {},
95
+ "outputs": [
96
+ {
97
+ "data": {
98
+ "text/plain": [
99
+ "{'dimension': 512,\n",
100
+ " 'index_fullness': 0.0,\n",
101
+ " 'namespaces': {},\n",
102
+ " 'total_vector_count': 0}"
103
+ ]
104
+ },
105
+ "execution_count": 7,
106
+ "metadata": {},
107
+ "output_type": "execute_result"
108
+ }
109
+ ],
110
+ "source": [
111
+ "index_name = 'jumia-product-embeddings'\n",
112
+ "\n",
113
+ "if index_name not in pinecone.list_indexes():\n",
114
+ " # now create the new index\n",
115
+ " pinecone.create_index(\n",
116
+ " index_name,\n",
117
+ " dimension= 512, # 768\n",
118
+ " metric='cosine',\n",
119
+ " pod_type='s1',\n",
120
+ " pods=1\n",
121
+ " )\n",
122
+ "\n",
123
+ "# connect to index\n",
124
+ "index = pinecone.Index(index_name)\n",
125
+ "# then check index status\n",
126
+ "index.describe_index_stats()"
127
+ ]
128
+ },
129
+ {
130
+ "cell_type": "code",
131
+ "execution_count": 8,
132
+ "id": "advance-composite",
133
+ "metadata": {},
134
+ "outputs": [],
135
+ "source": [
136
+ "import joblib\n",
137
+ "\n",
138
+ "\n",
139
+ "EMBED_FILE = \"../image_search_engine/artifacts/embeddings/embed_2023-07-09_15-17-45.pkl\"\n",
140
+ "\n",
141
+ "\n",
142
+ "def load_serialized_object(file_path):\n",
143
+ " try:\n",
144
+ " obj = joblib.load(file_path)\n",
145
+ " return obj\n",
146
+ " except FileNotFoundError:\n",
147
+ " print(f\"File not found: {file_path}\")\n",
148
+ " except Exception as e:\n",
149
+ " print(f\"Error loading serialized object: {str(e)}\")"
150
+ ]
151
+ },
152
+ {
153
+ "cell_type": "code",
154
+ "execution_count": 12,
155
+ "id": "lasting-wyoming",
156
+ "metadata": {},
157
+ "outputs": [],
158
+ "source": [
159
+ "embeddings = load_serialized_object(EMBED_FILE)"
160
+ ]
161
+ },
162
+ {
163
+ "cell_type": "code",
164
+ "execution_count": 48,
165
+ "id": "dramatic-superintendent",
166
+ "metadata": {},
167
+ "outputs": [],
168
+ "source": [
169
+ "embeddings = [embed.tolist() for embed in embeddings]\n"
170
+ ]
171
+ },
172
+ {
173
+ "cell_type": "code",
174
+ "execution_count": 10,
175
+ "id": "formal-million",
176
+ "metadata": {},
177
+ "outputs": [
178
+ {
179
+ "data": {
180
+ "text/plain": [
181
+ "2941"
182
+ ]
183
+ },
184
+ "execution_count": 10,
185
+ "metadata": {},
186
+ "output_type": "execute_result"
187
+ }
188
+ ],
189
+ "source": [
190
+ "len(embed)"
191
+ ]
192
+ },
193
+ {
194
+ "cell_type": "code",
195
+ "execution_count": 15,
196
+ "id": "equipped-conversion",
197
+ "metadata": {},
198
+ "outputs": [],
199
+ "source": [
200
+ "import json\n",
201
+ "def load_json_file(file_path):\n",
202
+ " with open(file_path, \"r\") as file:\n",
203
+ " data = json.load(file)\n",
204
+ " return data"
205
+ ]
206
+ },
207
+ {
208
+ "cell_type": "code",
209
+ "execution_count": 16,
210
+ "id": "veterinary-greenhouse",
211
+ "metadata": {},
212
+ "outputs": [],
213
+ "source": [
214
+ "json_data = load_json_file(\"processed/jumia_3650/jumia_3650.json\")"
215
+ ]
216
+ },
217
+ {
218
+ "cell_type": "code",
219
+ "execution_count": 19,
220
+ "id": "important-literacy",
221
+ "metadata": {
222
+ "collapsed": true,
223
+ "jupyter": {
224
+ "outputs_hidden": true
225
+ }
226
+ },
227
+ "outputs": [
228
+ {
229
+ "data": {
230
+ "application/vnd.jupyter.widget-view+json": {
231
+ "model_id": "8b01efeef77e42268c86219a3dab6a5a",
232
+ "version_major": 2,
233
+ "version_minor": 0
234
+ },
235
+ "text/plain": [
236
+ " 0%| | 0/5 [00:00<?, ?it/s]"
237
+ ]
238
+ },
239
+ "metadata": {},
240
+ "output_type": "display_data"
241
+ },
242
+ {
243
+ "name": "stdout",
244
+ "output_type": "stream",
245
+ "text": [
246
+ "['JUMIA3650.0', array([ 0.01932903, -1.791061 , 1.3284612 ], dtype=float32), {'filename': 'product_ear_pods_401_0.jpg', 'product_id': 'product_ear_pods_401', 'product_category': 'ear_pods', 'product_name': 'Power Pod Fingerprint Touch Bluetooth 5.0 Wireless Stereo Hear Phone Pod', 'product_image_url': 'https://ng.jumia.is/unsafe/fit-in/680x680/filters:fill(white)/product/66/4640212/1.jpg?9552', 'product_url': 'https://www.jumia.com.ng/power-pod-fingerprint-touch-bluetooth-5.0-wireless-stereo-hear-phone-pod-212046466.html', 'discounted_price': '₦ 6,500', 'original_price': '₦ 8,500'}]\n",
247
+ "['JUMIA3650.1', array([ 0.12243042, -1.9603508 , 2.0345879 ], dtype=float32), {'filename': 'product_headset_671_3.jpg', 'product_id': 'product_headset_671', 'product_category': 'headset', 'product_name': 'Solar Charging Bluetooth Earphone Wireless TWS Headset', 'product_image_url': 'https://ng.jumia.is/unsafe/fit-in/680x680/filters:fill(white)/product/43/4238202/1.jpg?0528', 'product_url': 'https://www.jumia.com.ng/generic-solar-charging-bluetooth-earphone-wireless-tws-headset-202832434.html', 'discounted_price': '₦ 8,190', 'original_price': '₦ 13,000'}]\n",
248
+ "['JUMIA3650.2', array([-0.71607244, -1.5286068 , 1.0747794 ], dtype=float32), {'filename': 'product_ear_pods_406_1.jpg', 'product_id': 'product_ear_pods_406', 'product_category': 'ear_pods', 'product_name': 'Wireless 5.0 Bluetooth Headset 8D Stereo Hear Pod', 'product_image_url': 'https://ng.jumia.is/unsafe/fit-in/680x680/filters:fill(white)/product/82/4189211/1.jpg?5980', 'product_url': 'https://www.jumia.com.ng/generic-wireless-5.0-bluetooth-headset-8d-stereo-hear-pod-112981428.html', 'discounted_price': '₦ 7,900', 'original_price': '₦ 10,000'}]\n",
249
+ "['JUMIA3650.3', array([-1.2911813 , -0.97381216, 0.1008972 ], dtype=float32), {'filename': 'product_ear_pods_524_0.jpg', 'product_id': 'product_ear_pods_524', 'product_category': 'ear_pods', 'product_name': 'Foam cover for Apple AirPods Max', 'product_image_url': 'https://ng.jumia.is/unsafe/fit-in/680x680/filters:fill(white)/product/19/8334991/1.jpg?4544', 'product_url': 'https://www.jumia.com.ng/generic-foam-cover-for-apple-airpods-max-199433891.html', 'discounted_price': '₦ 12,960', 'original_price': '₦ 15,552'}]\n",
250
+ "['JUMIA3650.4', array([ 0.7770873, -1.4093312, 0.375482 ], dtype=float32), {'filename': 'product_headset_672_6.jpg', 'product_id': 'product_headset_672', 'product_category': 'headset', 'product_name': 'I12TWS Wireless Bluetooth Earphone Earbuds For IOS/Android', 'product_image_url': 'https://ng.jumia.is/unsafe/fit-in/680x680/filters:fill(white)/product/28/177079/1.jpg?2017', 'product_url': 'https://www.jumia.com.ng/generic-i12tws-wireless-bluetooth-earphone-earbuds-for-iosandroid-97077182.html', 'discounted_price': '₦ 3,300', 'original_price': '₦ 5,704'}]\n"
251
+ ]
252
+ }
253
+ ],
254
+ "source": [
255
+ "from tqdm.auto import tqdm\n",
256
+ "\n",
257
+ "batch_size = 300\n",
258
+ "n_embed = len(embeddings) # number of records to index from each language\n",
259
+ "\n",
260
+ "for i in tqdm(range(0, 5)):\n",
261
+ " embed = embeddings[i]\n",
262
+ " id_ = f\"JUMIA3650.{i}\"\n",
263
+ " metadata = json_data[i]\n",
264
+ " \n",
265
+ " print([id_, embed[:3], metadata])\n",
266
+ "# index.upsert(zip(ids, embeds, metadata))"
267
+ ]
268
+ },
269
+ {
270
+ "cell_type": "code",
271
+ "execution_count": 49,
272
+ "id": "unnecessary-field",
273
+ "metadata": {},
274
+ "outputs": [
275
+ {
276
+ "data": {
277
+ "application/vnd.jupyter.widget-view+json": {
278
+ "model_id": "a697e31ff7a14a49a8138cd2db6eafc4",
279
+ "version_major": 2,
280
+ "version_minor": 0
281
+ },
282
+ "text/plain": [
283
+ " 0%| | 0/10 [00:00<?, ?it/s]"
284
+ ]
285
+ },
286
+ "metadata": {},
287
+ "output_type": "display_data"
288
+ }
289
+ ],
290
+ "source": [
291
+ "batch_size = 300\n",
292
+ "n_embed = len(embeddings) # number of records to index from each language\n",
293
+ "\n",
294
+ "\n",
295
+ "\n",
296
+ "upsert = []\n",
297
+ "for i in tqdm(range(0, n_embed, batch_size)):\n",
298
+ " ids = [f\"JUMIA_3650.{idx}\" for idx in range(i, i+batch_size)]\n",
299
+ " batch_embeddings = embeddings[i:i+batch_size]\n",
300
+ " batch_metadata = json_data[i:i+batch_size]\n",
301
+ " \n",
302
+ " index.upsert(zip(ids, batch_embeddings, batch_metadata))"
303
+ ]
304
+ },
305
+ {
306
+ "cell_type": "code",
307
+ "execution_count": 50,
308
+ "id": "friendly-mount",
309
+ "metadata": {},
310
+ "outputs": [
311
+ {
312
+ "data": {
313
+ "text/plain": [
314
+ "{'dimension': 512,\n",
315
+ " 'index_fullness': 0.0,\n",
316
+ " 'namespaces': {'': {'vector_count': 2941}},\n",
317
+ " 'total_vector_count': 2941}"
318
+ ]
319
+ },
320
+ "execution_count": 50,
321
+ "metadata": {},
322
+ "output_type": "execute_result"
323
+ }
324
+ ],
325
+ "source": [
326
+ "index.describe_index_stats()"
327
+ ]
328
+ },
329
+ {
330
+ "cell_type": "code",
331
+ "execution_count": 41,
332
+ "id": "lesser-outside",
333
+ "metadata": {},
334
+ "outputs": [
335
+ {
336
+ "data": {
337
+ "text/plain": [
338
+ "300"
339
+ ]
340
+ },
341
+ "execution_count": 41,
342
+ "metadata": {},
343
+ "output_type": "execute_result"
344
+ }
345
+ ],
346
+ "source": [
347
+ "len(embeddings[i:i+batch_size])"
348
+ ]
349
+ },
350
+ {
351
+ "cell_type": "code",
352
+ "execution_count": 32,
353
+ "id": "alpine-production",
354
+ "metadata": {},
355
+ "outputs": [
356
+ {
357
+ "data": {
358
+ "text/plain": [
359
+ "('JUMIA_3650.302',\n",
360
+ " {'filename': 'product_usb_hub_181_2.jpg',\n",
361
+ " 'product_id': 'product_usb_hub_181',\n",
362
+ " 'product_category': 'usb_hub',\n",
363
+ " 'product_name': '4 Ports USB Hub High Speed Adapter For DESKTOP LAPTOP Black Black',\n",
364
+ " 'product_image_url': 'https://ng.jumia.is/unsafe/fit-in/680x680/filters:fill(white)/product/42/215709/1.jpg?7924',\n",
365
+ " 'product_url': 'https://www.jumia.com.ng/generic-4-ports-usb-hub-high-speed-adapter-for-desktop-laptop-black-black-90751224.html',\n",
366
+ " 'discounted_price': '₦ 2,355',\n",
367
+ " 'original_price': '₦ 3,533'})"
368
+ ]
369
+ },
370
+ "execution_count": 32,
371
+ "metadata": {},
372
+ "output_type": "execute_result"
373
+ }
374
+ ],
375
+ "source": [
376
+ "upsert[1][2]"
377
+ ]
378
+ },
379
+ {
380
+ "cell_type": "code",
381
+ "execution_count": null,
382
+ "id": "mobile-printer",
383
+ "metadata": {},
384
+ "outputs": [],
385
+ "source": []
386
+ }
387
+ ],
388
+ "metadata": {
389
+ "kernelspec": {
390
+ "display_name": "Python 3",
391
+ "language": "python",
392
+ "name": "python3"
393
+ },
394
+ "language_info": {
395
+ "codemirror_mode": {
396
+ "name": "ipython",
397
+ "version": 3
398
+ },
399
+ "file_extension": ".py",
400
+ "mimetype": "text/x-python",
401
+ "name": "python",
402
+ "nbconvert_exporter": "python",
403
+ "pygments_lexer": "ipython3",
404
+ "version": "3.8.5"
405
+ }
406
+ },
407
+ "nbformat": 4,
408
+ "nbformat_minor": 5
409
+ }
data/processed/.gitkeep ADDED
File without changes
data/processed/jumia_3650/jumia_3650.json ADDED
The diff for this file is too large to render. See raw diff
 
data/processed/jumia_3650/test.csv ADDED
@@ -0,0 +1,710 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ filepath,filename,class
2
+ index/product_usb_hub_36_2.jpg,product_usb_hub_36_2.jpg,usb_hub
3
+ index/product_office_chairs_1324_1.jpg,product_office_chairs_1324_1.jpg,office_chairs
4
+ index/product_mouse_229_5.jpg,product_mouse_229_5.jpg,mouse
5
+ index/product_ear_pods_552_1.jpg,product_ear_pods_552_1.jpg,ear_pods
6
+ index/product_usb_hub_16_5.jpg,product_usb_hub_16_5.jpg,usb_hub
7
+ index/product_mouse_203_2.jpg,product_mouse_203_2.jpg,mouse
8
+ index/product_backpack_828_1.jpg,product_backpack_828_1.jpg,backpack
9
+ index/product_ear_pods_449_1.jpg,product_ear_pods_449_1.jpg,ear_pods
10
+ index/product_backpack_854_6.jpg,product_backpack_854_6.jpg,backpack
11
+ index/product_wrist_watch_1030_2.jpg,product_wrist_watch_1030_2.jpg,wrist_watch
12
+ index/product_flash_drive_1411_5.jpg,product_flash_drive_1411_5.jpg,flash_drive
13
+ index/product_backpack_865_3.jpg,product_backpack_865_3.jpg,backpack
14
+ index/product_ear_pods_421_5.jpg,product_ear_pods_421_5.jpg,ear_pods
15
+ index/product_mouse_263_0.jpg,product_mouse_263_0.jpg,mouse
16
+ index/product_wrist_watch_1049_0.jpg,product_wrist_watch_1049_0.jpg,wrist_watch
17
+ index/product_usb_hub_24_0.jpg,product_usb_hub_24_0.jpg,usb_hub
18
+ index/product_wrist_watch_1189_2.jpg,product_wrist_watch_1189_2.jpg,wrist_watch
19
+ index/product_backpack_885_4.jpg,product_backpack_885_4.jpg,backpack
20
+ index/product_wrist_watch_1048_1.jpg,product_wrist_watch_1048_1.jpg,wrist_watch
21
+ index/product_mouse_203_0.jpg,product_mouse_203_0.jpg,mouse
22
+ index/product_backpack_839_2.jpg,product_backpack_839_2.jpg,backpack
23
+ index/product_backpack_889_2.jpg,product_backpack_889_2.jpg,backpack
24
+ index/product_mouse_203_7.jpg,product_mouse_203_7.jpg,mouse
25
+ index/product_wrist_watch_1026_4.jpg,product_wrist_watch_1026_4.jpg,wrist_watch
26
+ index/product_wrist_watch_1164_1.jpg,product_wrist_watch_1164_1.jpg,wrist_watch
27
+ index/product_wrist_watch_1154_0.jpg,product_wrist_watch_1154_0.jpg,wrist_watch
28
+ index/product_backpack_828_4.jpg,product_backpack_828_4.jpg,backpack
29
+ index/product_wrist_watch_1124_1.jpg,product_wrist_watch_1124_1.jpg,wrist_watch
30
+ index/product_headset_774_0.jpg,product_headset_774_0.jpg,headset
31
+ index/product_mouse_246_0.jpg,product_mouse_246_0.jpg,mouse
32
+ index/product_wrist_watch_1061_0.jpg,product_wrist_watch_1061_0.jpg,wrist_watch
33
+ index/product_wrist_watch_1026_3.jpg,product_wrist_watch_1026_3.jpg,wrist_watch
34
+ index/product_backpack_862_2.jpg,product_backpack_862_2.jpg,backpack
35
+ index/product_usb_hub_37_0.jpg,product_usb_hub_37_0.jpg,usb_hub
36
+ index/product_backpack_839_1.jpg,product_backpack_839_1.jpg,backpack
37
+ index/product_headset_764_4.jpg,product_headset_764_4.jpg,headset
38
+ index/product_mouse_387_1.jpg,product_mouse_387_1.jpg,mouse
39
+ index/product_headset_662_1.jpg,product_headset_662_1.jpg,headset
40
+ index/product_mouse_221_0.jpg,product_mouse_221_0.jpg,mouse
41
+ index/product_flash_drive_1402_1.jpg,product_flash_drive_1402_1.jpg,flash_drive
42
+ index/product_backpack_854_3.jpg,product_backpack_854_3.jpg,backpack
43
+ index/product_ear_pods_593_4.jpg,product_ear_pods_593_4.jpg,ear_pods
44
+ index/product_backpack_880_5.jpg,product_backpack_880_5.jpg,backpack
45
+ index/product_ear_pods_445_4.jpg,product_ear_pods_445_4.jpg,ear_pods
46
+ index/product_flash_drive_1402_4.jpg,product_flash_drive_1402_4.jpg,flash_drive
47
+ index/product_wrist_watch_1095_0.jpg,product_wrist_watch_1095_0.jpg,wrist_watch
48
+ index/product_headset_721_1.jpg,product_headset_721_1.jpg,headset
49
+ index/product_usb_hub_68_2.jpg,product_usb_hub_68_2.jpg,usb_hub
50
+ index/product_usb_hub_12_1.jpg,product_usb_hub_12_1.jpg,usb_hub
51
+ index/product_headset_635_7.jpg,product_headset_635_7.jpg,headset
52
+ index/product_backpack_828_0.jpg,product_backpack_828_0.jpg,backpack
53
+ index/product_usb_hub_24_2.jpg,product_usb_hub_24_2.jpg,usb_hub
54
+ index/product_flash_drive_1407_3.jpg,product_flash_drive_1407_3.jpg,flash_drive
55
+ index/product_usb_hub_11_3.jpg,product_usb_hub_11_3.jpg,usb_hub
56
+ index/product_office_chairs_1325_1.jpg,product_office_chairs_1325_1.jpg,office_chairs
57
+ index/product_mouse_207_5.jpg,product_mouse_207_5.jpg,mouse
58
+ index/product_headset_669_1.jpg,product_headset_669_1.jpg,headset
59
+ index/product_backpack_802_4.jpg,product_backpack_802_4.jpg,backpack
60
+ index/product_backpack_885_1.jpg,product_backpack_885_1.jpg,backpack
61
+ index/product_mouse_374_1.jpg,product_mouse_374_1.jpg,mouse
62
+ index/product_mouse_246_1.jpg,product_mouse_246_1.jpg,mouse
63
+ index/product_wrist_watch_1006_2.jpg,product_wrist_watch_1006_2.jpg,wrist_watch
64
+ index/product_flash_drive_1420_8.jpg,product_flash_drive_1420_8.jpg,flash_drive
65
+ index/product_backpack_850_2.jpg,product_backpack_850_2.jpg,backpack
66
+ index/product_wrist_watch_1030_3.jpg,product_wrist_watch_1030_3.jpg,wrist_watch
67
+ index/product_mouse_203_1.jpg,product_mouse_203_1.jpg,mouse
68
+ index/product_backpack_889_4.jpg,product_backpack_889_4.jpg,backpack
69
+ index/product_headset_666_0.jpg,product_headset_666_0.jpg,headset
70
+ index/product_backpack_885_6.jpg,product_backpack_885_6.jpg,backpack
71
+ index/product_wrist_watch_1124_4.jpg,product_wrist_watch_1124_4.jpg,wrist_watch
72
+ index/product_headset_624_0.jpg,product_headset_624_0.jpg,headset
73
+ index/product_wrist_watch_1198_5.jpg,product_wrist_watch_1198_5.jpg,wrist_watch
74
+ index/product_backpack_974_1.jpg,product_backpack_974_1.jpg,backpack
75
+ index/product_usb_hub_136_4.jpg,product_usb_hub_136_4.jpg,usb_hub
76
+ index/product_ear_pods_591_5.jpg,product_ear_pods_591_5.jpg,ear_pods
77
+ index/product_usb_hub_176_1.jpg,product_usb_hub_176_1.jpg,usb_hub
78
+ index/product_usb_hub_11_4.jpg,product_usb_hub_11_4.jpg,usb_hub
79
+ index/product_ear_pods_567_0.jpg,product_ear_pods_567_0.jpg,ear_pods
80
+ index/product_mouse_324_5.jpg,product_mouse_324_5.jpg,mouse
81
+ index/product_office_chairs_1208_0.jpg,product_office_chairs_1208_0.jpg,office_chairs
82
+ index/product_usb_hub_68_3.jpg,product_usb_hub_68_3.jpg,usb_hub
83
+ index/product_flash_drive_1411_6.jpg,product_flash_drive_1411_6.jpg,flash_drive
84
+ index/product_wrist_watch_1189_3.jpg,product_wrist_watch_1189_3.jpg,wrist_watch
85
+ index/product_headset_787_4.jpg,product_headset_787_4.jpg,headset
86
+ index/product_backpack_854_1.jpg,product_backpack_854_1.jpg,backpack
87
+ index/product_headset_668_2.jpg,product_headset_668_2.jpg,headset
88
+ index/product_office_chairs_1315_0.jpg,product_office_chairs_1315_0.jpg,office_chairs
89
+ index/product_usb_hub_11_2.jpg,product_usb_hub_11_2.jpg,usb_hub
90
+ index/product_wrist_watch_1198_3.jpg,product_wrist_watch_1198_3.jpg,wrist_watch
91
+ index/product_usb_hub_68_5.jpg,product_usb_hub_68_5.jpg,usb_hub
92
+ index/product_headset_675_7.jpg,product_headset_675_7.jpg,headset
93
+ index/product_office_chairs_1393_1.jpg,product_office_chairs_1393_1.jpg,office_chairs
94
+ index/product_office_chairs_1337_0.jpg,product_office_chairs_1337_0.jpg,office_chairs
95
+ index/product_wrist_watch_1000_3.jpg,product_wrist_watch_1000_3.jpg,wrist_watch
96
+ index/product_usb_hub_37_1.jpg,product_usb_hub_37_1.jpg,usb_hub
97
+ index/product_ear_pods_456_2.jpg,product_ear_pods_456_2.jpg,ear_pods
98
+ index/product_backpack_817_3.jpg,product_backpack_817_3.jpg,backpack
99
+ index/product_usb_hub_36_0.jpg,product_usb_hub_36_0.jpg,usb_hub
100
+ index/product_usb_hub_16_2.jpg,product_usb_hub_16_2.jpg,usb_hub
101
+ index/product_usb_hub_36_3.jpg,product_usb_hub_36_3.jpg,usb_hub
102
+ index/product_flash_drive_1407_1.jpg,product_flash_drive_1407_1.jpg,flash_drive
103
+ index/product_wrist_watch_1022_5.jpg,product_wrist_watch_1022_5.jpg,wrist_watch
104
+ index/product_mouse_263_7.jpg,product_mouse_263_7.jpg,mouse
105
+ index/product_mouse_349_6.jpg,product_mouse_349_6.jpg,mouse
106
+ index/product_headset_662_0.jpg,product_headset_662_0.jpg,headset
107
+ index/product_office_chairs_1350_0.jpg,product_office_chairs_1350_0.jpg,office_chairs
108
+ index/product_usb_hub_136_2.jpg,product_usb_hub_136_2.jpg,usb_hub
109
+ index/product_backpack_910_5.jpg,product_backpack_910_5.jpg,backpack
110
+ index/product_backpack_839_3.jpg,product_backpack_839_3.jpg,backpack
111
+ index/product_headset_639_0.jpg,product_headset_639_0.jpg,headset
112
+ index/product_mouse_349_5.jpg,product_mouse_349_5.jpg,mouse
113
+ index/product_wrist_watch_1189_1.jpg,product_wrist_watch_1189_1.jpg,wrist_watch
114
+ index/product_flash_drive_1411_4.jpg,product_flash_drive_1411_4.jpg,flash_drive
115
+ index/product_ear_pods_456_1.jpg,product_ear_pods_456_1.jpg,ear_pods
116
+ index/product_backpack_854_0.jpg,product_backpack_854_0.jpg,backpack
117
+ index/product_ear_pods_552_3.jpg,product_ear_pods_552_3.jpg,ear_pods
118
+ index/product_wrist_watch_1006_4.jpg,product_wrist_watch_1006_4.jpg,wrist_watch
119
+ index/product_headset_662_7.jpg,product_headset_662_7.jpg,headset
120
+ index/product_flash_drive_1402_2.jpg,product_flash_drive_1402_2.jpg,flash_drive
121
+ index/product_usb_hub_16_3.jpg,product_usb_hub_16_3.jpg,usb_hub
122
+ index/product_wrist_watch_1098_0.jpg,product_wrist_watch_1098_0.jpg,wrist_watch
123
+ index/product_backpack_889_5.jpg,product_backpack_889_5.jpg,backpack
124
+ index/product_ear_pods_445_3.jpg,product_ear_pods_445_3.jpg,ear_pods
125
+ index/product_backpack_850_7.jpg,product_backpack_850_7.jpg,backpack
126
+ index/product_wrist_watch_1029_0.jpg,product_wrist_watch_1029_0.jpg,wrist_watch
127
+ index/product_wrist_watch_1122_7.jpg,product_wrist_watch_1122_7.jpg,wrist_watch
128
+ index/product_wrist_watch_1189_5.jpg,product_wrist_watch_1189_5.jpg,wrist_watch
129
+ index/product_usb_hub_176_0.jpg,product_usb_hub_176_0.jpg,usb_hub
130
+ index/product_headset_662_2.jpg,product_headset_662_2.jpg,headset
131
+ index/product_headset_666_1.jpg,product_headset_666_1.jpg,headset
132
+ index/product_wrist_watch_1090_0.jpg,product_wrist_watch_1090_0.jpg,wrist_watch
133
+ index/product_office_chairs_1199_0.jpg,product_office_chairs_1199_0.jpg,office_chairs
134
+ index/product_ear_pods_591_2.jpg,product_ear_pods_591_2.jpg,ear_pods
135
+ index/product_backpack_813_0.jpg,product_backpack_813_0.jpg,backpack
136
+ index/product_backpack_874_0.jpg,product_backpack_874_0.jpg,backpack
137
+ index/product_ear_pods_440_4.jpg,product_ear_pods_440_4.jpg,ear_pods
138
+ index/product_headset_681_1.jpg,product_headset_681_1.jpg,headset
139
+ index/product_ear_pods_585_1.jpg,product_ear_pods_585_1.jpg,ear_pods
140
+ index/product_wrist_watch_1198_2.jpg,product_wrist_watch_1198_2.jpg,wrist_watch
141
+ index/product_wrist_watch_1022_6.jpg,product_wrist_watch_1022_6.jpg,wrist_watch
142
+ index/product_ear_pods_430_3.jpg,product_ear_pods_430_3.jpg,ear_pods
143
+ index/product_backpack_889_3.jpg,product_backpack_889_3.jpg,backpack
144
+ index/product_headset_652_3.jpg,product_headset_652_3.jpg,headset
145
+ index/product_ear_pods_445_2.jpg,product_ear_pods_445_2.jpg,ear_pods
146
+ index/product_ear_pods_509_2.jpg,product_ear_pods_509_2.jpg,ear_pods
147
+ index/product_backpack_850_6.jpg,product_backpack_850_6.jpg,backpack
148
+ index/product_wrist_watch_1026_1.jpg,product_wrist_watch_1026_1.jpg,wrist_watch
149
+ index/product_ear_pods_488_1.jpg,product_ear_pods_488_1.jpg,ear_pods
150
+ index/product_headset_635_2.jpg,product_headset_635_2.jpg,headset
151
+ index/product_flash_drive_1420_7.jpg,product_flash_drive_1420_7.jpg,flash_drive
152
+ index/product_office_chairs_1296_1.jpg,product_office_chairs_1296_1.jpg,office_chairs
153
+ index/product_mouse_217_1.jpg,product_mouse_217_1.jpg,mouse
154
+ index/product_headset_631_1.jpg,product_headset_631_1.jpg,headset
155
+ index/product_wrist_watch_1030_5.jpg,product_wrist_watch_1030_5.jpg,wrist_watch
156
+ index/product_ear_pods_521_3.jpg,product_ear_pods_521_3.jpg,ear_pods
157
+ index/product_headset_631_2.jpg,product_headset_631_2.jpg,headset
158
+ index/product_flash_drive_1403_6.jpg,product_flash_drive_1403_6.jpg,flash_drive
159
+ index/product_wrist_watch_1022_1.jpg,product_wrist_watch_1022_1.jpg,wrist_watch
160
+ index/product_usb_hub_11_5.jpg,product_usb_hub_11_5.jpg,usb_hub
161
+ index/product_mouse_207_0.jpg,product_mouse_207_0.jpg,mouse
162
+ index/product_usb_hub_173_0.jpg,product_usb_hub_173_0.jpg,usb_hub
163
+ index/product_headset_615_8.jpg,product_headset_615_8.jpg,headset
164
+ index/product_backpack_831_4.jpg,product_backpack_831_4.jpg,backpack
165
+ index/product_backpack_828_2.jpg,product_backpack_828_2.jpg,backpack
166
+ index/product_backpack_855_4.jpg,product_backpack_855_4.jpg,backpack
167
+ index/product_ear_pods_430_0.jpg,product_ear_pods_430_0.jpg,ear_pods
168
+ index/product_mouse_267_6.jpg,product_mouse_267_6.jpg,mouse
169
+ index/product_wrist_watch_1175_0.jpg,product_wrist_watch_1175_0.jpg,wrist_watch
170
+ index/product_ear_pods_535_1.jpg,product_ear_pods_535_1.jpg,ear_pods
171
+ index/product_headset_635_1.jpg,product_headset_635_1.jpg,headset
172
+ index/product_backpack_817_7.jpg,product_backpack_817_7.jpg,backpack
173
+ index/product_wrist_watch_1006_0.jpg,product_wrist_watch_1006_0.jpg,wrist_watch
174
+ index/product_backpack_910_7.jpg,product_backpack_910_7.jpg,backpack
175
+ index/product_office_chairs_1296_2.jpg,product_office_chairs_1296_2.jpg,office_chairs
176
+ index/product_wrist_watch_1043_6.jpg,product_wrist_watch_1043_6.jpg,wrist_watch
177
+ index/product_ear_pods_434_4.jpg,product_ear_pods_434_4.jpg,ear_pods
178
+ index/product_flash_drive_1445_4.jpg,product_flash_drive_1445_4.jpg,flash_drive
179
+ index/product_wrist_watch_1178_1.jpg,product_wrist_watch_1178_1.jpg,wrist_watch
180
+ index/product_backpack_865_4.jpg,product_backpack_865_4.jpg,backpack
181
+ index/product_backpack_885_0.jpg,product_backpack_885_0.jpg,backpack
182
+ index/product_headset_652_0.jpg,product_headset_652_0.jpg,headset
183
+ index/product_ear_pods_585_0.jpg,product_ear_pods_585_0.jpg,ear_pods
184
+ index/product_flash_drive_1445_6.jpg,product_flash_drive_1445_6.jpg,flash_drive
185
+ index/product_headset_675_6.jpg,product_headset_675_6.jpg,headset
186
+ index/product_ear_pods_430_1.jpg,product_ear_pods_430_1.jpg,ear_pods
187
+ index/product_usb_hub_186_1.jpg,product_usb_hub_186_1.jpg,usb_hub
188
+ index/product_office_chairs_1208_3.jpg,product_office_chairs_1208_3.jpg,office_chairs
189
+ index/product_headset_693_5.jpg,product_headset_693_5.jpg,headset
190
+ index/product_mouse_374_0.jpg,product_mouse_374_0.jpg,mouse
191
+ index/product_backpack_812_4.jpg,product_backpack_812_4.jpg,backpack
192
+ index/product_mouse_203_5.jpg,product_mouse_203_5.jpg,mouse
193
+ index/product_mouse_246_4.jpg,product_mouse_246_4.jpg,mouse
194
+ index/product_wrist_watch_1198_6.jpg,product_wrist_watch_1198_6.jpg,wrist_watch
195
+ index/product_backpack_865_2.jpg,product_backpack_865_2.jpg,backpack
196
+ index/product_office_chairs_1325_0.jpg,product_office_chairs_1325_0.jpg,office_chairs
197
+ index/product_mouse_229_4.jpg,product_mouse_229_4.jpg,mouse
198
+ index/product_backpack_865_1.jpg,product_backpack_865_1.jpg,backpack
199
+ index/product_backpack_804_0.jpg,product_backpack_804_0.jpg,backpack
200
+ index/product_wrist_watch_1122_3.jpg,product_wrist_watch_1122_3.jpg,wrist_watch
201
+ index/product_mouse_221_1.jpg,product_mouse_221_1.jpg,mouse
202
+ index/product_usb_hub_165_5.jpg,product_usb_hub_165_5.jpg,usb_hub
203
+ index/product_usb_hub_24_7.jpg,product_usb_hub_24_7.jpg,usb_hub
204
+ index/product_office_chairs_1225_0.jpg,product_office_chairs_1225_0.jpg,office_chairs
205
+ index/product_usb_hub_68_4.jpg,product_usb_hub_68_4.jpg,usb_hub
206
+ index/product_wrist_watch_1122_2.jpg,product_wrist_watch_1122_2.jpg,wrist_watch
207
+ index/product_ear_pods_576_6.jpg,product_ear_pods_576_6.jpg,ear_pods
208
+ index/product_usb_hub_168_2.jpg,product_usb_hub_168_2.jpg,usb_hub
209
+ index/product_ear_pods_492_0.jpg,product_ear_pods_492_0.jpg,ear_pods
210
+ index/product_usb_hub_68_1.jpg,product_usb_hub_68_1.jpg,usb_hub
211
+ index/product_office_chairs_1393_0.jpg,product_office_chairs_1393_0.jpg,office_chairs
212
+ index/product_wrist_watch_1011_1.jpg,product_wrist_watch_1011_1.jpg,wrist_watch
213
+ index/product_mouse_207_3.jpg,product_mouse_207_3.jpg,mouse
214
+ index/product_usb_hub_3_0.jpg,product_usb_hub_3_0.jpg,usb_hub
215
+ index/product_flash_drive_1407_6.jpg,product_flash_drive_1407_6.jpg,flash_drive
216
+ index/product_mouse_390_0.jpg,product_mouse_390_0.jpg,mouse
217
+ index/product_mouse_390_2.jpg,product_mouse_390_2.jpg,mouse
218
+ index/product_usb_hub_185_0.jpg,product_usb_hub_185_0.jpg,usb_hub
219
+ index/product_backpack_864_5.jpg,product_backpack_864_5.jpg,backpack
220
+ index/product_wrist_watch_1067_1.jpg,product_wrist_watch_1067_1.jpg,wrist_watch
221
+ index/product_ear_pods_572_0.jpg,product_ear_pods_572_0.jpg,ear_pods
222
+ index/product_backpack_817_0.jpg,product_backpack_817_0.jpg,backpack
223
+ index/product_backpack_802_2.jpg,product_backpack_802_2.jpg,backpack
224
+ index/product_ear_pods_585_3.jpg,product_ear_pods_585_3.jpg,ear_pods
225
+ index/product_backpack_813_7.jpg,product_backpack_813_7.jpg,backpack
226
+ index/product_backpack_910_2.jpg,product_backpack_910_2.jpg,backpack
227
+ index/product_usb_hub_3_2.jpg,product_usb_hub_3_2.jpg,usb_hub
228
+ index/product_office_chairs_1208_1.jpg,product_office_chairs_1208_1.jpg,office_chairs
229
+ index/product_ear_pods_574_3.jpg,product_ear_pods_574_3.jpg,ear_pods
230
+ index/product_usb_hub_16_4.jpg,product_usb_hub_16_4.jpg,usb_hub
231
+ index/product_ear_pods_449_2.jpg,product_ear_pods_449_2.jpg,ear_pods
232
+ index/product_backpack_885_2.jpg,product_backpack_885_2.jpg,backpack
233
+ index/product_ear_pods_567_5.jpg,product_ear_pods_567_5.jpg,ear_pods
234
+ index/product_mouse_217_3.jpg,product_mouse_217_3.jpg,mouse
235
+ index/product_headset_764_0.jpg,product_headset_764_0.jpg,headset
236
+ index/product_ear_pods_552_2.jpg,product_ear_pods_552_2.jpg,ear_pods
237
+ index/product_headset_615_6.jpg,product_headset_615_6.jpg,headset
238
+ index/product_headset_649_0.jpg,product_headset_649_0.jpg,headset
239
+ index/product_headset_625_1.jpg,product_headset_625_1.jpg,headset
240
+ index/product_usb_hub_165_1.jpg,product_usb_hub_165_1.jpg,usb_hub
241
+ index/product_usb_hub_168_0.jpg,product_usb_hub_168_0.jpg,usb_hub
242
+ index/product_usb_hub_24_6.jpg,product_usb_hub_24_6.jpg,usb_hub
243
+ index/product_flash_drive_1420_6.jpg,product_flash_drive_1420_6.jpg,flash_drive
244
+ index/product_backpack_885_3.jpg,product_backpack_885_3.jpg,backpack
245
+ index/product_flash_drive_1402_0.jpg,product_flash_drive_1402_0.jpg,flash_drive
246
+ index/product_ear_pods_442_4.jpg,product_ear_pods_442_4.jpg,ear_pods
247
+ index/product_wrist_watch_1122_5.jpg,product_wrist_watch_1122_5.jpg,wrist_watch
248
+ index/product_backpack_813_6.jpg,product_backpack_813_6.jpg,backpack
249
+ index/product_ear_pods_574_0.jpg,product_ear_pods_574_0.jpg,ear_pods
250
+ index/product_ear_pods_434_3.jpg,product_ear_pods_434_3.jpg,ear_pods
251
+ index/product_flash_drive_1407_2.jpg,product_flash_drive_1407_2.jpg,flash_drive
252
+ index/product_wrist_watch_1022_0.jpg,product_wrist_watch_1022_0.jpg,wrist_watch
253
+ index/product_wrist_watch_1030_1.jpg,product_wrist_watch_1030_1.jpg,wrist_watch
254
+ index/product_backpack_817_4.jpg,product_backpack_817_4.jpg,backpack
255
+ index/product_wrist_watch_1006_1.jpg,product_wrist_watch_1006_1.jpg,wrist_watch
256
+ index/product_headset_641_5.jpg,product_headset_641_5.jpg,headset
257
+ index/product_wrist_watch_1000_0.jpg,product_wrist_watch_1000_0.jpg,wrist_watch
258
+ index/product_backpack_864_4.jpg,product_backpack_864_4.jpg,backpack
259
+ index/product_mouse_267_7.jpg,product_mouse_267_7.jpg,mouse
260
+ index/product_headset_639_3.jpg,product_headset_639_3.jpg,headset
261
+ index/product_ear_pods_574_5.jpg,product_ear_pods_574_5.jpg,ear_pods
262
+ index/product_headset_669_0.jpg,product_headset_669_0.jpg,headset
263
+ index/product_backpack_974_0.jpg,product_backpack_974_0.jpg,backpack
264
+ index/product_wrist_watch_1189_6.jpg,product_wrist_watch_1189_6.jpg,wrist_watch
265
+ index/product_mouse_203_6.jpg,product_mouse_203_6.jpg,mouse
266
+ index/product_headset_693_4.jpg,product_headset_693_4.jpg,headset
267
+ index/product_backpack_874_6.jpg,product_backpack_874_6.jpg,backpack
268
+ index/product_ear_pods_574_4.jpg,product_ear_pods_574_4.jpg,ear_pods
269
+ index/product_wrist_watch_1107_2.jpg,product_wrist_watch_1107_2.jpg,wrist_watch
270
+ index/product_ear_pods_488_2.jpg,product_ear_pods_488_2.jpg,ear_pods
271
+ index/product_headset_787_2.jpg,product_headset_787_2.jpg,headset
272
+ index/product_ear_pods_412_1.jpg,product_ear_pods_412_1.jpg,ear_pods
273
+ index/product_ear_pods_576_0.jpg,product_ear_pods_576_0.jpg,ear_pods
274
+ index/product_flash_drive_1420_2.jpg,product_flash_drive_1420_2.jpg,flash_drive
275
+ index/product_backpack_874_3.jpg,product_backpack_874_3.jpg,backpack
276
+ index/product_wrist_watch_1026_0.jpg,product_wrist_watch_1026_0.jpg,wrist_watch
277
+ index/product_ear_pods_593_5.jpg,product_ear_pods_593_5.jpg,ear_pods
278
+ index/product_headset_662_3.jpg,product_headset_662_3.jpg,headset
279
+ index/product_backpack_854_4.jpg,product_backpack_854_4.jpg,backpack
280
+ index/product_mouse_324_4.jpg,product_mouse_324_4.jpg,mouse
281
+ index/product_wrist_watch_1011_0.jpg,product_wrist_watch_1011_0.jpg,wrist_watch
282
+ index/product_headset_625_0.jpg,product_headset_625_0.jpg,headset
283
+ index/product_ear_pods_585_4.jpg,product_ear_pods_585_4.jpg,ear_pods
284
+ index/product_ear_pods_445_1.jpg,product_ear_pods_445_1.jpg,ear_pods
285
+ index/product_office_chairs_1215_0.jpg,product_office_chairs_1215_0.jpg,office_chairs
286
+ index/product_wrist_watch_1198_0.jpg,product_wrist_watch_1198_0.jpg,wrist_watch
287
+ index/product_usb_hub_24_4.jpg,product_usb_hub_24_4.jpg,usb_hub
288
+ index/product_mouse_349_0.jpg,product_mouse_349_0.jpg,mouse
289
+ index/product_mouse_324_6.jpg,product_mouse_324_6.jpg,mouse
290
+ index/product_headset_615_0.jpg,product_headset_615_0.jpg,headset
291
+ index/product_mouse_372_0.jpg,product_mouse_372_0.jpg,mouse
292
+ index/product_ear_pods_434_1.jpg,product_ear_pods_434_1.jpg,ear_pods
293
+ index/product_headset_652_2.jpg,product_headset_652_2.jpg,headset
294
+ index/product_office_chairs_1204_0.jpg,product_office_chairs_1204_0.jpg,office_chairs
295
+ index/product_mouse_292_0.jpg,product_mouse_292_0.jpg,mouse
296
+ index/product_wrist_watch_1107_3.jpg,product_wrist_watch_1107_3.jpg,wrist_watch
297
+ index/product_backpack_812_1.jpg,product_backpack_812_1.jpg,backpack
298
+ index/product_backpack_850_1.jpg,product_backpack_850_1.jpg,backpack
299
+ index/product_mouse_349_3.jpg,product_mouse_349_3.jpg,mouse
300
+ index/product_mouse_349_2.jpg,product_mouse_349_2.jpg,mouse
301
+ index/product_mouse_212_3.jpg,product_mouse_212_3.jpg,mouse
302
+ index/product_backpack_880_6.jpg,product_backpack_880_6.jpg,backpack
303
+ index/product_mouse_267_5.jpg,product_mouse_267_5.jpg,mouse
304
+ index/product_backpack_804_2.jpg,product_backpack_804_2.jpg,backpack
305
+ index/product_wrist_watch_1122_6.jpg,product_wrist_watch_1122_6.jpg,wrist_watch
306
+ index/product_usb_hub_176_7.jpg,product_usb_hub_176_7.jpg,usb_hub
307
+ index/product_backpack_813_1.jpg,product_backpack_813_1.jpg,backpack
308
+ index/product_headset_787_0.jpg,product_headset_787_0.jpg,headset
309
+ index/product_headset_641_2.jpg,product_headset_641_2.jpg,headset
310
+ index/product_backpack_812_0.jpg,product_backpack_812_0.jpg,backpack
311
+ index/product_wrist_watch_1178_0.jpg,product_wrist_watch_1178_0.jpg,wrist_watch
312
+ index/product_ear_pods_442_5.jpg,product_ear_pods_442_5.jpg,ear_pods
313
+ index/product_ear_pods_445_0.jpg,product_ear_pods_445_0.jpg,ear_pods
314
+ index/product_usb_hub_161_0.jpg,product_usb_hub_161_0.jpg,usb_hub
315
+ index/product_ear_pods_434_2.jpg,product_ear_pods_434_2.jpg,ear_pods
316
+ index/product_wrist_watch_1122_1.jpg,product_wrist_watch_1122_1.jpg,wrist_watch
317
+ index/product_mouse_246_3.jpg,product_mouse_246_3.jpg,mouse
318
+ index/product_backpack_885_7.jpg,product_backpack_885_7.jpg,backpack
319
+ index/product_backpack_874_4.jpg,product_backpack_874_4.jpg,backpack
320
+ index/product_ear_pods_591_3.jpg,product_ear_pods_591_3.jpg,ear_pods
321
+ index/product_backpack_812_3.jpg,product_backpack_812_3.jpg,backpack
322
+ index/product_headset_764_2.jpg,product_headset_764_2.jpg,headset
323
+ index/product_mouse_324_0.jpg,product_mouse_324_0.jpg,mouse
324
+ index/product_wrist_watch_1000_2.jpg,product_wrist_watch_1000_2.jpg,wrist_watch
325
+ index/product_wrist_watch_1006_6.jpg,product_wrist_watch_1006_6.jpg,wrist_watch
326
+ index/product_ear_pods_412_2.jpg,product_ear_pods_412_2.jpg,ear_pods
327
+ index/product_ear_pods_593_3.jpg,product_ear_pods_593_3.jpg,ear_pods
328
+ index/product_flash_drive_1402_3.jpg,product_flash_drive_1402_3.jpg,flash_drive
329
+ index/product_wrist_watch_1006_5.jpg,product_wrist_watch_1006_5.jpg,wrist_watch
330
+ index/product_mouse_246_6.jpg,product_mouse_246_6.jpg,mouse
331
+ index/product_backpack_802_1.jpg,product_backpack_802_1.jpg,backpack
332
+ index/product_ear_pods_412_0.jpg,product_ear_pods_412_0.jpg,ear_pods
333
+ index/product_headset_764_1.jpg,product_headset_764_1.jpg,headset
334
+ index/product_flash_drive_1445_3.jpg,product_flash_drive_1445_3.jpg,flash_drive
335
+ index/product_ear_pods_412_4.jpg,product_ear_pods_412_4.jpg,ear_pods
336
+ index/product_mouse_207_6.jpg,product_mouse_207_6.jpg,mouse
337
+ index/product_backpack_910_0.jpg,product_backpack_910_0.jpg,backpack
338
+ index/product_usb_hub_11_0.jpg,product_usb_hub_11_0.jpg,usb_hub
339
+ index/product_backpack_862_3.jpg,product_backpack_862_3.jpg,backpack
340
+ index/product_headset_625_2.jpg,product_headset_625_2.jpg,headset
341
+ index/product_backpack_910_6.jpg,product_backpack_910_6.jpg,backpack
342
+ index/product_headset_652_1.jpg,product_headset_652_1.jpg,headset
343
+ index/product_backpack_844_0.jpg,product_backpack_844_0.jpg,backpack
344
+ index/product_office_chairs_1204_1.jpg,product_office_chairs_1204_1.jpg,office_chairs
345
+ index/product_usb_hub_12_0.jpg,product_usb_hub_12_0.jpg,usb_hub
346
+ index/product_usb_hub_136_5.jpg,product_usb_hub_136_5.jpg,usb_hub
347
+ index/product_mouse_246_5.jpg,product_mouse_246_5.jpg,mouse
348
+ index/product_usb_hub_136_1.jpg,product_usb_hub_136_1.jpg,usb_hub
349
+ index/product_ear_pods_576_3.jpg,product_ear_pods_576_3.jpg,ear_pods
350
+ index/product_headset_721_2.jpg,product_headset_721_2.jpg,headset
351
+ index/product_wrist_watch_1000_1.jpg,product_wrist_watch_1000_1.jpg,wrist_watch
352
+ index/product_ear_pods_403_0.jpg,product_ear_pods_403_0.jpg,ear_pods
353
+ index/product_wrist_watch_1022_2.jpg,product_wrist_watch_1022_2.jpg,wrist_watch
354
+ index/product_usb_hub_24_3.jpg,product_usb_hub_24_3.jpg,usb_hub
355
+ index/product_headset_721_4.jpg,product_headset_721_4.jpg,headset
356
+ index/product_ear_pods_567_2.jpg,product_ear_pods_567_2.jpg,ear_pods
357
+ index/product_flash_drive_1445_1.jpg,product_flash_drive_1445_1.jpg,flash_drive
358
+ index/product_mouse_238_0.jpg,product_mouse_238_0.jpg,mouse
359
+ index/product_usb_hub_176_2.jpg,product_usb_hub_176_2.jpg,usb_hub
360
+ index/product_headset_774_2.jpg,product_headset_774_2.jpg,headset
361
+ index/product_usb_hub_11_1.jpg,product_usb_hub_11_1.jpg,usb_hub
362
+ index/product_flash_drive_1445_2.jpg,product_flash_drive_1445_2.jpg,flash_drive
363
+ index/product_ear_pods_434_0.jpg,product_ear_pods_434_0.jpg,ear_pods
364
+ index/product_headset_787_6.jpg,product_headset_787_6.jpg,headset
365
+ index/product_flash_drive_1445_5.jpg,product_flash_drive_1445_5.jpg,flash_drive
366
+ index/product_ear_pods_593_2.jpg,product_ear_pods_593_2.jpg,ear_pods
367
+ index/product_headset_721_0.jpg,product_headset_721_0.jpg,headset
368
+ index/product_backpack_889_1.jpg,product_backpack_889_1.jpg,backpack
369
+ index/product_ear_pods_576_4.jpg,product_ear_pods_576_4.jpg,ear_pods
370
+ index/product_mouse_324_3.jpg,product_mouse_324_3.jpg,mouse
371
+ index/product_flash_drive_1402_5.jpg,product_flash_drive_1402_5.jpg,flash_drive
372
+ index/product_usb_hub_176_5.jpg,product_usb_hub_176_5.jpg,usb_hub
373
+ index/product_usb_hub_112_0.jpg,product_usb_hub_112_0.jpg,usb_hub
374
+ index/product_ear_pods_457_0.jpg,product_ear_pods_457_0.jpg,ear_pods
375
+ index/product_mouse_267_0.jpg,product_mouse_267_0.jpg,mouse
376
+ index/product_backpack_854_5.jpg,product_backpack_854_5.jpg,backpack
377
+ index/product_backpack_835_0.jpg,product_backpack_835_0.jpg,backpack
378
+ index/product_backpack_874_7.jpg,product_backpack_874_7.jpg,backpack
379
+ index/product_backpack_855_3.jpg,product_backpack_855_3.jpg,backpack
380
+ index/product_flash_drive_1420_0.jpg,product_flash_drive_1420_0.jpg,flash_drive
381
+ index/product_headset_690_0.jpg,product_headset_690_0.jpg,headset
382
+ index/product_wrist_watch_1020_1.jpg,product_wrist_watch_1020_1.jpg,wrist_watch
383
+ index/product_wrist_watch_1180_2.jpg,product_wrist_watch_1180_2.jpg,wrist_watch
384
+ index/product_headset_668_3.jpg,product_headset_668_3.jpg,headset
385
+ index/product_ear_pods_585_6.jpg,product_ear_pods_585_6.jpg,ear_pods
386
+ index/product_usb_hub_168_3.jpg,product_usb_hub_168_3.jpg,usb_hub
387
+ index/product_wrist_watch_1122_4.jpg,product_wrist_watch_1122_4.jpg,wrist_watch
388
+ index/product_backpack_813_4.jpg,product_backpack_813_4.jpg,backpack
389
+ index/product_headset_641_3.jpg,product_headset_641_3.jpg,headset
390
+ index/product_ear_pods_430_2.jpg,product_ear_pods_430_2.jpg,ear_pods
391
+ index/product_mouse_282_2.jpg,product_mouse_282_2.jpg,mouse
392
+ index/product_usb_hub_16_1.jpg,product_usb_hub_16_1.jpg,usb_hub
393
+ index/product_wrist_watch_1061_1.jpg,product_wrist_watch_1061_1.jpg,wrist_watch
394
+ index/product_ear_pods_509_4.jpg,product_ear_pods_509_4.jpg,ear_pods
395
+ index/product_wrist_watch_1198_1.jpg,product_wrist_watch_1198_1.jpg,wrist_watch
396
+ index/product_usb_hub_11_6.jpg,product_usb_hub_11_6.jpg,usb_hub
397
+ index/product_ear_pods_574_2.jpg,product_ear_pods_574_2.jpg,ear_pods
398
+ index/product_backpack_813_5.jpg,product_backpack_813_5.jpg,backpack
399
+ index/product_wrist_watch_1033_0.jpg,product_wrist_watch_1033_0.jpg,wrist_watch
400
+ index/product_usb_hub_124_1.jpg,product_usb_hub_124_1.jpg,usb_hub
401
+ index/product_ear_pods_576_1.jpg,product_ear_pods_576_1.jpg,ear_pods
402
+ index/product_backpack_854_2.jpg,product_backpack_854_2.jpg,backpack
403
+ index/product_mouse_246_2.jpg,product_mouse_246_2.jpg,mouse
404
+ index/product_headset_657_1.jpg,product_headset_657_1.jpg,headset
405
+ index/product_wrist_watch_1061_2.jpg,product_wrist_watch_1061_2.jpg,wrist_watch
406
+ index/product_wrist_watch_1011_2.jpg,product_wrist_watch_1011_2.jpg,wrist_watch
407
+ index/product_headset_649_1.jpg,product_headset_649_1.jpg,headset
408
+ index/product_usb_hub_136_0.jpg,product_usb_hub_136_0.jpg,usb_hub
409
+ index/product_mouse_217_0.jpg,product_mouse_217_0.jpg,mouse
410
+ index/product_usb_hub_176_3.jpg,product_usb_hub_176_3.jpg,usb_hub
411
+ index/product_ear_pods_583_0.jpg,product_ear_pods_583_0.jpg,ear_pods
412
+ index/product_usb_hub_165_2.jpg,product_usb_hub_165_2.jpg,usb_hub
413
+ index/product_ear_pods_466_4.jpg,product_ear_pods_466_4.jpg,ear_pods
414
+ index/product_headset_781_1.jpg,product_headset_781_1.jpg,headset
415
+ index/product_wrist_watch_1022_4.jpg,product_wrist_watch_1022_4.jpg,wrist_watch
416
+ index/product_wrist_watch_1098_1.jpg,product_wrist_watch_1098_1.jpg,wrist_watch
417
+ index/product_flash_drive_1402_6.jpg,product_flash_drive_1402_6.jpg,flash_drive
418
+ index/product_ear_pods_552_5.jpg,product_ear_pods_552_5.jpg,ear_pods
419
+ index/product_backpack_889_0.jpg,product_backpack_889_0.jpg,backpack
420
+ index/product_mouse_372_4.jpg,product_mouse_372_4.jpg,mouse
421
+ index/product_backpack_831_1.jpg,product_backpack_831_1.jpg,backpack
422
+ index/product_backpack_874_5.jpg,product_backpack_874_5.jpg,backpack
423
+ index/product_usb_hub_36_1.jpg,product_usb_hub_36_1.jpg,usb_hub
424
+ index/product_backpack_850_0.jpg,product_backpack_850_0.jpg,backpack
425
+ index/product_ear_pods_567_3.jpg,product_ear_pods_567_3.jpg,ear_pods
426
+ index/product_wrist_watch_1189_4.jpg,product_wrist_watch_1189_4.jpg,wrist_watch
427
+ index/product_wrist_watch_1168_0.jpg,product_wrist_watch_1168_0.jpg,wrist_watch
428
+ index/product_wrist_watch_1180_1.jpg,product_wrist_watch_1180_1.jpg,wrist_watch
429
+ index/product_headset_774_4.jpg,product_headset_774_4.jpg,headset
430
+ index/product_usb_hub_24_1.jpg,product_usb_hub_24_1.jpg,usb_hub
431
+ index/product_flash_drive_1403_4.jpg,product_flash_drive_1403_4.jpg,flash_drive
432
+ index/product_mouse_263_2.jpg,product_mouse_263_2.jpg,mouse
433
+ index/product_headset_721_3.jpg,product_headset_721_3.jpg,headset
434
+ index/product_ear_pods_403_1.jpg,product_ear_pods_403_1.jpg,ear_pods
435
+ index/product_usb_hub_186_0.jpg,product_usb_hub_186_0.jpg,usb_hub
436
+ index/product_headset_765_0.jpg,product_headset_765_0.jpg,headset
437
+ index/product_backpack_910_3.jpg,product_backpack_910_3.jpg,backpack
438
+ index/product_headset_652_4.jpg,product_headset_652_4.jpg,headset
439
+ index/product_headset_774_3.jpg,product_headset_774_3.jpg,headset
440
+ index/product_flash_drive_1403_3.jpg,product_flash_drive_1403_3.jpg,flash_drive
441
+ index/product_backpack_802_3.jpg,product_backpack_802_3.jpg,backpack
442
+ index/product_headset_639_1.jpg,product_headset_639_1.jpg,headset
443
+ index/product_mouse_372_5.jpg,product_mouse_372_5.jpg,mouse
444
+ index/product_wrist_watch_1198_4.jpg,product_wrist_watch_1198_4.jpg,wrist_watch
445
+ index/product_backpack_839_0.jpg,product_backpack_839_0.jpg,backpack
446
+ index/product_wrist_watch_1022_3.jpg,product_wrist_watch_1022_3.jpg,wrist_watch
447
+ index/product_backpack_844_1.jpg,product_backpack_844_1.jpg,backpack
448
+ index/product_backpack_802_0.jpg,product_backpack_802_0.jpg,backpack
449
+ index/product_ear_pods_576_2.jpg,product_ear_pods_576_2.jpg,ear_pods
450
+ index/product_mouse_217_2.jpg,product_mouse_217_2.jpg,mouse
451
+ index/product_usb_hub_68_0.jpg,product_usb_hub_68_0.jpg,usb_hub
452
+ index/product_flash_drive_1403_1.jpg,product_flash_drive_1403_1.jpg,flash_drive
453
+ index/product_ear_pods_488_0.jpg,product_ear_pods_488_0.jpg,ear_pods
454
+ index/product_backpack_804_5.jpg,product_backpack_804_5.jpg,backpack
455
+ index/product_backpack_880_4.jpg,product_backpack_880_4.jpg,backpack
456
+ index/product_flash_drive_1403_2.jpg,product_flash_drive_1403_2.jpg,flash_drive
457
+ index/product_wrist_watch_1043_0.jpg,product_wrist_watch_1043_0.jpg,wrist_watch
458
+ index/product_backpack_932_0.jpg,product_backpack_932_0.jpg,backpack
459
+ index/product_wrist_watch_1006_3.jpg,product_wrist_watch_1006_3.jpg,wrist_watch
460
+ index/product_headset_662_4.jpg,product_headset_662_4.jpg,headset
461
+ index/product_mouse_263_1.jpg,product_mouse_263_1.jpg,mouse
462
+ index/product_usb_hub_168_5.jpg,product_usb_hub_168_5.jpg,usb_hub
463
+ index/product_office_chairs_1256_0.jpg,product_office_chairs_1256_0.jpg,office_chairs
464
+ index/product_wrist_watch_1124_3.jpg,product_wrist_watch_1124_3.jpg,wrist_watch
465
+ index/product_office_chairs_1296_0.jpg,product_office_chairs_1296_0.jpg,office_chairs
466
+ index/product_headset_641_0.jpg,product_headset_641_0.jpg,headset
467
+ index/product_wrist_watch_1020_0.jpg,product_wrist_watch_1020_0.jpg,wrist_watch
468
+ index/product_ear_pods_591_0.jpg,product_ear_pods_591_0.jpg,ear_pods
469
+ index/product_wrist_watch_1164_0.jpg,product_wrist_watch_1164_0.jpg,wrist_watch
470
+ index/product_headset_662_6.jpg,product_headset_662_6.jpg,headset
471
+ index/product_wrist_watch_1043_3.jpg,product_wrist_watch_1043_3.jpg,wrist_watch
472
+ index/product_ear_pods_509_1.jpg,product_ear_pods_509_1.jpg,ear_pods
473
+ index/product_wrist_watch_1180_0.jpg,product_wrist_watch_1180_0.jpg,wrist_watch
474
+ index/product_ear_pods_591_4.jpg,product_ear_pods_591_4.jpg,ear_pods
475
+ index/product_flash_drive_1403_0.jpg,product_flash_drive_1403_0.jpg,flash_drive
476
+ index/product_backpack_817_5.jpg,product_backpack_817_5.jpg,backpack
477
+ index/product_ear_pods_412_3.jpg,product_ear_pods_412_3.jpg,ear_pods
478
+ index/product_backpack_817_2.jpg,product_backpack_817_2.jpg,backpack
479
+ index/product_flash_drive_1424_0.jpg,product_flash_drive_1424_0.jpg,flash_drive
480
+ index/product_flash_drive_1407_4.jpg,product_flash_drive_1407_4.jpg,flash_drive
481
+ index/product_mouse_372_7.jpg,product_mouse_372_7.jpg,mouse
482
+ index/product_wrist_watch_1030_6.jpg,product_wrist_watch_1030_6.jpg,wrist_watch
483
+ index/product_ear_pods_521_0.jpg,product_ear_pods_521_0.jpg,ear_pods
484
+ index/product_mouse_324_7.jpg,product_mouse_324_7.jpg,mouse
485
+ index/product_backpack_831_2.jpg,product_backpack_831_2.jpg,backpack
486
+ index/product_ear_pods_466_5.jpg,product_ear_pods_466_5.jpg,ear_pods
487
+ index/product_ear_pods_449_0.jpg,product_ear_pods_449_0.jpg,ear_pods
488
+ index/product_backpack_817_1.jpg,product_backpack_817_1.jpg,backpack
489
+ index/product_ear_pods_552_6.jpg,product_ear_pods_552_6.jpg,ear_pods
490
+ index/product_wrist_watch_1026_2.jpg,product_wrist_watch_1026_2.jpg,wrist_watch
491
+ index/product_wrist_watch_1030_4.jpg,product_wrist_watch_1030_4.jpg,wrist_watch
492
+ index/product_ear_pods_593_0.jpg,product_ear_pods_593_0.jpg,ear_pods
493
+ index/product_mouse_207_4.jpg,product_mouse_207_4.jpg,mouse
494
+ index/product_backpack_855_1.jpg,product_backpack_855_1.jpg,backpack
495
+ index/product_mouse_212_2.jpg,product_mouse_212_2.jpg,mouse
496
+ index/product_headset_781_0.jpg,product_headset_781_0.jpg,headset
497
+ index/product_ear_pods_535_4.jpg,product_ear_pods_535_4.jpg,ear_pods
498
+ index/product_wrist_watch_1020_2.jpg,product_wrist_watch_1020_2.jpg,wrist_watch
499
+ index/product_usb_hub_176_4.jpg,product_usb_hub_176_4.jpg,usb_hub
500
+ index/product_mouse_203_4.jpg,product_mouse_203_4.jpg,mouse
501
+ index/product_mouse_324_2.jpg,product_mouse_324_2.jpg,mouse
502
+ index/product_ear_pods_593_1.jpg,product_ear_pods_593_1.jpg,ear_pods
503
+ index/product_backpack_865_0.jpg,product_backpack_865_0.jpg,backpack
504
+ index/product_wrist_watch_1048_0.jpg,product_wrist_watch_1048_0.jpg,wrist_watch
505
+ index/product_wrist_watch_1189_0.jpg,product_wrist_watch_1189_0.jpg,wrist_watch
506
+ index/product_backpack_839_4.jpg,product_backpack_839_4.jpg,backpack
507
+ index/product_usb_hub_3_1.jpg,product_usb_hub_3_1.jpg,usb_hub
508
+ index/product_headset_657_0.jpg,product_headset_657_0.jpg,headset
509
+ index/product_headset_774_1.jpg,product_headset_774_1.jpg,headset
510
+ index/product_wrist_watch_1043_5.jpg,product_wrist_watch_1043_5.jpg,wrist_watch
511
+ index/product_flash_drive_1445_7.jpg,product_flash_drive_1445_7.jpg,flash_drive
512
+ index/product_backpack_910_1.jpg,product_backpack_910_1.jpg,backpack
513
+ index/product_flash_drive_1445_0.jpg,product_flash_drive_1445_0.jpg,flash_drive
514
+ index/product_mouse_228_0.jpg,product_mouse_228_0.jpg,mouse
515
+ index/product_mouse_263_4.jpg,product_mouse_263_4.jpg,mouse
516
+ index/product_headset_764_3.jpg,product_headset_764_3.jpg,headset
517
+ index/product_wrist_watch_1067_0.jpg,product_wrist_watch_1067_0.jpg,wrist_watch
518
+ index/product_usb_hub_168_1.jpg,product_usb_hub_168_1.jpg,usb_hub
519
+ index/product_mouse_349_7.jpg,product_mouse_349_7.jpg,mouse
520
+ index/product_mouse_203_3.jpg,product_mouse_203_3.jpg,mouse
521
+ index/product_ear_pods_567_1.jpg,product_ear_pods_567_1.jpg,ear_pods
522
+ index/product_ear_pods_585_2.jpg,product_ear_pods_585_2.jpg,ear_pods
523
+ index/product_office_chairs_1324_0.jpg,product_office_chairs_1324_0.jpg,office_chairs
524
+ index/product_flash_drive_1420_1.jpg,product_flash_drive_1420_1.jpg,flash_drive
525
+ index/product_wrist_watch_1043_1.jpg,product_wrist_watch_1043_1.jpg,wrist_watch
526
+ index/product_ear_pods_509_0.jpg,product_ear_pods_509_0.jpg,ear_pods
527
+ index/product_mouse_390_1.jpg,product_mouse_390_1.jpg,mouse
528
+ index/product_headset_631_0.jpg,product_headset_631_0.jpg,headset
529
+ index/product_mouse_207_1.jpg,product_mouse_207_1.jpg,mouse
530
+ index/product_ear_pods_574_6.jpg,product_ear_pods_574_6.jpg,ear_pods
531
+ index/product_backpack_828_3.jpg,product_backpack_828_3.jpg,backpack
532
+ index/product_headset_681_0.jpg,product_headset_681_0.jpg,headset
533
+ index/product_usb_hub_165_0.jpg,product_usb_hub_165_0.jpg,usb_hub
534
+ index/product_backpack_885_5.jpg,product_backpack_885_5.jpg,backpack
535
+ index/product_wrist_watch_1189_7.jpg,product_wrist_watch_1189_7.jpg,wrist_watch
536
+ index/product_headset_625_3.jpg,product_headset_625_3.jpg,headset
537
+ index/product_wrist_watch_1018_0.jpg,product_wrist_watch_1018_0.jpg,wrist_watch
538
+ index/product_ear_pods_535_0.jpg,product_ear_pods_535_0.jpg,ear_pods
539
+ index/product_backpack_812_2.jpg,product_backpack_812_2.jpg,backpack
540
+ index/product_headset_635_0.jpg,product_headset_635_0.jpg,headset
541
+ index/product_backpack_855_2.jpg,product_backpack_855_2.jpg,backpack
542
+ index/product_backpack_831_3.jpg,product_backpack_831_3.jpg,backpack
543
+ index/product_wrist_watch_1124_2.jpg,product_wrist_watch_1124_2.jpg,wrist_watch
544
+ index/product_mouse_263_3.jpg,product_mouse_263_3.jpg,mouse
545
+ index/product_mouse_349_1.jpg,product_mouse_349_1.jpg,mouse
546
+ index/product_wrist_watch_1030_0.jpg,product_wrist_watch_1030_0.jpg,wrist_watch
547
+ index/product_backpack_910_4.jpg,product_backpack_910_4.jpg,backpack
548
+ index/product_backpack_850_3.jpg,product_backpack_850_3.jpg,backpack
549
+ index/product_ear_pods_574_1.jpg,product_ear_pods_574_1.jpg,ear_pods
550
+ index/product_headset_721_5.jpg,product_headset_721_5.jpg,headset
551
+ index/product_mouse_282_3.jpg,product_mouse_282_3.jpg,mouse
552
+ index/product_usb_hub_36_4.jpg,product_usb_hub_36_4.jpg,usb_hub
553
+ index/product_backpack_817_6.jpg,product_backpack_817_6.jpg,backpack
554
+ index/product_backpack_850_4.jpg,product_backpack_850_4.jpg,backpack
555
+ index/product_mouse_263_6.jpg,product_mouse_263_6.jpg,mouse
556
+ index/product_ear_pods_535_2.jpg,product_ear_pods_535_2.jpg,ear_pods
557
+ index/product_backpack_831_5.jpg,product_backpack_831_5.jpg,backpack
558
+ index/product_ear_pods_591_1.jpg,product_ear_pods_591_1.jpg,ear_pods
559
+ index/product_usb_hub_124_0.jpg,product_usb_hub_124_0.jpg,usb_hub
560
+ index/product_usb_hub_168_4.jpg,product_usb_hub_168_4.jpg,usb_hub
561
+ index/product_usb_hub_16_0.jpg,product_usb_hub_16_0.jpg,usb_hub
562
+ index/product_wrist_watch_1011_4.jpg,product_wrist_watch_1011_4.jpg,wrist_watch
563
+ index/product_usb_hub_17_0.jpg,product_usb_hub_17_0.jpg,usb_hub
564
+ index/product_office_chairs_1362_0.jpg,product_office_chairs_1362_0.jpg,office_chairs
565
+ index/product_backpack_813_3.jpg,product_backpack_813_3.jpg,backpack
566
+ index/product_ear_pods_521_2.jpg,product_ear_pods_521_2.jpg,ear_pods
567
+ index/product_backpack_831_0.jpg,product_backpack_831_0.jpg,backpack
568
+ index/product_backpack_873_0.jpg,product_backpack_873_0.jpg,backpack
569
+ index/product_usb_hub_17_1.jpg,product_usb_hub_17_1.jpg,usb_hub
570
+ index/product_ear_pods_456_0.jpg,product_ear_pods_456_0.jpg,ear_pods
571
+ index/product_usb_hub_136_3.jpg,product_usb_hub_136_3.jpg,usb_hub
572
+ index/product_ear_pods_552_0.jpg,product_ear_pods_552_0.jpg,ear_pods
573
+ index/product_backpack_804_1.jpg,product_backpack_804_1.jpg,backpack
574
+ index/product_wrist_watch_1006_7.jpg,product_wrist_watch_1006_7.jpg,wrist_watch
575
+ index/product_wrist_watch_1043_4.jpg,product_wrist_watch_1043_4.jpg,wrist_watch
576
+ index/product_office_chairs_1204_2.jpg,product_office_chairs_1204_2.jpg,office_chairs
577
+ index/product_ear_pods_528_0.jpg,product_ear_pods_528_0.jpg,ear_pods
578
+ index/product_mouse_324_1.jpg,product_mouse_324_1.jpg,mouse
579
+ index/product_ear_pods_567_4.jpg,product_ear_pods_567_4.jpg,ear_pods
580
+ index/product_wrist_watch_1029_1.jpg,product_wrist_watch_1029_1.jpg,wrist_watch
581
+ index/product_mouse_207_2.jpg,product_mouse_207_2.jpg,mouse
582
+ index/product_flash_drive_1407_0.jpg,product_flash_drive_1407_0.jpg,flash_drive
583
+ index/product_wrist_watch_1122_0.jpg,product_wrist_watch_1122_0.jpg,wrist_watch
584
+ index/product_flash_drive_1407_5.jpg,product_flash_drive_1407_5.jpg,flash_drive
585
+ index/product_flash_drive_1407_7.jpg,product_flash_drive_1407_7.jpg,flash_drive
586
+ index/product_wrist_watch_1124_0.jpg,product_wrist_watch_1124_0.jpg,wrist_watch
587
+ index/product_headset_668_0.jpg,product_headset_668_0.jpg,headset
588
+ index/product_headset_693_3.jpg,product_headset_693_3.jpg,headset
589
+ index/product_wrist_watch_1107_0.jpg,product_wrist_watch_1107_0.jpg,wrist_watch
590
+ index/product_mouse_397_2.jpg,product_mouse_397_2.jpg,mouse
591
+ index/product_ear_pods_442_1.jpg,product_ear_pods_442_1.jpg,ear_pods
592
+ index/product_backpack_880_3.jpg,product_backpack_880_3.jpg,backpack
593
+ index/product_ear_pods_440_0.jpg,product_ear_pods_440_0.jpg,ear_pods
594
+ index/product_usb_hub_123_0.jpg,product_usb_hub_123_0.jpg,usb_hub
595
+ index/product_mouse_397_1.jpg,product_mouse_397_1.jpg,mouse
596
+ index/product_backpack_880_7.jpg,product_backpack_880_7.jpg,backpack
597
+ index/product_ear_pods_421_0.jpg,product_ear_pods_421_0.jpg,ear_pods
598
+ index/product_headset_736_2.jpg,product_headset_736_2.jpg,headset
599
+ index/product_usb_hub_186_7.jpg,product_usb_hub_186_7.jpg,usb_hub
600
+ index/product_usb_hub_38_0.jpg,product_usb_hub_38_0.jpg,usb_hub
601
+ index/product_backpack_864_3.jpg,product_backpack_864_3.jpg,backpack
602
+ index/product_usb_hub_186_4.jpg,product_usb_hub_186_4.jpg,usb_hub
603
+ index/product_backpack_864_1.jpg,product_backpack_864_1.jpg,backpack
604
+ index/product_headset_629_3.jpg,product_headset_629_3.jpg,headset
605
+ index/product_mouse_212_5.jpg,product_mouse_212_5.jpg,mouse
606
+ index/product_ear_pods_442_0.jpg,product_ear_pods_442_0.jpg,ear_pods
607
+ index/product_mouse_229_3.jpg,product_mouse_229_3.jpg,mouse
608
+ index/product_wrist_watch_1164_2.jpg,product_wrist_watch_1164_2.jpg,wrist_watch
609
+ index/product_headset_675_0.jpg,product_headset_675_0.jpg,headset
610
+ index/product_wrist_watch_1164_5.jpg,product_wrist_watch_1164_5.jpg,wrist_watch
611
+ index/product_mouse_229_2.jpg,product_mouse_229_2.jpg,mouse
612
+ index/product_ear_pods_421_2.jpg,product_ear_pods_421_2.jpg,ear_pods
613
+ index/product_mouse_229_6.jpg,product_mouse_229_6.jpg,mouse
614
+ index/product_ear_pods_459_2.jpg,product_ear_pods_459_2.jpg,ear_pods
615
+ index/product_headset_629_0.jpg,product_headset_629_0.jpg,headset
616
+ index/product_office_chairs_1230_1.jpg,product_office_chairs_1230_1.jpg,office_chairs
617
+ index/product_ear_pods_586_0.jpg,product_ear_pods_586_0.jpg,ear_pods
618
+ index/product_wrist_watch_1107_6.jpg,product_wrist_watch_1107_6.jpg,wrist_watch
619
+ index/product_wrist_watch_1099_0.jpg,product_wrist_watch_1099_0.jpg,wrist_watch
620
+ index/product_usb_hub_186_2.jpg,product_usb_hub_186_2.jpg,usb_hub
621
+ index/product_mouse_229_1.jpg,product_mouse_229_1.jpg,mouse
622
+ index/product_headset_675_1.jpg,product_headset_675_1.jpg,headset
623
+ index/product_headset_657_2.jpg,product_headset_657_2.jpg,headset
624
+ index/product_headset_693_0.jpg,product_headset_693_0.jpg,headset
625
+ index/product_backpack_844_4.jpg,product_backpack_844_4.jpg,backpack
626
+ index/product_headset_675_4.jpg,product_headset_675_4.jpg,headset
627
+ index/product_usb_hub_180_2.jpg,product_usb_hub_180_2.jpg,usb_hub
628
+ index/product_flash_drive_1411_2.jpg,product_flash_drive_1411_2.jpg,flash_drive
629
+ index/product_ear_pods_442_3.jpg,product_ear_pods_442_3.jpg,ear_pods
630
+ index/product_ear_pods_403_5.jpg,product_ear_pods_403_5.jpg,ear_pods
631
+ index/product_backpack_880_1.jpg,product_backpack_880_1.jpg,backpack
632
+ index/product_headset_629_1.jpg,product_headset_629_1.jpg,headset
633
+ index/product_mouse_212_6.jpg,product_mouse_212_6.jpg,mouse
634
+ index/product_ear_pods_466_1.jpg,product_ear_pods_466_1.jpg,ear_pods
635
+ index/product_usb_hub_186_5.jpg,product_usb_hub_186_5.jpg,usb_hub
636
+ index/product_flash_drive_1411_3.jpg,product_flash_drive_1411_3.jpg,flash_drive
637
+ index/product_ear_pods_403_2.jpg,product_ear_pods_403_2.jpg,ear_pods
638
+ index/product_mouse_397_0.jpg,product_mouse_397_0.jpg,mouse
639
+ index/product_ear_pods_440_1.jpg,product_ear_pods_440_1.jpg,ear_pods
640
+ index/product_ear_pods_459_1.jpg,product_ear_pods_459_1.jpg,ear_pods
641
+ index/product_headset_736_0.jpg,product_headset_736_0.jpg,headset
642
+ index/product_backpack_864_7.jpg,product_backpack_864_7.jpg,backpack
643
+ index/product_headset_657_5.jpg,product_headset_657_5.jpg,headset
644
+ index/product_headset_657_4.jpg,product_headset_657_4.jpg,headset
645
+ index/product_office_chairs_1393_2.jpg,product_office_chairs_1393_2.jpg,office_chairs
646
+ index/product_ear_pods_459_4.jpg,product_ear_pods_459_4.jpg,ear_pods
647
+ index/product_headset_693_2.jpg,product_headset_693_2.jpg,headset
648
+ index/product_office_chairs_1230_2.jpg,product_office_chairs_1230_2.jpg,office_chairs
649
+ index/product_usb_hub_38_1.jpg,product_usb_hub_38_1.jpg,usb_hub
650
+ index/product_mouse_212_0.jpg,product_mouse_212_0.jpg,mouse
651
+ index/product_headset_668_1.jpg,product_headset_668_1.jpg,headset
652
+ index/product_ear_pods_459_3.jpg,product_ear_pods_459_3.jpg,ear_pods
653
+ index/product_usb_hub_142_0.jpg,product_usb_hub_142_0.jpg,usb_hub
654
+ index/product_usb_hub_180_0.jpg,product_usb_hub_180_0.jpg,usb_hub
655
+ index/product_office_chairs_1291_0.jpg,product_office_chairs_1291_0.jpg,office_chairs
656
+ index/product_backpack_864_0.jpg,product_backpack_864_0.jpg,backpack
657
+ index/product_ear_pods_403_7.jpg,product_ear_pods_403_7.jpg,ear_pods
658
+ index/product_headset_675_2.jpg,product_headset_675_2.jpg,headset
659
+ index/product_usb_hub_180_1.jpg,product_usb_hub_180_1.jpg,usb_hub
660
+ index/product_ear_pods_403_3.jpg,product_ear_pods_403_3.jpg,ear_pods
661
+ index/product_ear_pods_521_1.jpg,product_ear_pods_521_1.jpg,ear_pods
662
+ index/product_headset_668_4.jpg,product_headset_668_4.jpg,headset
663
+ index/product_mouse_212_4.jpg,product_mouse_212_4.jpg,mouse
664
+ index/product_flash_drive_1411_7.jpg,product_flash_drive_1411_7.jpg,flash_drive
665
+ index/product_ear_pods_440_2.jpg,product_ear_pods_440_2.jpg,ear_pods
666
+ index/product_headset_736_1.jpg,product_headset_736_1.jpg,headset
667
+ index/product_wrist_watch_1018_2.jpg,product_wrist_watch_1018_2.jpg,wrist_watch
668
+ index/product_backpack_864_6.jpg,product_backpack_864_6.jpg,backpack
669
+ index/product_backpack_844_6.jpg,product_backpack_844_6.jpg,backpack
670
+ index/product_headset_736_3.jpg,product_headset_736_3.jpg,headset
671
+ index/product_backpack_864_2.jpg,product_backpack_864_2.jpg,backpack
672
+ index/product_usb_hub_142_1.jpg,product_usb_hub_142_1.jpg,usb_hub
673
+ index/product_mouse_212_7.jpg,product_mouse_212_7.jpg,mouse
674
+ index/product_wrist_watch_1162_0.jpg,product_wrist_watch_1162_0.jpg,wrist_watch
675
+ index/product_ear_pods_421_1.jpg,product_ear_pods_421_1.jpg,ear_pods
676
+ index/product_wrist_watch_1107_4.jpg,product_wrist_watch_1107_4.jpg,wrist_watch
677
+ index/product_wrist_watch_1107_5.jpg,product_wrist_watch_1107_5.jpg,wrist_watch
678
+ index/product_mouse_212_1.jpg,product_mouse_212_1.jpg,mouse
679
+ index/product_backpack_862_4.jpg,product_backpack_862_4.jpg,backpack
680
+ index/product_headset_629_2.jpg,product_headset_629_2.jpg,headset
681
+ index/product_flash_drive_1411_0.jpg,product_flash_drive_1411_0.jpg,flash_drive
682
+ index/product_mouse_229_0.jpg,product_mouse_229_0.jpg,mouse
683
+ index/product_office_chairs_1253_0.jpg,product_office_chairs_1253_0.jpg,office_chairs
684
+ index/product_ear_pods_466_2.jpg,product_ear_pods_466_2.jpg,ear_pods
685
+ index/product_ear_pods_466_3.jpg,product_ear_pods_466_3.jpg,ear_pods
686
+ index/product_usb_hub_186_6.jpg,product_usb_hub_186_6.jpg,usb_hub
687
+ index/product_headset_693_1.jpg,product_headset_693_1.jpg,headset
688
+ index/product_ear_pods_403_4.jpg,product_ear_pods_403_4.jpg,ear_pods
689
+ index/product_backpack_880_0.jpg,product_backpack_880_0.jpg,backpack
690
+ index/product_ear_pods_466_0.jpg,product_ear_pods_466_0.jpg,ear_pods
691
+ index/product_headset_657_3.jpg,product_headset_657_3.jpg,headset
692
+ index/product_usb_hub_186_3.jpg,product_usb_hub_186_3.jpg,usb_hub
693
+ index/product_backpack_944_0.jpg,product_backpack_944_0.jpg,backpack
694
+ index/product_mouse_229_7.jpg,product_mouse_229_7.jpg,mouse
695
+ index/product_headset_675_3.jpg,product_headset_675_3.jpg,headset
696
+ index/product_wrist_watch_1164_4.jpg,product_wrist_watch_1164_4.jpg,wrist_watch
697
+ index/product_office_chairs_1230_0.jpg,product_office_chairs_1230_0.jpg,office_chairs
698
+ index/product_ear_pods_442_2.jpg,product_ear_pods_442_2.jpg,ear_pods
699
+ index/product_headset_757_0.jpg,product_headset_757_0.jpg,headset
700
+ index/product_backpack_880_2.jpg,product_backpack_880_2.jpg,backpack
701
+ index/product_headset_675_5.jpg,product_headset_675_5.jpg,headset
702
+ index/product_ear_pods_466_6.jpg,product_ear_pods_466_6.jpg,ear_pods
703
+ index/product_ear_pods_459_0.jpg,product_ear_pods_459_0.jpg,ear_pods
704
+ index/product_wrist_watch_1164_3.jpg,product_wrist_watch_1164_3.jpg,wrist_watch
705
+ index/product_wrist_watch_1164_6.jpg,product_wrist_watch_1164_6.jpg,wrist_watch
706
+ index/product_backpack_844_7.jpg,product_backpack_844_7.jpg,backpack
707
+ index/product_backpack_844_5.jpg,product_backpack_844_5.jpg,backpack
708
+ index/product_wrist_watch_1107_1.jpg,product_wrist_watch_1107_1.jpg,wrist_watch
709
+ index/product_ear_pods_440_3.jpg,product_ear_pods_440_3.jpg,ear_pods
710
+ index/product_flash_drive_1411_1.jpg,product_flash_drive_1411_1.jpg,flash_drive
data/processed/jumia_3650/train.csv ADDED
The diff for this file is too large to render. See raw diff
 
image_search_engine/__init__.py ADDED
File without changes
image_search_engine/artifacts/__init__.py ADDED
File without changes
image_search_engine/artifacts/config.json ADDED
@@ -0,0 +1 @@
 
 
1
+ {"seed": 2022, "epochs": 10, "img_size": 224, "model_name": "tf_efficientnet_b0_ns", "num_classes": 8, "train_batch_size": 32, "valid_batch_size": 32, "learning_rate": 0.001, "scheduler": "OneCycleLR", "min_lr": 1e-05, "T_max": 500, "weight_decay": 1e-06, "n_fold": 100, "n_accumulate": 1, "device": "cuda", "test_mode": true, "enable_amp_half_precision": false, "s": 10.0, "m": 0.1, "ls_eps": 0.0, "easy_margin": false}
image_search_engine/artifacts/label_encoder/class_encoder_jumia_3650.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5400e30ac91878cf846e975acb82b7972bf64cccf84d9040e6ef404047fee879
3
+ size 644
image_search_engine/artifacts/model_staged/index.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d05416e85b4ffa7eba35f9e453a1ad8153666a6917a56c9028089cf800fb2664
3
+ size 6023748
image_search_engine/artifacts/model_staged/model.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f5369b9fc74deea65f75cb5d219f26a717bec873d590e0f4771b58ae02b73b0e
3
+ size 18943957
image_search_engine/artifacts/weights/Loss0.6555_epoch3.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:12a5ae97a2fb28ea0d6845091646f90509c50013a7b441555aa3f58565621ae4
3
+ size 18971557
image_search_engine/data/__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+ from .jumia_3650_dataset import Jumia3650Dataset
image_search_engine/data/base_data_module.py ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import torch
3
+ from PIL import Image
4
+ from sklearn.preprocessing import LabelEncoder
5
+ from torch.utils.data import DataLoader, Dataset
6
+
7
+ from image_search_engine.metadata import jumia_3650
8
+
9
+ encoder = LabelEncoder()
10
+
11
+
12
+ class JumiaImageDataset(Dataset):
13
+ def __init__(self, data_filename, transforms=None):
14
+ self.df = pd.read_csv(data_filename)
15
+ self.file_paths = self.df["filepath"].values
16
+ self.labels = encoder.fit_transform(self.df["class"])
17
+ self.transforms = transforms
18
+
19
+ def __len__(self):
20
+ return len(self.df)
21
+
22
+ def __getitem__(self, index):
23
+ img_path = jumia_3650.PROCESSED_DATA_DIRNAME / self.file_paths[index]
24
+ img = Image.open(img_path).convert("RGB")
25
+ label = self.labels[index]
26
+
27
+ if self.transforms:
28
+ img = self.transforms(img)
29
+
30
+ return {"image": img, "label": torch.tensor(label, dtype=torch.long)}
31
+
32
+ def create_dataloader(self, batch_size, shuffle=True, num_workers=0):
33
+ return DataLoader(
34
+ self,
35
+ batch_size=batch_size,
36
+ shuffle=shuffle,
37
+ num_workers=num_workers,
38
+ pin_memory=True,
39
+ )
image_search_engine/data/jumia_3650_dataset.py ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pathlib import Path
2
+
3
+ import joblib
4
+ import pandas as pd
5
+ import torch
6
+ from PIL import Image
7
+ from torch.utils.data import DataLoader, Dataset
8
+ from torchvision import transforms
9
+
10
+ from image_search_engine.metadata import jumia_3650
11
+
12
+ PACKAGE_DIR = Path(__file__).parent.parent
13
+
14
+ # Load the pickled file
15
+ with open(
16
+ PACKAGE_DIR / "artifacts/label_encoder/class_encoder_jumia_3650.pkl", "rb"
17
+ ) as file:
18
+ encoder = joblib.load(file)
19
+
20
+
21
+ class Jumia3650Dataset(Dataset):
22
+ def __init__(self, data_filename, data_transforms=None, img_size=224):
23
+ self.df = pd.read_csv(data_filename)
24
+ self.file_paths = self.df["filepath"].values
25
+ self.labels = encoder.transform(self.df["class"])
26
+ self.classes = encoder.classes_
27
+ self.class_to_idx = {l: i for i, l in enumerate(encoder.classes_)}
28
+ if transforms is None:
29
+ self.data_transforms = transforms.Compose(
30
+ [
31
+ transforms.ToTensor(),
32
+ transforms.Resize((img_size, img_size)),
33
+ transforms.Normalize(
34
+ mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]
35
+ ),
36
+ ]
37
+ )
38
+ else:
39
+ self.data_transforms = data_transforms
40
+
41
+ def __len__(self):
42
+ return len(self.df)
43
+
44
+ def __getitem__(self, index):
45
+ img_path = jumia_3650.PROCESSED_DATA_DIRNAME / self.file_paths[index]
46
+ img = Image.open(img_path).convert("RGB")
47
+ label = self.labels[index]
48
+
49
+ img = self.data_transforms(img)
50
+
51
+ return {"image": img, "label": torch.tensor(label, dtype=torch.long)}
52
+
53
+ def create_dataloader(self, batch_size, shuffle=True, num_workers=0):
54
+ return DataLoader(
55
+ self,
56
+ batch_size=batch_size,
57
+ shuffle=shuffle,
58
+ num_workers=num_workers,
59
+ pin_memory=True,
60
+ )
image_search_engine/data/utils.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ from pathlib import Path
3
+
4
+ package_dir = Path(__file__).resolve().parents[1]
5
+
6
+
7
+ def load_config(
8
+ file_path=package_dir / "artifacts/config.json",
9
+ ):
10
+ with open(file_path) as file:
11
+ data = json.load(file)
12
+ return data
13
+
14
+
15
+ if __name__ == "__main__":
16
+ load_config()
image_search_engine/evaluation/__init__.py ADDED
File without changes
image_search_engine/image_search_engine.egg-info/PKG-INFO ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ Metadata-Version: 2.1
2
+ Name: image-search-engine
3
+ Version: 0.1.0
4
+ Summary: A visual search engine for Jumia that lets users search for products by uploading an image. It uses computer vision to find similar or identical products within the store's inventory, saving users time and providing a more personalized shopping experience.
5
+ Author: Paul Okewunmi
image_search_engine/image_search_engine.egg-info/SOURCES.txt ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ setup.py
2
+ artifacts/__init__.py
3
+ data/__init__.py
4
+ data/base_data_module.py
5
+ data/jumia_3650_dataset.py
6
+ data/utils.py
7
+ evaluation/__init__.py
8
+ image_search_engine.egg-info/PKG-INFO
9
+ image_search_engine.egg-info/SOURCES.txt
10
+ image_search_engine.egg-info/dependency_links.txt
11
+ image_search_engine.egg-info/top_level.txt
12
+ metadata/__init__.py
13
+ metadata/jumia_3650.py
14
+ metadata/shared.py
15
+ models/__init__.py
16
+ models/arc_margin_product.py
17
+ models/base.py
18
+ models/efficientnet_ns.py
19
+ models/gem_pooling.py
20
+ tests/__init__.py
image_search_engine/image_search_engine.egg-info/dependency_links.txt ADDED
@@ -0,0 +1 @@
 
 
1
+
image_search_engine/image_search_engine.egg-info/top_level.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ artifacts
2
+ data
3
+ evaluation
4
+ metadata
5
+ models
6
+ tests
image_search_engine/metadata/__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+ from . import jumia_3650, shared
image_search_engine/metadata/jumia_3650.py ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # from pathlib import Path
2
+ from image_search_engine.metadata import shared
3
+
4
+ RAW_DATA_DIRNAME = shared.DATA_DIRNAME / "raw" / "jumia_3650"
5
+ METADATA_FILENAME = RAW_DATA_DIRNAME / "metadata.toml"
6
+ DL_DATA_DIRNAME = shared.DATA_DIRNAME / "downloaded" / "jumia_3650"
7
+ PROCESSED_DATA_DIRNAME = shared.DATA_DIRNAME / "processed" / "jumia_3650"
8
+
9
+
10
+ CLASS_DICT = {
11
+ "backpack": 0,
12
+ "ear_pods": 1,
13
+ "flash_drive": 2,
14
+ "headset": 3,
15
+ "mouse": 4,
16
+ "office_chairs": 5,
17
+ "usb_hub": 6,
18
+ "wrist_watch": 7,
19
+ }
image_search_engine/metadata/shared.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ from pathlib import Path
2
+
3
+ DATA_DIRNAME = Path(__file__).resolve().parents[2] / "data"
4
+ DOWNLOADED_DATA_DIRNAME = DATA_DIRNAME / "downloaded"
image_search_engine/models/__init__.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ from .arc_margin_product import ArcMarginProduct
2
+ from .efficientnet_ns import EfficientNet_b0_ns
3
+ from .gem_pooling import GeM
image_search_engine/models/arc_margin_product.py ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+
3
+ import torch
4
+ import torch.nn.functional as F
5
+ from torch import nn
6
+
7
+ ENABLE_HALF_PRECISION = False
8
+ DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
9
+
10
+
11
+ class ArcMarginProduct(nn.Module):
12
+ r"""Implement of large margin arc distance: :
13
+ Args:
14
+ in_features: size of each input sample
15
+ out_features: size of each output sample
16
+ s: norm of input feature
17
+ m: margin
18
+ cos(theta + m)
19
+ """
20
+
21
+ def __init__(
22
+ self, in_features, out_features, s=10, m=0.10, easy_margin=False, ls_eps=0.0
23
+ ):
24
+ super(ArcMarginProduct, self).__init__()
25
+ self.in_features = in_features
26
+ self.out_features = out_features
27
+ self.s = s
28
+ self.m = m
29
+ self.ls_eps = ls_eps # label smoothing
30
+ self.weight = nn.Parameter(torch.FloatTensor(out_features, in_features))
31
+ nn.init.xavier_uniform_(self.weight)
32
+
33
+ self.easy_margin = easy_margin
34
+ self.cos_m = math.cos(m)
35
+ self.sin_m = math.sin(m)
36
+ self.th = math.cos(math.pi - m)
37
+ self.mm = math.sin(math.pi - m) * m
38
+
39
+ def forward(self, input, label):
40
+ # --------------------------- cos(theta) & phi(theta) ---------------------
41
+ cosine = F.linear(F.normalize(input), F.normalize(self.weight))
42
+ if ENABLE_HALF_PRECISION == True:
43
+ cosine = cosine.to(torch.float32)
44
+ sine = torch.sqrt(1.0 - torch.pow(cosine, 2))
45
+ phi = cosine * self.cos_m - sine * self.sin_m
46
+ if self.easy_margin:
47
+ phi = torch.where(cosine > 0, phi, cosine)
48
+ else:
49
+ phi = torch.where(cosine > self.th, phi, cosine - self.mm)
50
+ # --------------------------- convert label to one-hot ---------------------
51
+ # one_hot = torch.zeros(cosine.size(), requires_grad=True, device='cuda')
52
+ one_hot = torch.zeros(cosine.size(), device=DEVICE)
53
+ one_hot.scatter_(1, label.view(-1, 1).long(), 1)
54
+ if self.ls_eps > 0:
55
+ one_hot = (1 - self.ls_eps) * one_hot + self.ls_eps / self.out_features
56
+ # -------------torch.where(out_i = {x_i if condition_i else y_i) ------------
57
+ output = (one_hot * phi) + ((1.0 - one_hot) * cosine)
58
+ output *= self.s
59
+
60
+ return output
image_search_engine/models/base.py ADDED
@@ -0,0 +1,200 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import copy
2
+ import gc
3
+ import time
4
+ import warnings
5
+ from collections import defaultdict
6
+ from pathlib import Path
7
+
8
+ # Utils
9
+ import numpy as np
10
+
11
+ # Pytorch Imports
12
+ import torch
13
+ import torch.nn as nn
14
+ from colorama import Back, Fore, Style
15
+ from PIL import Image
16
+
17
+ # Sklearn Imports
18
+ from torch import nn
19
+ from torchvision import transforms
20
+ from tqdm import tqdm
21
+
22
+ # import torch.nn as nn
23
+
24
+
25
+ b_ = Fore.BLUE
26
+ sr_ = Style.RESET_ALL
27
+
28
+ warnings.filterwarnings("ignore")
29
+
30
+
31
+ DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
32
+
33
+
34
+ class BaseModel(nn.Module):
35
+ def __init__(self, predtrained=True) -> None:
36
+ super(BaseModel, self).__init__()
37
+
38
+ def forward(self):
39
+ pass
40
+
41
+ def _criterion(self, outputs, labels):
42
+ return nn.CrossEntropyLoss()(outputs, labels)
43
+
44
+ def _train_one_epoch(self, dataloader, optimizer, scheduler, device, epoch):
45
+ self.train()
46
+
47
+ dataset_size = 0
48
+ running_loss = 0.0
49
+
50
+ bar = tqdm(enumerate(dataloader), total=len(dataloader))
51
+ for step, data in bar:
52
+ images = data["image"].to(device, dtype=torch.float)
53
+ labels = data["label"].to(device, dtype=torch.long)
54
+
55
+ batch_size = images.size(0)
56
+
57
+ outputs, _ = self(images, labels)
58
+ loss = self._criterion(outputs, labels)
59
+
60
+ loss.backward()
61
+
62
+ optimizer.step()
63
+ optimizer.zero_grad()
64
+ if scheduler is not None:
65
+ scheduler.step()
66
+
67
+ running_loss += loss.item() * batch_size
68
+ dataset_size += batch_size
69
+
70
+ epoch_loss = running_loss / dataset_size
71
+
72
+ bar.set_postfix(
73
+ Epoch=epoch, Train_Loss=epoch_loss, LR=optimizer.param_groups[0]["lr"]
74
+ )
75
+ gc.collect()
76
+
77
+ return epoch_loss
78
+
79
+ @torch.inference_mode()
80
+ def _valid_one_epoch(self, dataloader, optimizer, device, epoch):
81
+ self.eval()
82
+
83
+ dataset_size = 0
84
+ running_loss = 0.0
85
+
86
+ bar = tqdm(enumerate(dataloader), total=len(dataloader))
87
+ for step, data in bar:
88
+ images = data["image"].to(device, dtype=torch.float)
89
+ labels = data["label"].to(device, dtype=torch.long)
90
+
91
+ batch_size = images.size(0)
92
+
93
+ outputs, _ = self(images, labels)
94
+ loss = self._criterion(outputs, labels)
95
+
96
+ running_loss += loss.item() * batch_size
97
+ dataset_size += batch_size
98
+
99
+ epoch_loss = running_loss / dataset_size
100
+
101
+ bar.set_postfix(
102
+ Epoch=epoch, Valid_Loss=epoch_loss, LR=optimizer.param_groups[0]["lr"]
103
+ )
104
+
105
+ gc.collect()
106
+
107
+ return epoch_loss
108
+
109
+ def run_training(
110
+ self,
111
+ train_loader,
112
+ valid_loader,
113
+ optimizer,
114
+ scheduler,
115
+ device,
116
+ num_epochs,
117
+ weights_dir,
118
+ ):
119
+ # To automatically log gradients
120
+
121
+ if torch.cuda.is_available():
122
+ print("[INFO] Using GPU: {}\n".format(torch.cuda.get_device_name()))
123
+
124
+ start = time.time()
125
+ best_model_wts = copy.deepcopy(self.state_dict())
126
+ best_epoch_loss = np.inf
127
+ history = defaultdict(list)
128
+
129
+ for epoch in range(1, num_epochs + 1):
130
+ gc.collect()
131
+
132
+ # dataloader, optimizer, scheduler, criterion, device, epoch
133
+ train_epoch_loss = self._train_one_epoch(
134
+ optimizer=optimizer,
135
+ scheduler=scheduler,
136
+ dataloader=train_loader,
137
+ device=device,
138
+ epoch=epoch,
139
+ )
140
+ val_epoch_loss = self._valid_one_epoch(
141
+ valid_loader, optimizer, device=device, epoch=epoch
142
+ )
143
+
144
+ history["Train Loss"].append(train_epoch_loss)
145
+ history["Valid Loss"].append(val_epoch_loss)
146
+
147
+ # deep copy the model
148
+ if val_epoch_loss <= best_epoch_loss:
149
+ print(
150
+ f"{b_}Validation Loss Improved ({best_epoch_loss} ---> {val_epoch_loss})"
151
+ )
152
+ best_epoch_loss = val_epoch_loss
153
+ best_model_wts = copy.deepcopy(self.state_dict())
154
+ PATH = "Loss{:.4f}_epoch{:.0f}.bin".format(best_epoch_loss, epoch)
155
+ torch.save(self.state_dict(), weights_dir / PATH)
156
+ # Save a model file from the current directory
157
+ print(f"Model Saved{sr_}")
158
+
159
+ print()
160
+
161
+ end = time.time()
162
+ time_elapsed = end - start
163
+ print(
164
+ "Training complete in {:.0f}h {:.0f}m {:.0f}s".format(
165
+ time_elapsed // 3600,
166
+ (time_elapsed % 3600) // 60,
167
+ (time_elapsed % 3600) % 60,
168
+ )
169
+ )
170
+ print("Best Loss: {:.4f}".format(best_epoch_loss))
171
+
172
+ # load best model weights
173
+ self.load_state_dict(best_model_wts)
174
+
175
+ return history
176
+
177
+ def generate_embeddings(self, image, data_transforms=None):
178
+ if data_transforms is None:
179
+ data_transforms = transforms.Compose(
180
+ [
181
+ transforms.ToTensor(),
182
+ transforms.Resize((224, 224)),
183
+ transforms.Normalize(
184
+ mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]
185
+ ),
186
+ ]
187
+ )
188
+
189
+ self.eval()
190
+
191
+ image = image.convert("RGB")
192
+ image = data_transforms(image)
193
+ image = image.unsqueeze(0) # Add batch dimension
194
+ image = image.to(DEVICE)
195
+
196
+ # Generate embedding
197
+ with torch.no_grad():
198
+ embedding = self(image)
199
+
200
+ return embedding.squeeze().cpu().numpy().tolist()
image_search_engine/models/efficientnet_ns.py ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import timm
2
+ import torch
3
+ import torch.nn as nn
4
+
5
+ from image_search_engine.models.arc_margin_product import ArcMarginProduct
6
+ from image_search_engine.models.base import BaseModel
7
+ from image_search_engine.models.gem_pooling import GeM
8
+ from image_search_engine.utils import PACKAGE_DIR
9
+
10
+ CLASSES = 8
11
+ SCALE = 10
12
+ MARGIN = 0.1
13
+ EMBEDING_SIZE = 512
14
+
15
+ WEIGHTS_DIR = PACKAGE_DIR / "artifacts/weights"
16
+ DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
17
+
18
+
19
+ class EfficientNet_b0_ns(BaseModel):
20
+ def __init__(self, pretrained=True, load_weights=False):
21
+ super(EfficientNet_b0_ns, self).__init__(predtrained=pretrained)
22
+ self.model = timm.create_model("tf_efficientnet_b0_ns", pretrained=pretrained)
23
+ in_features = self.model.classifier.in_features
24
+ self.model.classifier = nn.Identity()
25
+ self.model.global_pool = nn.Identity()
26
+ self.pooling = GeM()
27
+ self.drop = nn.Dropout(p=0.2, inplace=False)
28
+ self.fc = nn.Linear(in_features, EMBEDING_SIZE)
29
+ self.arc = ArcMarginProduct(
30
+ EMBEDING_SIZE,
31
+ CLASSES,
32
+ )
33
+ if load_weights:
34
+ self.load_state_dict(
35
+ torch.load(WEIGHTS_DIR / "Loss0.6555_epoch3.bin", map_location=DEVICE)
36
+ )
37
+
38
+ def forward(self, images, labels=None):
39
+ features = self.model(images)
40
+ pooled_features = self.pooling(features).flatten(1)
41
+ pooled_drop = self.drop(pooled_features)
42
+ emb = self.fc(pooled_drop)
43
+
44
+ if labels is not None:
45
+ output = self.arc(emb, labels)
46
+ return output, emb
47
+ else:
48
+ return emb
image_search_engine/models/gem_pooling.py ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ import torch.nn.functional as F
4
+
5
+
6
+ class GeM(nn.Module):
7
+ def __init__(self, p=3, eps=1e-6):
8
+ super(GeM, self).__init__()
9
+ self.p = nn.Parameter(torch.ones(1) * p)
10
+ self.eps = eps
11
+
12
+ def forward(self, x):
13
+ return self.gem(x, p=self.p, eps=self.eps)
14
+
15
+ def gem(self, x, p=3, eps=1e-6):
16
+ return F.avg_pool2d(x.clamp(min=eps).pow(p), (x.size(-2), x.size(-1))).pow(
17
+ 1.0 / p
18
+ )
19
+
20
+ def __repr__(self):
21
+ return (
22
+ self.__class__.__name__
23
+ + "("
24
+ + "p="
25
+ + "{:.4f}".format(self.p.data.tolist()[0])
26
+ + ", "
27
+ + "eps="
28
+ + str(self.eps)
29
+ + ")"
30
+ )
image_search_engine/product_image_search.py ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import torch
3
+ import os
4
+
5
+ from image_search_engine import utils
6
+ from image_search_engine.models import EfficientNet_b0_ns
7
+ from typing import Union
8
+ from pathlib import Path
9
+ from PIL import Image
10
+ from dotenv import load_dotenv
11
+ import pinecone
12
+
13
+ MODEL_FILE = "model.pt"
14
+ INDEX_FILE = "index.pkl"
15
+
16
+ PROJECT_DIR = utils.PACKAGE_DIR.parent
17
+ INDEX_NAME = "jumia-product-embeddings"
18
+
19
+ PINECONE_API_KEY = os.environ.get("PINECONE_API_KEY")
20
+ PINECONE_ENV = os.environ.get("PINECONE_ENV")
21
+
22
+
23
+ def load_pinecone_existing_index():
24
+ pinecone.init(api_key=PINECONE_API_KEY, environment=PINECONE_ENV)
25
+ index = pinecone.Index(INDEX_NAME)
26
+ return index
27
+
28
+
29
+ index = load_pinecone_existing_index()
30
+
31
+
32
+ class JumiaProductSearch:
33
+ def __init__(self, model_path=None):
34
+ if model_path is None:
35
+ model_path = utils.STAGED_MODEL_DIR / MODEL_FILE
36
+ self.model = EfficientNet_b0_ns()
37
+ self.model.load_state_dict(torch.load(model_path))
38
+ self.index = utils.load_serialized_object(utils.STAGED_MODEL_DIR / INDEX_FILE)
39
+
40
+ def _encode(self, image: Union[str, Path, Image.Image]):
41
+ image_pil = image
42
+ if not isinstance(image, Image.Image):
43
+ image_pil = utils.read_image_pil(image)
44
+
45
+ query_embedding = self.model.generate_embeddings(image_pil)
46
+
47
+ return query_embedding
48
+
49
+ def search(self, image, k):
50
+ xq = self._encode(image)
51
+ result = index.query(xq, top_k=k, include_metadata=True)
52
+ return result
53
+
54
+ def search_nn(self, image):
55
+ query_embedding = self.encode(image)
56
+ distances, idxs = self.index.kneighbors(query_embedding, return_distance=True)
57
+ return idxs
58
+
59
+
60
+ if __name__ == "__main__":
61
+ search = JumiaProductSearch()
62
+ test_img = utils.PACKAGE_DIR / "tests/test_img/1.jpg"
63
+ idx = search.search(test_img)
64
+ print(idx)
image_search_engine/tests/__init__.py ADDED
File without changes
image_search_engine/tests/test_img/1.jpg ADDED
image_search_engine/tests/test_img/2.jpg ADDED
image_search_engine/tests/test_img/3.jpg ADDED
image_search_engine/tests/test_img/4.jpg ADDED
image_search_engine/tests/test_img/5.jpg ADDED
image_search_engine/tests/test_img/6.jpg ADDED
image_search_engine/tests/test_img/7.jpg ADDED
image_search_engine/tests/test_img/8.jpg ADDED
image_search_engine/tests/test_img/Shark2.jpg ADDED
image_search_engine/tests/test_img/smart_band.jpg ADDED
image_search_engine/tests/test_img/smart_band_2.jpg ADDED
image_search_engine/tests/test_img/sony.png ADDED
image_search_engine/utils.py ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ from pathlib import Path
3
+ import smart_open
4
+ import joblib
5
+ from typing import Union
6
+ from PIL import Image
7
+
8
+ PACKAGE_DIR = Path(__file__).parent
9
+ STAGED_MODEL_DIR = PACKAGE_DIR / "artifacts/model_staged"
10
+
11
+
12
+ def read_image_pil(image_uri: Union[Path, str]) -> Image:
13
+ with smart_open.open(image_uri, "rb") as image_file:
14
+ return read_image_pil_file(image_file)
15
+
16
+
17
+ def read_image_pil_file(image_file) -> Image:
18
+ with Image.open(image_file) as image:
19
+ image = image.convert(mode=image.mode)
20
+ return image
21
+
22
+
23
+ def load_serialized_object(file_path):
24
+ try:
25
+ obj = joblib.load(file_path)
26
+ return obj
27
+ except FileNotFoundError:
28
+ print(f"File not found: {file_path}")
29
+ except Exception as e:
30
+ print(f"Error loading serialized object: {str(e)}")
31
+
32
+
33
+ def load_config(
34
+ file_path=PACKAGE_DIR / "artifacts/config.json",
35
+ ):
36
+ with open(file_path) as file:
37
+ data = json.load(file)
38
+ return data
39
+
40
+
41
+ def load_json_file(file_path):
42
+ with open(file_path, "r") as file:
43
+ data = json.load(file)
44
+ return data
45
+
46
+
47
+ if __name__ == "__main__":
48
+ load_config()