【Pytorch学习1】Introduction

Hualingz

Posted by Hualingz on 2023-10-23
Estimated Reading Time 10 Minutes
Words 2.3k In Total
Viewed Times

1.1 Pytorch的安装

Pytorch的安装要对应python版本,如果是cuda版本的(一般都用cuda版本),需要对应CUDA Version(cmd中输入nvidia-smi),这个对应最高支持版本,下载版本推荐使用nvcc -V指令查看CUDA API版本

同时为了独立性,建议使用conda进行虚拟环境的新建

1.1.1环境配置

我这里已经安装好了CUDA和cudnn,并且查到了自己的CUDA API版本为11.3

1
2
3
4
5
6
%conda create -p Your_PATH_to_Anaconda/env/dl python=3.9
%conda activate dl
# CUDA 11.3
%conda install pytorch==1.11.0 torchvision==0.12.0 torchaudio==0.11.0 cudatoolkit=11.3 -c pytorch
# 不推荐上面那个安装方式,推荐使用whl安装如下
%pip install torch==1.11.0+cu113 torchvision==0.12.0+cu113 torchaudio==0.11.0 --extra-index-url https://download.pytorch.org/whl/cu113

我们的anaconda有默认环境,我们直接使用python命令会使用默认的python(3.11),有三种方法

  1. 我们把默认的python.exe的文件名修改,使用py -0p找到默认的python,改名字为python11,但是这样的弊端也很明显,我们的原生系统使用python会出问题,我们需要激活conda环境再python或者用python11来代替,这样的好处是所有虚拟环境的python启动都只需要python即可

  2. 修改虚拟环境中的python.exe,在Anaconda\envs\YOUR_ENV\python.exe这里进行修改

  3. 每次都指定我们要的python

我使用第三种方法,知道机制就好,通常引起module not found错误

检查一下是否成功了

1
2
3
4
# 要在ipynb中运行还需要ipykernel库 %conda install ipykernel
import torch
print(torch.__version__)
print(torch.cuda.is_available())
e:\Environments\Anaconda3\envs\py39\lib\site-packages\tqdm\auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
  from .autonotebook import tqdm as notebook_tqdm


1.11.0+cu113
True

1.2 简单的例子

我们使用Pytorch官方的文档中的例子,使用FashionMNIST数据集来训练一个神经网络,预测输入图像是否属于以下类别之一:T恤/上衣,长裤,套头衫,连衣裙,外套,凉鞋,衬衫,运动鞋,包或踝靴

1
2
3
4
5
6
import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets
from torchvision.transforms import ToTensor, Lambda, Compose
import matplotlib.pyplot as plt
  • 这些库都是干什么的?
    • torchvision包含了一些经典的数据集,我们使用的FashionMNIST就是其中之一
    • torchvision中的transforms和target_transform则是用来修改样本和标签

接着我们需要下载数据,我们直接使用datasets中的FashionMNIST数据集,会自动进行下载,存储到data文件夹下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Download training data from open datasets.
training_data = datasets.FashionMNIST(
root="data",
train=True,
download=True,
transform=ToTensor(),
)

# Download test data from open datasets.
test_data = datasets.FashionMNIST(
root="data",
train=False,
download=True,
transform=ToTensor(),
)

数据的存储格式是[N,C,H,W]的,其中N为数据数量,C为通道数量,H为高度,W为宽度

一般来说,这里的N是根据我们的batch_size决定的

1
2
3
4
5
6
7
8
9
10
batch_size = 64

# Create data loaders.
train_dataloader = DataLoader(training_data, batch_size=batch_size)
test_dataloader = DataLoader(test_data, batch_size=batch_size)

for X, y in test_dataloader:
print("Shape of X [N, C, H, W]: ", X.shape)
print("Shape of y: ", y.shape, y.dtype)
break
Shape of X [N, C, H, W]:  torch.Size([64, 1, 28, 28])
Shape of y:  torch.Size([64]) torch.int64

我们的训练通常在GPU上进行,因此我们需要查看GPU是否可用

同时我们需要构建我们自己的神经网络,在Torch中神经网络的类一般继承于nn.Module的类,在init函数中我们定义我们的网络结构,在forward函数中我们定义数据通过网络的方式

为了加速神经网络的操作,我们可用将其移动到GPU上,使用.to(device)即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Get cpu or gpu device for training.
device = "cuda" if torch.cuda.is_available() else "cpu"
print("Using {} device".format(device))

# Define model
class NeuralNetwork(nn.Module):
def __init__(self):
super(NeuralNetwork, self).__init__()
self.flatten = nn.Flatten()
self.linear_relu_stack = nn.Sequential(
nn.Linear(28*28, 512),
nn.ReLU(),
nn.Linear(512, 512),
nn.ReLU(),
nn.Linear(512, 10)
)

def forward(self, x):
x = self.flatten(x)
logits = self.linear_relu_stack(x)
return logits

model = NeuralNetwork().to(device)
print(model)
Using cuda device
NeuralNetwork(
  (flatten): Flatten(start_dim=1, end_dim=-1)
  (linear_relu_stack): Sequential(
    (0): Linear(in_features=784, out_features=512, bias=True)
    (1): ReLU()
    (2): Linear(in_features=512, out_features=512, bias=True)
    (3): ReLU()
    (4): Linear(in_features=512, out_features=10, bias=True)
  )
)

1.2.1 优化模型参数

我们的模型结构已经定义,接下来我们的模型内部的参数需要优化.我们使用优化器和损失函数进行,这里的损失函数是在训练时计算神经网络的计算结果和真实值之间的差距,而优化器则是将误差不断缩小的算法.

1
2
loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=1e-3)

1.2.2 模型的训练

训练时我们要做的事情是

  1. 告诉模型要开始训练了,而不是测试
  2. 将数据载入器中的一个Batch_size的数据运送到device中去
  3. 将数据通过网络获得结果
  4. 用损失函数对比结果和标签获得误差
  5. 误差反向传播,更新权重
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
def train(dataloader, model, loss_fn, optimizer):
size = len(dataloader.dataset)

model.train() # 告诉模型要开始训练了,而不是测试

for batch, (X, y) in enumerate(dataloader):

# 将数据载入器中的`一个Batch_size`的数据运送到device中去

X, y = X.to(device), y.to(device)

# Compute prediction error

pred = model(X) # 将数据通过网络获得结果

loss = loss_fn(pred, y) # 用损失函数对比结果和标签获得误差

# Backpropagation
optimizer.zero_grad()
loss.backward()
optimizer.step()

# 误差反向传播,更新权重

if batch % 100 == 0:
loss, current = loss.item(), batch * len(X)
print(f"loss: {loss:>7f} [{current:>5d}/{size:>5d}]")

1.2.3 模型的验证

写好了训练函数,我们需要测试我们的模型准确率,那么就要进行验证,与训练类似,我们在验证中去掉了训练的误差反向传播和权重更新的步骤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def test(dataloader, model, loss_fn):
size = len(dataloader.dataset)
num_batches = len(dataloader)
model.eval()
test_loss, correct = 0, 0
with torch.no_grad():
for X, y in dataloader:
X, y = X.to(device), y.to(device)
pred = model(X)
test_loss += loss_fn(pred, y).item()
correct += (pred.argmax(1) == y).type(torch.float).sum().item()
test_loss /= num_batches
correct /= size
print(f"Test Error: \n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \n")

1.2.4 迭代训练

在训练时,对于一个数据集往往要多次迭代训练(epochs),在每一个epoch中我们要查看模型的损失和精确度,希望我们的损失在不断减少,精度在不断提高.

同时要注意可能发生的过拟合现象

1
2
3
4
5
6
epochs = 5
for t in range(epochs):
print(f"Epoch {t+1}\n-------------------------------")
train(train_dataloader, model, loss_fn, optimizer)
test(test_dataloader, model, loss_fn)
print("Done!")
Epoch 1
-------------------------------
loss: 2.307013  [    0/60000]
loss: 2.292086  [ 6400/60000]
loss: 2.269598  [12800/60000]
loss: 2.252709  [19200/60000]
loss: 2.254091  [25600/60000]
loss: 2.222050  [32000/60000]
loss: 2.225680  [38400/60000]
loss: 2.194172  [44800/60000]
loss: 2.188112  [51200/60000]
loss: 2.154680  [57600/60000]
Test Error: 
 Accuracy: 46.4%, Avg loss: 2.151008 

Epoch 2
-------------------------------
loss: 2.168256  [    0/60000]
loss: 2.153883  [ 6400/60000]
loss: 2.094078  [12800/60000]
loss: 2.095815  [19200/60000]
loss: 2.063817  [25600/60000]
loss: 2.000859  [32000/60000]
loss: 2.019217  [38400/60000]
loss: 1.943149  [44800/60000]
loss: 1.941912  [51200/60000]
loss: 1.864872  [57600/60000]
Test Error: 
 Accuracy: 58.6%, Avg loss: 1.869139 

Epoch 3
-------------------------------
loss: 1.909717  [    0/60000]
loss: 1.874612  [ 6400/60000]
loss: 1.760677  [12800/60000]
loss: 1.784906  [19200/60000]
loss: 1.697392  [25600/60000]
loss: 1.652777  [32000/60000]
loss: 1.659951  [38400/60000]
loss: 1.572913  [44800/60000]
loss: 1.595308  [51200/60000]
loss: 1.483235  [57600/60000]
Test Error: 
 Accuracy: 60.0%, Avg loss: 1.510369 

Epoch 4
-------------------------------
loss: 1.581239  [    0/60000]
loss: 1.544954  [ 6400/60000]
loss: 1.404787  [12800/60000]
loss: 1.462095  [19200/60000]
loss: 1.360219  [25600/60000]
loss: 1.358764  [32000/60000]
loss: 1.360219  [38400/60000]
loss: 1.298296  [44800/60000]
loss: 1.332410  [51200/60000]
loss: 1.226017  [57600/60000]
Test Error: 
 Accuracy: 62.3%, Avg loss: 1.258020 

Epoch 5
-------------------------------
loss: 1.335919  [    0/60000]
loss: 1.314676  [ 6400/60000]
loss: 1.161584  [12800/60000]
loss: 1.253099  [19200/60000]
loss: 1.135767  [25600/60000]
loss: 1.165522  [32000/60000]
loss: 1.172574  [38400/60000]
loss: 1.124036  [44800/60000]
loss: 1.163304  [51200/60000]
loss: 1.071299  [57600/60000]
Test Error: 
 Accuracy: 63.9%, Avg loss: 1.097218 

Done!

1.2.5 模型保存

模型训练好了!

我们要赶紧将模型进行保存,在下次使用时进行载入,我们保存一般是使用序列化内部状态字典(包含模型参数)

1
2
torch.save(model.state_dict(), "model.pth")
print("Saved PyTorch Model State to model.pth")
Saved PyTorch Model State to model.pth

1.2.6 模型载入

那么,当我们想要用这个模型实际解决问题时如何使用呢?

我们首先进行模型的载入,模型的载入需要知道模型的结构参数

因此需要我们之前定义的神经网络类和保存的模型参数

1
2
model = NeuralNetwork()
model.load_state_dict(torch.load("model.pth"))
<All keys matched successfully>

1.2.7 模型预测

载入后的模型就可以正常进行预测了

我们首先要知道最后输出的概率对应的类别是什么,这个一般会在数据集中给出

然后进行模型的预测

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
classes = [
"T-shirt/top",
"Trouser",
"Pullover",
"Dress",
"Coat",
"Sandal",
"Shirt",
"Sneaker",
"Bag",
"Ankle boot",
]

model.eval()
x, y = test_data[0][0], test_data[0][1]
with torch.no_grad():
pred = model(x)
predicted, actual = classes[pred[0].argmax(0)], classes[y]
print(f'Predicted: "{predicted}", Actual: "{actual}"')

Predicted: "Ankle boot", Actual: "Ankle boot"

如果您喜欢此博客或发现它对您有用,则欢迎对此发表评论。 也欢迎您共享此博客,以便更多人可以参与。 如果博客中使用的图像侵犯了您的版权,请与作者联系以将其删除。 谢谢 !