AlexNet总共包含8层变换,分别为5层卷积层、2个全连接层和一个全连接输出层
import time
import torch
from torch import nn, optim
import torchvision
import sys
# 如果有gpu计算设备,选择gpu计算设备,否则选择在cpu上训练
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
device
class AlexNet(nn.Module):
def __init__(self):
super(AlexNet, self).__init__()
# 卷积层
self.conv = nn.Sequential(
# 第一层卷积
# 如果使用mnist类的数据集,输入通道为1,如果使用的cifar等彩色图像的数据集,输入通道为3
nn.Conv2d(3, 96, 11, 4),
nn.ReLU(),
nn.MaxPool2d(3, 2),
# 第二层卷积,开始减小卷积窗口
nn.Conv2d(96, 256, 5, 1, 2),
nn.ReLU(),
nn.MaxPool2d(3, 2),
# 第三层卷积
nn.Conv2d(256, 384, 3, 1, 1),
nn.ReLU(),
# 第四层卷积
nn.Conv2d(384, 384, 3, 1, 1),
nn.ReLU(),
# 第五层卷积
nn.Conv2d(384, 256, 3, 1, 1),
nn.ReLU(),
nn.MaxPool2d(3, 2)
)
self.fc = nn.Sequential(
# 第一层全连接层
nn.Linear(256*5*5, 4096),
nn.ReLU(),
nn.Dropout(0.5),
# 第二层全连接层
nn.Linear(4096, 4096),
nn.ReLU(),
nn.Dropout(0.5),
# 第三层全连接层(输出层)
nn.Linear(4096, 10)
)
def forward(self, x):
x = self.conv(x)
x = self.fc(x.view(x.shape[0], -1))
return x
alexnet = AlexNet()
alexnet
def load_data(batch_size, resize=None, root='./data/CIFAR10'):
trans = []
if resize:
trans.append(torchvision.transforms.Resize(size=resize))
trans.append(torchvision.transforms.ToTensor())
transform = torchvision.transforms.Compose(trans)
# torchvision.datasets包内还有许多其他的数据集,只需要修改网络的输入通道数和输出类别数即可
data_train = torchvision.datasets.CIFAR10(root=root, train=True, download=True, transform=transform)
data_test = torchvision.datasets.CIFAR10(root=root, train=False, download=True, transform=transform)
if sys.platform.startswith('win'):
num_workers = 0 # 0表示不用额外的进程来加速读取数据
else:
num_workers = 4
train_iter = torch.utils.data.DataLoader(data_train, batch_size=batch_size, shuffle=True, num_workers=num_workers)
test_iter = torch.utils.data.DataLoader(data_test, batch_size=batch_size, shuffle=False, num_workers=num_workers)
return train_iter, test_iter
# batchsize可以根据电脑的实际情况进行修改
batchsize = 128
# 由于imagenet数据集图片的形状为224*224,所以需要将输入的图片resize为224*224
train_iter, test_iter = load_data(batch_size=batchsize, resize=224)
# lr, num_epochos可以根据实际情况进行修改
lr, num_epochos = 0.001, 5
# 优化算法采用Adam算法,也可以选择torch.optim包下其他的优化算法
optimizer = torch.optim.Adam(alexnet.parameters(), lr=lr)
def train(train_iter, test_iter, net, optimizer, device, num_epochs):
# 将网络部署在gpu设备上
net = net.to(device)
print("training on", device)
# 交叉熵
loss = torch.nn.CrossEntropyLoss()
batch_count = 0
for epoch in range(num_epochs):
train_l_sum, train_acc_sum, n, start = 0.0, 0.0, 0, time.time()
for X, y in train_iter:
# 输入的属性
X = X.to(device)
# 标签
y = y.to(device)
# 预测
y_hat = net(X)
# 计算损失
l = loss(y_hat, y)
# 梯度下降
optimizer.zero_grad()
l.backward()
optimizer.step()
train_l_sum += l.cpu().item()
train_acc_sum += (y_hat.argmax(dim=1) == y).sum().cpu().item()
n += y.shape[0]
batch_count += 1
# 测试集的准确率
test_acc = evaluate_accuracy(test_iter, net)
print('epoch {}, loss {:.4f}, train acc {:.4f}, test acc{:.4f}, time {:.2f} sec'
.format(epoch + 1, train_l_sum / batch_count, train_acc_sum / n, test_acc, time.time() - start))
# 评估模型在测试集的表现
def evaluate_accuracy(data_iter, net, device=None):
if device is None and isinstance(net, torch.nn.Module):
# 如果没指定device就使用net的device
device = list(net.parameters())[0].device
acc_sum, n = 0.0, 0
with torch.no_grad():
for X, y in data_iter:
if isinstance(net, torch.nn.Module):
# 评估模式, 关闭dropout
net.eval()
acc_sum += (net(X.to(device)).argmax(dim=1) == y.to(device)).float().sum().cpu().item()
# 改回训练模式
net.train()
else:
if ('is_training' in net.__code__.co_varnames): # 如果有is_training这个参数
# 将is_training设置成False
acc_sum += (net(X, is_training=False).argmax(dim=1) == y).float().sum().item()
else:
acc_sum += (net(X).argmax(dim=1) == y).float().sum().item()
n += y.shape[0]
return acc_sum / n
train(train_iter=train_iter, test_iter=test_iter, net=alexnet, optimizer=optimizer,
device=device,num_epochs=num_epochos)
%matplotlib inline
import os
import time
import torch
from torch import nn, optim
import torch.nn.functional as F
from torch.utils.data import Dataset, DataLoader
import torchvision
from IPython import display
from matplotlib import pyplot as plt
from PIL import Image
os.environ["CUDA_VISIBLE_DEVICES"] = "0"
import sys
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
device
# 读取图片
display.set_matplotlib_formats('svg')
plt.rcParams['figure.figsize'] = (3.5, 2.5)
img = Image.open('./dog.jpg')
plt.imshow(img)
def show_images(imgs, num_rows, num_cols, scale=2):
figsize = (num_cols * scale, num_rows * scale)
_, axes = d2l.plt.subplots(num_rows, num_cols, figsize=figsize)
for i in range(num_rows):
for j in range(num_cols):
axes[i][j].imshow(imgs[i * num_cols + j])
axes[i][j].axes.get_xaxis().set_visible(False)
axes[i][j].axes.get_yaxis().set_visible(False)
return axes
def apply(img, aug, num_rows=2, num_cols=4, scale=1.5):
Y = [aug(img) for _ in range(num_rows * num_cols)]
show_images(Y, num_rows, num_cols, scale)
# 一半概率的图像左右翻转
apply(img, torchvision.transforms.RandomHorizontalFlip())
# 一半概率的图像上下翻转
apply(img, torchvision.transforms.RandomVerticalFlip())
# 随机选取图像中10%-50%的区域,区域的宽和高之比为0.5-2,将该区域缩放到200像素
shape_aug = torchvision.transforms.RandomResizedCrop(200, scale=(0.1, 0.5), ratio=(0.5, 2))
apply(img, shape_aug)
# 将图像的亮度随机变化为源图像的50%
apply(img, torchvision.transforms.ColorJitter(brightness=0.5))
# 将图像的色调随机变化为源图像的50%
apply(img, torchvision.transforms.ColorJitter(hue=0.5))
# 将图像的对比度随机变化为源图像的50%
apply(img, torchvision.transforms.ColorJitter(contrast=0.5))
# 同时设置修改亮度,色调,对比度
# 将图像的亮度随机变化为源图像的50%
apply(img, torchvision.transforms.ColorJitter(
brightness=0.5, hue=0.5, contrast=0.5))
augs = torchvision.transforms.Compose([
torchvision.transforms.RandomHorizontalFlip(),
torchvision.transforms.ColorJitter(
brightness=0.5, hue=0.5, contrast=0.5),
torchvision.transforms.RandomResizedCrop(200, scale=(0.1, 0.5), ratio=(0.5, 2))
])
apply(img, augs)
在读取数据函数load_data里面添加图像增广的方法
def load_data(batch_size, resize=None, root='./data/CIFAR10'):
trans = []
if resize:
trans.append(torchvision.transforms.Resize(size=resize))
# 根据实际情况添加图像增广的方法
trans.append(torchvision.transforms.RandomHorizontalFlip())
trans.append(torchvision.transforms.ToTensor())
transform = torchvision.transforms.Compose(trans)
data_train = torchvision.datasets.CIFAR10(root=root, train=True, download=True, transform=transform)
data_test = torchvision.datasets.CIFAR10(root=root, train=False, download=True, transform=transform)
if sys.platform.startswith('win'):
num_workers = 0 # 0表示不用额外的进程来加速读取数据
else:
num_workers = 4
train_iter = torch.utils.data.DataLoader(data_train, batch_size=batch_size, shuffle=True, num_workers=num_workers)
test_iter = torch.utils.data.DataLoader(data_test, batch_size=batch_size, shuffle=False, num_workers=num_workers)
return train_iter, test_iter
pytorch继承好了许多预训练的模型,这些的模型的参数已经十分优秀了,对于
使用热狗数据集进行测试点击下载
import os
data_dir = './data'
os.listdir(os.path.join(data_dir, 'hotdog'))
alexnet.classifier
选择其他预训练的模型基本操作都是相同的,把最后一层的输出改成实际需要的输出
alexnet.classifier = nn.Sequential(
# 第一层全连接层
nn.Linear(9216, 4096),
nn.ReLU(),
nn.Dropout(0.5),
# 第二层全连接层
nn.Linear(4096, 4096),
nn.ReLU(),
nn.Dropout(0.5),
# 第三层全连接层(输出层)
nn.Linear(4096, 10)
)
alexnet.classifier
output_params = list(map(id, alexnet.classifier.parameters()))
features_params = filter(lambda p: id(p) not in output_params, alexnet.parameters())
lr = 0.01
optimizer = optim.Adam([
{'params': features_params},
{'params': alexnet.classifier.parameters(), 'lr': lr * 100}
], lr=lr, weight_decay=0.001)
from torchvision import transforms
normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
train_augs = transforms.Compose([
transforms.RandomResizedCrop(size=224),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
normalize
])
test_augs = transforms.Compose([
transforms.Resize(size=256),
transforms.CenterCrop(size=224),
transforms.ToTensor(),
normalize
])
from torch.utils.data import Dataset, DataLoader
from torchvision.datasets import ImageFolder
def train_fine_tuning(net, optimizer, batch_size=5, num_epochs=5):
train_iter = DataLoader(ImageFolder(os.path.join(data_dir, 'hotdog/train'), transform=train_augs),
batch_size, shuffle=True)
test_iter = DataLoader(ImageFolder(os.path.join(data_dir, 'hotdog/test'), transform=test_augs),
batch_size)
train(train_iter, test_iter, net, optimizer, device, num_epochs)
train_fine_tuning(alexnet, optimizer)