چیت‌شیت

معماری‌های CNN و یادگیری انتقالی

CNN Architectures and Transfer Learning

اندازه‌گذاری کانولوشن‌ها، ساخت LeNet تا ResNet، آموزش کلاسیفایر و فاین‌تیون بک‌بون از پیش‌آموزش‌دیده. PyTorch و NumPy.

  • ۱۲ بخش
  • ۴ درس مرتبط
  • کد و دستورها عیناً از دوره‌ی اصلی
فهرست مطالب
  1. فرمول‌ها
  2. چهار خانواده
  3. TinyResNet برای ورودی 32x32
  4. ResNet BasicBlock
  5. وظایف در کد
  6. یک اپوک آموزش
  7. فاین‌تیون با نرخ یادگیری تفکیکی (discriminative LR)
  8. انتخاب روش یادگیری انتقالی
  9. پیش‌فرض‌های آموزش
  10. عیب‌یابی
  11. پرسش‌ها
  12. ابعاد لایه کانولوشن

فرمول‌ها

مفهوم‌ها
اندازه خروجی
$H_{out} = \lfloor (H - K + 2P) / S \rfloor + 1$
پدینگ Same
$P = (K - 1) / 2$ برای $K$ فرد و $S = 1$.
پارامترهای کانولوشن
C_out * C_in * K * K + C_out. جمله آخر بایاس‌ها هستند.
میدان دید
$1 + L (K - 1)$ برای $L$ کانولوشن پشت‌هم با استراید 1.
دو 3x3 یا یک 5x5
میدان دید یکسان 5x5. $18C^2$ در مقابل $25C^2$ پارامتر.
بلاک باقیمانده
$y = F(x) + x$. این بلاک همانی را با $F(x) = 0$ یاد می‌گیرد.
آنتروپی متقاطع
$-z_y + \log \sum_j \exp(z_j)$ روی لاجیت‌های خام.
کاهش نرخ یادگیری لایه‌به‌لایه
$\mathrm{lr}_k = \mathrm{base} \cdot \mathrm{decay}^{L - k}$

چهار خانواده

مفهوم‌ها
LeNet-5 (1998)
کانولوشن، avg pool، لایه‌ی متراکم، tanh. 60٬000 پارامتر.
AlexNet (2012)
ReLU، دراپ‌اوت، 5 کانولوشن و 3 لایه‌ی متراکم. 60M پارامتر.
VGG (2014)
فقط کانولوشن‌های 3x3، 16 یا 19 لایه. 138M پارامتر.
Inception (2014)
1x1، 3x3، 5x5 و pool به صورت موازی، سپس الحاق (concatenate).
ResNet (2015)
اتصالات جهشی همانی. آموزش بیش از 100 لایه.
BasicBlock
دو کانولوشن 3x3 با یک اتصال جهشی. ResNet-18 و ResNet-34.
Bottleneck
1x1 کاهش، 3x3، 1x1 افزایش. ResNet-50، -101، -152.
ResNet-18 یا VGG-16
11.7M یا 138M پارامتر. دقت Top-1 برابر 69.8٪ یا 71.6٪.

TinyResNet برای ورودی 32x32

معماری
ورودی(1, 3, 32, 32)stemکانولوشن 3x3، 32 کانال، BN، ReLUlayer12 تا BasicBlock، 32 کانالlayer2استراید 2، 64 کانالlayer3استراید 2، 128 کانالlayer4استراید 2، 256 کانالheadAdaptiveAvgPool2d، Linearلاجیت‌ها10 کلاس

ResNet BasicBlock

کد
python
self.conv1 = nn.Conv2d(in_c, out_c, kernel_size=3, stride=stride, padding=1, bias=False)  # پارامتر beta در BN بایاس را نگه می‌دارد
self.conv2 = nn.Conv2d(out_c, out_c, kernel_size=3, stride=1, padding=1, bias=False)
if stride != 1 or in_c != out_c:
    self.shortcut = nn.Sequential(
        nn.Conv2d(in_c, out_c, kernel_size=1, stride=stride, bias=False),
        nn.BatchNorm2d(out_c))                                                            # کانولوشن 1x1 ابعاد را هم‌اندازه می‌کند
