კომპიუტერული ხედვა Jupyter ნოუთბუქი · PyTorch

წინასწარ მომზადებული მოდელები და გადაცემის სწავლა

ეს არის პრაქტიკული ნოუთბუქი. წაიკითხე კოდი და შედეგები აქ, ან გაუშვი ინტერაქტიულად Google Colab-ში ან Jupyter-ში.

CNN-ების ტრენინგს შეიძლება ბევრი დრო დასჭირდეს და ამ ამოცანისთვის ბევრი მონაცემია საჭირო. თუმცა, დროის დიდი ნაწილი იხარჯება საუკეთესო დაბალი დონის ფილტრების შესასწავლად, რომლებსაც ქსელი იყენებს სურათებიდან შაბლონების ამოსაღებად. ჩნდება ბუნებრივი კითხვა - შეგვიძლია გამოვიყენოთ ერთ მონაცემთა ბაზაზე მომზადებული ნერვული ქსელი და მოვარგოთ სხვადასხვა სურათების კლასიფიკაციას სრული სასწავლო პროცესის გარეშე?

ამ მიდგომას ეწოდება ტრანსფერული სწავლა, რადგან ჩვენ გადავცემთ გარკვეულ ცოდნას ერთი ნერვული ქსელის მოდელიდან მეორეზე. გადაცემის სწავლისას, ჩვენ ჩვეულებრივ ვიწყებთ წინასწარ გაწვრთნილი მოდელით, რომელიც გავლილი იყო გარკვეული დიდი სურათების მონაცემთა ბაზაზე, როგორიცაა ImageNet. ამ მოდელებს უკვე შეუძლიათ კარგი სამუშაოს შესრულება ზოგადი სურათებისგან განსხვავებული ფუნქციების ამოღებით და ხშირ შემთხვევაში მხოლოდ კლასიფიკატორის აგება ამ ამოღებულ მახასიათებლებზე შეიძლება კარგი შედეგის მომტანი იყოს.

იტვირთება…

კატები ძაღლების წინააღმდეგ მონაცემთა ნაკრები

ამ განყოფილებაში ჩვენ მოვაგვარებთ კატებისა და ძაღლების სურათების კლასიფიკაციის რეალურ პრობლემას. ამ მიზეზით, ჩვენ გამოვიყენებთ Kaggle Cats vs. Dogs მონაცემთა ნაკრები, რომლის ჩამოტვირთვაც შესაძლებელია Microsoft-ისგან.

გადმოვწეროთ ეს მონაცემთა ნაკრები და ამოვიტანოთ data დირექტორიაში (ამ პროცესს შეიძლება გარკვეული დრო დასჭირდეს!):

იტვირთება…
იტვირთება…

სამწუხაროდ, მონაცემთა ნაკრებში არის რამდენიმე კორუმპირებული გამოსახულების ფაილი. ჩვენ გვჭირდება სწრაფი გაწმენდა დაზიანებული ფაილების შესამოწმებლად. იმისათვის, რომ ეს ტუტორიალი არ დავკარგოთ, ჩვენ გადავიტანეთ კოდი მონაცემთა ნაკრების დასადასტურებლად მოდულში.

იტვირთება…
გამოტანა
Corrupt image: data/PetImages/Cat/666.jpg
/anaconda/envs/py38_pytorch/lib/python3.8/site-packages/PIL/TiffImagePlugin.py:793: UserWarning: Truncated File Read
  warnings.warn(str(msg))
Corrupt image: data/PetImages/Dog/11702.jpg

Next, let's load the images into PyTorch dataset, converting them to tensors and doing some normalization. We will apply std_normalize transform to bring images to the range expected by pre-trained VGG network:

იტვირთება…
გამოტანა
ნოუთბუქის გამოტანა

წინასწარ მომზადებული მოდელები

torchvision მოდულის შიგნით ბევრი სხვადასხვა წინასწარ მომზადებული მოდელია ხელმისაწვდომი და კიდევ უფრო მეტი მოდელის ნახვა შეგიძლიათ ინტერნეტში. ვნახოთ, რამდენად მარტივია VGG-16 მოდელის ჩატვირთვა და გამოყენება:

იტვირთება…
გამოტანა
Downloading: "https://download.pytorch.org/models/vgg16-397923af.pth" to /home/cathy/.cache/torch/hub/checkpoints/vgg16-397923af.pth
  0%|          | 0.00/528M [00:00<?, ?B/s]
