كيفية إنشاء مصنف صورة بدقة أكبر من 97٪

مخطط واضح وكامل للنجاح

كيف تقوم بتدريس الكمبيوتر للنظر إلى صورة وتحديدها كزهرة بشكل صحيح؟ كيف تُعلِّم الكمبيوتر رؤية صورة للزهرة ثم تخبرك بالضبط ما هي أنواع الزهرة كما لو كنت لا تعرف أي نوع منها؟

دعني اريك!

ستنتقل بك هذه المقالة إلى أساسيات إنشاء مصنف صور باستخدام PyTorch. يمكنك تخيل استخدام شيء مثل هذا في تطبيق الهاتف الذي يخبرك باسم الزهرة التي تنظر إليها الكاميرا. يمكنك ، إذا أردت ، تدريب هذا المصنف ثم تصديره للاستخدام في تطبيق خاص بك.

ما تفعله من هنا يعتمد كليًا عليك وعلى خيالك.

لقد وضعت هذه المقالة معًا لأي شخص جديد تمامًا لكل هذا وابحث عن مكان للبدء. الأمر متروك لك لأخذ هذه المعلومات وتحسينها وجعلها خاصة بك!

إذا كنت ترغب في عرض دفتر الملاحظات ، يمكنك العثور عليه هنا.

نظرًا لأن مصنف صور PyTorch تم إنشاؤه كمشروع نهائي لبرنامج Udacity ، فإن الرمز يعتمد على رمز من Udacity والذي بدوره يعتمد على وثائق PyTorch الرسمية. قدمت Udacity ملف JSON لتعيين التسمية. يمكن العثور على هذا الملف في هذا GitHub repo.

يمكن العثور على معلومات حول مجموعة بيانات الزهور هنا. تتضمن مجموعة البيانات مجلدًا منفصلاً لكل فئة من فئات الزهور 102. تتم تسمية كل زهرة كرقم وكل من الأدلة المرقمة يحمل عددًا من ملفات .jpg.

هيا بنا نبدأ!

الصورة من قبل آني سبرات على Unsplash

نظرًا لأن هذه شبكة عصبية تستخدم مجموعة بيانات أكبر من قدرة وحدة المعالجة المركزية الخاصة بي على معالجة أي قدر معقول من الوقت ، فقد تقدمت وأعدت مصنف الصور الخاص بي في Google Colab. كولاب رائع حقا لأنه يوفر GPU مجانا. (إذا كنت جديدًا في Colab ، فتحقق من هذه المقالة حول البدء باستخدام Google Colab!)

لأنني كنت أستخدم Colab ، كنت بحاجة للبدء من خلال استيراد PyTorch. لست بحاجة إلى القيام بذلك إذا كنت لا تستخدم Colab.

*** تحديث! (01/29) *** Colab يدعم الآن PyTorch الأصلي !!! لا يلزمك تشغيل الشفرة أدناه ، لكنني أتركها في حال واجه أي شخص أي مشاكل!

# استيراد PyTorch إذا كنت تستخدم Google Colab
# http://pytorch.org/
من استيراد os.path موجود
من wheel.pep425tags ، استيراد get_abbr_impl ، get_impl_ver ، get_abi_tag
النظام الأساسي = '{} {} - {}'. التنسيق (get_abbr_impl () ، get_impl_ver () ، get_abi_tag ())
cuda_output =! ldconfig -p | grep cudart.so | sed -e / s /. \ \ \ [[0-9] * \) \. \ ([0-9] * \) $ / cu \ 1 \ 2 / '
المعجل = cuda_output [0] إذا كان موجودًا ('/ dev / nvidia0') آخر 'cpu'
! pip install -q http://download.pytorch.org/whl/{accelerator}/torch-0.4.1-{platform}-linux_x86_64.whl torchvision
استيراد الشعلة

بعد ذلك ، وبعد أن واجهت بعض المشاكل مع Pillow (إنها عربات التي تجرها الدواب في Colab!) ، تقدمت للتو وذهبت إلى هذا:

استيراد PIL
طباعة (PIL.PILLOW_VERSION)

إذا حصلت على أي شيء أقل من 5.3.0 ، فاستخدم القائمة المنسدلة ضمن "وقت التشغيل" لإعادة تشغيل وقت التشغيل وتشغيل هذه الخلية مرة أخرى. يجب أن تكون جيدة للذهاب!

ستحتاج إلى استخدام GPU لهذا المشروع ، وهو أمر بسيط بشكل لا يصدق لإعداده في Colab. كل ما عليك هو الانتقال إلى القائمة المنسدلة "وقت التشغيل" ، ثم تحديد "تغيير نوع وقت التشغيل" ، ثم تحديد "GPU" في القائمة المنسدلة تسريع الأجهزة!

ثم أحب أن أركض

train_on_gpu = torch.cuda.is_available ()
إن لم يكن train_on_gpu:
    طباعة ("Bummer! تدريب على وحدة المعالجة المركزية ...")
آخر:
    طباعة ("أنت على ما يرام! التدريب على GPU ...")

فقط للتأكد من أنها تعمل. ثم اركض

device = torch.device ("cuda: 0" if torch.cuda.is_available () آخر "cpu")

لتحديد الجهاز.

بعد ذلك ، قم باستيراد الملفات. هناك الكثير من الطرق للقيام بذلك ، بما في ذلك تركيب Google Drive الخاص بك إذا كان لديك مجموعة بيانات مخزنة هناك ، وهو في الواقع بسيط للغاية. على الرغم من أنني لم أنتهي من العثور على ذلك ليكون الحل الأكثر فائدة ، إلا أنني أدرج ذلك أدناه ، لمجرد أنه سهل ومفيد.

من google.colab استيراد محرك الأقراص
drive.mount ( '/ المحتوى / gdrive')

بعد ذلك ، سترى رابطًا ، وانقر على ذلك ، واسمح له بالوصول ، وانسخ الرمز الذي ينبثق ، والصقه في المربع ، واضغط على إدخال ، ومن الأفضل أن تذهب! إذا لم تشاهد محرك الأقراص في المربع الجانبي على اليسار ، فما عليك سوى النقر على "تحديث" ويجب أن يظهر.

(قم بتشغيل الخلية ، وانقر فوق الارتباط ، وانسخ الرمز الموجود في الصفحة ، والصقه في المربع ، واضغط على "الإدخال" ، وستظهر لك هذه الميزة عند تثبيت محرك الأقراص بنجاح):

إنه في الواقع سهل للغاية!

ومع ذلك ، إذا كنت تفضل تنزيل رابط ملف مضغوط مشترك (يكون هذا الخيار أسهل وأسرع لهذا المشروع) ، يمكنك استخدام:

! مجلد مشترك
! بفك

فمثلا:

! wget -cq https://s3.amazonaws.com/content.udacity-data.com/courses/nd188/flower_data.zip
unzip -qq flower_data.zip

من شأن ذلك أن يمنحك مجموعة بيانات زهرة Udacity في ثوانٍ!

(إذا كنت تحمِّل ملفات صغيرة ، فيمكنك تحميلها مباشرةً برمز بسيط. ومع ذلك ، إذا كنت ترغب في ذلك ، يمكنك أيضًا الانتقال إلى الجانب الأيسر من الشاشة والنقر فوق "تحميل الملفات" إذا لم تقم بذلك. أشعر بالرغبة في تشغيل بعض التعليمات البرمجية البسيطة للاستيلاء على ملف محلي.)

بعد تحميل البيانات ، قمت باستيراد المكتبات التي أردت استخدامها:

٪ matplotlib مضمنة
٪ config InlineBackend.figure_format = 'شبكية العين'
وقت الاستيراد
استيراد جسون
استيراد نسخة
استيراد matplotlib.pyplot كما PLT
استيراد بحرا كما SNS
استيراد numpy كـ np
استيراد PIL
من PIL استيراد صورة
من مجموعات استيراد OrderedDict
استيراد الشعلة
من استيراد الشعلة ن ، الأمثل
من torch.optim استيراد lr_scheduler
من torch.autograd استيراد متغير
استيراد torchvision
من مجموعات بيانات استيراد torchvision ، النماذج ، التحويلات
من torch.utils.data.sampler استيراد SubsetRandomSampler
استيراد torch.nn مثل nn
استيراد torch.nn.functional كـ F

التالي يأتي تحويلات البيانات! تريد التأكد من استخدام عدة أنواع مختلفة من التحويلات في مجموعة التدريب الخاصة بك من أجل مساعدة برنامجك على التعلم قدر المستطاع. يمكنك إنشاء نموذج أكثر قوة من خلال تدريبه على الصور المقلوبة والمدارة والمقطورة.

تعني أن الانحرافات المعيارية يتم توفيرها لتطبيع قيم الصورة قبل نقلها إلى شبكتنا ، ولكن يمكن العثور عليها أيضًا من خلال النظر إلى قيم الانحراف المعياري والمتوسط ​​للأبعاد المختلفة لتنسوجات الصورة. الوثائق الرسمية مفيدة بشكل لا يصدق هنا!

لمصنف الصور الخاص بي ، ظللت الأمر بسيطًا مع:

data_transforms = {
    "القطار": converts.Compose ([
        transforms.RandomRotation (30)،
        transforms.RandomResizedCrop (224)،
        transforms.RandomHorizontalFlip ()
        transforms.ToTensor ()
        تحويلات. تطبيع ([0.485 ، 0.456 ، 0.406] ،
                             [0.229 ، 0.224 ، 0.225])
    ])،
    "صالح": converts.Compose ([
        transforms.Resize (256)،
        transforms.CenterCrop (224)،
        transforms.ToTensor ()
        تحويلات. تطبيع ([0.485 ، 0.456 ، 0.406] ،
                             [0.229 ، 0.224 ، 0.225])
    ])
}
# قم بتحميل مجموعات البيانات باستخدام ImageFolder
image_datasets = {x: datasets.ImageFolder (os.path.join (data_dir، x)،
                                          data_transforms [س])
                  لـ x في ['قطار' ، 'صالح']}
# باستخدام مجموعات بيانات الصور وأشكال القطار ، حدد أدوات التحميل
batch_size = 64
dataloaders = {x: torch.utils.data.DataLoader (image_datasets [x]، batch_size = batch_size ،
                                             خلط ورق اللعب = صحيح ، عدد العاملين = 4)
              لـ x في ['قطار' ، 'صالح']}
class_names = image_datasets ['train']
dataset_sizes = {x: len (image_datasets [x]) لـ x في ['قطار' ، 'صالح']}
class_names = image_datasets ['train']

كما ترون أعلاه ، حددت أيضًا حجم الدُفعات ومحمل البيانات وأسماء الفئات في الكود أعلاه.

لإلقاء نظرة سريعة للغاية على البيانات والتحقق من جهازي ، قمت بتشغيل:

طباعة (dataset_sizes)
طباعة (الجهاز)
{'القطار': 6552 ، 'صالح': 818}
CUDA: 0

بعد ذلك ، نحتاج إلى إجراء بعض التعيينات من رقم التسمية واسم الزهرة الفعلي. قدمت Udacity ملف JSON لهذا التعيين ليتم القيام به ببساطة.

مع open ('cat_to_name.json'، 'r') كـ f:
    cat_to_name = json.load (f)

لاختبار أداة تحميل البيانات ، قم بتشغيل:

الصور ، التسميات = next (iter (dataloaders ['train']))
rand_idx = np.random.randint (لين (صور))
# طباعة (rand_idx)
print ("label: {}، class: {}، name: {}". format (labels [rand_idx] .item ()،
                                               class_names [تسميات [rand_idx] والبند ()]،
                                               cat_to_name [class_names [تسميات [rand_idx] والبند ()]]))

