你已經學習了如何定義神經網絡,計算損失和執行網絡權重的更新。
現在你或許在思考。
What about data?
通常當你需要處理圖像,文本,音頻,視頻數據,你能夠使用標準的python包將數據加載進numpy數組。之后你能夠轉換這些數組到torch.*Tensor。
- 對于圖片,類似于Pillow,OPenCV的包很有用
- 對于音頻,類似于scipy和librosa的包
- 對于文字,無論是基于原生python和是Cython的加載,或者NLTK和SpaCy都有效
對于視覺,我們特意創建了一個包叫做torchvision,它有常見數據集的數據加載,比如ImageNet,CIFAR10,MNIST等,還有圖片的數據轉換,torchvision.datasets和torch.utils.data.Dataloader。
這提供了很方便的實現,避免了寫樣板代碼。
對于這一文章,我們將使用CIFAR10數據集。它擁有飛機,汽車,鳥,貓,鹿,狗,霧,馬,船,卡車等類別。CIFAR-10的圖片尺寸為3*32*32,也就是3個顏色通道和32*32個像素。
?
Training? an image classifier
?我們將按照順序執行如下步驟:
- 使用torchvision加載并且標準化CIFAR10訓練和測試數據集
- 定義一個卷積神經網絡
- 定義損失函數
- 使用訓練數據訓練網絡
- 使用測試數據測試網絡
?
1.加載并標準化CIFAR10
使用torchvision,加載CIFAR10非常簡單
import torch import torchvision import torchvision.transforms as transforms
torchvision數據集的輸出是PIL圖片庫圖片,范圍為[0,1]。我們將它們轉換為tensor并標準化為[-1,1]。
import torch import torchvision import torchvision.transforms as transformstransform=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.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')
out: Downloading https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz to ./data/cifar-10-python.tar.gz Files already downloaded and verified
?我們來觀察一下訓練集圖片
import matplotlib.pyplot as plt import numpy as npdef imshow(img):img=img/2+0.5npimg=img.numpy()plt.imshow(np.transpose(npimg,(1,2,0)))dataiter=iter(trainloader) images,labels=dataiter.next()imshow(torchvision.utils.make_grid(images)) plt.show() print(''.join('%5s'%classes[labels[j]] for j in range(4)))
?
out:
truck truck dog truck
?
?2.定義卷積神經網絡
從前面神經網絡章節復制神經網絡,并把它改成接受3維圖片輸入(而不是之前定義的一維圖片)。
import torch.nn as nn import torch.nn.functional as Fclass 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 xnet=Net()
?
?3.定義損失函數和優化器
我們使用分類交叉熵損失和帶有動量的SGD
import torch.optim as optim criterion = nn.CrossEntropyLoss() optimizer=optim.SGD(net.parameters(),lr=0.001,momentum=0.9)
?
4.訓練網絡
我們只需要簡單地迭代數據,把輸入喂進網絡并優化。
import torch.optim as optim criterion = nn.CrossEntropyLoss() optimizer = optim.SGD(net.parameters(),lr=0.001,momentum=0.9)for epoch in range(2):running_loss=0.0for i,data in enumerate(trainloader,0):inputs,labels=dataoptimizer.zero_grad()outputs=net(inputs)loss=criterion(outputs,labels)loss.backward()optimizer.step()running_loss+=loss.item()if i%2000==1999:print('[%d, %5d] loss: %.3f' %(epoch + 1, i + 1, running_loss / 2000))running_loss=0 print('Finished Training')
out: [1, 2000] loss: 2.208 [1, 4000] loss: 1.797 [1, 6000] loss: 1.627 [1, 8000] loss: 1.534 [1, 10000] loss: 1.508 [1, 12000] loss: 1.453 [2, 2000] loss: 1.378 [2, 4000] loss: 1.365 [2, 6000] loss: 1.326 [2, 8000] loss: 1.309 [2, 10000] loss: 1.290 [2, 12000] loss: 1.262 Finished Training
?
?
4.在測試數據集上測試網絡
我們已經遍歷了兩遍訓練集來訓練網絡。需要檢查下網絡是不是已經學習到了什么。
我們將檢查神經網絡輸出的預測標簽是否與真實標簽相同。如果預測是正確的,我們將這一樣本加入到正確預測的列表。
我們先來熟悉一下訓練圖片。
dataiter=iter(testloader) images,labes=dataiter.next()imshow(torchvision.utils.make_grid(images)) plt.show() print('GroundTruth: ',' '.join('%5s' % classes[labels[j]] for j in range(4)))
?
out:
GroundTruth: plane deer dog horse
?ok,現在讓我們看一下神經網絡認為這些樣本是什么。
outputs=net(images)
?輸出是10個類別的量值,大的值代表網絡認為某一類的可能性更大。所以我們來獲得最大值得索引:
_,predicted=torch.max(outputs,1) print("Predicted: ",' '.join('%5s' %classes[predicted[j]] for j in range(4)))
out:
Predicted: bird dog deer horse
?讓我們看看整個數據集上的模型表現。
out:
Accuracy of the network on the 10000 test images: 54 %
?這看起來要好過瞎猜,隨機的話只要10%的準確率(因為是10類)。看來網絡是學習到了一些東西。
我們來繼續看看在哪些類上的效果好,在哪些類上的效果比較差:
out: Accuracy of plane : 56 % Accuracy of car : 70 % Accuracy of bird : 27 % Accuracy of cat : 16 % Accuracy of deer : 44 % Accuracy of dog : 64 % Accuracy of frog : 61 % Accuracy of horse : 73 % Accuracy of ship : 68 % Accuracy of truck : 61 %
好了,接下來該干點啥?
我們怎樣將這個神經網絡運行在GPU上呢?
Trainning on GPU
就像你怎么把一個Tensor轉移到GPU上一樣,現在把神經網絡轉移到GPU上。
如果我們有一個可用的CUDA,首先將我們的設備定義為第一個可見的cuda設備:
device=torch.device("cuda:0" if torch.cuda.is_available() else "cpu") print(device)
out:
cuda:0
?剩下的章節我們假定我們的設備是CUDA。
之后這些方法將遞歸到所有模塊,將其參數和緩沖區轉換為CUDA張量:
net.to(device)
?記得你還需要在每步循環里將數據轉移到GPU上:
inputs,labels=inputs.to(device),labels.to(device)
為什么沒注意到相對于CPU巨大的速度提升?這是因為你的網絡還非常小。
?
練習:嘗試增加你網絡的寬度(第一個nn.Conv2d的參數2應該與第二個nn.Conv2d的參數1是相等的數字),觀察你得到的速度提升。
達成目標:
- 更深一步理解Pytorch的Tensor庫和神經網絡
- 訓練一個小神經網絡來分類圖片
?Trainning on multiple GPUs
如果你想看到更加顯著的GPU加速,請移步:https://pytorch.org/tutorials/beginner/blitz/data_parallel_tutorial.html
?