[深度學習]使用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權重。接下來會慢慢更新。