06.md 11.7 KB
Newer Older
W
wizardforcel 已提交
1 2
# 训练分类器

W
wizardforcel 已提交
3
> 原文:<https://pytorch.org/tutorials/beginner/blitz/cifar10_tutorial.html#sphx-glr-beginner-blitz-cifar10-tutorial-py>
W
wizardforcel 已提交
4

W
wizardforcel 已提交
5
就是这个。 您已经了解了如何定义神经网络,计算损失并更新网络的权重。
W
wizardforcel 已提交
6 7 8

现在您可能在想,

W
wizardforcel 已提交
9
## 数据呢?
W
wizardforcel 已提交
10

W
wizardforcel 已提交
11
通常,当您必须处理图像,文本,音频或视频数据时,可以使用将数据加载到 NumPy 数组中的标准 Python 包。 然后,您可以将该数组转换为`torch.*Tensor`
W
wizardforcel 已提交
12 13

*   对于图像,Pillow,OpenCV 等软件包很有用
W
wizardforcel 已提交
14
*   对于音频,请使用 SciPy 和 librosa 等软件包
W
wizardforcel 已提交
15 16 17 18 19 20
*   对于文本,基于 Python 或 Cython 的原始加载,或者 NLTK 和 SpaCy 很有用

专门针对视觉,我们创建了一个名为`torchvision`的程序包,其中包含用于常见数据集(例如 Imagenet,CIFAR10,MNIST 等)的数据加载器,以及用于图像(即`torchvision.datasets``torch.utils.data.DataLoader`)的数据转换器。

这提供了极大的便利,并且避免了编写样板代码。

W
wizardforcel 已提交
21
在本教程中,我们将使用 CIFAR10 数据集。 它具有以下类别:“飞机”,“汽车”,“鸟”,“猫”,“鹿”,“狗”,“青蛙”,“马”,“船”,“卡车”。 CIFAR-10 中的图像尺寸为`3x32x32`,即尺寸为`32x32`像素的 3 通道彩色图像。
W
wizardforcel 已提交
22 23 24 25 26

![cifar10](img/ae800707f2489607d51d67499071db16.png)

cifar10

W
wizardforcel 已提交
27
## 训练图像分类器
W
wizardforcel 已提交
28 29 30 31 32 33 34 35 36

我们将按顺序执行以下步骤:

1.  使用`torchvision`加载并标准化 CIFAR10 训练和测试数据集
2.  定义卷积神经网络
3.  定义损失函数
4.  根据训练数据训练网络
5.  在测试数据上测试网络

W
wizardforcel 已提交
37
### 1.加载并标准化 CIFAR10
W
wizardforcel 已提交
38 39 40 41 42 43 44 45 46 47

使用`torchvision`,加载 CIFAR10 非常容易。

```py
import torch
import torchvision
import torchvision.transforms as transforms

```

W
wizardforcel 已提交
48
TorchVision 数据集的输出是`[0, 1]`范围的`PILImage`图像。 我们将它们转换为归一化范围`[-1, 1]`的张量。 .. 注意:
W
wizardforcel 已提交
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118

```py
If running on Windows and you get a BrokenPipeError, try setting
the num_worker of torch.utils.data.DataLoader() to 0.

```

```py
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')

```

出:

```py
Downloading https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz to ./data/cifar-10-python.tar.gz
Extracting ./data/cifar-10-python.tar.gz to ./data
Files already downloaded and verified

```

让我们展示一些训练图像,很有趣。

```py
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)))
    plt.show()

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

```

![../../_img/sphx_glr_cifar10_tutorial_001.png](img/aaf8c905effc5044cb9691420e5261fa.png)

出:

```py
dog truck  frog horse

```

W
wizardforcel 已提交
119
### 2.定义卷积神经网络
W
wizardforcel 已提交
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149

之前从“神经网络”部分复制神经网络,然后对其进行修改以获取 3 通道图像(而不是定义的 1 通道图像)。

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

