#### 什幺是迁移学习?

1. 加载数据并执行转换

2. 构建和训练模型

3.  用不可视数据测试模型

#importing libraries

import numpy as np # linear algebra

import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)

import matplotlib.pyplot as plt

import matplotlib.image as mpimg

import torch

from torchvision import datasets,transforms,models

from torch import nn,optim

import torch.nn.functional as F

from torch.utils.data import *

import time

import json

import copy

import os

from PIL import Image

from collections import OrderedDict

# check if CUDA is available

train_on_gpu = torch.cuda.is_available()

if not train_on_gpu:

print(‘CUDA is not available.  Training on CPU …’)

else:

print(‘CUDA is available!  Training on GPU …’)

1.   加载数据并执行转换

1.1 下载数据集

#Mounting google drive inorder to access data

drive.mount(‘/content/drive’)

!pip install kaggle

!mkdir .kaggle

import json

with open(‘/content/.kaggle/kaggle.json’, ‘w’) as file:

json.dump(token, file)

!chmod 600 /content/.kaggle/kaggle.json

!cp /content/.kaggle/kaggle.json ~/.kaggle/kaggle.json

!kaggle config set -n path -v{/content}

!unzip \*.zip

1.2 数据转换

· 数据扩张

· 数据规范化

# Tansform with data augmentation and normalization for training

# Just normalization for validation

data_transforms = {

‘train’: transforms.Compose([

transforms.RandomRotation(30),

transforms.RandomResizedCrop(224),

#transforms.RandomResizedCrop(299),  #size for inception architecture

transforms.RandomHorizontalFlip(),

transforms.ToTensor(),

transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])

]),

‘valid’: transforms.Compose([

#transforms.Resize(256),

transforms.CenterCrop(224),

transforms.CenterCrop(299),

transforms.ToTensor(),

transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])

]),

‘test’: transforms.Compose([

transforms.Resize(256),

transforms.CenterCrop(224),

#transforms.CenterCrop(299),

transforms.ToTensor(),

transforms.Normalize([0.485, 0.456, 0.406],[0.229, 0.224, 0.225])

]),

}

train_dir = ‘car_data/train’

test_dir = ‘car_data/test’

label_dir = ‘names.csv’

batch_size=32

dataset = datasets.ImageFolder(train_dir,transform=data_transforms[‘train’])

# splitting our data

valid_size  = int(0.1 * len(dataset))

train_size = len(dataset) – valid_size

dataset_sizes = {‘train’: train_size, ‘valid’: valid_size}

# now we get our datasets

train_dataset, valid_dataset = torch.utils.data.random_split(dataset, [train_size, valid_size])

‘valid’: DataLoader(valid_dataset, batch_size = batch_size, shuffle = False)}

print(“Total Number of Samples: “,len(dataset))

print(“Number of Samples in Train: “,len(train_dataset))

print(“Number of Samples in Valid: “,len(valid_dataset))

print(“Number of Classes: “,len(dataset.classes))

print(dataset.classes[0])

· 可视化标签

1.3 可视化图像

## Method to display Image for Tensor

def imshow(image, ax=None, title=None, normalize=True):

“””Imshow for Tensor.”””

if ax is None:

fig, ax = plt.subplots()

image = image.numpy().transpose((1, 2, 0))

if normalize:

mean = np.array([0.485, 0.456, 0.406])

std = np.array([0.229, 0.224, 0.225])

image = std * image + mean

image = np.clip(image, 0, 1)

ax.imshow(image)

ax.spines[‘top’].set_visible(False)

ax.spines[‘right’].set_visible(False)

ax.spines[‘left’].set_visible(False)

ax.spines[‘bottom’].set_visible(False)

ax.tick_params(axis=’both’, length=0)

ax.set_xticklabels(”)

ax.set_yticklabels(”)

return ax

print(” Sizes of Datasets: “, len(valid_dataset), len(train_dataset))

# Displaying Training Images

fig, axes = plt.subplots(figsize=(16,5), ncols=5)

for ii in range(5):

ax = axes[ii]

#ax.set_title(label_map[class_names[labels[ii].item()]])

imshow(images[ii], ax=ax, normalize=True)

#### 2. 构建和训练模型

2.1 加载预训练模型

device = torch.device(“cuda” if torch.cuda.is_available() else “cpu”)

model_name = ‘resnet’ #vgg

# Densenet

if model_name == ‘densenet’:

model = models.densenet161(pretrained=True)

num_in_features = 2208

print(model)

# VGGNet

elif model_name == ‘vgg’:

model = models.vgg19(pretrained=True)

num_in_features = 25088

print(model.classifier)

# Resnet

elif model_name == ‘resnet’:

model = models.resnet152(pretrained=True)

#model = models.resnet34(pretrained=True)

num_in_features = 2048 #512

print(model.fc)

# Inception

elif model_name == ‘inception’:

model = models.inception_v3(pretrained=True)

model.aux_logits=False

num_in_features = 2048

print(model.fc)

else:

print(“Unknown model, please choose ‘densenet’ or ‘vgg'”)

2.2 冻结参数，创建自定义分类器

# Freezing parameters

for param in model.parameters():

# Create Custom Classifier

def build_classifier(num_in_features, hidden_layers, num_out_features):

classifier = nn.Sequential()

# when we don’t have any hidden layers

if hidden_layers == None:

#when we have hidden layers

else:

layer_sizes = zip(hidden_layers[:-1], hidden_layers[1:])

for i, (h1, h2) in enumerate(layer_sizes):

return classifier

#define our hidden layers

hidden_layers = None #[1050,500]

classifier = build_classifier(num_in_features, hidden_layers, 196)

print(classifier)

# Defining model hyperparameters

if model_name == ‘densenet’:

model.classifier = classifier

criterion = nn.CrossEntropyLoss()

# Decay Learning Rate by a factor of 0.1 every 4 epochs

sched = optim.lr_scheduler.StepLR(optimizer, step_size=4)

elif model_name == ‘vgg’:

model.classifier = classifier

criterion = nn.CrossEntropyLoss()

sched = optim.lr_scheduler.StepLR(optimizer, step_size=4, gamma=0.1)

elif model_name == ‘resnet’:

model.fc = classifier

criterion = nn.CrossEntropyLoss()

optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)

sched = optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode=’max’, patience=3, threshold = 0.9)

elif model_name == ‘inception’:

model.fc = classifier

criterion = nn.CrossEntropyLoss()

optimizer = optim.SGD(model.parameters(), lr=0.001,momentum=0.9)

else:

pass

torch.optim.lr_scheduler提供了几种依据epoch数量调整学习率的方法。

torch.optim.lr_scheduler.ReduceLROnPlateau（https://pytorch.org/docs/stable/optim.html#torch.optim.lr_scheduler.ReduceLROnPlateau） 允许基于一些验证测量的动态学习率降低。 详情： https://pytorch.org/docs/stable/optim.html。

2.3 训练与验证

· 在网络中使用前向（传播）进行前向传播

· 使用标准函数中的网络输出计算损耗

· 使用loss.backwards()对网络执行反向传播来计算梯度

· 利用优化器更新权重optimizer. step()

# Training

def train_model(model, criterion, optimizer, sched, num_epochs=5,device=’cuda’):

start = time.time()

train_results = []

valid_results = []

best_model_wts = copy.deepcopy(model.state_dict())

best_acc = 0.0

for epoch in range(num_epochs):

print(‘Epoch {}/{}’.format(epoch+1, num_epochs))

print(‘-‘ * 10)

# Each epoch has a training and validation phase

for phase in [‘train’, ‘valid’]:

if phase == ‘train’:

model.train()  # Set model to training mode

else:

model.eval()   # Set model to evaluate mode

# statistics

running_loss += loss.item() * inputs.size(0)

running_corrects += torch.sum(preds == labels.data)

epoch_loss = running_loss / dataset_sizes[phase]

epoch_acc = running_corrects.double() / dataset_sizes[phase]

if(phase == ‘train’):

train_results.append([epoch_loss,epoch_acc])

if(phase == ‘valid’):

valid_results.append([epoch_loss,epoch_acc])

print(‘{} Loss: {:.4f} Acc: {:.4f}’.format(phase, epoch_l oss, epoch_acc))

# deep copy the model (Early Stopping) and Saving our model, when we get best accuracy

if phase == ‘valid’ and epoch_acc > best_acc:

best_acc = epoch_acc

best_model_wts = copy.deepcopy(model.state_dict())

model_save_name = “resnetCars.pt”

path = F”/content/drive/My Drive/{model_save_name}”

torch.save(model.state_dict(), path)

print()

# Calculating time it took for model to train

time_elapsed = time.time() – start

print(‘Training complete in {:.0f}m {:.0f}s’.format(

time_elapsed // 60, time_elapsed % 60))

print(‘Best val Acc: {:4f}’.format(best_acc))

return model,train_results,valid_results

epochs = 60

#move model to GPU

model.to(device)

model,train_results,valid_results = train_model(model, criterion, optimizer, sched, epochs)

Epoch 1/60

———-

train Loss: 0.5672 Acc: 0.8441

valid Loss: 0.6750 Acc: 0.8329

Epoch 2/60

———-

train Loss: 0.6184 Acc: 0.8357

valid Loss: 0.5980 Acc: 0.8415

Epoch 3/60

———-

train Loss: 0.5695 Acc: 0.8487

valid Loss: 0.5503 Acc: 0.8575

#### 3. 用不可视数据测试模型

model.to(device)

# import pathlib libary to get filename without the extension

from pathlib import Path

# Load the datasets with ImageFolder

test_dir = ‘car_data/test’

print(“Predictions on Test Set:”)

model.eval()

dataset = datasets.ImageFolder(test_dir,transform=data_transforms[‘test’])

shuffle=False, num_workers=2)

image_names = []

pred = []

image_names.append(Path(index[0]).stem)

results = []

file_names = []

predicted_car = []

predicted_class = []

inputs = inputs.to(device)

#labels = labels.to(device)

outputs = model(inputs)

_, pred = torch.max(outputs, 1)

for i in range(len(inputs)):

file_names.append(image_names[i])

predicted_car.append(int(pred[i] + 1))

results.append((file_names, predicted_car))

print(“Predictions on Test Set:”)

df = pd.DataFrame({‘Id’: image_names, ‘Predicted’: results})

pd.set_option(‘display.max_colwidth’, -1)

# df = df.sort_values(by=[‘Id’])

df.to_csv(‘/content/drive/My Drive/predictions.csv’)

df