Transfer learning — eng foydali ko'nikma
Bu bob amalda eng ko'p ishlatiladigan usulni o'rgatadi.
Haqiqiy ishda siz modelni noldan o'qitmaysiz. Deyarli hech qachon. Tayyor modelni olib, o'z vazifangizga moslashtirasiz.
Nima uchun noldan o'qitmaymiz
ResNet-50 ni ImageNet da noldan o'qitish uchun kerak:
- 1.2 million belgilangan rasm
- Bir necha kun GPU vaqti
- Ko'p tajriba (learning rate, augmentatsiya, regularizatsiya)
Sizda esa odatda 200–2000 rasm bor va bir soat vaqt.
Noldan o'qitsangiz — model overfitting qiladi va ishlamaydi.
G'oya: birinchi qatlamlar UNIVERSAL
4-bobning oxirini eslang: birinchi qatlamlar chet, burchak va tekstura topadi. Bu har qanday rasm uchun foydali — mushuk bo'ladimi, hujjat bo'ladimi.
Faqat oxirgi qatlam vazifaga xos: "bu 1000 ta ImageNet sinfidan qaysi biri?"
Shuning uchun:
Tayyor ResNet [conv qatlamlar] <- SAQLAYMIZ (chet, tekstura — universal) [oxirgi qatlam] <- ALMASHTIRAMIZ (bizning sinflar)
Tayyor model yuklash
import torch import torch.nn as nn from torchvision import models model = models.resnet18(weights=models.ResNet18_Weights.DEFAULT) print("oxirgi qatlam:", model.fc) print("parametr:", sum(p.numel() for p in model.parameters()))
Natija:
oxirgi qatlam: Linear(in_features=512, out_features=1000, bias=True) parametr: 11,689,512
1000 chiqish — ImageNet ning 1000 ta sinfi. Bizga bu kerak emas, shuning uchun almashtiramiz.
weights=...DEFAULT — ImageNet da o'qitilgan vaznlar yuklanadi.
weights=None bersangiz — tasodifiy vaznlar, ya'ni noldan.
Birinchi marta ishga tushirganda model yuklab olinadi (~45 MB).
Oxirgi qatlamni almashtirish
SINFLAR = 2 # masalan: hujjat / hujjat emas model.fc = nn.Linear(model.fc.in_features, SINFLAR) print("yangi qatlam:", model.fc)
model.fc.in_features — eski qatlamning kirish o'lchamini
o'qiymiz (ResNet-18 da 512). Qo'lda yozmang — model o'zgarsa
xato bo'ladi.
Yangi qatlam tasodifiy vaznlar bilan boshlanadi — uni o'qitish kerak.
Ikki strategiya
A. Feature extraction — faqat oxirgi qatlamni o'qitish
model = models.resnet18(weights=models.ResNet18_Weights.DEFAULT) for p in model.parameters(): p.requires_grad = False # HAMMASINI muzlatamiz model.fc = nn.Linear(model.fc.in_features, SINFLAR) # yangi qatlam avtomatik requires_grad=True bo'ladi oqitiladigan = sum(p.numel() for p in model.parameters() if p.requires_grad) jami = sum(p.numel() for p in model.parameters()) print(f"o'qitiladigan: {oqitiladigan:,} / {jami:,}")
Natija:
o'qitiladigan: 1,026 / 11,177,538
Atigi 1026 ta parametr o'qitiladi (512x2 vazn + 2 bias). Qolgan 11 milliondan ortig'i muzlatilgan. Shuning uchun bu usul CPU da ham daqiqalarda ishlaydi.
Qachon: ma'lumot kam (< 1000 rasm), yoki vazifa ImageNet ga o'xshash.
Afzalligi: juda tez, CPU da ham bo'ladi, overfitting kam.
B. Fine-tuning — hammasini kichik learning rate bilan
model_ft = models.resnet18(weights=models.ResNet18_Weights.DEFAULT) model_ft.fc = nn.Linear(model_ft.fc.in_features, SINFLAR) # hech narsa muzlatilmaydi optimizator = torch.optim.Adam(model_ft.parameters(), lr=1e-4)
lr=1e-4 — 10 barobar KICHIK. Noldan o'qitishda 1e-3
ishlatgan edik.
Nega kichik: vaznlar allaqachon yaxshi. Katta qadam ularni buzadi — bu "catastrophic forgetting" deyiladi.
Qachon: ma'lumot ko'p (> 5000 rasm) va vazifa ImageNet dan farq qiladi (masalan tibbiy rasm, hujjat).
Oraliq variant: oxirgi bloklarni ochish
model_q = models.resnet18(weights=models.ResNet18_Weights.DEFAULT) for p in model_q.parameters(): p.requires_grad = False for p in model_q.layer4.parameters(): # faqat oxirgi blok p.requires_grad = True model_q.fc = nn.Linear(model_q.fc.in_features, SINFLAR) n = sum(p.numel() for p in model_q.parameters() if p.requires_grad) print(f"o'qitiladigan: {n:,}")
Amalda eng ko'p ishlatiladigan variant: past qatlamlar (universal belgilar) muzlatilgan, yuqori qatlamlar (vazifaga xos) o'qitiladi.
BATCHNORM MUAMMOSI — jimgina buziladigan xato
Bu — transfer learning dagi eng ko'p uchraydigan yashirin xato.
requires_grad = False vaznlarni muzlatadi. Lekin BatchNorm
qatlamida vazndan tashqari yana ikkita narsa bor:
import torch import torch.nn as nn bn = nn.BatchNorm2d(4) print("o'qitiladigan (parameters):") for nom, _ in bn.named_parameters(): print(" ", nom) print("BUFERLAR (o'qitilmaydi, lekin O'ZGARADI):") for nom, _ in bn.named_buffers(): print(" ", nom)
running_mean va running_var — bu parametr EMAS, bufer.
requires_grad ularga ta'sir qilmaydi.
Muammoni ko'rsatamiz
bn = nn.BatchNorm2d(4) for p in bn.parameters(): p.requires_grad = False # "muzlatdik" boshlangich = bn.running_mean.clone() bn.train() # o'qitish rejimi for _ in range(5): bn(torch.randn(8, 4, 16, 16) * 5 + 10) # boshqa taqsimot print("o'zgardimi:", not torch.allclose(boshlangich, bn.running_mean)) print("boshlang'ich:", boshlangich.tolist()) print("keyin :", [round(x, 3) for x in bn.running_mean.tolist()])
Natija:
o'zgardimi: True boshlang'ich: [0.0, 0.0, 0.0, 0.0] keyin : [4.11, 4.098, 4.102, 4.099]
0 dan 4.1 ga siljidi — atigi 5 ta partiyadan keyin. Vaznlar muzlatilgan bo'lsa ham.
Vaznlar muzlatilgan, lekin statistika o'zgardi. Ya'ni "muzlatilgan" backbone aslida o'zgaryapti.
Nega bu zarar
Tayyor model ImageNet statistikasi bilan kalibrlangan. Sizning 1000 ta rasmingiz boshqa taqsimotga ega. BatchNorm bufer sekin-asta shu kichik taqsimotga siljiydi va ImageNet belgilarini buzadi.
Natija: aniqlik kutilganidan past, lekin xato xabari yo'q. Sabab topish juda qiyin.
Yechim: BatchNorm ni eval rejimida qoldirish
def bn_muzlat(model): """BatchNorm qatlamlarini eval rejimiga o'tkazadi.""" for m in model.modules(): if isinstance(m, (nn.BatchNorm1d, nn.BatchNorm2d, nn.BatchNorm3d)): m.eval() bn = nn.BatchNorm2d(4) bn.train() bn_muzlat(bn) boshlangich = bn.running_mean.clone() for _ in range(5): bn(torch.randn(8, 4, 16, 16) * 5 + 10) print("eval bilan o'zgardimi:", not torch.allclose(boshlangich, bn.running_mean))
Natija: eval bilan o'zgardimi: False — endi haqiqatan muzlatilgan.
MUHIM: model.train() dan KEYIN chaqiring. model.train()
hamma narsani train rejimiga qaytaradi, shu jumladan BatchNorm ni.
To'g'ri tartib har epochda:
# parcha model.train() # avval hammasi train bn_muzlat(model) # keyin BatchNorm ni qaytarib eval ga
Teskari qilsangiz — tuzatish bekor bo'ladi.
Qachon muzlatish kerak
| Vaziyat | BatchNorm |
|---|---|
| Feature extraction (hamma muzlatilgan) | eval — albatta |
| Kam ma'lumot (< 1000 rasm) | eval — tavsiya |
| Ko'p ma'lumot (> 10 000) | train qoldirish mumkin |
| Batch juda kichik (< 8) | eval — statistika ishonchsiz |
Oxirgi qator alohida muhim: kichik batch da BatchNorm statistikasi shovqinli bo'ladi. CPU da o'qitayotgan bo'lsangiz — batch kichik, demak BatchNorm ni eval da qoldiring.
MUHIM: kirishni to'g'ri tayyorlash
Tayyor model aniq qanday tayyorlangan rasmni kutadi. Boshqacha bersangiz — aniqlik keskin tushadi, lekin xato chiqmaydi.
from torchvision import transforms IMAGENET_ORT = [0.485, 0.456, 0.406] IMAGENET_STD = [0.229, 0.224, 0.225] test_ozgartirish = transforms.Compose([ transforms.Resize(256), transforms.CenterCrop(224), transforms.ToTensor(), transforms.Normalize(IMAGENET_ORT, IMAGENET_STD), ])
Bu uchta son ImageNet ning haqiqiy statistikasi. Ular bilan o'qitilgan model shu bilan ishlashi kerak.
5-bobda MNIST uchun (0.1307,), (0.3081,) ishlatgan edik —
boshqa dataset, boshqa sonlar.
224x224 — ResNet ImageNet da shu o'lchamda o'qitilgan.
Augmentatsiya — faqat o'qitish uchun
oqitish_ozgartirish = transforms.Compose([ transforms.RandomResizedCrop(224), transforms.RandomHorizontalFlip(), transforms.ColorJitter(brightness=0.2, contrast=0.2), transforms.ToTensor(), transforms.Normalize(IMAGENET_ORT, IMAGENET_STD), ])
Har epochda rasm biroz boshqacha ko'rinadi — model yodlab ola olmaydi. Kam ma'lumotda bu juda yordam beradi.
Testda augmentatsiya QILMANG. Baholash barqaror bo'lishi kerak.
Diqqat — hujjat uchun RandomHorizontalFlip ISHLATMANG.
Ko'zguga aylantirilgan matn — bu boshqa narsa. Mushuk uchun
mayli, matn uchun zarar.
To'liq misol
def transfer_model(sinflar, strategiya="feature"): """Tayyor ResNet-18 ni yangi vazifaga moslashtiradi.""" m = models.resnet18(weights=models.ResNet18_Weights.DEFAULT) if strategiya == "feature": for p in m.parameters(): p.requires_grad = False elif strategiya == "qisman": for p in m.parameters(): p.requires_grad = False for p in m.layer4.parameters(): p.requires_grad = True elif strategiya != "full": raise ValueError(f"noma'lum strategiya: {strategiya}") m.fc = nn.Linear(m.fc.in_features, sinflar) return m for s in ("feature", "qisman", "full"): m = transfer_model(2, s) n = sum(p.numel() for p in m.parameters() if p.requires_grad) print(f"{s:<8} o'qitiladigan parametr: {n:,}")
Natija:
feature o'qitiladigan parametr: 1,026 qisman o'qitiladigan parametr: 8,394,754 full o'qitiladigan parametr: 11,177,538
Uch daraja: 1 mingdan 8 millionga, keyin 11 millionga. Har qadamda ko'proq moslashuvchanlik, lekin ko'proq ma'lumot va ehtiyotkorlik kerak.
Diqqat: qisman da 8.4 million — bu jami ning 75% i. ResNet
parametrlarining katta qismi oxirgi blokda joylashgan.
Learning rate — strategiyaga qarab
# parcha tavsiya = { "feature": 1e-3, # faqat yangi qatlam — katta qadam mumkin "qisman": 1e-4, # tayyor vaznlar bor — ehtiyot "full": 1e-5, # hammasi tayyor — juda ehtiyot }
Qoida: qancha ko'p tayyor vazn o'qitilsa, learning rate shuncha kichik.
Eng ko'p uchraydigan xato — fine-tuning da 1e-3 ishlatish.
Birinchi epochda aniqlik tushib ketadi va tiklanmaydi. Model
ImageNet da o'rgangan hamma narsani unutgan bo'ladi.
Qaysi modelni tanlash
| Model | Hajm | Qachon |
|---|---|---|
resnet18 |
45 MB | boshlash uchun, CPU da ham tez |
resnet50 |
98 MB | aniqroq, GPU bo'lsa |
efficientnet_b0 |
21 MB | kichik va aniq, mobil uchun |
mobilenet_v3_small |
10 MB | telefon, edge qurilma |
resnet18 dan boshlang. Ishlasa — yetarli. Ishlamasa,
kattaroqqa o'ting.
Katta model doim yaxshi emas: kam ma'lumotda u tezroq overfitting qiladi.
Amaliy tartib
1. resnet18 + feature extraction bilan boshlang 2. O'lchang (aniqlik, chalkashlik matritsasi) 3. Yetarli bo'lsa — TO'XTANG 4. Yetmasa: "qisman" ga o'ting, lr=1e-4 5. Hali yetmasa: ko'proq MA'LUMOT yig'ing Ma'lumot qo'shish deyarli doim modelni kattalashtirish dan foydaliroq.
Keyingi bobda shu usulni hujjat vazifasiga qo'llaymiz.
Bu bobni bepul o'qidingiz.
Kitob o'rgatadi, lekin sizning kodingiz nega ishlamaganini ayta olmaydi. Kursda uy vazifangiz tekshiriladi.