else:
    self.shortcut = nn.Identity()                                                         # اتصال جهشی بدون عملگر (no-op)
out = F.relu(self.bn1(self.conv1(x)))
out = self.bn2(self.conv2(out))                                                           # بدون ReLU قبل از جمع
out = out + self.shortcut(x)                 # F(x) + x
return F.relu(out)

وظایف در کد

کار و کد
وظیفهکد
اندازه خروجی یک کانولوشنoutput_size(h_in, k, p, s)
میدان دید دسته‌ای از کانولوشن‌هاreceptive_field(layers)
کانولوشن به‌صورت یک ضرب ماتریسیconv2d_im2col(x, w, b, padding=1)
اعمال یک کرنل دستیapply_kernel(x[0], KERNELS["sobel_x"])
میکس کردن یک دستهmixup_batch(x, y, num_classes, alpha=0.2)
تابع زیان (loss) روی برچسب‌های نرمsoft_cross_entropy(logits, soft_targets)
بک‌بون منجمد، هد جدیدmake_feature_extractor(num_classes=10)
حفظ آماره‌های متحرک BNfreeze_bn_stats(model)

یک اپوک آموزش

گام‌به‌گام
  1. افزایش دادهrandom_hflip() و random_crop(pad=4) با reflect pad. فقط مجموعه آموزش.
  2. نرمال‌سازیstandardize(mean, std) با میانگین و انحراف معیار مجموعه آموزش شما.
  3. دیتالودرshuffle=True برای آموزش. shuffle=False برای اعتبارسنجی.
  4. مدلاول model.train(). مدل لاجیت‌های خام (N, C) را می‌دهد.
  5. تابع زیانsoft_cross_entropy با میکس‌آپ، در غیر این صورت cross_entropy با label_smoothing=0.1.
  6. گام بهینه‌سازیoptimizer.zero_grad()، loss.backward()، optimizer.step().
  7. متریک‌هااضافه کردن loss.item()، تا گرافی در حافظه باقی نماند.
  8. پایان اپوکscheduler.step(). سپس model.eval() و ارزیابی تحت torch.no_grad.

فاین‌تیون با نرخ یادگیری تفکیکی (discriminative LR)

کد
python
model = resnet18(weights=ResNet18_Weights.IMAGENET1K_V1)
model.fc = nn.Linear(model.fc.in_features, 10)  # هد جدید
groups = discriminative_param_groups(model, base_lr=1e-3, decay=0.3)
optimizer = SGD(groups, momentum=0.9, weight_decay=1e-4, nesterov=True)
scheduler = CosineAnnealingLR(optimizer, T_max=epochs)
for epoch in range(epochs):
    model.train()
    if freeze_bn:
        freeze_bn_stats(model)                  # بعد از model.train()
start, unfreeze = progressive_unfreeze_schedule(model)
start()                                         # فقط fc آموزش می‌بیند
unfreeze(epoch)                                 # اول layer4، بعد layer3

انتخاب روش یادگیری انتقالی

مفهوم‌ها
کمتر از 1k تصویر، نزدیک به ImageNet
بک‌بون را منجمد کنید. فقط هد را آموزش دهید.
1k تا 10k تصویر، نزدیک
2 تا 3 مرحله اول را منجمد کنید. بقیه را فاین‌تیون کنید.
10k تا 100k تصویر، هر دامنه‌ای
فاین‌تیون سرتاسری با نرخ یادگیری تفکیکی.
بیش از 100k تصویر، دامنه دور
همه را فاین‌تیون کنید. آموزش از صفر را هم در نظر بگیرید.
در BN با >= 5k نمونه
BN را در حالت train نگه دارید. آماره‌های متحرک خود را به‌روزرسانی می‌کند.
در BN با دیتاست کوچک
BN را در حالت eval منجمد کنید. آماره‌های ImageNet را نگه دارید.
دسته بسیار کوچک به ازای هر GPU
لایه BN را با GroupNorm جایگزین کنید.
هد برای جایگزینی
backbone.fc (ResNet)، backbone.classifier[1] (EfficientNet، MobileNet).