الآن يبدأ الحصول على أكثر إثارة! تم إنشاء عدد من النماذج في السنوات القليلة الماضية من قبل أشخاص مؤهلين أكثر بكثير من معظمنا لإعادة استخدامها في مشاكل رؤية الكمبيوتر. تعمل PyTorch على تسهيل تحميل النماذج المدربة مسبقًا والبناء عليها ، وهذا بالضبط ما سنفعله لهذا المشروع. اختيار النموذج متروك لك تمامًا!

بعض النماذج الأكثر شعبية المدربة مسبقًا ، مثل ResNet و AlexNet و VGG ، تأتي من ImageNet Challenge. تتيح هذه النماذج المدربة مسبقًا للآخرين الحصول بسرعة على أحدث النتائج في رؤية الكمبيوتر دون الحاجة إلى مثل هذه الكميات الكبيرة من طاقة الكمبيوتر والصبر والوقت. لقد حصلت بالفعل على نتائج رائعة مع DenseNet وقررت استخدام DenseNet161 ، مما أعطاني نتائج جيدة جدًا نسبيًا.

يمكنك إعداد هذا بسرعة عن طريق تشغيل

model = models.densenet161 (pretrained = True)

ولكن قد يكون أكثر إثارة للاهتمام أن تقدم لنفسك اختيارًا للطراز والمحسّن والجدولة. من أجل إعداد اختيار في الهندسة المعمارية ، تشغيل

model_name = 'densenet' #vgg
إذا كان model_name == 'densenet':
    model = models.densenet161 (pretrained = True)
    num_in_features = 2208
    طباعة (نموذج)
elif model_name == 'vgg':
    model = models.vgg19 (pretrained = True)
    num_in_features = 25088
    طباعة (model.classifier)
آخر:
    طباعة ("نموذج غير معروف ، يرجى اختيار" densenet "أو" vgg "")

والذي يسمح لك بإعداد نموذج بديل بسرعة.

بعد ذلك ، يمكنك البدء في إنشاء المصنف الخاص بك ، باستخدام المعلمات التي تناسبك. ذهبت إلى الأمام وبنيت

لمعرف في النموذج. المعلمات ():
    param.requires_grad = خطأ
def build_classifier (num_in_features ، hidden_layers ، num_out_features):
   
    مصنف = nn.Sequential ()
    إذا كانت مخفية == لا شيء:
        classifier.add_module ('fc0' ، nn.Linear (num_in_features ، 102))
    آخر:
        layer_sizes = zip (hidden_layers [: - 1]، hidden_layers [1:])
        classifier.add_module ('fc0' ، nn.Linear (num_in_features ، hidden_layers [0]))
        classifier.add_module ('relu0' ، nn.ReLU ())
        classifier.add_module ('drop0' ، nn.Dropout (.6))
        classifier.add_module ('relu1' ، nn.ReLU ())
        classifier.add_module ('drop1' ، nn.Dropout (.5))
        بالنسبة إلى i ، (h1 ، h2) في التعداد (layer_sizes):
            classifier.add_module ('fc' + str (i + 1) ، nn.Linear (h1، h2))
            classifier.add_module ('relu' + str (i + 1)، nn.ReLU ())
            classifier.add_module ('drop' + str (i + 1)، nn.Dropout (.5))
        classifier.add_module ('الإخراج' ، nn.Linear (hidden_layers [-1] ، num_out_features))
        
    العودة المصنف

مما يتيح طريقة سهلة لتغيير عدد الطبقات المخفية التي أستخدمها ، وكذلك ضبط معدل التسرب بسرعة. قد تقرر إضافة طبقات إضافية من قائمة ReLU و التسرب من أجل صقل النموذج الخاص بك بشكل أكثر دقة.

بعد ذلك ، اعمل على تدريب معلمات المصنف. قررت التأكد من أنني قمت فقط بتدريب معلمات المصنف هنا أثناء تجميد معلمات المعالم. يمكنك أن تكون مبدعًا كما تريد مع المُحسِّن والمعيِّن والجدولة. المعيار هو الطريقة المستخدمة لتقييم ملائمة النموذج ، والمحسن هو طريقة التحسين المستخدمة لتحديث الأوزان ، ويوفر المجدول طرقًا مختلفة لضبط معدل التعلم وحجم الخطوة المستخدمة أثناء التحسين.

