[ pytorch ] —— 深度学习代码框架:(1) cifar-10图像分类

主要参考的是pytorch官网的60分钟入门教程:https://pytorch.org/tutorials/beginner/blitz/cifar10_tutorial.html

pytorch版本:0.4.0


主要有以下几个部分:

    零、创建的项目文件一览

    一、数据提取与准备

    二、模型的定义

    三、定义损失函数 and 

    四、训练


零、创建的项目文件一览

[ pytorch ] —— 深度学习代码框架:(1) cifar-10图像分类_第1张图片


一、数据提取与准备

    说明:由于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











你可能感兴趣的:([ pytorch ] —— 深度学习代码框架:(1) cifar-10图像分类)