tensor(282)

The result that we have received is a number of an ImageNet class, which can be looked up აქ. ჩვენ შეგვიძლია გამოვიყენოთ შემდეგი კოდი ამ კლასის ცხრილის ავტომატურად ჩატვირთვისთვის და შედეგის დასაბრუნებლად:

იტვირთება…
გამოტანა
['n02123159', 'tiger_cat']

მოდით ასევე ვნახოთ VGG-16 ქსელის არქიტექტურა:

იტვირთება…
გამოტანა
==========================================================================================
Layer (type:depth-idx)                   Output Shape              Param #
==========================================================================================
VGG                                      --                        --
├─Sequential: 1-1                        [1, 512, 7, 7]            --
│    └─Conv2d: 2-1                       [1, 64, 224, 224]         1,792
│    └─ReLU: 2-2                         [1, 64, 224, 224]         --
│    └─Conv2d: 2-3                       [1, 64, 224, 224]         36,928
│    └─ReLU: 2-4                         [1, 64, 224, 224]         --
│    └─MaxPool2d: 2-5                    [1, 64, 112, 112]         --
│    └─Conv2d: 2-6                       [1, 128, 112, 112]        73,856
│    └─ReLU: 2-7                         [1, 128, 112, 112]        --
│    └─Conv2d: 2-8                       [1, 128, 112, 112]        147,584
│    └─ReLU: 2-9                         [1, 128, 112, 112]        --
│    └─MaxPool2d: 2-10                   [1, 128, 56, 56]          --
│    └─Conv2d: 2-11                      [1, 256, 56, 56]          295,168
│    └─ReLU: 2-12                        [1, 256, 56, 56]          --
│    └─Conv2d: 2-13                      [1, 256, 56, 56]          590,080
│    └─ReLU: 2-14                        [1, 256, 56, 56]          --
│    └─Conv2d: 2-15                      [1, 256, 56, 56]          590,080
│    └─ReLU: 2-16                        [1, 256, 56, 56]          --
│    └─MaxPool2d: 2-17                   [1, 256, 28, 28]          --
│    └─Conv2d: 2-18                      [1, 512, 28, 28]          1,180,160
│    └─ReLU: 2-19                        [1, 512, 28, 28]          --
│    └─Conv2d: 2-20                      [1, 512, 28, 28]          2,359,808
│    └─ReLU: 2-21                        [1, 512, 28, 28]          --
│    └─Conv2d: 2-22                      [1, 512, 28, 28]          2,359,808
│    └─ReLU: 2-23                        [1, 512, 28, 28]          --
│    └─MaxPool2d: 2-24                   [1, 512, 14, 14]          --
│    └─Conv2d: 2-25                      [1, 512, 14, 14]          2,359,808
│    └─ReLU: 2-26                        [1, 512, 14, 14]          --
│    └─Conv2d: 2-27                      [1, 512, 14, 14]          2,359,808
│    └─ReLU: 2-28                        [1, 512, 14, 14]          --
│    └─Conv2d: 2-29                      [1, 512, 14, 14]          2,359,808
│    └─ReLU: 2-30                        [1, 512, 14, 14]          --
│    └─MaxPool2d: 2-31                   [1, 512, 7, 7]            --
├─AdaptiveAvgPool2d: 1-2                 [1, 512, 7, 7]            --
├─Sequential: 1-3                        [1, 1000]                 --
│    └─Linear: 2-32                      [1, 4096]                 102,764,544
│    └─ReLU: 2-33                        [1, 4096]                 --
│    └─Dropout: 2-34                     [1, 4096]                 --
│    └─Linear: 2-35                      [1, 4096]                 16,781,312
│    └─ReLU: 2-36                        [1, 4096]                 --
│    └─Dropout: 2-37                     [1, 4096]                 --
│    └─Linear: 2-38                      [1, 1000]                 4,097,000
==========================================================================================
Total params: 138,357,544
Trainable params: 138,357,544
Non-trainable params: 0
Total mult-adds (G): 15.48
==========================================================================================
Input size (MB): 0.60
Forward/backward pass size (MB): 108.45
Params size (MB): 553.43
Estimated Total Size (MB): 662.49
==========================================================================================

გარდა ფენისა, რომელიც ჩვენ უკვე ვიცით, ასევე არსებობს ფენის სხვა ტიპი, სახელად Dropout. ეს ფენები მოქმედებს როგორც რეგულარიზაციის ტექნიკა. რეგულარიზაცია სწავლის ალგორითმში მცირე ცვლილებებს ახდენს, რათა მოდელი უკეთესად განზოგადდეს. ვარჯიშის დროს, მიტოვებული ფენები ანადგურებენ წინა ფენის ნეირონების გარკვეულ ნაწილს (დაახლოებით 30%) და ვარჯიში მათ გარეშე ხდება. ეს ხელს უწყობს ოპტიმიზაციის პროცესის ლოკალური მინიმუმიდან გამოყვანას და გადამწყვეტი ძალის განაწილებას სხვადასხვა ნერვულ ბილიკებს შორის, რაც აუმჯობესებს ქსელის საერთო სტაბილურობას.

GPU გამოთვლები

ღრმა ნეირონული ქსელები, როგორიცაა VGG-16 და სხვა უფრო თანამედროვე არქიტექტურა, საკმაოდ დიდ გამოთვლით ძალას მოითხოვს. აზრი აქვს GPU აჩქარების გამოყენებას, თუ ის ხელმისაწვდომია. ამის გასაკეთებლად, ჩვენ გვჭირდება ცალსახად გადავიტანოთ გამოთვლაში ჩართული ყველა ტენსორი GPU-ზე.

როგორც წესი, ეს კეთდება არის კოდში GPU-ს ხელმისაწვდომობის შემოწმება და device ცვლადის განსაზღვრა, რომელიც მიუთითებს გამოთვლით მოწყობილობაზე - ან GPU ან CPU.

იტვირთება…
გამოტანა
Doing computations on device = cuda
tensor(282, device='cuda:0')

VGG მახასიათებლების ამოღება

თუ გვინდა გამოვიყენოთ VGG-16 ჩვენი სურათებიდან ფუნქციების ამოსაღებად, გვჭირდება მოდელი საბოლოო კლასიფიკაციის ფენების გარეშე. სინამდვილეში, ამ "ფუნქციების ამომყვანის" მიღება შესაძლებელია vgg.features მეთოდის გამოყენებით:

იტვირთება…
გამოტანა
torch.Size([1, 512, 7, 7])
ნოუთბუქის გამოტანა

მახასიათებლის ტენზორის განზომილება არის 512x7x7, მაგრამ მისი ვიზუალიზაციისთვის ჩვენ უნდა გადაგვეკეთებინა 2D ფორმაში.

ახლა ვცადოთ ვნახოთ, შეიძლება თუ არა ამ ფუნქციების გამოყენება სურათების კლასიფიკაციისთვის. მოდით ხელით ავიღოთ სურათების გარკვეული ნაწილი (ჩვენს შემთხვევაში 800) და წინასწარ გამოვთვალოთ მათი ფუნქციების ვექტორები. ჩვენ შევინახავთ შედეგს ერთ დიდ ტენზორში, სახელად feature_tensor, და ასევე ეტიკეტებს label_tensor:

იტვირთება…
გამოტანა
....................................................................................................

ახლა ჩვენ შეგვიძლია განვსაზღვროთ vgg_dataset, რომელიც იღებს მონაცემებს ამ ტენსორიდან, დაყოფს მას სავარჯიშო და სატესტო ნაკრებებად random_split ფუნქციის გამოყენებით და მოვამზადებთ პატარა ერთფენიანი მკვრივი კლასიფიკატორის ქსელს ამოღებულ ფუნქციებზე:

იტვირთება…
გამოტანა
/anaconda/envs/py38_pytorch/lib/python3.8/site-packages/torch/nn/modules/container.py:119: UserWarning: Implicit dimension choice for log_softmax has been deprecated. Change the call to include dim=X as an argument.
  input = module(input)