جرب أكبر عدد ممكن من الخيارات والمجموعات لمعرفة ما يمنحك أفضل نتيجة. يمكنك الاطلاع على جميع الوثائق الرسمية هنا. أوصي بإلقاء نظرة عليه واتخاذ القرارات الخاصة بك حول ما تريد استخدامه. ليس لديك حرفيًا عددًا لا حصر له من الخيارات هنا ، لكن من المؤكد أنك تشعر بذلك بمجرد بدء اللعب!

مخفية = لا شيء
المصنف = build_classifier (num_in_features ، hidden_layers ، 102)
طباعة (المصنف)
# فقط تدريب المعلمات المصنف ، يتم تجميد المعلمات الميزة
إذا كان model_name == 'densenet':
    model.classifier = المصنف
    المعيار = nn.CrossEntropyLoss ()
    محسن = optim.Adadelta (model.parameters ())
    sched = optim.lr_scheduler.StepLR (محسن ، step_size = 4)
elif model_name == 'vgg':
    model.classifier = المصنف
    المعيار = nn.NLLLoss ()
    محسن = optim.Adam (model.classifier.parameters () ، lr = 0.0001)
    sched = lr_scheduler.StepLR (محسن ، step_size = 4 ، جاما = 0.1)
آخر:
    البشري

الآن حان الوقت لتدريب النموذج الخاص بك.

# مقتبس من https://pytorch.org/tutorials/beginner/transfer_learning_tutorial.html
def train_model (نموذج ، معيار ، مُحسِّن ، جدول ، num_epochs = 5):
    منذ = الوقت ()
best_model_wts = copy.deepcopy (model.state_dict ())
    best_acc = 0.0
لعصر في المدى (num_epochs):
        print ('Epoch {} / {}'. format (epoch + 1، num_epochs))
        طباعة ('-' * 10)
# كل حقبة لديها مرحلة التدريب والتحقق من الصحة
        للمرحلة في ['قطار' ، 'صالح']:
            إذا المرحلة == "القطار":
                model.train () # تعيين نموذج لوضع التدريب
            آخر:
                model.eval () # قم بتعيين النموذج لتقييم الوضع
running_loss = 0.0
            running_corrects = 0
# تكرار على البيانات.
            للمدخلات والعلامات في dataloaders [المرحلة]:
                المدخلات = المدخلات. (الجهاز)
                labels = labels.to (الجهاز)
# صفر التدرجات المعلمة
                optimizer.zero_grad ()
# إلى الأمام
                # تتبع التاريخ إذا كان فقط في القطار
                مع torch.set_grad_enabled (المرحلة == "القطار"):
                    مخرجات = نموذج (المدخلات)
                    _ ، preds = torch.max (المخرجات ، 1)
                    الخسارة = المعيار (المخرجات ، الملصقات)
# الوراء + الأمثل إلا إذا كان في مرحلة التدريب
                    إذا المرحلة == "القطار":
                        # sched.step ()
                        loss.backward ()
                        
                        optimizer.step ()
# الإحصاء
                running_loss + = loss.item () * المدخلات. الحجم (0)
                running_corrects + = torch.sum (preds == labels.data)
epoch_loss = running_loss / dataset_sizes [المرحلة]
            epoch_acc = running_corrects.double () / dataset_sizes [الطور]
print ('{} الخسارة: {: .4f} Acc: {: .4f}'. format (
                المرحلة ، epoch_loss ، epoch_acc))
# نسخة عميقة النموذج
            إذا كانت المرحلة == "صالحة" و epoch_acc> best_acc:
                best_acc = epoch_acc
                best_model_wts = copy.deepcopy (model.state_dict ())
