تنظیم دقیق Pytorch ViT برای CIFAR10


نویسنده(های): احمد مصطفی

در ابتدا منتشر شد به سمت هوش مصنوعی.

در مقاله قبلی اینجا ما یک مدل ViT را از ابتدا ایجاد کردیم و آن را بر روی مجموعه داده CIFAR10 آموزش دادیم. با این حال، دقت مدل بدون تنظیم دقیق فراپارامترهای عمدی به 67 درصد رسید. این انتظار می رود زیرا سازندگان اصلی مدل ViT خاطرنشان کردند که این مدل ها عملکرد متوسطی در مقایسه با آن دارند CNN ها هنگامی که در کوچک آموزش دیده است مجموعه داده ها. با این حال، هنگامی که در یک مجموعه داده بزرگ مقیاس بندی می شوند، شروع به همتراز شدن با آنها می کنند CNN ها یا حتی بهتر به همین دلیل است که توصیه می شود مدل های ViT را که در ابعاد بزرگ از قبل آموزش داده شده اند تنظیم کنید مجموعه داده ها مانند ImageNet. و این دقیقاً همان کاری است که ما در پست انجام خواهیم داد.

حلقه آموزش

ما با نوشتن کد دیگ بخار برای آموزش و آزمایش هر مدل در مجموعه داده CIFAR10 شروع می کنیم. متوجه خواهید شد که ما اندازه تصاویر را در آموزش و آزمایش تبدیل تصویر به 224 تغییر دادیم، توجه داشته باشید که اندازه تصویر اصلی CIFAR10 32 است. این به این دلیل است که مدلی که از Pytorch استفاده خواهد شد، نیاز به اندازه ورودی 224 دارد. در ImageNet آموزش دیده است.

transform_train = transforms.Compose([
transforms.Resize(224),
transforms.ToTensor(),
transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)),
])

transform_test = transforms.Compose([
transforms.Resize(224),
transforms.ToTensor(),
transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)),
])

train_set = CIFAR10(root='./datasets', train=True, download=True, transform=transform_train)
test_set = CIFAR10(root='./datasets', train=False, download=True, transform=transform_test)

train_loader = DataLoader(train_set, shuffle=True, batch_size=64)
test_loader = DataLoader(test_set, shuffle=False, batch_size=64)

n_epochs = 10
lr = 0.0001

optimizer = Adam(model.parameters(), lr=lr)
criterion = CrossEntropyLoss()

for epoch in range(n_epochs):
train_loss = 0.0
for i,batch in enumerate(train_loader):
x, y = batch
x, y = x.to(device), y.to(device)
y_hat = model(x)
loss = criterion(y_hat, y)

batch_loss = loss.detach().cpu().item()
train_loss += batch_loss / len(train_loader)

optimizer.zero_grad()
loss.backward()
optimizer.step()

if i%100==0:
print(f"Batch {i}/{len(train_loader)} loss: {batch_loss:.03f}")

print(f"Epoch {epoch + 1}/{n_epochs} loss: {train_loss:.03f}")

در حال بارگذاری مدل

حالا باید مدل ViT_b_16 را از torchvision.models بارگذاری کنیم. تمامی مدل های ViT موجود در Torchvision در لینک زیر آمده است اینجا. اگر لینک را بررسی کنید، چندین مدل با برچسب هایی مانند b، l، و h پیدا خواهید کرد. این برچسب ها با اندازه مدل پایه، بزرگ و بزرگ مطابقت دارند. معماری این مدل ها دقیقا همان هایی است که در اولین مقاله ViT با عنوان منتشر شده است ارزش یک تصویر 16×16 کلمه است: ترانسفورماتور برای تشخیص تصویر در مقیاس. تعداد مربوط به این برچسب ها مانند 16، 32 و 14 مربوط به اندازه پچ مورد استفاده مدل است. تمامی این مدل ها در ImageNet آموزش دیده اند. با بارگذاری مدل شروع می کنیم. مدل پیش‌فرض ارائه‌شده برای اطمینان از بارگذاری یک مدل از پیش آموزش‌دیده، از قبل آموزش‌دیده نشده است.

from torchvision.models import ViT_B_16_Weights, vit_b_16

model = vit_b_16(ViT_B_16_Weights.IMAGENET1K_V1)

به طور پیش فرض، خروجی این مدل از 1000 کلاس همانطور که در ImageNet آموزش داده شده است. با این حال، مجموعه داده ما فقط شامل 10 کلاس است. بنابراین باید هد این مدل را از 1000 به 10 لجیت تغییر دهیم. لایه بیرونی مدل بارگذاری شده، لایه “سر” است که یک لایه متوالی است که فقط یک لایه خطی را شامل می شود. برای تطبیق مدل، ما به سادگی یک لایه Linear جدید به لایه “heads” اختصاص می دهیم و در عین حال ویژگی های ورودی لایه را حفظ می کنیم و ویژگی های خارجی را با 10 جایگزین می کنیم.

model = vit_b_16(ViT_B_16_Weights.IMAGENET1K_V1)

model.heads = nn.Sequential(
nn.Linear(model.heads.head.in_features, 10)
)

به‌جای آموزش یا بلوک‌های ترانسفورماتور در مدل بارگذاری شده، می‌توانیم تمام لایه‌ها را به جز آخرین لایه ترانسفورماتور منجمد کنیم. با انجام این کار، فرآیند تنظیم دقیق را فشرده‌تر می‌کنیم. در نهایت مدل را به قسمت منتقل می کنیم پردازنده گرافیکی دستگاه را با استفاده از حلقه آموزشی قبلی آموزش دهید.

model = vit_b_16(ViT_B_16_Weights.IMAGENET1K_V1)

model.heads = nn.Sequential(
nn.Linear(model.heads.head.in_features, 10)
)

# Freeze all layers
for param in model.parameters():
param.requires_grad = False

# Unfreeze the last encoder layer and the head
for param in model.encoder.layers[-1].parameters():
param.requires_grad = True
for param in model.heads.parameters():
param.requires_grad = True

حلقه تست

ما در نهایت مدل خود را بر روی مجموعه داده آزمایشی CIFAR10 آزمایش می کنیم. متوجه خواهید شد که این مدل حتی پس از آموزش تنها در یک دوره به دقت بسیار بالایی می رسد. این به دلیل ویژگی های قدرتمندی است که هنگام آموزش مدل در ImageNet ایجاد شده است.

with torch.no_grad():
correct, total = 0, 0
test_loss = 0.0
for batch in tqdm(test_loader, desc="Testing"):
x, y = batch
x, y = x.to(device), y.to(device)
y_hat = model(x)
loss = criterion(y_hat, y)
test_loss += loss.detach().cpu().item() / len(test_loader)

correct += torch.sum(torch.argmax(y_hat, dim=1) == y).detach().cpu().item()
total += len(x)
print(f"Test loss: {test_loss:.2f}")
print(f"Test accuracy: {correct / total * 100:.2f}%")

منتشر شده از طریق به سمت هوش مصنوعی



منبع: https://towardsai.net/p/machine-learning/fine-tuning-pytorch-vit-for-cifar10