溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

使用PyTorch怎么訓(xùn)練一個(gè)圖像分類器

發(fā)布時(shí)間:2021-03-22 16:41:29 來源:億速云 閱讀:218 作者:Leah 欄目:開發(fā)技術(shù)

這篇文章將為大家詳細(xì)講解有關(guān)使用PyTorch怎么訓(xùn)練一個(gè)圖像分類器,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。

如下所示:

import torch
import torchvision
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
import numpy as np

print("torch: %s" % torch.__version__)
print("tortorchvisionch: %s" % torchvision.__version__)
print("numpy: %s" % np.__version__)

Out:

torch: 1.0.0
tortorchvisionch: 0.2.1
numpy: 1.15.4

數(shù)據(jù)從哪兒來?

通常來說,你可以通過一些python包來把圖像、文本、音頻和視頻數(shù)據(jù)加載為numpy array。然后將其轉(zhuǎn)換為torch.*Tensor。

圖像。Pillow、OpenCV是用得比較多的

音頻。scipy和librosa

文本。純Python或者Cython就可以完成數(shù)據(jù)加載,可以在NLTK和SpaCy找到數(shù)據(jù)

對(duì)于計(jì)算機(jī)視覺而言,我們有torchvision包,它可以用來加載一下常用數(shù)據(jù)集如Imagenet、CIFAR10、MINIST等等,也有一些常用的為圖像準(zhǔn)備數(shù)據(jù)轉(zhuǎn)換例如torchvision.datasets和torch.utils.data.DataLoader。

這次的教程中,我們使用CIFAR10數(shù)據(jù)集,他有‘a(chǎn)irplane', ‘a(chǎn)utomobile', ‘bird', ‘cat', ‘deer', ‘dog', ‘frog', ‘horse', ‘ship', ‘truck'這幾個(gè)類別的圖像。圖像大小都是3x32x32的。也就是說,圖像都是三通道的,每一張圖的尺寸都是32x32。

使用PyTorch怎么訓(xùn)練一個(gè)圖像分類器

訓(xùn)練一個(gè)圖像分類器

步驟如下:

使用torchvision加載、歸一化訓(xùn)練集和測(cè)試集

定義卷積神經(jīng)網(wǎng)絡(luò)

定義損失函數(shù)

使用訓(xùn)練集訓(xùn)練網(wǎng)絡(luò)

使用測(cè)試集測(cè)試網(wǎng)絡(luò)

1. 加載、歸一化CIFAR10

我們可以使用torchvision很輕松的完成

torchvision的數(shù)據(jù)集是基于PILImage的,數(shù)值是[0, 1],我們需要將其轉(zhuǎn)成范圍為[-1, 1]的Tensor

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=4)

testset = torchvision.datasets.CIFAR10(root='./data', train=False, 
                    download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=4, 
                     shuffle=True, num_workers=4)
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

讓我們來看看訓(xùn)練集的圖片

# 顯示一張圖片
def imshow(img):
  img = img / 2 + 0.5   # 逆歸一化
  npimg = img.numpy()
  plt.imshow(np.transpose(npimg, (1, 2, 0)))
  plt.show()


# 任意地拿到一些圖片
dataiter = iter(trainloader)
images, labels = dataiter.next()

# 顯示圖片
imshow(torchvision.utils.make_grid(images))
# 顯示類標(biāo)
print(' '.join('%5s' % classes[labels[j]] for j in range(4)))

Out:

使用PyTorch怎么訓(xùn)練一個(gè)圖像分類器

truck  dog ship  dog

2. 定義卷積神經(jīng)網(wǎng)絡(luò)

可以直接復(fù)制神經(jīng)網(wǎng)絡(luò)的代碼,修改里面的幾層即可。

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()

3. 定義損失函數(shù)和優(yōu)化器

使用多分類交叉熵?fù)p失函數(shù),和帶有momentum的SGD作為優(yōu)化器

import torch.optim as optim

criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=1e-3, momentum=0.9)

4. 訓(xùn)練網(wǎng)絡(luò)

我們直接使用循環(huán)語句遍歷數(shù)據(jù)集即可完成訓(xùn)練

nums_epoch = 2
for epoch in range(nums_epoch):
  _loss = 0.0
  for i, (inputs, labels) in enumerate(trainloader, 0):
    inputs, labels = inputs.to(device), labels.to(device)
    optimizer.zero_grad()
    
    outputs = net(inputs)
    loss = criterion(outputs, labels)
    loss.backward()
    optimizer.step()
    
    _loss += loss.item()
    if i % 2000 == 1999:  # 每2000步打印一次損失值
      print('[%d, %5d] loss: %.3f' %
         (epoch + 1, i + 1, _loss / 2000))
      _loss = 0.0

print('Finished Training')

Out:

[1, 2000] loss: 1.178
[1, 4000] loss: 1.200
[1, 6000] loss: 1.168
[1, 8000] loss: 1.175
[1, 10000] loss: 1.185
[1, 12000] loss: 1.165
[2, 2000] loss: 1.073
[2, 4000] loss: 1.066
[2, 6000] loss: 1.100
[2, 8000] loss: 1.107
[2, 10000] loss: 1.083
[2, 12000] loss: 1.103
Finished Training