Epoch  0, Train acc=0.879, Val acc=0.990, Train loss=0.110, Val loss=0.007
Epoch  1, Train acc=0.981, Val acc=0.980, Train loss=0.015, Val loss=0.021
Epoch  2, Train acc=0.999, Val acc=0.990, Train loss=0.001, Val loss=0.002
Epoch  3, Train acc=1.000, Val acc=0.980, Train loss=0.000, Val loss=0.002
Epoch  4, Train acc=1.000, Val acc=0.980, Train loss=0.000, Val loss=0.002
Epoch  5, Train acc=1.000, Val acc=0.980, Train loss=0.000, Val loss=0.002
Epoch  6, Train acc=1.000, Val acc=0.980, Train loss=0.000, Val loss=0.002
Epoch  7, Train acc=1.000, Val acc=0.980, Train loss=0.000, Val loss=0.002
Epoch  8, Train acc=1.000, Val acc=0.980, Train loss=0.000, Val loss=0.002
Epoch  9, Train acc=1.000, Val acc=0.980, Train loss=0.000, Val loss=0.002

შედეგი შესანიშნავია, თითქმის 98%-იანი ალბათობით შეგვიძლია განვასხვავოთ კატა და ძაღლი! თუმცა, ჩვენ გამოვცადეთ ეს მიდგომა მხოლოდ ყველა სურათის მცირე ქვეჯგუფზე, რადგან, როგორც ჩანს, ფუნქციების ხელით ამოღებას დიდი დრო სჭირდება.

სწავლის გადაცემა ერთი VGG ქსელის გამოყენებით

ჩვენ ასევე შეგვიძლია თავიდან ავიცილოთ ფუნქციების ხელით წინასწარი გამოთვლა, ვარჯიშის დროს მთლიანობაში ორიგინალური VGG-16 ქსელის გამოყენებით. მოდით შევხედოთ VGG-16 ობიექტის სტრუქტურას:

იტვირთება…
გამოტანა
VGG(
  (features): Sequential(
    (0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (1): ReLU(inplace=True)
    (2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (3): ReLU(inplace=True)
    (4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (5): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (6): ReLU(inplace=True)
    (7): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (8): ReLU(inplace=True)
    (9): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (10): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (11): ReLU(inplace=True)
    (12): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (13): ReLU(inplace=True)
    (14): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (15): ReLU(inplace=True)
    (16): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (17): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (18): ReLU(inplace=True)
    (19): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (20): ReLU(inplace=True)
    (21): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (22): ReLU(inplace=True)
    (23): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (24): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (25): ReLU(inplace=True)
    (26): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (27): ReLU(inplace=True)
    (28): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (29): ReLU(inplace=True)
    (30): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  )
  (avgpool): AdaptiveAvgPool2d(output_size=(7, 7))
  (classifier): Sequential(
    (0): Linear(in_features=25088, out_features=4096, bias=True)
    (1): ReLU(inplace=True)
    (2): Dropout(p=0.5, inplace=False)
    (3): Linear(in_features=4096, out_features=4096, bias=True)
    (4): ReLU(inplace=True)
    (5): Dropout(p=0.5, inplace=False)
    (6): Linear(in_features=4096, out_features=1000, bias=True)
  )
)

თქვენ ხედავთ, რომ ქსელი შეიცავს:

  • ფუნქციის ამომყვანი (features), რომელიც შედგება რამდენიმე კონვოლუციური და გაერთიანებული ფენებისგან
  • საშუალო გაერთიანების ფენა (avgpool)
  • საბოლოო classifier, რომელიც შედგება რამდენიმე მკვრივი ფენისგან, რომელიც აქცევს 25088 შეყვანის ფუნქციას 1000 კლასად (რაც არის კლასების რაოდენობა ImageNet-ში)

იმისთვის, რომ მოვამზადოთ ბოლოდან ბოლომდე მოდელი, რომელიც კლასიფიცირებს ჩვენს მონაცემთა ბაზას, ჩვენ გვჭირდება:

  • შეცვალეთ საბოლოო კლასიფიკატორი იმით, რომელიც გამოიმუშავებს კლასების საჭირო რაოდენობას. ჩვენს შემთხვევაში, ჩვენ შეგვიძლია გამოვიყენოთ ერთი Linear ფენა 25088 შეყვანით და 2 გამომავალი ნეირონით.
  • გაყინეთ კონვოლუციური მახასიათებლის ამომყვანის წონები, რათა არ ივარჯიშონ. რეკომენდირებულია ამ გაყინვის თავიდან გაკეთება, რადგან სხვაგვარად გაუწვრთნელი კლასიფიკატორის ფენას შეუძლია გაანადგუროს კონვოლუციური ექსტრაქტორის ორიგინალური წინასწარ მომზადებული წონა. წონების გაყინვა შეიძლება განხორციელდეს ყველა პარამეტრის requires_grad თვისების False-ზე დაყენებით
იტვირთება…
გამოტანა
==========================================================================================
Layer (type:depth-idx)                   Output Shape              Param #
==========================================================================================
VGG                                      --                        --
├─Sequential: 1-1                        [1, 512, 7, 7]            --
│    └─Conv2d: 2-1                       [1, 64, 244, 244]         (1,792)
│    └─ReLU: 2-2                         [1, 64, 244, 244]         --
│    └─Conv2d: 2-3                       [1, 64, 244, 244]         (36,928)
│    └─ReLU: 2-4                         [1, 64, 244, 244]         --
│    └─MaxPool2d: 2-5                    [1, 64, 122, 122]         --
│    └─Conv2d: 2-6                       [1, 128, 122, 122]        (73,856)
│    └─ReLU: 2-7                         [1, 128, 122, 122]        --
│    └─Conv2d: 2-8                       [1, 128, 122, 122]        (147,584)
│    └─ReLU: 2-9                         [1, 128, 122, 122]        --
│    └─MaxPool2d: 2-10                   [1, 128, 61, 61]          --
│    └─Conv2d: 2-11                      [1, 256, 61, 61]          (295,168)
│    └─ReLU: 2-12                        [1, 256, 61, 61]          --
│    └─Conv2d: 2-13                      [1, 256, 61, 61]          (590,080)
│    └─ReLU: 2-14                        [1, 256, 61, 61]          --
│    └─Conv2d: 2-15                      [1, 256, 61, 61]          (590,080)
│    └─ReLU: 2-16                        [1, 256, 61, 61]          --
│    └─MaxPool2d: 2-17                   [1, 256, 30, 30]          --
│    └─Conv2d: 2-18                      [1, 512, 30, 30]          (1,180,160)
│    └─ReLU: 2-19                        [1, 512, 30, 30]          --
│    └─Conv2d: 2-20                      [1, 512, 30, 30]          (2,359,808)
│    └─ReLU: 2-21                        [1, 512, 30, 30]          --
│    └─Conv2d: 2-22                      [1, 512, 30, 30]          (2,359,808)
│    └─ReLU: 2-23                        [1, 512, 30, 30]          --
│    └─MaxPool2d: 2-24                   [1, 512, 15, 15]          --
│    └─Conv2d: 2-25                      [1, 512, 15, 15]          (2,359,808)
│    └─ReLU: 2-26                        [1, 512, 15, 15]          --
│    └─Conv2d: 2-27                      [1, 512, 15, 15]          (2,359,808)
│    └─ReLU: 2-28                        [1, 512, 15, 15]          --
│    └─Conv2d: 2-29                      [1, 512, 15, 15]          (2,359,808)
│    └─ReLU: 2-30                        [1, 512, 15, 15]          --
│    └─MaxPool2d: 2-31                   [1, 512, 7, 7]            --
├─AdaptiveAvgPool2d: 1-2                 [1, 512, 7, 7]            --
├─Linear: 1-3                            [1, 2]                    50,178
==========================================================================================
Total params: 14,764,866
Trainable params: 50,178
Non-trainable params: 14,714,688
Total mult-adds (G): 17.99
==========================================================================================
Input size (MB): 0.71
Forward/backward pass size (MB): 128.13
Params size (MB): 59.06
Estimated Total Size (MB): 187.91
==========================================================================================

როგორც შეჯამებიდან ხედავთ, ეს მოდელი შეიცავს დაახლოებით 15 მილიონ პარამეტრს, მაგრამ მათგან მხოლოდ 50 ათასია მომზადებადი - ეს არის კლასიფიკაციის ფენის წონა. ეს კარგია, რადგან ჩვენ შეგვიძლია უფრო მცირე რაოდენობის პარამეტრების დაზუსტება მაგალითების მცირე რაოდენობით.

ახლა მოდით ვავარჯიშოთ მოდელი ჩვენი ორიგინალური მონაცემთა ნაკრების გამოყენებით. ამ პროცესს დიდი დრო დასჭირდება, ამიტომ გამოვიყენებთ train_long ფუნქციას, რომელიც დაბეჭდავს შუალედურ შედეგებს ეპოქის დასასრულის მოლოდინში. რეკომენდირებულია ამ ტრენინგის გაშვება GPU-ზე ჩართული გამოთვლებით!

იტვირთება…
გამოტანა
Epoch 0, minibatch 0: train acc = 0.5, train loss = 0.0431101992726326
Epoch 0, minibatch 90: train acc = 0.9539835164835165, train loss = 0.0960497070144821
/anaconda/envs/py38_pytorch/lib/python3.8/site-packages/PIL/TiffImagePlugin.py:793: UserWarning: Truncated File Read
  warnings.warn(str(msg))
Epoch 0, minibatch 180: train acc = 0.9582182320441989, train loss = 0.12481052967724879
Epoch 0, minibatch 270: train acc = 0.9587177121771218, train loss = 0.14185787918822793
Epoch 0, minibatch 360: train acc = 0.9634695290858726, train loss = 0.14566257719848294
Epoch 0, minibatch 450: train acc = 0.966879157427938, train loss = 0.13402751914149114
Epoch 0, minibatch 540: train acc = 0.9686922365988909, train loss = 0.13931148902766144
Epoch 0, minibatch 630: train acc = 0.9694928684627575, train loss = 0.1386710044510202
Epoch 0, minibatch 720: train acc = 0.970613730929265, train loss = 0.13363790313678375
Epoch 0, minibatch 810: train acc = 0.9709463625154131, train loss = 0.1342217084364885
Epoch 0, minibatch 900: train acc = 0.9721143174250833, train loss = 0.13233261023721474
Epoch 0, minibatch 990: train acc = 0.9726286579212916, train loss = 0.1334670727957871
Epoch 0, minibatch 1080: train acc = 0.9733464384828863, train loss = 0.13777193110039893
Epoch 0, minibatch 1170: train acc = 0.9734735269000854, train loss = 0.14239378162778207
Epoch 0 done, validation acc = 0.9671868747499, validation loss = 0.25287964306816474

როგორც ჩანს, ჩვენ მივიღეთ საკმაოდ ზუსტი კლასიფიკატორი კატები ძაღლების წინააღმდეგ! მოდით შევინახოთ იგი მომავალი გამოყენებისთვის!

იტვირთება…

შემდეგ ჩვენ შეგვიძლია ჩატვირთოთ მოდელი ფაილიდან ნებისმიერ დროს. შეიძლება გამოგადგეთ იმ შემთხვევაში, თუ მომდევნო ექსპერიმენტმა გაანადგურა მოდელი - თქვენ არ მოგიწევთ თავიდან დაწყება ნულიდან.

იტვირთება…

დახვეწილი გადაცემის სწავლა

წინა განყოფილებაში, ჩვენ ვავარჯიშეთ საბოლოო კლასიფიკატორის ფენა სურათების კლასიფიკაციისთვის ჩვენს მონაცემთა ბაზაში. თუმცა, ჩვენ არ გადავარჯიშეთ ფუნქციების ამომყვანი და ჩვენი მოდელი ეყრდნობოდა იმ ფუნქციებს, რომლებიც მოდელმა ისწავლა ImageNet-ის მონაცემებზე. თუ თქვენი ობიექტები ვიზუალურად განსხვავდებიან ჩვეულებრივი ImageNet სურათებისგან, ფუნქციების ეს კომბინაცია შესაძლოა საუკეთესოდ არ იმუშაოს. ამრიგად, აზრი აქვს კონვოლუციური ფენების ვარჯიშის დაწყებასაც.

ამისათვის ჩვენ შეგვიძლია გავაყინოთ კონვოლუციური ფილტრის პარამეტრები, რომლებიც ადრე გავყინეთ.

შენიშვნა: მნიშვნელოვანია, რომ ჯერ გაყინოთ პარამეტრები და განახორციელოთ ვარჯიშის რამდენიმე ეპოქა, რათა დასტაბილურდეს წონა კლასიფიკაციის ფენაში. თუ დაუყონებლივ დაიწყებთ ქსელის ბოლომდე ვარჯიშს გაყინული პარამეტრებით, დიდი შეცდომები სავარაუდოდ გაანადგურებს წინასწარ მომზადებულ წონებს კონვოლუციურ ფენებში.

იტვირთება…

გაყინვის შემდეგ კიდევ რამდენიმე ეპოქის ვარჯიში შეგვიძლია. თქვენ ასევე შეგიძლიათ აირჩიოთ უფრო დაბალი სწავლის სიჩქარე, რათა მინიმუმამდე დაიყვანოთ გავლენა წინასწარ მომზადებულ წონებზე. თუმცა, სწავლის დაბალი სიჩქარითაც კი, თქვენ შეგიძლიათ მოელოდეთ, რომ სიზუსტე დაეცემა ვარჯიშის დასაწყისში, სანამ საბოლოოდ არ მიაღწევთ ოდნავ უფრო მაღალ დონეს, ვიდრე ფიქსირებული წონის შემთხვევაში.

შენიშვნა: ეს ტრენინგი გაცილებით ნელა მიმდინარეობს, რადგან ჩვენ გვჭირდება გრადიენტების გავრცელება ქსელის მრავალ ფენაში! თქვენ შეგიძლიათ უყუროთ პირველ რამდენიმე მინი ჯგუფს, რომ ნახოთ ტენდენცია და შემდეგ შეწყვიტოთ გამოთვლა.

იტვირთება…
გამოტანა
Epoch 0, minibatch 0: train acc = 1.0, train loss = 0.0
Epoch 0, minibatch 90: train acc = 0.8990384615384616, train loss = 0.2978392171335744
Epoch 0, minibatch 180: train acc = 0.9060773480662984, train loss = 0.1658294214069514
Epoch 0, minibatch 270: train acc = 0.9102859778597786, train loss = 0.11819224340009514
Epoch 0, minibatch 360: train acc = 0.9191481994459834, train loss = 0.09244130522920814
Epoch 0, minibatch 450: train acc = 0.9261363636363636, train loss = 0.07583886292451236
Epoch 0, minibatch 540: train acc = 0.928373382624769, train loss = 0.06537413817456822
Epoch 0, minibatch 630: train acc = 0.9318541996830428, train loss = 0.057419379426257924
Epoch 0, minibatch 720: train acc = 0.9361130374479889, train loss = 0.05114534460059813
Epoch 0, minibatch 810: train acc = 0.938347718865598, train loss = 0.04657612246737968
Epoch 0, minibatch 900: train acc = 0.9407602663706992, train loss = 0.04258851655712403
Epoch 0, minibatch 990: train acc = 0.9431130171543896, train loss = 0.03927870595491257
Epoch 0, minibatch 1080: train acc = 0.945536540240518, train loss = 0.03652716609309053
Epoch 0, minibatch 1170: train acc = 0.9463065755764304, train loss = 0.03445258006186286
Epoch 0 done, validation acc = 0.974389755902361, validation loss = 0.005457923144233279

სხვა კომპიუტერული ხედვის მოდელები

VGG-16 არის ერთ-ერთი უმარტივესი კომპიუტერული ხედვის არქიტექტურა. torchvision პაკეტი უზრუნველყოფს კიდევ ბევრ წინასწარ მომზადებულ ქსელს. მათ შორის ყველაზე ხშირად გამოყენებულია ResNet არქიტექტურები, შემუშავებული Microsoft-ის მიერ და Inception Google-ის მიერ. მაგალითად, მოდით გამოვიკვლიოთ უმარტივესი ResNet-18 მოდელის არქიტექტურა (ResNet არის სხვადასხვა სიღრმის მოდელების ოჯახი, შეგიძლიათ სცადოთ ResNet-151-ის ექსპერიმენტები, თუ გსურთ ნახოთ, როგორ გამოიყურება მართლაც ღრმა მოდელი):

იტვირთება…
გამოტანა
ResNet(
  (conv1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)
  (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (relu): ReLU(inplace=True)
  (maxpool): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)
  (layer1): Sequential(
    (0): BasicBlock(
      (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
    (1): BasicBlock(
      (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
  )
  (layer2): Sequential(
    (0): BasicBlock(
      (conv1): Conv2d(64, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (downsample): Sequential(
        (0): Conv2d(64, 128, kernel_size=(1, 1), stride=(2, 2), bias=False)
        (1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
    )
    (1): BasicBlock(
      (conv1): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
  )
  (layer3): Sequential(
    (0): BasicBlock(
      (conv1): Conv2d(128, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (downsample): Sequential(
        (0): Conv2d(128, 256, kernel_size=(1, 1), stride=(2, 2), bias=False)
        (1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
    )
    (1): BasicBlock(
      (conv1): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
  )
  (layer4): Sequential(
    (0): BasicBlock(
      (conv1): Conv2d(256, 512, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (downsample): Sequential(
        (0): Conv2d(256, 512, kernel_size=(1, 1), stride=(2, 2), bias=False)
        (1): 
… (გამოტანა შემოკლებულია)

როგორც ხედავთ, მოდელი შეიცავს იგივე სამშენებლო ბლოკებს: მახასიათებლების ამომყვანი და საბოლოო კლასიფიკატორი (fc). ეს საშუალებას გვაძლევს გამოვიყენოთ ეს მოდელი ზუსტად ისევე, როგორც ჩვენ ვიყენებდით VGG-16-ს გადაცემის სწავლისთვის. შეგიძლიათ სცადოთ ექსპერიმენტი ზემოთ მოცემულ კოდზე, გამოიყენოთ სხვადასხვა ResNet მოდელები, როგორც საბაზისო მოდელი და ნახოთ, როგორ იცვლება სიზუსტე.

სერიის ნორმალიზაცია

ეს ქსელი შეიცავს კიდევ ერთი ტიპის ფენას: Batch Normalization. სურათების ნორმალიზაციის იდეა არის მნიშვნელობების მიყვანა, რომლებიც მიედინება ნერვულ ქსელში სწორ ინტერვალამდე. როგორც წესი, ნერვული ქსელები საუკეთესოდ მუშაობს, როდესაც ყველა მნიშვნელობა არის [-1,1] ან [0,1] დიაპაზონში, და ეს არის მიზეზი იმისა, რომ ჩვენ შესაბამისად ვადიდებთ/ნორმალიზებთ შეყვანის მონაცემებს. თუმცა, ღრმა ქსელის ვარჯიშის დროს, შეიძლება მოხდეს, რომ მნიშვნელობები მნიშვნელოვნად გასცდეს ამ დიაპაზონს, რაც ვარჯიშს პრობლემურია. სერიის ნორმალიზაციის ფენა ითვლის საშუალო და სტანდარტულ გადახრას მიმდინარე მინი-სამეფოში ყველა მნიშვნელობისთვის და იყენებს მათ სიგნალის ნორმალიზებისთვის, სანამ ის გაივლის ნერვული ქსელის შრეში. ეს მნიშვნელოვნად აუმჯობესებს ღრმა ქსელების სტაბილურობას.

Takeaway

ტრანსფერის სწავლის გამოყენებით, ჩვენ შევძელით სწრაფად შეგვექმნა კლასიფიკატორი ჩვენი მორგებული ობიექტების კლასიფიკაციის ამოცანისთვის და მივაღწიეთ მაღალ სიზუსტეს. თუმცა, ეს მაგალითი არ იყო სრულიად სამართლიანი, რადგან ორიგინალური VGG-16 ქსელი წინასწარ იყო გაწვრთნილი კატებისა და ძაღლების ამოცნობისთვის და, ამრიგად, ჩვენ უბრალოდ ხელახლა ვიყენებდით ქსელში უკვე არსებული შაბლონების უმეტესობას. თქვენ შეგიძლიათ ველოდოთ უფრო დაბალ სიზუსტეს უფრო ეგზოტიკურ დომენის სპეციფიკურ ობიექტებზე, როგორიცაა მცენარის წარმოების ხაზის დეტალები ან ხის სხვადასხვა ფოთლებზე.

თქვენ ხედავთ, რომ უფრო რთული ამოცანები, რომლებსაც ჩვენ ახლა ვწყვეტთ, მოითხოვს უფრო მაღალ გამოთვლით სიმძლავრეს და ადვილად ვერ გადაიჭრება CPU-ზე. მომდევნო განყოფილებაში ჩვენ შევეცდებით გამოვიყენოთ უფრო მსუბუქი დანერგვა იმავე მოდელის მოსამზადებლად დაბალი გამოთვლითი რესურსების გამოყენებით, რაც იწვევს ოდნავ დაბალ სიზუსტეს.

ეს გაკვეთილი არის Microsoft “AI for Beginners” კურსის ქართული თარგმანი, გავრცელებული MIT ლიცენზიით.