قبل الخوض في أي مشكلة تعلم ألة علينا أن نولي عناية لطريقة ترتيب المشروع و في هذه المقالة من سلسة التعامل مع مسائل تعلم الأله سنقوم ببناء إطار عمل لمسائل التصنيف بطريقة تجعل معظم هذه المشكلات تصبح عبارة عن وصل و شغل. سنتمكن من تدريب نموذج دون إجراء الكثير من التغييرات على الكود ، وعندما نقوم بتحسين نماذجنا ، سنتمكن من تتبعها باستخدام git. دعونا نلقي نظرة على هيكل الملفات أولا وقبل كل شيء. لأي مشروع تقوم به ، نقوم بإنشاء مجلد جديد.
داخل هذه مجلد المشروع يجب أن يبدو كشي من هذا القبيل
├── input │ ├── train.csv │ └── test.csv ├── src │ ├── create_folds.py │ ├── train.py │ ├── inference.py │ ├── models.py │ ├── config.py │ └── model_dispatcher.py ├── models │ ├── model_rf.bin │ └── model_et.bin ├── notebooks │ ├── exploration.ipynb │ └── check_data.ipynb ├── README.md └── LICENSE
دعونا نرى ما هي هذه المجلدات والملفات.
input /: يتكون هذا المجلد من جميع ملفات الإدخال والبيانات لمشروع التعلم الآلي الخاص بك. إذا كنت تعمل في مشاريع معالجة اللغة الطبيعية ، يمكنك الاحتفاظ بتضميناتك هنا. إذا كنت تعمل في مشاريع الصور ، تنتقل جميع الصور إلى مجلد فرعي داخل هذا المجلد.
src /: سنحتفظ بجميع نصوص Python المرتبطة بالمشروع هنا. إذا تحدثت عن برنامج نصي من نوع python ، أي أي ملف * .py ، فسيتم تخزينه في مجلد src.
models /: يحتفظ هذا المجلد بجميع النماذج المدربة هنا .
notebooks /: يتم تخزين جميع دفاتر jupyter (أي ملف * .ipynb) في مجلد دفاتر الملاحظات.
README.md: هذا ملف ماركداون حيث يمكنك وصف مشروعك وكتابة تعليمات حول كيفية تدريب النموذج أو تقديمه في بيئة إنتاج.
LICENSE: هذا ملف نصي بسيط يتكون من ترخيص للمشروع ، مثل MIT ، و Apache ، وما إلى ذلك.
لنفترض أنك تبني نموذجًا لتصنيف مجموعة بيانات MNIST (مجموعة بيانات تم استخدامها في كل كتاب من كتب التعلم الآلي تقريبًا). إذا كنت تتذكر ، فقد تطرقنا إلى مجموعة بيانات MNIST في مقال التحقق المتقاطع أيضًا هناك العديد من التنسيقات المختلفة لمجموعة بيانات MNIST المتاحة عبر الإنترنت ، لكننا سنستخدم تنسيق CSV لمجموعة البيانات. في هذا التنسيق لمجموعة البيانات ، يتكون كل صف من ملف CSV من تسمية الصورة وقيم 784 بكسل تتراوح من 0 إلى 255. تتكون مجموعة البيانات من 60000 صورة بهذا التنسيق.
يمكننا استخدام Pandas لقراءة تنسيق البيانات هذا بسهولة. يرجى ملاحظة أنه على الرغم من أن الشكل 1 يعرض جميع قيم البكسل كأصفار ، فإن الأمر ليس كذلك.
دعنا نلقي نظرة على أعداد عمود التصنيف في مجموعة البيانات هذه.
لسنا بحاجة إلى المزيد من الاستكشاف لمجموعة البيانات هذه. نحن نعلم بالفعل ما لدينا ، وليست هناك حاجة لعمل مخططات على قيم بكسل مختلفة. من الصورة أعلاه ، من الواضح تمامًا أن توزيع المسميات جيد جدًا.
وبالتالي يمكننا استخدام الدقة / F1 كمقاييس. هذه هي الخطوة الأولى عند التعامل مع مشكلة التعلم الآلي: تحديد المقياس!
الآن ، يمكننا البرمجة قليلاً. نحتاج إلى إنشاء مجلد src / وبعض نصوص python.
يرجى ملاحظة أن ملف CSV للتدريب موجود في مجلد input ويسمى mnist_train.csv. كيف يجب أن تبدو هذه الملفات لمثل هذا المشروع؟
البرنامج النصي الأول الذي يجب على المرء إنشاؤه هو create_folds.py.
سيؤدي هذا إلى إنشاء ملف جديد في مجلد input/ يسمى mnist_train_folds.csv ، وهو نفس الملف mnist_train.csv. الاختلافات الوحيدة هي أن ملف CSV هذا تم خلطه ولديه عمود جديد يسمى kfold.
بمجرد أن نقرر نوع مقياس التقييم الذي نريد استخدامه وأنشأنا الطيات ، فمن الجيد أن نبدأ في إنشاء نموذج أساسي. يتم ذلك في train.py
import joblib import pandas as pd from sklearn import metrics from sklearn import tree def run(fold): # قراءة ملف التدريب مع فولد df = pd.read_csv("../input/mnist_train_folds.csv") # تدريب البيانات بحيث أن كي فولد لا تساوي فولد # كما نقوم أيضا بإعادة تعيين الفهرس df_train = df[df.kfold != fold].reset_index(drop=True) # بيانات التحقق هي حيث كي فولد تساوي فولد df_valid = df[df.kfold == fold].reset_index(drop=True) # قم بإسقاط عمود التسمية من dataframe وقم بتحويله إلى #مصفوفة عددية باستخدام قيم. # الهدف هو عمود التسمية في إطار البيانات x_train = df_train.drop("label", axis = 1).values y_train = df_train.label.values # sklearn تهيئة مصنف شجرة القرار البسيط من x_valid = df_valid.drop("label", axis=1).values y_valid = df_valid.label.values clf = tree.DecisionTreeClassifier() clf.fit(x_train, y_train) # إنشاء تنبؤات لعينات التحقق preds = clf.predict(x_valid) # حساب و طباعة الدقة accuracy = metrics.accuracy_score(y_valid, preds) print(f"Fold={fold}, Accuracy={accuracy}") # حفظ النموذج joblib.dump(clf, f"../models/dt_{fold}.bin") if __name__ == "__name__": run(fold=0) run(fold=1) run(fold=2) run(fold=3) run(fold=4)
يمكنك تشغيل هذا البرنامج النصي عن طريق استدعاء python train.py
python train.py Fold=0, Accuracy=0.8680833333333333 Fold=1, Accuracy=0.8685 Fold=2, Accuracy=0.8674166666666666 Fold=3, Accuracy=0.8703333333333333 Fold=4, Accuracy=0.8699166666666667
عندما تنظر إلى البرنامج النصي للتدريب ، سترى أنه لا يزال هناك عدد قليل من الأشياء التي نحتاج إلى إدخالها يدوياً في كل مرة ، على سبيل المثال ، أرقام الطيات وملف التدريب ومجلد الإخراج. يمكننا بالتالي إنشاء ملف تهيئة بكل هذه المعلومات: config.py.
TRAINING_FILE = "../input/mnist_train_folds.csv" MODEL_OUTPUT = "../models/"
ونجري بعض التغييرات على برنامج التدريب أيضًا. يستخدم ملف التدريب ملف التهيئة الآن. وبالتالي تسهيل تغيير البيانات أو إخراج النموذج.
import os import joblib import config import pandas as pd from sklearn import metrics from sklearn import tree def run(fold): # قراءة ملف التدريب مع فولد df = pd.read_csv(config.TRAINING_FILE) # تدريب البيانات بحيث أن كي فولد لا تساوي فولد # كما نقوم أيضا بإعادة تعيين الفهرس df_train = df[df.kfold != fold].reset_index(drop=True) # بيانات التحقق هي حيث كي فولد تساوي فولد df_valid = df[df.kfold == fold].reset_index(drop=True) # قم بإسقاط عمود التسمية من dataframe وقم بتحويله إلى #مصفوفة عددية باستخدام قيم. # الهدف هو عمود التسمية في إطار البيانات x_train = df_train.drop("label", axis=1).values y_train = df_train.label.values # sklearn تهيئة مصنف شجرة القرار البسيط من x_valid = df_valid.drop("label", axis=1).values y_valid = df_valid.label.values clf = tree.DecisionTreeClassifier() clf.fit(x_train, y_train) # إنشاء تنبؤات لعينات التحقق preds = clf.predict(x_valid) # حساب و طباعة الدقة accuracy = metrics.accuracy_score(y_valid, preds) print(f"Fold={fold}, Accuracy={accuracy}") # حفظ النموذج joblib.dump(clf,os.path.join(config.MODEL_OUTPUT, f"dt_{fold}.bin")) if __name__ == "__main__": run(fold=0) run(fold=1) run(fold=2) run(fold=3) run(fold=4)
لا يزال هناك شيء آخر يتعلق بملف التدريب يمكن تحسينه. كما ترى ، نستدعي الدالة run عدة مرات لكل طي (fold). في بعض الأحيان لا يُنصح بتشغيل عدة طيات في نفس البرنامج النصي حيث أن استهلاك الذاكرة قد يستمر في الزيادة ، وقد ينهار برنامجك. للتعامل مع هذه المشكلة ، يمكننا تمرير الحجج إلى ملف للتدريب. أفضل القيام بذلك باستخدام argparse.
import os import argparse import joblib import config import pandas as pd from sklearn import metrics from sklearn import tree def run(fold): # قراءة ملف التدريب مع فولد df = pd.read_csv(config.TRAINING_FILE) # تدريب البيانات بحيث أن كي فولد لا تساوي فولد # كما نقوم أيضا بإعادة تعيين الفهرس df_train = df[df.kfold != fold].reset_index(drop=True) # بيانات التحقق هي حيث كي فولد تساوي فولد df_valid = df[df.kfold == fold].reset_index(drop=True) # قم بإسقاط عمود التسمية من dataframe وقم بتحويله إلى #مصفوفة عددية باستخدام قيم. # الهدف هو عمود التسمية في إطار البيانات x_train = df_train.drop("label", axis=1).values y_train = df_train.label.values # sklearn تهيئة مصنف شجرة القرار البسيط من x_valid = df_valid.drop("label", axis=1).values y_valid = df_valid.label.values clf = tree.DecisionTreeClassifier() clf.fit(x_train, y_train) # إنشاء تنبؤات لعينات التحقق preds = clf.predict(x_valid) # حساب و طباعة الدقة accuracy = metrics.accuracy_score(y_valid, preds) print(f"Fold={fold}, Accuracy={accuracy}") # حفظ النموذج joblib.dump(clf,os.path.join(config.MODEL_OUTPUT, f"dt_{fold}.bin")) if __name__ == "__main__": # argumentPaser تهيئة الـ parser = argparse.ArgumentParser() # إضافة الحجج التي نريدها و نوعهم # حاليا نريد الطيات فقط parser.add_argument( "--fold" , type= int ) # قراءة الحجة args = parser.parse_args() # قم بتشغيل الطية المحددة run(fold=args.fold)
الآن ، يمكننا تشغيل نص Python مرة أخرى ، ولكن فقط لطية معينة.
❯ python train.py --fold 0 Fold=0, Accuracy=0.8656666666666667
إذا نظرت بعناية ، فإن نتيجة 0 كانت مختلفة قليلاً من قبل. هذا بسبب العشوائية في النموذج.
الآن ، إذا كنت ترغب في ذلك ، يمكنك إنشاء نص برمجي (shell script) بأوامر مختلفة لطيات مختلفة وتشغيلها جميعًا معًا ، كما هو موضح أدناه.
#!/bin/sh python train.py --fold 0 python train.py --fold 1 python train.py --fold 2 python train.py --fold 3 python train.py --fold 4
ويمكنك تشغيل هذا بالأمر التالي.
❯ sh run.sh Fold=0, Accuracy=0.8675 Fold=1, Accuracy=0.8693333333333333 Fold=2, Accuracy=0.8683333333333333 Fold=3, Accuracy=0.8704166666666666 Fold=4, Accuracy=0.8685
لقد أحرزنا بعض التقدم الآن ، ولكن إذا نظرنا إلى نص التدريب الخاص بنا ، فإننا لا نزال مقيدون ببعض الأشياء ، على سبيل المثال ، النموذج.
النموذج مضمن في الملف النصي للتدريب ، والطريقة الوحيدة لتغييره هي تعديل الملف النصي. لذلك ، سنقوم بإنشاء نص برمجي جديد للبيثون يسمى model_dispatcher.py
model_dispatcher.py ، كما يوحي الاسم ، سيرسل نماذجنا إلى الملف النصي للتدريب.
from sklearn import tree from sklearn import ensemble models = { "decision_tree_gini" : tree.DecisionTreeClassifier(criterion="gini"), "decision_tree_entropy" : tree.DecisionTreeClassifier(criterion="entropy"), }
يستورد model_dispatcher.py شجرة من scikit-learn ويحدد قاموسًا بمفاتيح تمثل أسماء النماذج والقيم هي النماذج نفسها. هنا ، نحدد شجرتين مختلفتين للقرار ، واحدة بمعيار جيني والأخرى مع إنتروبيا. لاستخدام model_dispatcher.py ، نحتاج إلى إجراء بعض التغييرات على ألملف النصي للتدريب.
import os import argparse import joblib import pandas as pd from sklearn import metrics from sklearn import tree import config import model_dispatcher def run(fold, model): # قراءة ملف التدريب مع فولد df = pd.read_csv(config.TRAINING_FILE) # تدريب البيانات بحيث أن كي فولد لا تساوي فولد # كما نقوم أيضا بإعادة تعيين الفهرس df_train = df[df.kfold != fold].reset_index(drop=True) # بيانات التحقق هي حيث كي فولد تساوي فولد df_valid = df[df.kfold == fold].reset_index(drop=True) # قم بإسقاط عمود التسمية من dataframe وقم بتحويله إلى #مصفوفة عددية باستخدام قيم. # الهدف هو عمود التسمية في إطار البيانات x_train = df_train.drop("label", axis=1).values y_train = df_train.label.values # sklearn تهيئة مصنف شجرة القرار البسيط من x_valid = df_valid.drop("label", axis=1).values y_valid = df_valid.label.values # model dispatcher الحصول على النموذج من clf = model_dispatcher.models[model] clf.fit(x_train, y_train) # إنشاء تنبؤات لعينات التحقق preds = clf.predict(x_valid) # حساب و طباعة الدقة accuracy = metrics.accuracy_score(y_valid, preds) print(f"Fold={fold}, Accuracy={accuracy}") # حفظ النموذج joblib.dump(clf,os.path.join(config.MODEL_OUTPUT, f"dt_{fold}.bin")) if __name__ == "__main__": # argumentPaser تهيئة الـ parser = argparse.ArgumentParser() # إضافة الحجج التي نريدها و نوعهم # الطيات parser.add_argument( "--fold" , type= int ) # النموذج parser.add_argument( "--model" , type= str ) # قراءة الحجة args = parser.parse_args() # قم بتشغيل الطية و النموذج المحددة run(fold=args.fold, model=args.model)
هناك بعض التغييرات الرئيسية في train.py:
• استيراد model_dispatcher
• إضافة –model إلى ArgumentParser
• إضافة model إلى دالة run()
الآن ، يمكننا تشغيل البرنامج النصي باستخدام الأمر التالي:
❯ python train.py --fold 0 --model decision_tree_gini Fold=0, Accuracy=0.8665833333333334
أو الأمر التالي
❯ python train.py --fold 0 --model decision_tree_entropy Fold=0, Accuracy=0.8705833333333334
الآن ، إذا أضفت نموذجًا جديدًا ، فكل ما عليك فعله هو إجراء تغييرات على model_dispatcher.py. دعونا نحاول إضافة نموذج الغابة العشوائية (random forest) ونرى ما سيحدث لدقتنا.
from sklearn import tree from sklearn import ensemble models = { "decision_tree_gini" : tree.DecisionTreeClassifier(criterion="gini"), "decision_tree_entropy" : tree.DecisionTreeClassifier(criterion="entropy"), "rf" : ensemble.RandomForestClassifier(), }
دعونا ننفذ هذا الرمز.
❯ python train.py --fold 0 --model rf Fold=0, Accuracy=0.9670833333333333
واو ، لقد أعطى تغيير بسيط مثل هذا التحسن الهائل في النتيجة!
لنقم بتشغيل جميع الطيات الخمس باستخدام البرنامج النصي run.sh الآن!
#!/bin/sh python train.py --fold 0 --model rf python train.py --fold 1 --model rf python train.py --fold 2 --model rf python train.py --fold 3 --model rf python train.py --fold 4 --model rf
والنتائج تبدو كما يلي.
sh run.sh Fold=0, Accuracy=0.9674166666666667 Fold=1, Accuracy=0.9698333333333333 Fold=2, Accuracy=0.96575 Fold=3, Accuracy=0.9684166666666667 Fold=4, Accuracy=0.9666666666666667
MNIST هي مشكلة تمت مناقشتها في كل كتاب وكل مدونة تقريبًا. لكنني حاولت تحويل هذه المشكلة إلى المزيد من المرح وأظهر لك كيفية كتابة إطار عمل أساسي لأي مشروع تعلم آلي تقوم به تقريبًا ، أو تخطط للقيام به في المستقبل القريب. هناك العديد من الطرق المختلفة لتحسين نموذج MNIST هذا وأيضًا إطار العمل هذا ، وسنرى ذلك في مقالات مستقبلية.
إضافة تعليق