- نظام توصية للأزياء مع التعلم العميق
- اختبار نظام توصية للأزياء
في هذه المقالة، سوف أطلعك على كيفية إنشاء نظام توصية للأزياء باستخدام التعلم الآلي الذي سيعمل مثل توصيات التسوق عبر الإنترنت المخصصة للغاية. ولكن قبل المضي قدمًا، عليك أن تعرف ما هو نظام التوصية recommendation system.
نظام التوصية هو نظام مبرمج للتنبؤ بالعناصر المفضلة في المستقبل من مجموعة كبيرة من المجموعات. يعمل نظام التوصية إما باستخدام تفضيلات المستخدم أو باستخدام العناصر الأكثر تفضيلاً من قبل جميع المستخدمين. التحدي الرئيسي في بناء نظام توصية للأزياء هو أنها صناعة ديناميكية للغاية. يتغير كثيرًا عندما يتعلق الأمر بالمواسم والمهرجانات والظروف الوبائية مثل فيروس كورونا وغيرها الكثير.
نظام توصية للأزياء مع التعلم العميق
على عكس المجالات الأخرى، لا ينبغي أن تستند توصيات الأزياء فقط على الذوق الشخصي والنشاط السابق للعميل. هناك العديد من العوامل الخارجية (العديد منها عاطفية) التي تجعل إنشاء نظام توصية للأزياء أكثر تعقيدًا. يجب أن تؤخذ التصورات العامة في الاعتبار، وكذلك قواعد الموضة وقواعد اللباس والتوجهات الحالية.
دعنا نتعمق الآن في بناء نظام توصية للأزياء باستخدام التعلم الآلي. سأبدأ ببساطة باستيراد جميع الحزم التي نحتاجها لهذه المهمة:
1 2 3 4 5 6 7 8 9 10 11 | import matplotlib.pyplot as plt import numpy as np import pandas as pd import gdown from fastai.vision import * from fastai.metrics import accuracy, top_k_accuracy from annoy import AnnoyIndex import zipfile import time from google.colab import drive % matplotlib inline |
الآن، تحتاج إلى جمع البيانات في محرك google الخاص بك، وعليك لصق عناوين URL لهذه الروابط لاستيراد مجموعة البيانات في دفتر ملاحظاتك:
1 2 3 4 5 6 7 8 9 10 11 12 | # get the meta data output = 'list_category_cloth.txt' gdown.download(url, output, quiet = False ) output = 'list_category_img.txt' gdown.download(url, output, quiet = False ) output = 'list_eval_partition.txt' gdown.download(url, output, quiet = False ) |
الآن، دعنا نحصل على جميع الصور من محرك google الخاص بنا:
1 2 3 4 5 6 7 | # get the images root_path = './' output = 'img.zip' gdown.download(url, output, quiet = False ) with zipfile.ZipFile( "img.zip" , "r" ) as zip_ref: zip_ref.extractall(root_path) |
سأقوم الآن ببعض خطوات تحضير البيانات وتنظيف البيانات لتأطير البيانات بطريقة مفيدة:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | category_list = [] image_path_list = [] data_type_list = [] # category names with open ( 'list_category_cloth.txt' , 'r' ) as f: for i, line in enumerate (f.readlines()): if i > 1 : category_list.append(line.split( ' ' )[ 0 ]) # category map with open ( 'list_category_img.txt' , 'r' ) as f: for i, line in enumerate (f.readlines()): if i > 1 : image_path_list.append([word.strip() for word in line.split( ' ' ) if len (word) > 0 ]) # train, valid, test with open ( 'list_eval_partition.txt' , 'r' ) as f: for i, line in enumerate (f.readlines()): if i > 1 : data_type_list.append([word.strip() for word in line.split( ' ' ) if len (word) > 0 ]) data_df = pd.DataFrame(image_path_list, columns = [ 'image_path' , 'category_number' ]) data_df[ 'category_number' ] = data_df[ 'category_number' ].astype( int ) data_df = data_df.merge(pd.DataFrame(data_type_list, columns = [ 'image_path' , 'dataset_type' ]), on = 'image_path' ) data_df[ 'category' ] = data_df[ 'category_number' ]. apply ( lambda x: category_list[ int (x) - 1 ]) data_df = data_df.drop( 'category_number' , axis = 1 ) |
الآن، سيقوم الكود أدناه بتحويل جميع الصور إلى التضمينات embeddings:
1 2 3 4 5 6 7 8 | train_image_list = ImageList.from_df(df = data_df, path = root_path, cols = 'image_path' ).split_by_idxs( (data_df[data_df[ 'dataset_type' ] = = 'train' ].index), (data_df[data_df[ 'dataset_type' ] = = 'val' ].index)).label_from_df(cols = 'category' ) test_image_list = ImageList.from_df(df = data_df[data_df[ 'dataset_type' ] = = 'test' ], path = root_path, cols = 'image_path' ) data = train_image_list.transform(get_transforms(), size = 224 ).databunch(bs = 128 ).normalize(imagenet_stats) data.add_test(test_image_list) data.show_batch(rows = 3 , figsize = ( 8 , 8 )) |

الآن، سأقوم ببعض الخطوات لنقل التعلم باستخدام مكتبة resnet و PyTorch للحصول على معدل التعلم:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | # More layers are generally more accurate but take longer to train: resnet18, resnet34, resnet50, resnet101, resnet152 # get top 1 and top 5 accuracy def train_model(data, pretrained_model, model_metrics): learner = cnn_learner(data, pretrained_model, metrics = model_metrics) learner.model = torch.nn.DataParallel(learner.model) learner.lr_find() learner.recorder.plot(suggestion = True ) return learner pretrained_model = models.resnet18 # simple model that can be trained on free tier # pretrained_model = models.resnet50 # need pro tier, model I used model_metrics = [accuracy, partial(top_k_accuracy, k = 1 ), partial(top_k_accuracy, k = 5 )] learner = train_model(data, pretrained_model, model_metrics) learner.fit_one_cycle( 10 , max_lr = 1e - 02 ) |
الآن، دعنا نقيم نموذج نقل التعلم:
1 2 | interp = ClassificationInterpretation.from_learner(learner) interp.plot_top_losses( 9 , largest = False , figsize = ( 15 , 11 ), heatmap_thresh = 5 ) |

يبدو الناتج جيدًا، الآن قبل المضي قدمًا، دعنا نحفظ هذا النموذج حتى نتمكن من استخدامه بسهولة لمهامنا المستقبلية:
1 2 | # saving the model (temporary, will lose model once environment resets) learner.save( 'resnet-fashion' ) |
الآن، سأستخدم طريقة FastAI لاسترداد صور التضمينات:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | class SaveFeatures(): features = None def __init__( self , m): self .hook = m.register_forward_hook( self .hook_fn) self .features = None def hook_fn( self , module, input , output): out = output.detach().cpu().numpy() if isinstance ( self .features, type ( None )): self .features = out else : self .features = np.row_stack(( self .features, out)) def remove( self ): self .hook.remove() # load the trained model def load_learner(data, pretrained_model, model_metrics, model_path): learner = cnn_learner(data, pretrained_model, metrics = model_metrics) learner.model = torch.nn.DataParallel(learner.model) learner = learner.load(model_path) return learner pretrained_model = models.resnet18 # simple model that can be trained on free tier # pretrained_model = models.resnet50 # need pro tier model_metrics = [accuracy, partial(top_k_accuracy, k = 1 ), partial(top_k_accuracy, k = 5 )] # if gdrive not mounted: drive.mount( '/content/gdrive' ) model_path = "/content/gdrive/My Drive/resnet18-fashion" # model_path = "/content/gdrive/My Drive/resnet50-fashion" learner = load_learner(data, pretrained_model, model_metrics, model_path) |
أتمنى أن تكون قد فهمت شيئًا من العملية المذكورة أعلاه، والآن سأستخدم طريقة أقرب جيران nearest neighbours لإنشاء نظام توصية للأزياء:
1 2 3 4 5 6 | # takes time to populate the embeddings for each image # Get 2nd last layer of the model that stores the embedding for the image representations # the last linear layer is the output layer. saved_features = SaveFeatures(learner.model.module[ 1 ][ 4 ]) _ = learner.get_preds(data.train_ds) _ = learner.get_preds(DatasetType.Valid) |
أخيرًا، نقوم بإدراج عمليات التضمين الخاصة بـ 12 عنصرًا (أو أكثر) من تحديد المستخدم في قائمة ومتوسط قيم التضمينات في كل من الأبعاد؛ يؤدي هذا إلى إنشاء كائن شبح ghost object يمثل القيمة الإجمالية لجميع العناصر المحددة.
يمكننا بعد ذلك العثور على أقرب جار لهذا الكائن الشبح:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | # prepare the data for generating recommendations (exlcude test data) # get the embeddings from trained model img_path = [ str (x) for x in ( list (data.train_ds.items) + list (data.valid_ds.items))] label = [data.classes[x] for x in ( list (data.train_ds.y.items) + list (data.valid_ds.y.items))] label_id = [x for x in ( list (data.train_ds.y.items) + list (data.valid_ds.y.items))] data_df_ouput = pd.DataFrame({ 'img_path' : img_path, 'label' : label, 'label_id' : label_id}) data_df_ouput[ 'embeddings' ] = np.array(saved_features.features).tolist() # Using Spotify's Annoy def get_similar_images_annoy(annoy_tree, img_index, number_of_items = 12 ): start = time.time() img_id, img_label = data_df_ouput.iloc[img_index, [ 0 , 1 ]] similar_img_ids = annoy_tree.get_nns_by_item(img_index, number_of_items + 1 ) end = time.time() print (f '{(end - start) * 1000} ms' ) # ignore first item as it is always target image return img_id, img_label, data_df_ouput.iloc[similar_img_ids[ 1 :]] # for images similar to centroid def get_similar_images_annoy_centroid(annoy_tree, vector_value, number_of_items = 12 ): start = time.time() similar_img_ids = annoy_tree.get_nns_by_vector(vector_value, number_of_items + 1 ) end = time.time() print (f '{(end - start) * 1000} ms' ) # ignore first item as it is always target image return data_df_ouput.iloc[similar_img_ids[ 1 :]] def show_similar_images(similar_images_df, fig_size = [ 10 , 10 ], hide_labels = True ): if hide_labels: category_list = [] for i in range ( len (similar_images_df)): # replace category with blank so it wont show in display category_list.append(CategoryList(similar_images_df[ 'label_id' ].values * 0 , [''] * len (similar_images_df)).get(i)) else : category_list = [learner.data.train_ds.y.reconstruct(y) for y in similar_images_df[ 'label_id' ]] return learner.data.show_xys([open_image(img_id) for img_id in similar_images_df[ 'img_path' ]], category_list, figsize = fig_size) # more tree = better approximation ntree = 100 #"angular", "euclidean", "manhattan", "hamming", or "dot" metric_choice = 'angular' annoy_tree = AnnoyIndex( len (data_df_ouput[ 'embeddings' ][ 0 ]), metric = metric_choice) # # takes a while to build the tree for i, vector in enumerate (data_df_ouput[ 'embeddings' ]): annoy_tree.add_item(i, vector) _ = annoy_tree.build(ntree) |
اختبار نظام توصية للأزياء
الآن، دعنا نختبر نظام توصيات الأزياء لدينا. لهذا، نحتاج إلى إنشاء بعض الرموز. أولاً، دعنا نرى التوصيات لأي شيء يتعلق بالسراويل القصيرة “shorts”:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | def centroid_embedding(outfit_embedding_list): number_of_outfits = outfit_embedding_list.shape[ 0 ] length_of_embedding = outfit_embedding_list.shape[ 1 ] centroid = [] for i in range (length_of_embedding): centroid.append(np. sum (outfit_embedding_list[:, i]) / number_of_outfits) return centroid # shorts outfit_img_ids = [ 109938 , 106385 , 113703 , 98666 , 113467 , 120667 , 20840 , 8450 , 142843 , 238607 , 124505 , 222671 ] outfit_embedding_list = [] for img_index in outfit_img_ids: outfit_embedding_list.append(data_df_ouput.iloc[img_index, 3 ]) outfit_embedding_list = np.array(outfit_embedding_list) outfit_centroid_embedding = centroid_embedding(outfit_embedding_list) outfits_selected = data_df_ouput.iloc[outfit_img_ids] similar_images_df = get_similar_images_annoy_centroid(annoy_tree, outfit_centroid_embedding, 30 ) |
وأخيرًا، سنرى توصيات “السراويل القصيرة”:

هذه استجابة جيدة جدًا من نموذجنا. آمل أن تكون قد أحببت هذه المقالة حول نظام توصية الموضة مع التعلم العميق.
Hi, this is a comment.
To get started with moderating, editing, and deleting comments, please visit the Comments screen in the dashboard.