Co je Transfer Learning?
Transfer Learning je technika používání trénovaného modelu k řešení dalšího souvisejícího úkolu. Jedná se o metodu výzkumu Machine Learning, která ukládá znalosti získané při řešení konkrétního problému a používá stejné znalosti k řešení jiného jiného, přesto souvisejícího problému. To zvyšuje efektivitu opětovným použitím informací shromážděných z dříve naučené úlohy.
Je populární používat jinou váhu síťového modelu ke zkrácení doby tréninku, protože k trénování síťového modelu potřebujete hodně dat. Chcete-li zkrátit dobu tréninku, použijete jiné sítě a jejich váhu a upravíte poslední vrstvu k vyřešení našeho problému. Výhodou je, že k vycvičení poslední vrstvy můžete použít malou datovou sadu.
Dále v tomto výukovém kurzu pro přenos PyTorch se naučíme, jak používat Transfer Learning s PyTorch.
Načítání datové sady
Zdroj: Alien vs. Predator Kaggle
Než začnete používat Transfer Learning PyTorch, musíte porozumět datové sadě, kterou budete používat. V tomto příkladu Transfer Learning PyTorch klasifikujete Alien a Predator z téměř 700 obrázků. Pro tuto techniku nepotřebujete k trénování opravdu velké množství dat. Datovou sadu si můžete stáhnout z Kaggle: Alien vs. Predator.
Jak používat Transfer Learning?
Tady je krok za krokem postup, jak používat Transfer Learning pro Deep Learning s PyTorch:
Krok 1) Načtěte data
Prvním krokem je načíst naše data a provést nějakou transformaci na obrázky tak, aby odpovídaly požadavkům na síť.
Data načtete ze složky s torchvision.dataset. Modul bude iterovat ve složce, aby rozdělil data pro vlak a ověření. Proces transformace ořízne obrázky ze středu, provede horizontální převrácení, normalizuje a nakonec jej pomocí funkce Deep Learning převede na tenzor.
from __future__ import print_function, divisionimport osimport timeimport torchimport torchvisionfrom torchvision import datasets, models, transformsimport torch.optim as optimimport numpy as npimport matplotlib.pyplot as pltdata_dir = "alien_pred"input_shape = 224mean = [0.5, 0.5, 0.5]std = [0.5, 0.5, 0.5]#data transformationdata_transforms = {'train': transforms.Compose([transforms.CenterCrop(input_shape),transforms.ToTensor(),transforms.Normalize(mean, std)]),'validation': transforms.Compose([transforms.CenterCrop(input_shape),transforms.ToTensor(),transforms.Normalize(mean, std)]),}image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x),transform=data_transforms[x])for x in ['train', 'validation']}dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size=32,shuffle=True, num_workers=4)for x in ['train', 'validation']}dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'validation']}print(dataset_sizes)class_names = image_datasets['train'].classesdevice = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
Pojďme si představit naši datovou sadu pro PyTorch Transfer Learning. Proces vizualizace získá další dávku obrázků z vlakových datových nakladačů a štítků a zobrazí je pomocí matplot.
images, labels = next(iter(dataloaders['train']))rows = 4columns = 4fig=plt.figure()for i in range(16):fig.add_subplot(rows, columns, i+1)plt.title(class_names[labels[i]])img = images[i].numpy().transpose((1, 2, 0))img = std * img + meanplt.imshow(img)plt.show()
Krok 2) Definujte model
V tomto procesu Deep Learning budete používat ResNet18 z modulu torchvision.
Pomocí torchvision.models načtete resnet18 s předem vycvičenou váhou nastavenou na True. Poté vrstvy zmrazíte, aby je nebylo možné trénovat. Poslední vrstvu také upravíte lineární vrstvou tak, aby vyhovovala našim potřebám, což jsou 2 třídy. CrossEntropyLoss také používáte pro funkci ztráty více tříd a pro optimalizátor použijete SGD s rychlostí učení 0,0001 a hybností 0,9, jak je ukázáno v níže uvedeném příkladu PyTorch Transfer Learning.
## Load the model based on VGG19vgg_based = torchvision.models.vgg19(pretrained=True)## freeze the layersfor param in vgg_based.parameters():param.requires_grad = False# Modify the last layernumber_features = vgg_based.classifier[6].in_featuresfeatures = list(vgg_based.classifier.children())[:-1] # Remove last layerfeatures.extend([torch.nn.Linear(number_features, len(class_names))])vgg_based.classifier = torch.nn.Sequential(*features)vgg_based = vgg_based.to(device)print(vgg_based)criterion = torch.nn.CrossEntropyLoss()optimizer_ft = optim.SGD(vgg_based.parameters(), lr=0.001, momentum=0.9)
Struktura výstupního modelu
VGG((features): Sequential((0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(1): ReLU(inplace)(2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(3): ReLU(inplace)(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)(7): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(8): ReLU(inplace)(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)(12): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(13): ReLU(inplace)(14): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(15): ReLU(inplace)(16): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(17): ReLU(inplace)(18): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)(19): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(20): ReLU(inplace)(21): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(22): ReLU(inplace)(23): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(24): ReLU(inplace)(25): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(26): ReLU(inplace)(27): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)(28): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(29): ReLU(inplace)(30): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(31): ReLU(inplace)(32): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(33): ReLU(inplace)(34): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(35): ReLU(inplace)(36): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False))(classifier): Sequential((0): Linear(in_features=25088, out_features=4096, bias=True)(1): ReLU(inplace)(2): Dropout(p=0.5)(3): Linear(in_features=4096, out_features=4096, bias=True)(4): ReLU(inplace)(5): Dropout(p=0.5)(6): Linear(in_features=4096, out_features=2, bias=True)))
Krok 3) Trénujte a testujte model
Některé z funkcí z Transfer Learning PyTorch Tutorial použijeme, abychom nám pomohli trénovat a hodnotit náš model.
def train_model(model, criterion, optimizer, num_epochs=25):since = time.time()for epoch in range(num_epochs):print('Epoch {}/{}'.format(epoch, num_epochs - 1))print('-' * 10)#set model to trainable# model.train()train_loss = 0# Iterate over data.for i, data in enumerate(dataloaders['train']):inputs , labels = datainputs = inputs.to(device)labels = labels.to(device)optimizer.zero_grad()with torch.set_grad_enabled(True):outputs = model(inputs)loss = criterion(outputs, labels)loss.backward()optimizer.step()train_loss += loss.item() * inputs.size(0)print('{} Loss: {:.4f}'.format('train', train_loss / dataset_sizes['train']))time_elapsed = time.time() - sinceprint('Training complete in {:.0f}m {:.0f}s'.format(time_elapsed // 60, time_elapsed % 60))return modeldef visualize_model(model, num_images=6):was_training = model.trainingmodel.eval()images_so_far = 0fig = plt.figure()with torch.no_grad():for i, (inputs, labels) in enumerate(dataloaders['validation']):inputs = inputs.to(device)labels = labels.to(device)outputs = model(inputs)_, preds = torch.max(outputs, 1)for j in range(inputs.size()[0]):images_so_far += 1ax = plt.subplot(num_images//2, 2, images_so_far)ax.axis('off')ax.set_title('predicted: {} truth: {}'.format(class_names[preds[j]], class_names[labels[j]]))img = inputs.cpu().data[j].numpy().transpose((1, 2, 0))img = std * img + meanax.imshow(img)if images_so_far == num_images:model.train(mode=was_training)returnmodel.train(mode=was_training)
Nakonec v tomto příkladu Transfer Learning v PyTorch začněme náš tréninkový proces s počtem epoch nastaveným na 25 a po tréninku vyhodnotíme. V každém kroku školení model převezme vstup a předpovídá výstup. Poté bude předávaný výstup předán kritériu pro výpočet ztrát. Potom ztráty provedou zpětný výpočet pro výpočet gradientu a nakonec výpočet vah a optimalizaci parametrů pomocí autogradu.
Na vizualizačním modelu bude trénovaná síť testována s dávkou obrázků k předpovědi štítků. Poté bude vizualizován pomocí matplotlib.
vgg_based = train_model(vgg_based, criterion, optimizer_ft, num_epochs=25)visualize_model(vgg_based)plt.show()
Krok 4) Výsledky
Konečným výsledkem je, že jste dosáhli přesnosti 92%.
Epoch 23/24----------train Loss: 0.0044train Loss: 0.0078train Loss: 0.0141train Loss: 0.0221train Loss: 0.0306train Loss: 0.0336train Loss: 0.0442train Loss: 0.0482train Loss: 0.0557train Loss: 0.0643train Loss: 0.0763train Loss: 0.0779train Loss: 0.0843train Loss: 0.0910train Loss: 0.0990train Loss: 0.1063train Loss: 0.1133train Loss: 0.1220train Loss: 0.1344train Loss: 0.1382train Loss: 0.1429train Loss: 0.1500Epoch 24/24----------train Loss: 0.0076train Loss: 0.0115train Loss: 0.0185train Loss: 0.0277train Loss: 0.0345train Loss: 0.0420train Loss: 0.0450train Loss: 0.0490train Loss: 0.0644train Loss: 0.0755train Loss: 0.0813train Loss: 0.0868train Loss: 0.0916train Loss: 0.0980train Loss: 0.1008train Loss: 0.1101train Loss: 0.1176train Loss: 0.1282train Loss: 0.1323train Loss: 0.1397train Loss: 0.1436train Loss: 0.1467Training complete in 2m 47s
Na konci bude výstup našeho modelu vizualizován pomocí matplot níže:
souhrn
Takže shrňme vše! Prvním faktorem je PyTorch je rostoucí rámec hlubokého učení pro začátečníky nebo pro výzkumné účely. Nabízí vysoký výpočetní čas, dynamický graf, podporu GPU a je zcela napsán v Pythonu. Jste schopni snadno definovat náš vlastní síťový modul a provést tréninkový proces se snadnou iterací. Je zřejmé, že PyTorch je ideální pro začátečníky k hlubokému učení a pro profesionální výzkumníky je velmi užitečný s rychlejším výpočtovým časem a také velmi užitečnou funkcí autogradu, která pomáhá dynamickému grafu.