5. 測(cè)試網(wǎng)絡(luò)

這個(gè)網(wǎng)絡(luò)已經(jīng)訓(xùn)練了兩個(gè)epoch,我們現(xiàn)在來看看這個(gè)網(wǎng)絡(luò)是不是學(xué)到了一些什么東西。

我們讓這個(gè)神經(jīng)網(wǎng)絡(luò)預(yù)測(cè)幾張圖片,看看它的答案與真實(shí)答案的差別。

下面我們選取一些測(cè)試數(shù)據(jù)集中的數(shù)據(jù),看看他們的真實(shí)標(biāo)簽。

# 展示測(cè)試數(shù)據(jù)集
dataiter = iter(testloader)
images, labels = dataiter.next()
imshow(torchvision.utils.make_grid(images))
print('GraoundTruth: ', ' '.join(['%5s' % classes[labels[j]] for j in range(4)]))

Out:

使用PyTorch怎么訓(xùn)練一個(gè)圖像分類器

GraoundTruth:  ship ship deer ship

接著我們讓神經(jīng)網(wǎng)絡(luò)來給出預(yù)測(cè)標(biāo)簽

神經(jīng)網(wǎng)絡(luò)的輸出是10個(gè)信號(hào)值,信號(hào)值最高的那個(gè)神經(jīng)元表示整個(gè)網(wǎng)絡(luò)的預(yù)測(cè)值,所以我們需要拿到信號(hào)最強(qiáng)的那個(gè)節(jié)點(diǎn)的索引值

# 展示預(yù)測(cè)值
outputs = net(images)
_, predicted = torch.max(outputs, 1)
print('Predicted: ', ' '.join(['%5s' % classes[predicted[j]] for j in range(4)]))

Out:

Predicted:  car ship horse ship

下面我們對(duì)整個(gè)測(cè)試集做一次評(píng)估:

# 評(píng)估測(cè)試數(shù)據(jù)集
correct, total = 0, 0
with torch.no_grad():
  for images, labels in testloader:
    outputs = net(images)
    _, predicted = torch.max(outputs, 1)
    total += labels.size(0)
    correct += (labels == predicted).sum().item()
  
print('Accuracy of the network on the 10000 test images: %d %%' % (
  100 * correct / total))

Out:

Accuracy of the network on the 10000 test images: 58 %

整個(gè)結(jié)果比隨機(jī)猜要好得多(隨機(jī)猜是10%的概率)??磥砦覀兊纳窠?jīng)網(wǎng)絡(luò)還是學(xué)到了點(diǎn)東西。

下面我們來看看它在哪一個(gè)類別的分類上做得最好:

# 按類標(biāo)評(píng)估
n_classes = len(classes)
class_correct, class_total = [0]*n_classes, [0]* n_classes

with torch.no_grad():
  for images, labels in testloader:
    outputs = net(images)
    _, predicted = torch.max(outputs, 1)
    is_correct = (labels == predicted).squeeze()
    for i in range(len(labels)):
      label = labels[i]
      class_total[label] += 1
      class_correct[label] += is_correct[i].item()

for i in range(n_classes):
  print('Accuracy of %5s: %.2f %%' % (
    classes[i], 100.0 * class_correct[i] / class_total[i]
  ))

Out:

Accuracy of plane: 67.00 %
Accuracy of  car: 71.50 %
Accuracy of bird: 55.20 %
Accuracy of  cat: 45.60 %
Accuracy of deer: 38.20 %
Accuracy of  dog: 47.00 %
Accuracy of frog: 78.80 %
Accuracy of horse: 55.90 %
Accuracy of ship: 72.70 %
Accuracy of truck: 57.50 %

在GPU上訓(xùn)練

就像把Tensor從CPU轉(zhuǎn)移到GPU一樣,神經(jīng)網(wǎng)絡(luò)也可以轉(zhuǎn)移到GPU上

首先需要檢查是否有可用的GPU

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
# 假設(shè)我們?cè)谥С諧UDA的機(jī)器上,我們可以打印出CUDA設(shè)備:

print(device)

Out:

cuda:0

我們假設(shè)device已經(jīng)是CUDA設(shè)備了

下面命令將遞歸的將所有模塊和參數(shù)、緩存轉(zhuǎn)移到CUDA設(shè)備上去

net.to(device)

Out:

Net(
 (conv1): Conv2d(3, 6, kernel_size=(5, 5), stride=(1, 1))
 (pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
 (conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))
 (fc1): Linear(in_features=400, out_features=120, bias=True)
 (fc2): Linear(in_features=120, out_features=84, bias=True)
 (fc3): Linear(in_features=84, out_features=10, bias=True)
)

注意,在訓(xùn)練過程中的傳入輸入數(shù)據(jù)時(shí),也需要轉(zhuǎn)移到GPU上

并且,需要重新實(shí)例化優(yōu)化器,否則會(huì)報(bào)錯(cuò)

inputs, labels = inputs.to(device), labels.to(device)

關(guān)于使用PyTorch怎么訓(xùn)練一個(gè)圖像分類器就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI