主要参考的是pytorch官网的60分钟入门教程:https://pytorch.org/tutorials/beginner/blitz/cifar10_tutorial.html
pytorch版本:0.4.0
主要有以下几个部分:
零、创建的项目文件一览
一、数据提取与准备
二、模型的定义
三、定义损失函数 and
四、训练
零、创建的项目文件一览
一、数据提取与准备
说明:由于cifar-10的python版本是用pickle打包好的,因此需要手动提取。
1、官网是用封装好的函数来提取cifar-10的图片数据。
transform = transforms.Compose(
[transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
download=True, 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=True, 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')
但是在我的电脑上,当把这个数据放到网络里的时候就会报错,想要改动的话还得改动官方的封装程序。因此我还是决定自己写一个数据提取的程序,这样有错误的话也好调试。
2、我的提取程序。(就用一个batch中的文件train一下)
# ■■■■■■■■■■■ [1]、数据准备 ■■■■■■■■■■■
with open('./data/cifar-10-batches-py/data_batch_1', 'rb') as fo:
dict = pickle.load(fo, encoding='bytes') # dict是一个字典:
# dict[b'data']:存储图片数据。
# dict[b'labels']:存储标签。
print(dict[b'data'].shape) # 数据存储形式: (10000,3072)
# 提取数据集中第一张图片
cifar = dict[b'data']
cifar_labels=dict[b'labels']
cifar_trans_with_labels = []
for i,cifar_one in enumerate(cifar):
print(cifar_one.shape)
cifar_one = np.reshape(cifar_one,(3, 32, 32)) # 由于cifar存储格式的影响,只能先reshape成:(通道(RGB),长,宽)
# [图片通道变换]**
cifar_one = np.transpose(cifar_one, (0, 1, 2)) # [关键函数] 将原图片(3(RGB), 32(长), 32(宽))的通道顺序改变成(32(长), 32(宽), 3(RGB))
print('transpose之后:',cifar_one.shape)
cifar_trans_with_labels.append([cifar_one, cifar_labels[i]])
# 把 每张图片矩阵 与 对应标签 组成一个列表,再将这个列表作为一个元素,依次添加进cifar_trans_with_labels这个列表中。
# [cifar_one, cifar_labels[i]] <=> [第i+1张图片矩阵, 对应标签]
# 用PLT显示图片
# plt.imshow(cifar_one)
# plt.show()
cifar_trans_with_labels = np.array(cifar_trans_with_labels)
classes = ('plane', 'car', 'bird', 'cat',
'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
二、模型的定义
和官网的一样。
# ■■■■■■■■■■■ [2]、模型定义 ■■■■■■■■■■■
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()
(三、四部分我准备一块写了,因为我发现当loss选用MSELoss() 和 CrossEntropyLoss() 对后面把样本输入到模型那块有很大差异,好像是MSELoss() 和 CrossEntropyLoss()分别需要输入数据有不同的tensor类型和形状(具体我也没有弄明白为什么会这样),所以我准备分别写下当loss选用 MSELoss() 和 CrossEntropyLoss()时候,输入样本应该用什么样的tensor类型和形状)
三、定义损失函数 and 四、训练
△、Loss选用 MSELoss()
# ■■■■■■■■■■■ [3]、定义损失函数 ■■■■■■■■■■■
import torch.optim as optim
# criterion = nn.CrossEntropyLoss()
criterion = nn.MSELoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
# ■■■■■■■■■■■ [4]、训练 ■■■■■■■■■■■
for epoch in range(2): # loop over the dataset multiple times
running_loss = 0.0
for i, data in enumerate(cifar_trans_with_labels, 0):
# cifar_trans_with_labels中的每个元素:[cifar_one, cifar_labels[i]] <=> [第i+1张图片矩阵, 对应标签]
# —————————— 输入数据(data,labels)预备 ——————————
# 获取每张图片的 数据(data)矩阵
inputs, labels = data
inputs = torch.from_numpy(inputs) # 把numpy_array转化成torch.Tensor
inputs = inputs.float()
inputs = inputs.view(1, 3, 32, 32)
# 获取每张图片的 标签(one-hot编码)
batch_size = 1
nb_digits = 10
labels_onehot = torch.FloatTensor(batch_size, nb_digits)
labels = np.array([labels])
# print('num', i, ' labels_numpy:', labels)
labels = torch.from_numpy(labels)
labels = labels.long() # 下面的 labels_onehot.scatter_(1, labels, 1) 需要labels中的数据是long类型
labels = labels.view(1, -1) # 把labels的形状变成与模型输出形状一致的tensor形状:torch.SIZE([1,10])
# print('num', i, ' labels_torchTensor_shape:', labels.shape)
# print('num', i, ' labels_torchTensor_value:', labels)
labels_onehot.zero_()
labels_onehot.scatter_(1, labels, 1) # 把labels进行one-hot编码,输出tensor是float类型。
# print('num', i, ' labels_One-shot:', labels_onehot)
# 将梯度初始化
optimizer.zero_grad()
# —————————— 数据输入 (forward) ——————————
outputs = net(inputs)
# print('outputs:',outputs)
# print('outputs_shape:',outputs.shape)
# 计算loss
loss = criterion(outputs, labels_onehot)
# —————————— 反向传播 + 梯度优化 (backward + optimize) ——————————
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')
【实验结果】
[1, 2000] loss: 0.095
[1, 4000] loss: 0.090
[1, 6000] loss: 0.090
[1, 8000] loss: 0.090
[1, 10000] loss: 0.090
[2, 2000] loss: 0.090
[2, 4000] loss: 0.090
[2, 6000] loss: 0.090
[2, 8000] loss: 0.090
[2, 10000] loss: 0.090
Finished Training
△、Loss选用 MSELoss()
# ■■■■■■■■■■■ [3]、定义损失函数 ■■■■■■■■■■■
import torch.optim as optim
criterion = nn.CrossEntropyLoss()
# criterion = nn.MSELoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
# ■■■■■■■■■■■ [4]、训练 ■■■■■■■■■■■
for epoch in range(2): # loop over the dataset multiple times
running_loss = 0.0
for i, data in enumerate(cifar_trans_with_labels, 0):
# cifar_trans_with_labels中的每个元素:[cifar_one, cifar_labels[i]] <=> [第i+1张图片矩阵, 对应标签]
# —————————— 输入数据(data,labels)预备 ——————————
# 获取每张图片的 数据(data)矩阵
inputs, labels = data
inputs = torch.from_numpy(inputs) # 把numpy_array转化成torch.Tensor
inputs = inputs.float()
inputs = inputs.view(1, 3, 32, 32)
# 获取每张图片的 标签(one-hot编码)
batch_size = 1
nb_digits = 10
labels_onehot = torch.FloatTensor(batch_size, nb_digits)
labels = np.array([labels])
# print('num', i, ' labels_numpy:', labels)
labels = torch.from_numpy(labels)
labels = labels.long() # 下面的 labels_onehot.scatter_(1, labels, 1) 需要labels中的数据是long类型
# labels = labels.view(1, -1) # CrossEntropyLoss()不需要使用这一步,不知道为啥。。
# labels = labels.long()
# print('num', i, ' labels_torchTensor_shape:', labels.shape)
# print('num', i, ' labels_torchTensor_value:', labels)
# labels_onehot.zero_()
# labels_onehot.scatter_(1, labels, 1) # 也不需要one-hot编码,不知道为啥。。。
# labels_onehot = labels_onehot.long()
# print('num', i, ' labels_One-shot:', labels_onehot)
# 将梯度初始化
optimizer.zero_grad()
# —————————— 数据输入 (forward) ——————————
outputs = net(inputs)
# print('outputs:',outputs)
# print('outputs_shape:',outputs.shape)
# 计算loss
loss = criterion(outputs, labels)
# —————————— 反向传播 + 梯度优化 (backward + optimize) ——————————
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')
【实验结果】
[1, 2000] loss: 2.312
[1, 4000] loss: 2.305
[1, 6000] loss: 2.307
[1, 8000] loss: 2.305
[1, 10000] loss: 2.304
[2, 2000] loss: 2.305
[2, 4000] loss: 2.299
[2, 6000] loss: 2.300
[2, 8000] loss: 2.294
[2, 10000] loss: 2.304
Finished Training