1. 程式人生 > >[深度學習]使用torchvison經典模型訓練cifar10(AlexNet,VGG,ResNet等)

[深度學習]使用torchvison經典模型訓練cifar10(AlexNet,VGG,ResNet等)

而我想看看torchvison裡經典模型的效能如何,所以就做了一些修改。因為torchvison是在imagenet上訓練,所以對於輸入輸出的大小需要修改,cifar10比imagenet資料簡單得多,而且可以直接從網上下載而不用申請。

最好是在jupyter notebook上執行。推薦谷歌的conlab免費的GPU服務,可以自己百度怎麼使用。

首先是匯入必要的 包,看一下當前是否具備gpu cuda環境,程式碼在cpu也能執行。

import torch
import torchvision
import torchvision.transforms as transforms


# Assume that we are on a CUDA machine, then this should print a CUDA device:
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

  
print(device)

然後transfrom是對資料集進行預處理,它可以是多個操作,resize是為了匹配imagenet的輸入大小,本來cifar10的資料集只有32*32,為了匹配(256*256)就要resize。 後面還有totensor變成張量和normalize歸一化處理。

torchvision.datasets.CIFAR10是torchvison為我們寫好,可以下載資料集到指定的root路徑,具體的引數可以去官網上找,其實也不難理解,train就是是否為訓練資料,shuffle是否洗牌,num_workers是多少個程序一起工作,0就是隻有一個程序。

loader可以看做是一個容器,把訓練和測試的資料放入一個容器裡,後面會根據batchsize大小取出來。

classes裡面代表了分類的類別有哪些。

transform = transforms.Compose(
    [transforms.Resize(252),
     transforms.ToTensor(),
     transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])

batch_size = 8

trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
                                        download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=batch_size,
                                          shuffle=True, num_workers=0)

testset = torchvision.datasets.CIFAR10(root='./data', train=False,
                                       download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=batch_size,
                                         shuffle=False, num_workers=0)

classes = ('plane', 'car', 'bird', 'cat',
           'deer', 'dog', 'frog', 'horse', 'ship', 'truck')

下面這一段是我們可以看一下其中一個batch是什麼樣子的圖片。注意在imshow之前不能把資料傳入cuda(如果用gpu),因為imshow只能響應cpu裡面的tensor。 

import matplotlib.pyplot as plt
import numpy as np

# functions to show an image


def imshow(img):
    img = img / 2 + 0.5     # unnormalize
    npimg = img.numpy()
    plt.imshow(np.transpose(npimg, (1, 2, 0)))


# get some random training images
dataiter = iter(trainloader)
images, labels = dataiter.next()


# show images
imshow(torchvision.utils.make_grid(images))
# print labels
print(' '.join('%5s' % classes[labels[j]] for j in range(batch_size)))
images, labels = images.to(device), labels.to(device)

結果是這樣的。

這裡就是我們使用經典的models定義神經網路了,關於原始碼的解讀你可以檢視我的部落格:

【1】pytorch torchvision原始碼解讀之Alexnet

【2】pytorch torchvision原始碼解讀之VGG 

【3】pytorch torchvision原始碼解讀之Inception V3

【4】pytorch torchvision原始碼解讀之ResNet

請注意,因為是十分類,所以num_classes=10,imagenet訓練的原始模型都是1000分類輸出的。

import torch.nn as nn
import torch.nn.functional as F


# net = torchvision.models.alexnet(num_classes = 10)

# net = torchvision.models.vgg11(num_classes = 10)

# net = torchvision.models.inception_v3(num_classes = 10)

# net = torchvision.models.resnet18(num_classes = 10)

net = torchvision.models.densenet121(num_classes = 10)


net.to(device)

 定義損失函式,你也可以嘗試不同的,adam等等。

import torch.optim as optim

criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.01, momentum=0.9)

接下來就是訓練的過程了,第一個迴圈就是遍歷多少次資料集,第二個迴圈就是對於每一個minibatch做數值前向傳播梯度反向傳播的過程,然後就是權重的更新。每兩百個minibatch就輸出一次loss。

for epoch in range(10):  # loop over the dataset multiple times

    running_loss = 0.0
    for i, data in enumerate(trainloader, 0):
        # get the inputs
        inputs, labels = data
        inputs, labels = inputs.to(device), labels.to(device)

        # zero the parameter gradients
        optimizer.zero_grad()

        # forward + backward + optimize
        outputs = net(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()      
        # print statistics
        running_loss += loss.item()
        if i % 200 == 199:    # print every 2000 mini-batches
            print('[%d, %5d] loss: %.3f' %
                  (epoch + 1, i + 1, running_loss / 200))
            running_loss = 0.0


print('Finished Training')

下圖是還沒訓練完的網路。 

 

接下來就是測試的部分了,我們先從testloader取出一個 batch,列印他們看看。

dataiter = iter(testloader)
images, labels = dataiter.next()

# print images
imshow(torchvision.utils.make_grid(images))
print('GroundTruth: ', ' '.join('%5s' % classes[labels[j]] for j in range(batch_size)))
images, labels = images.to(device), labels.to(device)

把他們送到網路裡,測試一下他們的結果看看怎麼樣。

outputs = net(images)
_, predicted = torch.max(outputs, 1)

print('Predicted: ', ' '.join('%5s' % classes[predicted[j]]
                              for j in range(batch_size)))

 

接下來是大規模的測試。

correct = 0
total = 0
with torch.no_grad():
    for data in testloader:
        images, labels = data
        images, labels = images.to(device), labels.to(device)
        outputs = net(images)
        _, predicted = torch.max(outputs.data, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()

print('Accuracy of the network on the 10000 test images: %d %%' % (
    100 * correct / total))

 Accuracy of the network on the 10000 test images: 34 %。

有些準有些不準,這是我在還沒訓練完全就預測的,一般達到飽和準確率都能達到百分之八十多。

再來看看什麼是表現良好的類,以及表現不佳的類。

class_correct = list(0. for i in range(10))
class_total = list(0. for i in range(10))
with torch.no_grad():
    for data in testloader:
        images, labels = data
        images, labels = images.to(device), labels.to(device)
        outputs = net(images)
        _, predicted = torch.max(outputs, 1)
        c = (predicted == labels).squeeze()
        for i in range(batch_size):
            label = labels[i]
            class_correct[label] += c[i].item()
            class_total[label] += 1


for i in range(10):
    print('Accuracy of %5s : %2d %%' % (
        classes[i], 100 * class_correct[i] / class_total[i]))

總結一下,這裡我們使用了經典的model,包括alexnet,vgg,resnet,inceptionv3等網路用於訓練cifar資料集。其實還能用於transfer learning,使用自己的資料集合預訓練的models權重。接下來會慢慢更新。