本文使用18-layer结构
1导入常用的包
import time
import torch
import torchvision.transforms as transforms
import torch.nn as nn
import torchvision
import torch.nn.functional as F
2导入并处理数据
device =torch.device('cuda')
data_tansform={
'train': transforms.Compose([
transforms.ToTensor(),
transforms.Resize((224,224))]
)
,
'test':transforms.Compose([
transforms.ToTensor(),
transforms.Resize((224,224))]
)
}
train_data=torchvision.datasets.FashionMNIST(root='E:\PycharmProjects\data',train=True,transform=data_tansform['train'])
test_data=torchvision.datasets.FashionMNIST(root='E:\PycharmProjects\data',train=False,transform=data_tansform['test'])
print(len(train_data))
# 60000
batch_size=64
train_iter=torch.utils.data.DataLoader(train_data,batch_size,shuffle=True)
test_iter=torch.utils.data.DataLoader(test_data,batch_size,shuffle=True)
for x,y in train_iter:
print(x.shape)
break
# torch.Size([64, 1, 224, 224])
3构造单个残差网络Residual
class Residual(nn.Module):
def __init__(self,in_channels,out_channels,use_1x1conv=False,stride=1):
super(Residual, self).__init__()
self.conv1=nn.Conv2d(in_channels,out_channels,kernel_size=3,padding=1,stride=stride)
self.conv2=nn.Conv2d(out_channels,out_channels,kernel_size=3,padding=1)
if use_1x1conv:
self.conv3=nn.Conv2d(in_channels,out_channels,kernel_size=1,stride=stride)
else :
self.conv3=None
self.bn1=nn.BatchNorm2d(out_channels)
self.bn2=nn.BatchNorm2d(out_channels)
def forward(self,x):
y=F.relu(self.bn1(self.conv1(x)))
y=self.bn2(self.conv2(y))
if self.conv3:
x=self.conv3(x)
return F.relu(y+x)
4构造残差块
def resnet_block(in_channel,out_channel,num_residuals,first_block=False):
if first_block:
assert in_channel == out_channel
blk =[]
for i in range(num_residuals):
if i==0 and not first_block:
blk.append(Residual(in_channel,out_channel,use_1x1conv=True,stride=2))
else :
blk.append(Residual(out_channel,out_channel))
return nn.Sequential(*blk)
5构造ResNet
net = nn.Sequential(
nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3),
nn.BatchNorm2d(64),
nn.ReLU(),
nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
)
net.add_module("resnet_block1", resnet_block(64, 64, 2, first_block=True))
net.add_module("resnet_block2", resnet_block(64, 128, 2))
net.add_module("resnet_block3", resnet_block(128, 256, 2))
net.add_module("resnet_block4", resnet_block(256, 512, 2))
class GlobalAvgPool2d(nn.Module):
# 全局平均池化层可通过将池化窗口形状设置成输入的高和宽实现
def __init__(self):
super(GlobalAvgPool2d, self).__init__()
def forward(self, x):
return F.avg_pool2d(x, kernel_size=x.size()[2:])
net.add_module("global_avg_pool", GlobalAvgPool2d()) # GlobalAvgPool2d的输出: (Batch, 512, 1, 1)
net.add_module("fc", nn.Sequential(torch.nn.Flatten(), nn.Linear(512, 10)))
6训练网络
def evaluate_accuracy(data_iter,net):
with torch.no_grad():
acc_sum,n=0.0,0
net.eval()
for x,y in data_iter:
acc_sum += (net(x.to(device)).argmax(dim=1)==y.to(device)).float().sum().item()
n+=len(y)
net.train()
return acc_sum / n
net=net.to(device)
Loss=nn.CrossEntropyLoss()
optimizer=torch.optim.Adam(net.parameters())
for epoch in range(1):
acc_train,acc_test,loss=0.0,0.0,0.0
start=time.time()
n=0
for x,y in train_iter:
x=x.to(device)
y=y.to(device)
y_hat=net(x)
loss=Loss(y_hat,y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
acc_train=evaluate_accuracy(train_iter,net)
acc_test=evaluate_accuracy(test_iter,net)
print('loss=%.4f, acc_train=%.4f, acc_test=%.4f, time=%.3f' % (loss.cpu(),acc_train,acc_test,time.time()-start))
loss=0.3769, acc_train=0.8844, acc_test=0.8757, time=327.016