Pytorch总结
目录
使用torchvision加载并且归一化CIFAR10的训练和测试数据集
PyTorch的概述
PyTorch是一个基于Torch的Python开源机器学习库,用来提供一个具有灵活性的深度学习开发平台。它主要由Facebookd的人工智能小组开发,不仅能够实现强大的GPU加速,同时还支持动态神经网络,这一点是现在很多主流框架如TensorFlow都不支持的。 PyTorch提供了两个高级功能: 具有强大的GPU加速的张量计算(如Numpy);包含自动求导系统的深度神经网络。
Pytorch基础
PyTorch有抽象的三个层次:Tensor: 张量,类似ndarray,可在GPU上运行 。Variable:计算图中的节点;存储数据和渐变 。Module:神经网络层,可以存储状态或可学习的权重。
Tensor
Tensors 类似于 NumPy 的 ndarrays ,Tensors 可以使用 GPU 进行计算。
#导入 Pytorch
import torch
#随机初始化的矩阵
a = torch.rand(5, 3)
同时Tensor和numpy.array之间也可以相互转换。
#紧接上面代码
#导入Numpy
import numpy as np
#numpy 和 tensor相互转换
b = a.numpy()
c = np.array([1,2,3],[2,4,5])
d = torch.from_numpy(c)
与numpy一样,科学计算库非常重要的一点是能够实现高效的数学功能。
import torch
a = torch.rand(3,3)
a.t()#转置
a.pow(2)#四则运算都行
Autograd模块
Autograd 包是 PyTorch 中所有神经网络的核心。该 Autograd 软件包为 Tensors 上的所有操作提供自动微分。自动微分操作又另外一个基本元素提供,Variable:
本质上Variable和Tensor没有区别,不过Variabel会放入一个计算图,然后进行前向传播,反向传播以及自动求导一个Variable里面包含着三个属性,data,grad和creator,其中creator表示得到这个Variabel的操作,比如乘法或者加法等等,grad表示方向传播的梯度,data表示取出这个Variabel里面的数据。
#导入 pytorch的自动求导工具包在torch.autograd中
from torch.autograd import Variable
import torch
x = Variable(torch.rand(5),requires_grad = True)
y = x*2
grads = torch.FloatTensor([1,2,3,4,5])
y.backward(grads)
print(x.grad)#输出 tensor([ 2., 4., 6., 8., 10.])
Variable和tensor的区别和联系:Variable是篮子,而tensor是鸡蛋,鸡蛋应该放在篮子里才能方便拿走(定义variable时第一个参数就是tensor)。Variable这个篮子里除了装了tensor外还有requires_grad参数,表示是否需要对其求导,默认为False。Variable这个篮子呢,自身有一些属性:比如grad,梯度variable.grad是d(y)/d(variable)保存的是变量y对variable变量的梯度值,如果requires_grad参数为False,所以variable.grad返回值为None,如果为True,返回值就为对variable的梯度值;比如grad_fn,对于用户自己创建的变量(Variable()),grad_fn是为none的,也就是不能调用backward函数,但对于由计算生成的变量,如果存在一个生成中间变量的requires_grad为true,那其的grad_fn不为none,反则为none;比如data,这个就很简单,这个属性就是装的鸡蛋(tensor) 。
Autograd可以根据用户对Variable的操作来构建其计算图。对于Varialbe的属性和方法,requires_grad:variable默认是不需要被求导的,即requires_grad属性默认为False,如果某一个节点的requires_grad为True,那么所有依赖它的节点requires_grad都为True。volatile:variable的volatile属性默认为False,如果某一个variable的volatile属性被设为True,那么所有依赖它的节点volatile属性都为True。volatile属性为True的节点不会求导,volatile的优先级比requires_grad高。retain_graph:多次反向传播(多层监督)时,梯度是累加的。一般来说,单次反向传播后,计算图会free掉,也就是反向传播的中间缓存会被清空(这就是动态度的特点)。为进行多次反向传播需指定retain_graph=True来保存这些缓存。.backward()反向传播,求解Variable的梯度,放在中间缓存中。
Optim模块
Torch.optim是一个实现各种优化算法的模块,用于构建神经网络。它支持大多数常用的方法,因此我们不必从头开始构建它们。下面是使用Adam优化器的代码:
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
神经网络模块
神经网络可以通过 torch.nn 包来构建。使用torch.nn包中的工具来构建神经网络 需要以下几步:定义神经网络的权重,搭建网络结构;遍历整个数据集进行训练;将数据输入神经网络;计算loss;计算网络权重的梯度;更新网络权重,典型的用一个简单的更新方法:weight = weight - learning_rate *gradient。
先看看仅用Tensor实现的神经网络:
'''Tensors 操作 '''
import torch
dtype = torch.FloatTensor #GPU:torch.cuda.FloatTensor
N,D_in,H,D_out = 64,1000,100,10
x = torch.randn(N,D_in).type(dtype)
y = torch.randn(N,D_out).type(dtype)
w1 = torch.randn(D_in,H).type(dtype)
w2 = torch.randn(H,D_out).type(dtype)
lr = 1e-6 #学习率
for t in range(500):
#前向传递:计算预测和损失
h = x.mm(w1) #xh权重
h_relu = h.clamp(min=0) #relu激活函数
y_pred = h_relu.mm(w2)#hy权重
loss = (y_pred - y ).pow(2).sum()#损失函数L2
#反动传递:手动计算梯度
grad_y_pred =2.0 *(y_pred - y)#损失求导
grad_w2 = h_relu.t().mm(grad_y_pred)
grad_h_relu = grad_y_pred.mm(w2.t())
grad_h = grad_h_relu.clone() #clone 和copy
grad_h[h<0] = 0
grad_w1 = x.t().mm(grad_h)
#计算权重的梯度
w1 -= lr * grad_w1
w2 -= lr * grad_w2
使用Variable的自动求导后实现的:
import torch
from torch.autograd import Variable
"""from … import 语句 让你从模块中导入一个指定的部分到当前命名空间"""
""" 使用导入的项目名即可"""
class ReLU(torch.autograd.Function):
'''New Autograd Functions'''
def forward(self,x):
self.save_for_backward(x)
return x.clamp(min=0)
def backward(self,grad_y):
x, = self.saved_tensors
grad_input = grad_y.clone()
grad_input[x<0] = 0
return grad_input
'''Autograd'''
N,D_in,H,D_out = 64,1000,100,10
x = Variable(torch.randn(N,D_in),requires_grad=False)
y = Variable(torch.randn(N,D_out),requires_grad=False)#我们不希望有关数据的渐变(损失)
w1 = Variable(torch.randn(D_in,H),requires_grad=True)#想要权重的梯度
w2 = Variable(torch.randn(H,D_out),requires_grad=True)
lr = 1e-6
for t in range(500):
relu = ReLU()
j = j + 1
y_pred = relu.forward(x.mm(w1)).mm(w2)#自己创建的激活函数
# y_pred = x.mm(w1).clamp(min=0).mm(w2)
loss = (y_pred - y).pow(2).sum() #求损失
if w1.grad:#计算相对于w1和w2的损失梯度(首先为零)
w1.grad.data.zero_()
if w2.grad:
w2.grad.data.zero_()#在grad更新时,每一次运算后都需要将上一次的梯度记录清空
loss.backward()#计算梯度
w1.data -= lr * w1.grad.data #更新
w2.data -= lr * w2.grad.data
基于torch.nn 包来构建Module实现神经网络的:
'''pytorch nn
用于神经网络的高级包装
'''
import torch
from torch.autograd import Variable
N,D_in,H,D_out = 64,1000,100,10
x = Variable(torch.randn(N,D_in))
y = Variable(torch.randn(N,D_out),requires_grad= False)
model = torch.nn.Sequential(
torch.nn.Linear(D_in,H),
torch.nn.ReLU(),
torch.nn.Linear(H,D_out)
)
'''
将我们的模型定义为一系列层
nn还定义了常见的损失函数
'''
loss_fn = torch.nn.MSELoss(size_average=False)
# A reduce = False,返回向量形式的 loss
# B reduce = True, 返回标量形式的loss
# C size_average = True,返回 loss.mean();
# D 如果 size_average = False,返回 loss.sum()
# 默认情况下:两个参数都为True.
lr = 1e-4
'''
PyTorch: optim
'''
#对不同的更新规则使用优化器
optimizer = torch.optim.Adam(model.parameters(),lr = lr)
'''使用optim'''
for t in range(500):
y_pred = model(x)
loss = loss_fn(y_pred,y)
optimizer.zero_grad() #区别 model.zero_grad()
loss.backward()
optimizer.step()#计算梯度后更新所有参数
'''
Pytorch DataLoaders
DataLoader包装数据集,并为您提供小型化,多线程
当您需要加载自定义数据时,只需编写自己的Dataset类
'''
import torch
from torch.autograd import Variable
from torch.utils.data import TensorDataset,DataLoader
'''
基于nn
Define New Modules
PyTorch模块是一个神经网络层; 它输入和输出变量
模块可以包含权重(作为变量)或其他模块
您可以使用自动格式定义自己的模块!
'''
class TwoLayerNet(torch.nn.Module):
'''将我们的整个模型定义为单个模块'''
def __init__(self,D_in,D_out,H):
'''初始化器设置两个子项(模块可以包含模块'''
super(TwoLayerNet,self).__init__()
self.linear1 = torch.nn.Linear(D_in,H)
self.linear2 = torch.nn.Linear(H,D_out)
def forward(self):
'''使用子模块定义转发,并在变量上自动格式化操作无需定义向后 - 自动调整将处理它'''
h_relu = self.linear1(x).clamp(min = 0)
y_pred = self.linear2(h_relu)
return y_pred
N,D_in,H,D_out = 64,1000,100,10
x = torch.randn(N,D_in)
y = torch.randn(N,D_out)
loader = DataLoader(TensorDataset(x,y),batch_size= 8)
'''构建和训练我们的模型实例'''
module1 = TwoLayerNet(D_in,D_out,H)
loss_fn = torch.nn.MSELoss(size_average=False)
optimizer = torch.optim.SGD(module1.parameters(),lr=1e-4)
for epoch in range(10):
for x_batch, y_batch in loader:
"""在装载机上迭代形成小批量
装载机给定标,所以你需要包装变量
"""
x_var,y_var = Variable(x),Variable(y)
y_pred = module1(x)
loss = loss_fn(y_pred,y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
Torchvision模块
Torchvision包服务于PyTorch框架,包括了计算机视觉中一些流行的数据集、网络模型以及常见的图片变换方法,主要由以下几部分构成:torchvision.datasets
: 一些加载数据的函数和常用的数据集接口;torchvision.models
:包含常用的模型结构(含预训练模型);torchvision.transforms
:常见的图片变换,如裁剪、旋转等;torchvision.utils
:其它一些有用的方法。
'''
Pytorch
预训练模型
'''
import torch
import torchvision
#PyTorch框架中torchvision模块下有:torchvision.datasets、torchvision.models、torchvision.transforms这3个子包。
'''此模块下有常用的 alexnet、densenet、inception、resnet、squeezenet、vgg(关于网络详情请查看)等常用的网络结构,
并且提供了预训练模型,我们可以通过简单调用来读取网络结构和预训练模型,同时使用fine tuning(微调)来使用。'''
alexnet = torchvision.models.alexnet(pretrained=True)
vgg16 = torchvision.models.vgg16(pretrained=True)
resnet101 = torchvision.models.resnet101(pretrained=True)
Pytorch小实战
图像分类
使用torchvision加载并且归一化CIFAR10的训练和测试数据集
加载并归一化 CIFAR10 使用 torchvision。CIFAR10数据集,它包含十个类别:‘airplane’, ‘automobile’, ‘bird’, ‘cat’, ‘deer’, ‘dog’, ‘frog’, ‘horse’, ‘ship’, ‘truck’。CIFAR-10 中的图像尺寸为33232,也就是RGB的3层颜色通道,每层通道内的尺寸为32*32。torchvision 数据集的输出是范围在[0,1]之间的 PILImage,要转换成归一化范围为[-1,1]之间的张量 Tensors。
import torch
import torchvision
import torchvision.transforms as transforms
#
# #加载并归一化 CIFAR10 使用 torchvision ,用它来加载 CIFAR10 数据非常简单
transform = transforms.Compose(
[transforms.ToTensor(),#range 0~1
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])#(channel-mean)/std 因为是RGB (x-0.5)/0.5 range -1~1
trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
download=False, transform=transform)# 我是本地下载的数据集 不需要从网上再下载了
trainloader = torch.utils.data.DataLoader(trainset, batch_size=4,
shuffle=True, num_workers=2)
testset = torchvision.datasets.CIFAR10(root='./data', train=False,
download=False, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=4,
shuffle=False, num_workers=2)
classes = ('plane', 'car', 'bird', 'cat',
'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
print("Initializing Datasets and Dataloaders...")
本地离线下载的数据集,需要在文件cifar.py 修改 url 成本地路径才行。
base_folder = 'cifar-10-batches-py'
# url = "https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz"
url ="file:///D:/python_ducment/Python_Project/Pytorch/data/cifar-10-python.tar.gz" #修改为你自己的本地路径
filename = "cifar-10-python.tar.gz"
tgz_md5 = 'c58f30108f718f92721af3b95e74349a'
train_list = [
['data_batch_1', 'c99cafc152244af753f735de768cd75f'],
['data_batch_2', 'd4bba439e000b95fd0a9bffe97cbabec'],
['data_batch_3', '54ebc095f3ab1f0389bbae665268c751'],
['data_batch_4', '634d18415352ddfa80567beed471001a'],
['data_batch_5', '482c414d41f54cd18b22e5b47cb7c3cb'],
]
定义一个卷积神经网络和损失函数
import torch.nn as nn
import torch.nn.functional as F
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(3, 6, 5)
self.pool = nn.MaxPool2d(2, 2)
self.conv2 = nn.Conv2d(6, 16, 5)
self.fc1 = nn.Linear(16 * 5 * 5, 120)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self, x):
x = self.pool(F.relu(self.conv1(x)))
x = self.pool(F.relu(self.conv2(x)))
x = x.view(-1, 16 * 5 * 5)
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
net = Net()
import torch.optim as optim
#定义一个损失函数和优化器 让我们使用分类交叉熵Cross-Entropy 作损失函数,动量SGD做优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
在训练样本数据上训练网络
数据迭代器上循环传给网络和优化器输入测试集数据。通过训练数据集对网络进行了2次训练。
for epoch in range(2): # loop over the dataset multiple times
running_loss = 0.0
for i, data in enumerate(trainloader, 0):
# get the inputs
inputs, labels = data
# zero the parameter gradients
optimizer.zero_grad()
# forward + backward + optimize
outputs = net(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
# print statistics
running_loss += loss.item()
if i % 2000 == 1999: # print every 2000 mini-batches
print('[%d, %5d] loss: %.3f' %
(epoch + 1, i + 1, running_loss / 2000))
running_loss = 0.0
print('Finished Training')
在测试样本数据上测试网络
将用神经网络的输出作为预测的类标来检查网络的预测性能,用样本的真实类标来校对。如果预测是正确的,将样本添加到正确预测的列表里。先展示图片
import matplotlib.pyplot as plt
import numpy as np
# functions to show an image
def imshow(img):
img = img / 2 + 0.5 # unnormalize
npimg = img.numpy()
plt.imshow(np.transpose(npimg, (1, 2, 0)))#顺序是0 12 对于的位置xyz
'''因为在plt.imshow在现实的时候输入的是(imagesize,imagesize,channels)imshow中,参数img的格式为(channels,imagesize,imagesize),这两者的格式不一致,我们需要调用一次np.transpose函数'''
plt.show()
# get some random testing images
dataiter = iter(testloader)#iter() 函数用来生成迭代器。
images, labels = dataiter.next()
# show images
imshow(torchvision.utils.make_grid(images))
# print labels
print('GroundTruth:'+ ' '.join('%5s' % classes[labels[j]] for j in range(4)))
outputs = net(images)# 将测试集图片放入神经网络 这些样本应该预测成什么
_, predicted = torch.max(outputs, 1) #输出是预测与十个类的近似程度,与某一个类的近似程度越高,网络就越认为图像是属于这一类别。
print('Predicted: ', ' '.join('%5s' % classes[predicted[j]] for j in range(4)))
看看网络在整个数据集上的表现
correct = 0
total = 0
with torch.no_grad():
for data in testloader:
images, labels = data
outputs = net(images)
_, predicted = torch.max(outputs.data, 1)#dim是max函数索引的维度0/1,0是每列的最大值,1是每行的最大值
total += labels.size(0)
correct += (predicted == labels).sum().item()
print('Accuracy of the network on the 10000 test images: %d %%' % (
100 * correct / total))
'''分类看准确率'''
class_correct = list(0. for i in range(10))
class_total = list(0. for i in range(10))
with torch.no_grad():
for data in testloader:
images, labels = data
outputs = net(images)
_, predicted = torch.max(outputs, 1)
c = (predicted == labels).squeeze()#squeeze()函数将表示向量的数组转换为秩为1的数组
for i in range(4):
label = labels[i]
class_correct[label] += c[i].item()
class_total[label] += 1
for i in range(10):
print('Accuracy of %5s : %2d %%' % (
classes[i], 100 * class_correct[i] / class_total[i]))
迁移学习
微调Convnet
使用预训练的网络来初始化自己的网络,而不是随机初始化。其他的训练步骤不变。
-
导入相关的包
import torch
import torch.nn as nn
import torch.optim as optim
from torch.optim import lr_scheduler
import numpy as np
import torchvision
from torchvision import datasets, models, transforms
import matplotlib.pyplot as plt
import time
import os
import copy
plt.ion() # interactive mode
'''因为python可视化库matplotlib的显示模式默认为阻塞(block)模式。什么是阻塞模式那?
我的理解就是在plt.show()之后,程序会暂停到那儿,并不会继续执行下去。
如果需要继续执行程序,就要关闭图片。那如何展示动态图或多个窗口呢?
这就要使用plt.ion()这个函数,使matplotlib的显示模式转换为交互(interactive)模式。
即使在脚本中遇到plt.show(),代码还是会继续执行'''
-
加载数据
训练一个模型来分类蚂蚁ants和蜜蜂bees。ants和bees各有约120张训练图片。每个类有75张验证图片。离线下载数据集,并解压到目录下。
#训练集数据扩充和归一化
#在验证集上仅需要归一化
data_transforms = {
'train': transforms.Compose([
transforms.RandomResizedCrop(224), #随机裁剪一个area然后再resize
transforms.RandomHorizontalFlip(), #随机水平翻转
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),
'val': transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),
}
data_dir = 'data/hymenoptera_data'
image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x),
data_transforms[x])
for x in ['train', 'val']}
dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size=4,
shuffle=True, num_workers=4)
for x in ['train', 'val']}
dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'val']}
class_names = image_datasets['train'].classes
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
-
可视化部分图像数据
可视化部分训练图像,以便了解数据扩充。
def imshow(inp, title=None):
"""Imshow for Tensor."""
inp = inp.numpy().transpose((1, 2, 0))
mean = np.array([0.485, 0.456, 0.406])
std = np.array([0.229, 0.224, 0.225])
inp = std * inp + mean # unnormalize
inp = np.clip(inp, 0, 1) #截取数组中0~1的部分
plt.imshow(inp)
if title is not None:
plt.title(title)
plt.pause(0.001) # pause a bit so that plots are updated
# 获取一批训练数据
inputs, classes = next(iter(dataloaders['train']))
# 批量制作网格
out = torchvision.utils.make_grid(inputs)
imshow(out, title=[class_names[x] for x in classes])
-
训练模型
编写一个通用函数来训练模型:调整学习率;保存最优模型。
def train_model(model, criterion, optimizer, scheduler, num_epochs=25):
since = time.time()
best_model_wts = copy.deepcopy(model.state_dict())#copy 模块的 deepcopy 方法,完全拷贝了父对象及其子对象
best_acc = 0.0
for epoch in range(num_epochs):
print('Epoch {}/{}'.format(epoch, num_epochs - 1))
print('-' * 10)
# 每个epoch都有一个训练和验证阶段
for phase in ['train', 'val']:
if phase == 'train':
#scheduler.step()
model.train() # Set model to training mode
else:
model.eval() # Set model to evaluate mode
running_loss = 0.0
running_corrects = 0
# 迭代数据.
for inputs, labels in dataloaders[phase]:
inputs = inputs.to(device)
labels = labels.to(device)
# 零参数梯度
optimizer.zero_grad()
# 前向
# track history if only in train
with torch.set_grad_enabled(phase == 'train'):
outputs = model(inputs)
_, preds = torch.max(outputs, 1)
loss = criterion(outputs, labels)
# 后向+仅在训练阶段进行优化
if phase == 'train':
loss.backward()
optimizer.step()
# 统计
running_loss += loss.item() * inputs.size(0)
running_corrects += torch.sum(preds == labels.data)
if phase == 'train':
scheduler.step()
epoch_loss = running_loss / dataset_sizes[phase]
epoch_acc = running_corrects.double() / dataset_sizes[phase]
print('{} Loss: {:.4f} Acc: {:.4f}'.format(
phase, epoch_loss, epoch_acc))
# 深度复制mo
if phase == 'val' and epoch_acc > best_acc:
best_acc = epoch_acc
best_model_wts = copy.deepcopy(model.state_dict())
time_elapsed = time.time() - since
print('Training complete in {:.0f}m {:.0f}s'.format(
time_elapsed // 60, time_elapsed % 60))
print('Best val Acc: {:4f}'.format(best_acc))
# 加载最佳模型权重
model.load_state_dict(best_model_wts)
return model
-
可视化模型的预测结果
展示部分预测图像的通用函数
#一个通用的展示少量预测图片的函数
def visualize_model(model, num_images=6):
was_training = model.training
model.eval()
images_so_far = 0
fig = plt.figure()
with torch.no_grad():
for i, (inputs, labels) in enumerate(dataloaders['val']):
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 += 1
ax = plt.subplot(num_images//2, 2, images_so_far)
ax.axis('off')
ax.set_title('predicted: {}'.format(class_names[preds[j]]))
imshow(inputs.cpu().data[j])
if images_so_far == num_images:
model.train(mode=was_training)
return
model.train(mode=was_training)
- 训练和评估模型
加载预训练模型并重置最终完全连接的图层,训练和评估模型。
model_ft = models.resnet18(pretrained=False)
model_ft.load_state_dict(torch.load('D:/python_ducment/Python_Project/Pytorch/weight/resnet18-5c106cde.pth'))
num_ftrs = model_ft.fc.in_features
model_ft.fc = nn.Linear(num_ftrs, 2)
model_ft = model_ft.to(device)
criterion = nn.CrossEntropyLoss()
# 观察所有参数都正在优化
optimizer_ft = optim.SGD(model_ft.parameters(), lr=0.001, momentum=0.9)
# 每7个epochs衰减LR通过设置gamma=0.1
exp_lr_scheduler = lr_scheduler.StepLR(optimizer_ft, step_size=7, gamma=0.1)
model_ft = train_model(model_ft, criterion, optimizer_ft, exp_lr_scheduler,
num_epochs=25)
# #模型评估效果可视化
visualize_model(model_ft)
plt.ioff()
plt.show()
将Convnet看成固定的特征提取器
首先固定ConvNet除了最后的全连接层外的其他所有层。最后的全连接层被替换成一个新的随机 初始化的层,只有这个新的层会被训练[只有这层参数会在反向传播时更新]
前面与微调一样,只需要冻结除最后一层之外的所有网络。通过设置requires_grad == Falsebackward()
来冻结参数,这样在反向传播backward()的时候他们的梯度就不会被计算。
model_ft = models.resnet18(pretrained=False)
model_ft.load_state_dict(torch.load('D:/python_ducment/Python_Project/Pytorch/weight/resnet18-5c106cde.pth'))
for param in model_conv.parameters():
param.requires_grad = False
# Parameters of newly constructed modules have requires_grad=True by default
num_ftrs = model_conv.fc.in_features
model_conv.fc = nn.Linear(num_ftrs, 2)
model_conv = model_conv.to(device)
criterion = nn.CrossEntropyLoss()
# Observe that only parameters of final layer are being optimized as
# opposed to before.
optimizer_conv = optim.SGD(model_conv.fc.parameters(), lr=0.001, momentum=0.9)
# Decay LR by a factor of 0.1 every 7 epochs
exp_lr_scheduler = lr_scheduler.StepLR(optimizer_conv, step_size=7, gamma=0.1)
model_conv = train_model(model_conv, criterion, optimizer_conv,
exp_lr_scheduler, num_epochs=25)
visualize_model(model_conv)
plt.ioff()
plt.show()