```

W
wizardforcel 已提交
150
### 3.定义损失函数和优化器
W
wizardforcel 已提交
151 152 153 154 155 156 157 158 159 160 161

让我们使用分类交叉熵损失和带有动量的 SGD。

```py
import torch.optim as optim

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

```

W
wizardforcel 已提交
162
### 4.训练网络
W
wizardforcel 已提交
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212

这是事情开始变得有趣的时候。 我们只需要遍历数据迭代器,然后将输入馈送到网络并进行优化即可。

```py
for epoch in range(2):  # loop over the dataset multiple times

    running_loss = 0.0
    for i, data in enumerate(trainloader, 0):
        # get the inputs; data is a list of [inputs, labels]
        inputs, labels = data

        # 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 % 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')

```

出:

```py
[1,  2000] loss: 2.196
[1,  4000] loss: 1.849
[1,  6000] loss: 1.671
[1,  8000] loss: 1.589
[1, 10000] loss: 1.547
[1, 12000] loss: 1.462
[2,  2000] loss: 1.382
[2,  4000] loss: 1.389
[2,  6000] loss: 1.369
[2,  8000] loss: 1.332
[2, 10000] loss: 1.304
[2, 12000] loss: 1.288
Finished Training

```

W
wizardforcel 已提交
213
让我们快速保存我们训练过的模型:
W
wizardforcel 已提交
214 215 216 217 218 219 220

```py
PATH = './cifar_net.pth'
torch.save(net.state_dict(), PATH)

```

W
wizardforcel 已提交
221
有关保存 PyTorch 模型的更多详细信息,请参见[此处](https://pytorch.org/docs/stable/notes/serialization.html)
W
wizardforcel 已提交
222

W
wizardforcel 已提交
223
### 5.根据测试数据测试网络
W
wizardforcel 已提交
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308

我们已经在训练数据集中对网络进行了 2 次训练。 但是我们需要检查网络是否学到了什么。

我们将通过预测神经网络输出的类别标签并根据实际情况进行检查来进行检查。 如果预测正确,则将样本添加到正确预测列表中。

好的,第一步。 让我们显示测试集中的图像以使其熟悉。

```py
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(4)))

```

![../../_img/sphx_glr_cifar10_tutorial_002.png](img/d148a5bd51a3278e9698bba522cbc34a.png)

出:

```py
GroundTruth:    cat  ship  ship plane

```

接下来,让我们重新加载保存的模型(注意:这里不需要保存和重新加载模型,我们只是为了说明如何这样做):

```py
net = Net()
net.load_state_dict(torch.load(PATH))

```

好的,现在让我们看看神经网络对以上这些示例的看法:

```py
outputs = net(images)

```

输出是 10 类的能量。 一个类别的能量越高,网络就认为该图像属于特定类别。 因此,让我们获取最高能量的指数:

```py
_, predicted = torch.max(outputs, 1)

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

```

出:

```py
Predicted:    cat  ship  ship plane

```

结果似乎还不错。

让我们看一下网络在整个数据集上的表现。

```py
correct = 0
total = 0
with torch.no_grad():
    for data in testloader:
        images, labels = data
        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))

```

出:

```py
Accuracy of the network on the 10000 test images: 53 %

```

W
wizardforcel 已提交
309
看起来比偶然更好,准确率是 10%(从 10 个班级中随机选择一个班级)。 好像网络学到了一些东西。
W
wizardforcel 已提交
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352

嗯,哪些类的表现良好,哪些类的表现不佳:

```py
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
        outputs = net(images)
        _, predicted = torch.max(outputs, 1)
        c = (predicted == labels).squeeze()
        for i in range(4):
            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]))

```

出:

```py
Accuracy of plane : 50 %
Accuracy of   car : 62 %
Accuracy of  bird : 51 %
Accuracy of   cat : 32 %
Accuracy of  deer : 31 %
Accuracy of   dog : 35 %
Accuracy of  frog : 77 %
Accuracy of horse : 70 %
Accuracy of  ship : 71 %
Accuracy of truck : 52 %

```

好的,那下一步呢?

我们如何在 GPU 上运行这些神经网络?

W
wizardforcel 已提交
353
## 在 GPU 上进行训练
W
wizardforcel 已提交
354

W
wizardforcel 已提交
355
就像将张量转移到 GPU 上一样,您也将神经网络转移到 GPU 上。
W
wizardforcel 已提交
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392

如果可以使用 CUDA,首先将我们的设备定义为第一个可见的 cuda 设备:

```py
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

# Assuming that we are on a CUDA machine, this should print a CUDA device:

print(device)

```

出:

```py
cuda:0

```

本节的其余部分假定`device`是 CUDA 设备。

然后,这些方法将递归遍历所有模块,并将其参数和缓冲区转换为 CUDA 张量:

```py
net.to(device)

```

请记住,您还必须将每一步的输入和目标也发送到 GPU:

```py
inputs, labels = data[0].to(device), data[1].to(device)

```

与 CPU 相比,为什么我没有注意到 MASSIVE 加速? 因为您的网络真的很小。

W
wizardforcel 已提交
393
**练习**:尝试增加网络的宽度(第一个`nn.Conv2d`的参数 2 和第二个`nn.Conv2d`的参数 1 –它们必须是相同的数字),看看您可以得到哪种加速。
W
wizardforcel 已提交
394 395 396

**已实现的目标**

W
wizardforcel 已提交
397
*   全面了解 PyTorch 的张量库和神经网络。
W
wizardforcel 已提交
398 399
*   训练一个小型神经网络对图像进行分类

W
wizardforcel 已提交
400
## 在多个 GPU 上进行训练
W
wizardforcel 已提交
401 402 403

如果您想使用所有 GPU 来获得更大的大规模加速,请查看[可选:数据并行](data_parallel_tutorial.html)

W
wizardforcel 已提交
404
## 我下一步要去哪里?
W
wizardforcel 已提交
405 406

*   [训练神经网络玩视频游戏](../../intermediate/reinforcement_q_learning.html)
W
wizardforcel 已提交
407
*   [在 imagenet 上训练最先进的 ResNet 网络](https://github.com/pytorch/examples/tree/master/imagenet) 
W
wizardforcel 已提交
408 409 410 411 412
*   [使用生成对抗网络训练人脸生成器](https://github.com/pytorch/examples/tree/master/dcgan)
*   [使用递归 LSTM 网络训练单词级语言模型](https://github.com/pytorch/examples/tree/master/word_language_model)
*   [更多示例](https://github.com/pytorch/examples)
*   [更多教程](https://github.com/pytorch/tutorials)
*   [在论坛上讨论 PyTorch](https://discuss.pytorch.org/)
W
wizardforcel 已提交
413
*   [在 Slack 上与其他用户聊天](https://pytorch.slack.com/messages/beginner/) 
W
wizardforcel 已提交
414

W
wizardforcel 已提交
415
**脚本的总运行时间**:(2 分钟 39.965 秒)
W
wizardforcel 已提交
416

W
wizardforcel 已提交
417
[下载 Python 源码:`cifar10_tutorial.py`](https://pytorch.org/tutorials/_downloads/ba100c1433c3c42a16709bb6a2ed0f85/cifar10_tutorial.py)
W
wizardforcel 已提交
418

W
wizardforcel 已提交
419
[下载 Jupyter 笔记本:`cifar10_tutorial.ipynb`](https://pytorch.org/tutorials/_downloads/17a7c7cb80916fcdf921097825a0f562/cifar10_tutorial.ipynb)
W
wizardforcel 已提交
420

W
wizardforcel 已提交
421
[由 Sphinx 画廊](https://sphinx-gallery.readthedocs.io)生成的画廊