پیش‌فرض‌های آموزش

پیش‌فرض‌ها
تنظیمپیش‌فرضنکته
SGD `lr`0.1TinyResNet از صفر، کسینوسی طی 10 اپوک
momentum0.9با nesterov=True
weight_decay5e-4فاین‌تیون از 1e-4 استفاده می‌کند
label_smoothing0.1هدف 1-eps برای کلاس واقعی
Mixup `alpha`0.2مقدار لاندا از Beta(a, a)
base_lr1e-3گروه fc. مراحل اولیه نرخ کمتری می‌گیرند
decay0.3لایه conv1 حدود 0.00243 برابر base_lr دریافت می‌کند
batch_size128لودر اعتبارسنجی از 256 استفاده می‌کند

عیب‌یابی

عیب‌یابی
  • گرادیان اشتباه، منحنی تخت

    علت
    اعمال Softmax قبل از تابع زیان (loss)
    راه‌حل
    پاس دادن لاجیت‌های خام به CrossEntropyLoss
  • شبیه به ناپایداری LR

    علت
    انباشته شدن گرادیان‌ها
    راه‌حل
    فراخوانی optimizer.zero_grad() در هر گام
  • حدود 1٪ افت دقت

    علت
    میانگین و انحراف معیار ImageNet روی CIFAR-10
    راه‌حل
    محاسبه آماره‌ها روی مجموعه آموزش خودتان
  • تبدیل شدن «6» به «9»

    علت
    تغییر برچسب بر اثر افزایش داده
    راه‌حل
    استفاده از بازه‌های چرخش کوچک‌تر
  • نتیجه فاین‌تیون بدتر از حالت فقط پیش‌آموزش‌دیده

    علت
    باگ LR یا BN
    راه‌حل
    استفاده از نرخ یادگیری تفکیکی، بررسی حالت BN
  • افت بی‌صدای 5 تا 15 درصدی دقت

    علت
    آماره‌های BN متعلق به توزیع دیگری است
    راه‌حل
    منجمد کردن آماره‌های BN یا استفاده از GroupNorm
  • تمام تصاویر یک کلاس را می‌گیرند

    علت
    نرخ یادگیری فیچرهای از پیش‌آموزش‌دیده را از بین می‌برد
    راه‌حل
    کاهش نرخ یادگیری بک‌بون
  • آموزش ضعیف‌تر شبکه ساده و عمیق

    علت
    افت کارایی بعد از حدود 20 لایه
    راه‌حل
    افزودن اتصالات باقیمانده

پرسش‌ها

پرسش و پاسخ
چرا کرنل‌های 3x3؟
کوچک‌ترین کرنل فرد دارای نقطه مرکز است.
چگونه بدون pooling ابعاد را کاهش دهیم؟
از کانولوشن با stride=2 استفاده کنید. ابعاد H و W را نصف می‌کند.
چرا میکس‌آپ زیان آموزش را بالا می‌برد؟
برچسب‌های هدف نرم هستند. دقت تست افزایش می‌یابد.
دو عدد کلیدی برای یادگیری انتقالی کدامند؟
فقط پیش‌آموزش‌دیده کف است. فاین‌تیون‌شده سقف است.
چرا نرخ یادگیری برای لایه‌های اولیه کمتر است؟
آن‌ها حامل فیچرهای عمومی مانند لبه‌ها و بافت‌ها هستند.
چه زمانی اپتیمایزر را دوباره بسازیم؟
هر بار که مجموعه پارامترهای آموزش‌پذیر تغییر می‌کند.

ابعاد لایه کانولوشن

کد
python
conv = nn.Conv2d(in_channels=3, out_channels=64, kernel_size=3, stride=1, padding=1)
tuple(conv.weight.shape)               # (C_out, C_in, K, K)
sum(p.numel() for p in conv.parameters())   # 64 * 3 * 3 * 3 + 64 = 1,792
y = conv(torch.randn(8, 3, 224, 224))  # مقدار padding=0 خروجی 222x222 می‌دهد