一、Pytorch基本介绍
1. 什么是Pytorch
- Pytorch是一个基于Numpy的科学计算包, 向它的使用者提供了两大功能.
- 作为Numpy的替代者, 向用户提供使用GPU强大功能的能力.
- 做为一款深度学习的平台, 向用户提供最大的灵活性和速度.
2. Pytorch的基本元素操作
from __future__ import print_function
import torch
# 创建一个没有初始化的矩阵:
x = torch.empty(5, 3)
print(x)
# 创建一个有初始化的矩阵:
x = torch.rand(5, 3)
print(x)
# 创建一个全零矩阵并可指定数据元素的类型为long
x = torch.zeros(5, 3, dtype=torch.long)
print(x)
# 直接通过数据创建张量
x = torch.tensor([2.5, 3.5])
print(x)
# 通过已有的一个张量创建相同尺寸的新张量
# 利用news_methods方法得到一个张量
x = x.new_ones(5, 3, dtype=torch.double)
print(x)
# 利用randn_like方法得到相同张量尺寸的一个新张量, 并且采用随机初始化来对其赋值
y = torch.randn_like(x, dtype=torch.float)
print(y)
# 得到张量的尺寸
print(x.size())
3. Pytorch基本运算操作
# 加法操作
y = torch.rand(5, 3)
print(x + y)
# 第二种方式
print(torch.add(x, y))
# 第三种方式
# 提前设定一个空的张量
result = torch.empty(5, 3)
# 将空的张量作为加法的结果存储张量
torch.add(x, y, out=result)
print(result)
# 第四种方式:原地置换
y.add_(x)
print(y)
# 用类似于Numpy的方式对张量进行操作
print(x[:, 1])
# 改变张量的形状: torch.view()
x = torch.randn(4, 4)
# tensor.view()操作需要保证数据元素的总数量不变
y = x.view(16)
# -1代表自动匹配个数
z = x.view(-1, 8)
print(x.size(), y.size(), z.size())
# 如果张量中只有一个元素, 可以用.item()将值取出, 作为一个python number
x = torch.randn(1)
print(x)
print(x.item())
4. Torch Tensor和Numpy array之间的相互转换
a = torch.ones(5)
print(a)
b = a.numpy()
print(b)
a.add_(1)
print(a)
print(b)
# 将Numpy array转换为Torch Tensor
import numpy as np
a = np.ones(5)
b = torch.from_numpy(a)
np.add(a, 1, out=a)
print(a)
print(b)
使用GPU运行
# 如果服务器上已经安装了GPU和CUDA
if torch.cuda.is_available():
# 定义一个设备对象, 这里指定成CUDA, 即使用GPU
device = torch.device("cuda")
# 直接在GPU上创建一个Tensor
y = torch.ones_like(x, device=device)
# 将在CPU上面的x张量移动到GPU上面
x = x.to(device)
# x和y都在GPU上面, 才能支持加法运算
z = x + y
# 此处的张量z在GPU上面
print(z)
# 也可以将z转移到CPU上面, 并同时指定张量元素的数据类型
print(z.to("cpu", torch.double))
二、Pytorch中的autograd
1. 关于torch.Tensor
- torch.Tensor是整个package中的核心类, 如果将属性.requires_grad设置为True, 它将追踪在这个类上定义的所有操作. 当代码要进行反向传播的时候, 直接调用.backward()就可以自动计算所有的梯度. 在这个Tensor上的所有梯度将被累加进属性.grad中.
- 如果想终止一个Tensor在计算图中的追踪回溯, 只需要执行.detach()就可以将该Tensor从计算图中撤下, 在未来的回溯计算中也不会再计算该Tensor.
- 除了.detach(), 如果想终止对计算图的回溯, 也就是不再进行方向传播求导数的过程, 也可以采用代码块的方式with torch.no_grad():, 这种方式非常适用于对模型进行预测的时候, 因为预测阶段不再需要对梯度进行计算.
2. 关于torch.Function
- Function类是和Tensor类同等重要的一个核心类, 它和Tensor共同构建了一个完整的类, 每一个Tensor拥有一个.grad_fn属性, 代表引用了哪个具体的Function创建了该Tensor.
- 如果某个张量Tensor是用户自定义的, 则其对应的grad_fn is None.
3. 代码
x1 = torch.ones(3, 3)
print(x1)
x = torch.ones(2, 2, requires_grad=True)
print(x)
y = x + 2
print(y)
print(x.grad_fn)
print(y.grad_fn)
z = y * y * 3
out = z.mean()
print(z, out)
a = torch.randn(2, 2)
a = ((a * 3) / (a - 1))
print(a.requires_grad)
a.requires_grad_(True)
print(a.requires_grad)
b = (a * a).sum()
print(b.grad_fn)
4. 关于梯度Gradient
out.backward()
print(x.grad)
print(x.requires_grad)
print((x ** 2).requires_grad)
# 关于自动求导的属性设置: 可以通过设置.requires_grad=True来执行自动求导, 也可以通过代码块的限制来停止自动求导.
with torch.no_grad():
print((x ** 2).requires_grad)
# 可以通过.detach()获得一个新的Tensor, 拥有相同的内容但不需要自动求导.
print(x.requires_grad)
y = x.detach()
print(y.requires_grad)
print(x.eq(y).all())
三、Pytorch初步应用
1. 构建神经网络的流程
- 构建神经网络的典型流程:
- 定义一个拥有可学习参数的神经网络
- 遍历训练数据集
- 处理输入数据使其流经神经网络
- 计算损失值
- 将网络参数的梯度进行反向传播
- 以一定的规则更新网络的权重
2. Pytorch实现的神经网络
# 导入若干工具包
import torch
import torch.nn as nn
import torch.nn.functional as F
# 定义一个简单的网络类
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
# 定义第一层卷积神经网络, 输入通道维度=1, 输出通道维度=6, 卷积核大小3*3
self.conv1 = nn.Conv2d(1, 6, 3)
# 定义第二层卷积神经网络, 输入通道维度=6, 输出通道维度=16, 卷积核大小3*3
self.conv2 = nn.Conv2d(6, 16, 3)
# 定义三层全连接网络
self.fc1 = nn.Linear(16 * 6 * 6, 120)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self, x):
# 在(2, 2)的池化窗口下执行最大池化操作
x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
x = F.max_pool2d(F.relu(self.conv2(x)), 2)
x = x.view(-1, self.num_flat_features(x))
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
def num_flat_features(self, x):
# 计算size, 除了第0个维度上的batch_size
size = x.size()[1:]
num_features = 1
for s in size:
num_features *= s
return num_features
net = Net()
print(net)
params = list(net.parameters())
print(len(params))
print(params[0].size())
input = torch.randn(1, 1, 32, 32)
out = net(input)
print(out)
# 有了输出张量后, 就可以执行梯度归零和反向传播的操作了.
net.zero_grad()
out.backward(torch.randn(1, 10))
3. 损失函数
- 损失函数的输入是一个输入的pair: (output, target), 然后计算出一个数值来评估output和target之间的差距大小.
- 在torch.nn中有若干不同的损失函数可供使用, 比如nn.MSELoss就是通过计算均方差损失来评估输入和目标值之间的差距.
output = net(input)
target = torch.randn(10)
# 改变target的形状为二维张量, 为了和output匹配
target = target.view(1, -1)
criterion = nn.MSELoss()
loss = criterion(output, target)
print(loss)
关于方向传播的链条: 如果我们跟踪loss反向传播的方向, 使用.grad_fn属性打印, 将可以看到一张完整的计算图如下:
input -> conv2d -> relu -> maxpool2d -> conv2d -> relu -> maxpool2d
-> view -> linear -> relu -> linear -> relu -> linear
-> MSELoss
-> loss
当调用loss.backward()时, 整张计算图将对loss进行自动求导, 所有属性requires_grad=True的Tensors都将参与梯度求导的运算, 并将梯度累加到Tensors中的.grad属性中.
print(loss.grad_fn) # MSELoss
print(loss.grad_fn.next_functions[0][0]) # Linear
print(loss.grad_fn.next_functions[0][0].next_functions[0][0]) # ReLU
4. 反向传播
# Pytorch中执行梯度清零的代码
net.zero_grad()
print('conv1.bias.grad before backward')
print(net.conv1.bias.grad)
# Pytorch中执行反向传播的代码
loss.backward()
print('conv1.bias.grad after backward')
print(net.conv1.bias.grad)
5. 更新网络参数
更新参数最简单的算法就是SGD(随机梯度下降). 具体的算法公式表达式为: weight = weight - learning_rate * gradient
# 首先用传统的Python代码来实现SGD如下
learning_rate = 0.01
for f in net.parameters():
f.data.sub_(f.grad.data * learning_rate)
# 然后使用Pytorch官方推荐的标准代码如下
# 首先导入优化器的包, optim中包含若干常用的优化算法, 比如SGD, Adam等
import torch.optim as optim
# 通过optim创建优化器对象
optimizer = optim.SGD(net.parameters(), lr=0.01)
# 将优化器执行梯度清零的操作
optimizer.zero_grad()
output = net(input)
loss = criterion(output, target)
# 对损失值执行反向传播的操作
loss.backward()
# 参数的更新通过一行标准代码来执行
optimizer.step()
四、使用Pytorch构建一个分类器
1. 下载CIFAR10数据集
import torch
import torchvision
import torchvision.transforms as transforms
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')
2. 展示训练集的图片
# 导入画图包和numpy
import matplotlib.pyplot as plt
import numpy as np
# 构建展示图片的函数
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))
# 打印标签label
print(' '.join('%5s' % classes[labels[j]] for j in range(4)))
3. 定义卷积神经网络
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()
4. 定义损失函数
import torch.optim as optim
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
5. 在训练集上训练模型
for epoch in range(2): # loop over the dataset multiple times
running_loss = 0.0
for i, data in enumerate(trainloader, 0):
# data中包含输入图像张量inputs, 标签张量labels
inputs, labels = data
# 首先将优化器梯度归零
optimizer.zero_grad()
# 输入图像张量进网络, 得到输出张量outputs
outputs = net(inputs)
# 利用网络的输出outputs和标签labels计算损失值
loss = criterion(outputs, labels)
# 反向传播+参数更新, 是标准代码的标准流程
loss.backward()
optimizer.step()
# 打印轮次和损失值
running_loss += loss.item()
if (i + 1) % 2000 == 0:
print('[%d, %5d] loss: %.3f' %
(epoch + 1, i + 1, running_loss / 2000))
running_loss = 0.0
print('Finished Training')
# 保存模型
# 首先设定模型的保存路径
PATH = './cifar_net.pth'
# 保存模型的状态字典
torch.save(net.state_dict(), PATH)
6. 在测试集上测试模型
dataiter = iter(testloader)
images, labels = dataiter.next()
# 打印原始图片
imshow(torchvision.utils.make_grid(images))
# 打印真实的标签
print('GroundTruth: ', ' '.join('%5s' % classes[labels[j]] for j in range(4)))
# 加载模型并对测试图片进行预测
# 首先实例化模型的类对象
net = Net()
# 加载训练阶段保存好的模型的状态字典
net.load_state_dict(torch.load(PATH))
# 利用模型对图片进行预测
outputs = net(images)
# 共有10个类别, 采用模型计算出的概率最大的作为预测的类别
_, predicted = torch.max(outputs, 1)
# 打印预测标签的结果
print('Predicted: ', ' '.join('%5s' % classes[predicted[j]] for j in range(4)))
7. 模型评估
# 在全部测试集上的表现
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))
# 在每个类别上的表现
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]))
8. 在GPU上训练模型
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print(device)
# 将模型转移到GPU上
net.to(device)
# 将输入的图片张量和标签张量转移到GPU上
inputs, labels = data[0].to(device), data[1].to(device)
五、NLP所需环境
通过 pip3 freeze >requirements.tx 导出
absl-py==0.8.1
alabaster==0.7.12
anaconda-client==1.7.2
anaconda-navigator==1.9.7
anaconda-project==0.8.3
asn1crypto==1.0.1
astor==0.8.0
astroid==2.3.1
astropy==3.2.2
astunparse==1.6.3
atomicwrites==1.3.0
attrs==19.2.0
Babel==2.7.0
backcall==0.1.0
backports.functools-lru-cache==1.5
backports.os==0.1.1
backports.shutil-get-terminal-size==1.0.0
backports.tempfile==1.0
backports.weakref==1.0.post1
beautifulsoup4==4.8.0
bert-for-tf2==0.12.7
bitarray==1.0.1
bkcharts==0.2
bleach==3.1.0
blinker==1.4
bokeh==1.3.4
boto==2.49.0
boto3==1.10.29
botocore==1.13.29
bottle==0.12.18
Bottleneck==1.2.1
cachetools==3.1.1
certifi==2019.9.11
cffi==1.12.3
chardet==3.0.4
Click==7.0
cloudpickle==1.2.2
clyent==1.2.2
colorama==0.4.1
conda==4.7.12
conda-build==3.18.9
conda-package-handling==1.6.0
conda-verify==3.4.2
contextlib2==0.6.0
cryptography==2.7
cycler==0.10.0
Cython==0.29.13
cytoolz==0.10.0
dask==2.5.2
decorator==4.4.0
defusedxml==0.6.0
dill==0.3.1.1
distributed==2.5.2
docutils==0.15.2
entrypoints==0.3
et-xmlfile==1.0.1
fastcache==1.1.0
fasttext==0.9.1
filelock==3.0.12
Flask==1.1.1
fsspec==0.5.2
future==0.17.1
gast==0.3.3
gevent==1.4.0
glob2==0.7
gmpy2==2.0.8
google-auth==1.7.1
google-auth-oauthlib==0.4.1
google-pasta==0.1.8
googleapis-common-protos==1.51.0
googletrans==2.4.0
greenlet==0.4.15
grpcio==1.25.0
gunicorn==20.0.4
h5py==2.10.0
hanlp==2.0.0a10
HeapDict==1.0.1
html5lib==1.0.1
htmlmin==0.1.12
idna==2.8
imageio==2.6.0
imagesize==1.1.0
importlib-metadata==0.23
ipykernel==5.1.2
ipython==7.8.0
ipython-genutils==0.2.0
ipywidgets==7.5.1
isort==4.3.21
itsdangerous==1.1.0
jdcal==1.4.1
jedi==0.15.1
jeepney==0.4.1
jieba==0.40
Jinja2==2.10.3
jmespath==0.9.4
joblib==0.13.2
jsmin==2.2.2
json5==0.8.5
jsonschema==3.0.2
jupyter==1.0.0
jupyter-client==5.3.3
jupyter-console==6.0.0
jupyter-core==4.5.0
jupyterlab==1.1.4
jupyterlab-server==1.0.6
Keras==2.3.1
Keras-Applications==1.0.8
Keras-Preprocessing==1.1.0
keyring==18.0.0
kiwisolver==1.1.0
lazy-object-proxy==1.4.2
libarchive-c==2.8
lief==0.9.0
livereload==2.6.1
llvmlite==0.29.0
locket==0.2.0
lxml==4.4.1
Markdown==3.1.1
MarkupSafe==1.1.1
matplotlib==3.1.1
mccabe==0.6.1
mistune==0.8.4
mkdocs==1.0.4
mkdocs-material==4.6.0
mkdocs-minify-plugin==0.2.1
mkl-fft==1.0.14
mkl-random==1.1.0
mkl-service==2.3.0
mock==3.0.5
more-itertools==7.2.0
mpmath==1.1.0
msgpack==0.6.1
multipledispatch==0.6.0
navigator-updater==0.2.1
nbconvert==5.6.0
nbformat==4.4.0
neo4j==1.7.6
neo4j-driver==1.7.6
neobolt==1.7.15
neotime==1.7.4
networkx==2.3
nltk==3.4.5
nose==1.3.7
notebook==6.0.1
numba==0.45.1
numexpr==2.7.0
numpy==1.17.2
numpydoc==0.9.1
oauthlib==3.1.0
olefile==0.46
openpyxl==3.0.0
opt-einsum==3.1.0
packaging==19.2
pandas==0.25.3
pandocfilters==1.4.2
params-flow==0.7.4
parso==0.5.1
partd==1.0.0
path.py==12.0.1
pathlib2==2.3.5
patsy==0.5.1
pep562==1.0
pep8==1.7.1
pexpect==4.7.0
pickleshare==0.7.5
Pillow==6.2.0
pkginfo==1.5.0.1
pluggy==0.13.0
ply==3.11
prometheus-client==0.7.1
promise==2.3
prompt-toolkit==2.0.10
protobuf==3.11.0
psutil==5.6.3
ptyprocess==0.6.0
py==1.8.0
py-params==0.8.2
py2neo==4.3.0
pyasn1==0.4.8
pyasn1-modules==0.2.7
pybind11==2.4.3
pycodestyle==2.5.0
pycosat==0.6.3
pycparser==2.19
pycrypto==2.6.1
pycurl==7.43.0.3
pyflakes==2.1.1
Pygments==2.3.1
pylint==2.4.2
pymdown-extensions==6.2.1
pyodbc==4.0.27
pyOpenSSL==19.0.0
pyparsing==2.4.2
pyrsistent==0.15.4
PySocks==1.7.1
pytest==5.2.1
pytest-arraydiff==0.3
pytest-astropy==0.5.0
pytest-doctestplus==0.4.0
pytest-openfiles==0.4.0
pytest-remotedata==0.3.2
python-dateutil==2.8.0
pytz==2019.3
PyWavelets==1.0.3
PyYAML==5.1.2
pyzmq==18.1.0
QtAwesome==0.6.0
qtconsole==4.5.5
QtPy==1.9.0
redis==3.3.11
regex==2019.11.1
requests==2.22.0
requests-oauthlib==1.3.0
rope==0.14.0
rsa==4.0
ruamel-yaml==0.15.46
s3transfer==0.2.1
sacremoses==0.0.35
scikit-image==0.15.0
scikit-learn==0.19.2
scipy==1.4.1
seaborn==0.9.0
SecretStorage==3.1.1
selenium==3.141.0
Send2Trash==1.5.0
sentencepiece==0.1.85
sentry-sdk==0.10.2
seqeval==0.0.12
simplegeneric==0.8.1
singledispatch==3.4.0.3
six==1.12.0
snowballstemmer==2.0.0
sortedcollections==1.1.2
sortedcontainers==2.1.0
soupsieve==1.9.3
Sphinx==2.2.0
sphinxcontrib-applehelp==1.0.1
sphinxcontrib-devhelp==1.0.1
sphinxcontrib-htmlhelp==1.0.2
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==1.0.2
sphinxcontrib-serializinghtml==1.1.3
sphinxcontrib-websupport==1.1.2
spyder==3.3.6
spyder-kernels==0.5.2
SQLAlchemy==1.3.9
statsmodels==0.10.1
sympy==1.4
tables==3.5.2
tblib==1.4.0
tensorboard==2.2.2
tensorboard-plugin-wit==1.7.0
tensorboardX==1.9
tensorflow==2.2.0
tensorflow-datasets==2.0.0
tensorflow-estimator==2.2.0
tensorflow-hub==0.8.0
tensorflow-metadata==0.21.1
termcolor==1.1.0
terminado==0.8.2
testpath==0.4.2
toolz==0.10.0
torch==1.3.1
torchtext==0.4.0
torchvision==0.4.2
tornado==6.0.3
tqdm==4.36.1
traitlets==4.3.3
transformers==2.3.0
unicodecsv==0.14.1
urllib3==1.24.2
wcwidth==0.1.7
webencodings==0.5.1
Werkzeug==0.16.0
WeRoBot==1.9.0
widgetsnbextension==3.5.1
wrapt==1.11.2
wurlitzer==1.0.3
xlrd==1.2.0
XlsxWriter==1.2.1
xlwt==1.3.0
xmltodict==0.12.0
zict==1.0.0
zipp==0.6.0