طباعة()
time_elapsed = time.time () - منذ ذلك الحين
    print (اكتمل التدريب بـ {: .0f} m {: .0f} s'.format (
        time_elapsed // 60 ، time_elapsed٪ 60))
    print ('best val Acc: {: 4f}'. format (best_acc))
# تحميل أفضل الأوزان نموذج
    model.load_state_dict (best_model_wts)
    
    نموذج العودة
فترة = 30
model.to (الجهاز)
نموذج = train_model (نموذج ، معيار ، محسن ، جدول ، فترة)

أردت أن أكون قادرًا على مراقبة عهودي بسهولة وكذلك تتبع الوقت المنقضي أثناء تشغيل نموذجي. الكود أعلاه يشمل كليهما ، والنتائج جيدة! يمكنك أن ترى أن النموذج يتعلم بسرعة وأن دقة مجموعة التحقق من الصحة وصلت بسرعة إلى أكثر من 95 ٪ بحلول عصر 7!

عصر 1/30
----------
خسارة القطار: 2.4793 حسب: 0.4791
خسارة صالحة: 0.9688 acc: 0.8191

عصر 2/30
----------
خسارة القطار: 0.8288 Acc: 0.8378
خسارة صالحة: 0.4714 acc: 0.9010

عصر 3/30
----------
خسارة القطار: 0.5191 Acc: 0.8890
خسارة صالحة: 0.3197 acc: 0.9181

عصر 4/30
----------
خسارة القطار: 0.4064 Acc: 0.9095
خسارة صالحة: 0.2975 acc: 0.9169

عصر 5/30
----------
خسارة القطار: 0.3401 Acc: 0.9214
خسارة صالحة: 0.2486 acc: 0.9401

عصر 6/30
----------
خسارة القطار: 0.3111 Acc: 0.9303
خسارة صالحة: 0.2153 acc: 0.9487

عصر 7/30
----------
خسارة القطار: 0.2987 Acc: 0.9298
خسارة صالحة: 0.1969 acc: 0.9584
...
التدريب الكامل في 67m 43s
أفضل فال acc: 0.973105

يمكنك أن ترى أن تشغيل هذا الرمز على Google Colab مع GPU استغرق أكثر من ساعة.

الآن حان وقت التقييم

model.eval ()
دقة = 0
بالنسبة إلى المدخلات والعلامات في dataloaders ['صالحة']:
    المدخلات ، التسميات = المدخلات. (الجهاز) ، labels.to (الجهاز)
    مخرجات = نموذج (المدخلات)
    
    # فئة مع أعلى احتمال هو فصلنا المتوقع
    المساواة = (labels.data == outputs.max (1) [1])
# دقة = عدد التنبؤات الصحيحة مقسوما على جميع التوقعات
    دقة + = المساواة. النوع (torch.FloatTensor ()). يعني ()
    
طباعة ("دقة الاختبار: {: .3f}". التنسيق (دقة / لين (محملو الحفاز ['صالح'])))
دقة الاختبار: 0.973

من المهم حفظ نقطة التفتيش الخاصة بك

model.class_to_idx = image_datasets ['train']. class_to_idx
نقطة تفتيش = {'input_size': 2208 ،
              'output_size': 102 ،
              "عصر": عصر ،
              'batch_size': 64 ،
              'model': models.densenet161 (pretrained = True) ،
              "المصنف": المصنف ،
              "المجدول": الجدول الزمني ،
              "محسن": optimizer.state_dict () ،
              'state_dict': model.state_dict () ،
              'class_to_idx': model.class_to_idx
             }
   
torch.save (نقطة تفتيش ، 'checkpoint.pth')

ليس عليك حفظ جميع المعلمات ، لكنني أدرجها هنا كمثال. تقوم نقطة التفتيش هذه على وجه التحديد بحفظ النموذج بهندسة densenet11 المدربة مسبقًا ، ولكن إذا كنت تريد حفظ نقطة التفتيش الخاصة بك مع خيار الاختيار الثاني ، فيمكنك فعل ذلك تمامًا. ببساطة ضبط حجم الإدخال والطراز.

يمكنك الآن تحميل نقطة التفتيش الخاصة بك. إذا كنت ترسل مشروعك إلى مساحة عمل Udacity ، فيمكن أن تصبح الأمور صعبة بعض الشيء. إليك بعض المساعدة في استكشاف أخطاء تحميل نقطة التفتيش.

يمكنك التحقق من المفاتيح الخاصة بك عن طريق تشغيل

ckpt = torch.load ('checkpoint.pth')
ckpt.keys ()

ثم تحميل وإعادة بناء النموذج الخاص بك!

def load_checkpoint (filepath):
    نقطة تفتيش = torch.load (filepath)
    نموذج = نقطة تفتيش ['نموذج']
    model.classifier = نقطة تفتيش ['مصنف']
    model.load_state_dict (نقطة تفتيش [ 'state_dict'])
    model.class_to_idx = نقطة تفتيش ['class_to_idx']
    محسن = نقطة تفتيش ['محسن']
    عصور = نقطة تفتيش ["عصور"]
    
    لمعرف في النموذج. المعلمات ():
        param.requires_grad = خطأ
        
    نموذج الإرجاع ، نقطة تفتيش ['class_to_idx']
model، class_to_idx = load_checkpoint ('checkpoint.pth')

تريد أن تستمر؟ إنها لفكرة جيدة القيام ببعض المعالجة المسبقة للصور والاستدلال على التصنيف. تابع وتحديد مسار صورتك وافتح صورة:

image_path = 'flower_data / valid / 102 / image_08006.jpg'
img = Image.open (image_path)

قم بمعالجة صورتك وإلقاء نظرة على الصورة التي تمت معالجتها:

def process_image (صورة):
    '' 'تحجيم صورة PIL وتقطيعها وتطبيعها لنموذج PyTorch ،
        إرجاع صفيف Numpy
    '' '
    # معالجة صورة PIL لاستخدامها في نموذج PyTorch
    # tensor.numpy (). تبديل (1 ، 2 ، 0)
    preprocess = converts.Compose ([
        transforms.Resize (256)،
        transforms.CenterCrop (224)،
        transforms.ToTensor ()
        تحويلات. تطبيع (يعني = [0.485 ، 0.456 ، 0.406] ،
                             الأمراض المنقولة جنسياً = [0.229 ، 0.224 ، 0.225])
    ])
    الصورة = المعالجة المسبقة (الصورة)
    عودة الصورة
def imshow (image، ax = None، title = None):
    "" "Imshow لـ Tensor." ""
    إذا الفأس هو لا شيء:
        التين ، الفأس = plt.subplots ()
    
    # tensors PyTorch نفترض أن قناة اللون هي البعد الأول
    # ولكن matplotlib يفترض هو البعد الثالث
    image = image.numpy (). تبديل ((1 ، 2 ، 0))
    
    # التراجع عن المعالجة
    يعني = np.array ([0.485 ، 0.456 ، 0.406])
    الأمراض المنقولة جنسياً = np.array ([0.229 ، 0.224 ، 0.225])
    صورة = الأمراض المنقولة جنسيا * صورة + يعني
    
    # يجب قص الصورة بين 0 و 1 أو تبدو كضوضاء عند عرضها
    image = np.clip (الصورة ، 0 ، 1)
    
    ax.imshow (صورة)
    
    الفأس العودة
مع Image.open ('flower_data / valid / 102 / image_08006.jpg') كصورة:
    plt.imshow (صورة)
model.class_to_idx = image_datasets ['train']. class_to_idx

إنشاء وظيفة للتنبؤ:

def Forecast2 (image_path ، النموذج ، topk = 5):
    توقع الفصل (أو الفصول) لصورة باستخدام نموذج تعليمي عميق.
    '' '
    
    # تنفيذ التعليمات البرمجية للتنبؤ بالفصل من ملف صورة
    img = Image.open (image_path)
    img = process_image (img)
    
    # تحويل الصورة 2D إلى ناقلات 1D
    img = np.expand_dims (img ، 0)
    
    
    img = torch.from_numpy (img)
    
    model.eval ()
    المدخلات = المتغير (img). إلى (الجهاز)
    logits = model.forward (المدخلات)
    
    ps = F.softmax (logits، dim = 1)
    topk = ps.cpu (). topk (topk)
    
    return (e.data.numpy (). squeeze (). tolist () for e in topk)

بمجرد أن تكون الصور بالتنسيق الصحيح ، يمكنك كتابة دالة لعمل تنبؤات باستخدام النموذج الخاص بك. هناك ممارسة شائعة تتمثل في توقع أفضل 5 فئات أو أكثر (تسمى عادةً أعلى KK) بالفئات الأكثر احتمالًا. ستحتاج إلى حساب احتمالات الفصل ثم العثور على أكبر قيم KK.

للحصول على أكبر قيم KK في الموتر استخدم k.topk (). تُرجع هذه الطريقة كلاً من أعلى الاحتمالات k ومؤشرات تلك الاحتمالات المقابلة للفئات. تحتاج إلى التحويل من هذه المؤشرات إلى تسميات الصفوف الفعلية باستخدام class_to_idx ، والتي أضفتها إلى النموذج أو من مجلد الصور الذي استخدمته لتحميل البيانات. تأكد من عكس القاموس حتى تحصل على تعيين من الفهرس إلى الفصل أيضًا.

يجب أن تأخذ هذه الطريقة مسارًا إلى صورة ونقطة تفتيش نموذجية ، ثم تُرجع الاحتمالات والفئات.

img_path = 'flower_data / valid / 18 / image_04252.jpg'
probs، classes = Forecast2 (img_path، model.to (device))
طباعة (probs)
طباعة (فئات)
flower_names = [cat_to_name [class_names [e]] لـ e في الفصول]
طباعة (flower_names)

لقد كنت سعيدًا جدًا بأداء نموذجي!

[0.9999195337295532 ، 1.4087702766119037e-05 ، 1.3897360986447893e-05 ، 1.1400215043977369e-05 ، 6.098791800468462e-06]
[12 ، 86 ، 7 ، 88 ، 40]
["زنبق بيرو" ، "وردة الصحراء" ، "ملك البروتيا" ، "ماغنوليا" ، "زنبق السيف"]

في الأساس ، من المحتمل أن تكون الصورة التي حددتها هي زنبق بيرو 100٪ تقريبًا. تريد أن نلقي نظرة؟ حاول استخدام matplotlib لرسم احتمالات الفئات الخمسة العليا في رسم بياني شريطي مع صورة الإدخال:

def view_classify (img_path، prob، classes، mapping):
    '' 'وظيفة لعرض صورة وتوقعت الطبقات.
    '' '
    image = Image.open (img_path)
fig ، (ax1 ، ax2) = plt.subplots (figsize = (6،10) ، ncols = 1 ، nrows = 2)
    flower_name = تعيين [img_path.split ('/') [- 2]]
    ax1.set_title (flower_name)
    ax1.imshow (صورة)
    ax1.axis ( 'خارج')
    
    y_pos = np.arange (len (prob))
    ax2.barh (y_pos، prob، align = 'center')
    ax2.set_yticks (y_pos)
    ax2.set_yticklabels (flower_names)
    ax2.invert_yaxis () # تسميات تقرأ من أعلى إلى أسفل
    ax2.set_title ('الاحتمالية الصفية')
view_classify (img_path ، probs ، classes ، cat_to_name)

يجب أن نرى شيئا من هذا القبيل:

يجب أن أقول ، أنا سعيد جدًا بهذا! أوصي باختبار بعض الصور الأخرى لمعرفة مدى قرب تنبؤاتك على مجموعة متنوعة من الصور.

حان الوقت الآن لعمل نموذج خاص بك واسمحوا لي أن أعرف كيف تسير الاستجابات أدناه!

الصورة من قبل Pon González على Unsplash

هل انتهيت من نموذج التعلم العميق أو التعلم الآلي الخاص بك ، لكنك لا تعرف ماذا تفعل به بعد ذلك؟ لماذا لا تنشرها على الإنترنت؟

الحصول على النموذج الخاص بك هناك حتى يتمكن الجميع من رؤيته!

تحقق من هذه المقالة لمعرفة كيفية نشر نموذج التعلم الآلي الخاص بك مع Flask!