![](https://img-blog.csdnimg.cn/20210929205255783.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5rKZ6ZuV5Ye6546w5LqG,size_20,color_FFFFFF,t_70,g_se,x_16)
网络:
import torch
from torch import nn
from torch.nn import functional as F
class Lenet5(nn.Module):
"""
for cifar 10 dataset
"""
def __init__(self):
super(Lenet5, self).__init__()
self.conv_unit = nn.Sequential(
# x: [b, 3, 32, 32] => [b, 6, ]
nn.Conv2d(3, 6, kernel_size=5, stride=1, padding=0),
nn.AvgPool2d(kernel_size=2, stride=2, padding=0),
nn.Conv2d(6, 16, kernel_size=5, stride=1, padding=0),
nn.AvgPool2d(kernel_size=2, stride=2, padding=0),
)
#flatten
#fc unit
self.fc_unit = nn.Sequential(
nn.Linear(16*5*5, 120),
nn.ReLU(),
nn.Linear(120, 84),
nn.ReLU(),
nn.Linear(84,10)
)
# 表示一个随机生成的tensor[b, 3, 32, 32]
temp = torch.randn(2,3,32,32)
out = self.conv_unit(temp)
# [2, 16, 5, 5] 这属于测试了conv_unit的输出,那么flatten的数据就是16*5*5
print('conv_out:', out.shape)
# use 交叉熵损失
#self.criteon = nn.MSELoss()
#分类问题使用交叉熵,逼近使用MSE
self.criteon = nn.CrossEntropyLoss()
#这一整个函数直接包括了softmax过程+计算loss
#backward不用写,往前走一遍,pytorch自动记录往前的路径,bk会自动往回走
def forward(self, x):
"""
:param x: [b, 3, 32, 32]
:return:
"""
batchsz = x.size(0)
# size 返回一个list,[b, 3, 32, 32],取第0个,就是b
# [b, 32, 32, 32] => [b, 16, 5, 5]
x = self.conv_unit(x)
# [b, 16, 5, 5] => [b, 16*5*5]
#x = x.view(batchsz, -1)
x = x.view(batchsz, 16*5*5) #这样更严谨,这样后面不一样就会报错
# [b, 16*5*5] => [b, 10]
logits = self.fc_unit(x)
# softmax前一个变量称为logits
# loggits: [b, 10]
# pred = F.softmax(logits, dim=1)
# loss = self.criteon(logits, y)
return logits
def main():
net = Lenet5()
temp = torch.randn(2, 3, 32, 32)
out = net(temp)
# [2, 16, 5, 5] 这属于测试了conv_unit的输出,那么flatten的数据就是16*5*5
print('lenet_out:', out.shape)
if __name__ == '__main__':
main()
加载数据集
def main():
batchsz = 32
#太小就不稳定了,梯度计算是把当前batchsize的平均方向作为update的方向,太小就会具有随机性
cifar_train = datasets.CIFAR10('cifar',True, transform=transforms.Compose([
transforms.Resize((32, 32)),
transforms.ToTensor()
]), download=True)
cifar_train = DataLoader(cifar_train, batch_size=batchsz, shuffle=True)
cifar_test = datasets.CIFAR10('cifar', False, transform=transforms.Compose([
transforms.Resize((32, 32)),
transforms.ToTensor()
]), download=True)
cifar_test = DataLoader(cifar_test, batch_size=batchsz, shuffle=True)
#########注意,第一个别填错,一开始天了cifar_train,也就是会去这边索引,但是呢,这个是个dataloader,是无法索引的!!
x, label = iter(cifar_train).next()
# inter把dataload的迭代器得到,使用next方法得到一个batch
print('x:', x.shape, 'label', label.shape)
训练、测试
device = torch.device('cuda')
model = Lenet5().to(device)
print(model)
criteon = nn.CrossEntropyLoss().to(device)
optimizer = optim.Adam(model.parameters(), lr=1e-3)
for epoch in range(1000):
model.train()
for batchidx, (x, label) in enumerate(cifar_train):
# [b,3,32,32]
# [b]
x, label = x.to(device), label.to(device)
logits = model(x)
# logits:[b,10]
# label: [b]
# loss: tensor scalar 长度为0的标量
loss = criteon(logits, label)
# backprop
optimizer.zero_grad()
loss.backward()
optimizer.step()
#对于标量,用item转化为numpy打印
print(epoch, loss.item())
model.eval()
with torch.no_grad():
# test 不需要计算梯度可以把它包在with里面,告诉计算机,不需要做backward
total_correct = 0
total_num = 0
for x, label in cifar_test:
x, label = x.to(device), label.to(device)
#[b,10]
logits = model(x)
#输出在一维上面数据最大值所在的索引,索引是0~9
##dim = 1指定列,也就是行不变,列之间的比较
pred = logits.argmax(dim=1)
# [b] vs [b] => scalar tensor
#[2] [2] [1]
#[1] eq [2] => [0] sum => 1 这是一个三行一列的tensor
#[2] [0] [0]
total_correct += torch.eq(pred, label).float().sum().item()
#item是转化为numpy的意思
total_num += x.size(0)
acc = total_correct / total_num
print(epoch, acc)
if __name__ == '__main__':
main()