第一章:PyTorch 入门

2023-06-26,

第一章:PyTorch 入门

1.1 Pytorch 简介
1.1.1 PyTorch的由来
1.1.2 Torch是什么?
1.1.3 重新介绍 PyTorch
1.1.4 对比PyTorch和Tensorflow
1.1.5 再次总结
1.2 Pytorch环境搭建
1.2.1 安装Pytorch
1.2.2 配置 Jupyter Notebook
1.2.3 测试
1.2.4 问题解决
问题1:启动python提示编码错误
问题2 默认目录设置不起效
1.3 PyTorch 深度学习:60分钟快速入门 (官方)
1. 张量
PyTorch是什么?
开始
NumPy 转换
CUDA 张量
2. Autograd: 自动求导
Autograd: 自动求导机制
张量(Tensor)
梯度

1.1 Pytorch 简介

1.1.1 PyTorch的由来

很多人都会拿PyTorch和Google的Tensorflow进行比较,这个肯定是没有问题的,因为他们是最火的两个深度学习框架了。但是说到PyTorch,其实应该先说Torch。

1.1.2 Torch是什么?

Torch英译中:火炬

A Tensor library like Numpy, unlike Numpy it has strong GPU support. Lua is a wrapper for Torch (Yes! you need to have a good understanding of Lua), and for that you will need LuaRocks package manager.

1

Torch是一个与Numpy类似的张量(Tensor)操作库,与Numpy不同的是Torch对GPU支持的很好,Lua是Torch的上层包装。

Torch is not going anywhere. PyTorch and Torch use the same C libraries that contain all the performance: TH, THC, THNN, THCUNN and they will continue to be shared.
We still and will have continued engineering on Torch itself, and we have no immediate plan to remove that.

2

PyTorch和Torch使用包含所有相同性能的C库:TH, THC, THNN, THCUNN,并且它们将继续共享这些库。

这样的回答就很明确了,其实PyTorch和Torch都使用的是相同的底层,只是使用了不同的上层包装语言。

注:LUA虽然快,但是太小众了,所以才会有PyTorch的出现。

1.1.3 重新介绍 PyTorch

PyTorch is an open source machine learning library for Python, based on Torch, used for applications such as natural language processing. It is primarily developed by Facebook's artificial-intelligence research group, and Uber's "Pyro" software for probabilistic programming is built on it.

3

PyTorch是一个基于Torch的Python开源机器学习库,用于自然语言处理等应用程序。 它主要由Facebook的人工智能研究小组开发。Uber的"Pyro"也是使用的这个库。

PyTorch is a Python package that provides two high-level features:

    Tensor computation (like NumPy) with strong GPU acceleration

    Deep neural networks built on a tape-based autograd system
You can reuse your favorite Python packages such as NumPy, SciPy and Cython to extend PyTorch when needed.

4

PyTorch是一个Python包,提供两个高级功能:

具有强大的GPU加速的张量计算(如NumPy)
包含自动求导系统的的深度神经网络

1.1.4 对比PyTorch和Tensorflow

没有好的框架,只有合适的框架, 这篇知乎文章有个简单的对比,所以这里就不详细再说了。
并且技术是发展的,知乎上的对比也不是绝对的,比如Tensorflow在1.5版的时候就引入了Eager Execution机制实现了动态图,PyTorch的可视化,windows支持,沿维翻转张量等问题都已经不是问题了。

1.1.5 再次总结

PyTorch算是相当简洁优雅且高效快速的框架
设计追求最少的封装,尽量避免重复造轮子
算是所有的框架中面向对象设计的最优雅的一个,设计最符合人们的思维,它让用户尽可能地专注于实现自己的想法
大佬支持,与google的Tensorflow类似,FAIR的支持足以确保PyTorch获得持续的开发更新
不错的的文档(相比FB的其他项目,PyTorch的文档简直算是完善了,参考Thrift),PyTorch作者亲自维护的论坛 供用户交流和求教问题
入门简单

所以如果以上信息有吸引你的内容,那么请一定要读完这本书:)

1.2 Pytorch环境搭建

PyTorch的安装十分简单,根据PyTorch官网,对系统选择和安装方式等灵活选择即可。
这里以anaconda为例,简单的说一下步骤和要点。
国内安装anaconda建议使用清华镜像。

前些日子,由于合规问题中科大、清华镜像都已经关闭。目前只有清华镜像恢复,所以目前可以继续使用

1.2.1 安装Pytorch

pytorch的安装经过了几次变化,请大家以官网的安装命令为准。另外需要说明的就是在1.2版本以后,pytorch只支持cuda 9.2以上了,所以需要对cuda进行升级,目前测试大部分显卡都可以用,包括笔记本的MX250也是可以顺利升级到cuda 10.1。

我个人测试使用官网的安装命令进行安装时并不能安装1.3版原因未知(如果大家conda安装也有问题可以一起讨论下原因),所以这里建议大家使用pip进行安装,经过测试 pip是没有任何问题的。

目前(2020/7)的稳定版本为1.5.1。

#默认 使用 cuda10.2
pip3 install torch===1.5.1 torchvision===0.6.1 -f https://download.pytorch.org/whl/torch_stable.html #cuda 9.2
pip3 install torch==1.5.1+cu92 torchvision==0.6.1+cu92 -f https://download.pytorch.org/whl/torch_stable.html #cpu版本
pip install torch==1.5.1+cpu torchvision==0.6.1+cpu -f https://download.pytorch.org/whl/torch_stable.html

验证输入python 进入

import torch
torch.__version__
# 得到结果'1.5.0'

1.2.2 配置 Jupyter Notebook

新建的环境是没有安装安装ipykernel的所以无法注册到Jupyter Notebook中,所以先要准备下环境

#安装ipykernel
conda install ipykernel
#写入环境
python -m ipykernel install --name pytorch --display-name "Pytorch for Deeplearning"

下一步就是定制 Jupyter Notebook

#切换回基础环境
activate base
#创建jupyter notebook配置文件
jupyter notebook --generate-config
## 这里会显示创建jupyter_notebook_config.py的具体位置

打开文件,修改

c.NotebookApp.notebook_dir = '' 默认目录位置
c.NotebookApp.iopub_data_rate_limit = 100000000 这个改大一些否则有可能报错

1.2.3 测试

至此 Pytorch 的开发环境安装完成,可以在开始菜单中打开Jupyter Notebook 在New 菜单中创建文件时选择Pytorch for Deeplearning 创建PyTorch的相关开发环境了

1.2.4 问题解决

问题1:启动python提示编码错误

删除 .python_history 来源

问题2 默认目录设置不起效

打开快捷方式,看看快捷方式是否跟这个截图一样,如果是则删除 %USERPROFILE% 改参数会覆盖掉notebook_dir设置,导致配置不起效

如果你还发现其他问题,请直接留言

1.3 PyTorch 深度学习:60分钟快速入门 (官方)

%matplotlib inline

1. 张量

PyTorch是什么?

基于Python的科学计算包,服务于以下两种场景:

作为NumPy的替代品,可以使用GPU的强大计算能力
提供最大的灵活性和高速的深度学习研究平台

开始


Tensors(张量)

Tensors与Numpy中的 ndarrays类似,但是在PyTorch中
Tensors 可以使用GPU进行计算.

from __future__ import print_function
import torch

创建一个 5x3 矩阵, 但是未初始化:

x = torch.empty(5, 3)
print(x)
tensor([[1.0745e-38, 1.1112e-38, 1.0286e-38],
[1.0653e-38, 1.0194e-38, 8.4490e-39],
[1.1112e-38, 9.5511e-39, 1.0102e-38],
[4.6837e-39, 5.0510e-39, 5.1429e-39],
[9.9184e-39, 9.0000e-39, 1.0561e-38]])

创建一个随机初始化的矩阵:

x = torch.rand(5, 3)
print(x)
tensor([[0.6972, 0.0231, 0.3087],
[0.2083, 0.6141, 0.6896],
[0.7228, 0.9715, 0.5304],
[0.7727, 0.1621, 0.9777],
[0.6526, 0.6170, 0.2605]])

创建一个0填充的矩阵,数据类型为long:

x = torch.zeros(5, 3, dtype=torch.long)
print(x)
tensor([[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]])

创建tensor并使用现有数据初始化:

x = torch.tensor([5.5, 3])
print(x)
tensor([5.5000, 3.0000])

根据现有的张量创建张量。 这些方法将重用输入张量的属性,例如, dtype,除非设置新的值进行覆盖

x = x.new_ones(5, 3, dtype=torch.double)      # new_* 方法来创建对象
print(x) x = torch.randn_like(x, dtype=torch.float) # 覆盖 dtype!
print(x) # 对象的size 是相同的,只是值和类型发生了变化
tensor([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]], dtype=torch.float64)
tensor([[ 0.5691, -2.0126, -0.4064],
[-0.0863, 0.4692, -1.1209],
[-1.1177, -0.5764, -0.5363],
[-0.4390, 0.6688, 0.0889],
[ 1.3334, -1.1600, 1.8457]])

获取 size

译者注:使用size方法与Numpy的shape属性返回的相同,张量也支持shape属性,后面会详细介绍

print(x.size())
torch.Size([5, 3])

Note

``torch.Size`` 返回值是 tuple类型, 所以它支持tuple类型的所有操作.

操作

操作有多种语法。

我们将看一下加法运算。

加法1:

y = torch.rand(5, 3)
print(x + y)
tensor([[ 0.7808, -1.4388,  0.3151],
[-0.0076, 1.0716, -0.8465],
[-0.8175, 0.3625, -0.2005],
[ 0.2435, 0.8512, 0.7142],
[ 1.4737, -0.8545, 2.4833]])

加法2

print(torch.add(x, y))
tensor([[ 0.7808, -1.4388,  0.3151],
[-0.0076, 1.0716, -0.8465],
[-0.8175, 0.3625, -0.2005],
[ 0.2435, 0.8512, 0.7142],
[ 1.4737, -0.8545, 2.4833]])

提供输出tensor作为参数

result = torch.empty(5, 3)
torch.add(x, y, out=result)
print(result)
tensor([[ 0.7808, -1.4388,  0.3151],
[-0.0076, 1.0716, -0.8465],
[-0.8175, 0.3625, -0.2005],
[ 0.2435, 0.8512, 0.7142],
[ 1.4737, -0.8545, 2.4833]])

替换

# adds x to y
y.add_(x)
print(y)
tensor([[ 0.7808, -1.4388,  0.3151],
[-0.0076, 1.0716, -0.8465],
[-0.8175, 0.3625, -0.2005],
[ 0.2435, 0.8512, 0.7142],
[ 1.4737, -0.8545, 2.4833]])

Note

任何 以``_`` 结尾的操作都会用结果替换原变量. 例如: ``x.copy_(y)``, ``x.t_()``, 都会改变 ``x``.

你可以使用与NumPy索引方式相同的操作来进行对张量的操作

print(x[:, 1])
tensor([-2.0126,  0.4692, -0.5764,  0.6688, -1.1600])

torch.view: 可以改变张量的维度和大小

译者注:torch.view 与Numpy的reshape类似

x = torch.randn(4, 4)
y = x.view(16)
z = x.view(-1, 8) # size -1 从其他维度推断
print(x.size(), y.size(), z.size())
torch.Size([4, 4]) torch.Size([16]) torch.Size([2, 8])

如果你有只有一个元素的张量,使用.item()来得到Python数据类型的数值

x = torch.randn(1)
print(x)
print(x.item())
tensor([-0.2368])
-0.23680149018764496

Read later:

100+ Tensor operations, including transposing, indexing, slicing,
mathematical operations, linear algebra, random numbers, etc.,
are described
here <https://pytorch.org/docs/torch>_.

NumPy 转换

将一个Torch Tensor转换为NumPy数组是一件轻松的事,反之亦然。

Torch Tensor与NumPy数组共享底层内存地址,修改一个会导致另一个的变化。

将一个Torch Tensor转换为NumPy数组

a = torch.ones(5)
print(a)
tensor([1., 1., 1., 1., 1.])
b = a.numpy()
print(b)
[1. 1. 1. 1. 1.]

观察numpy数组的值是如何改变的。

a.add_(1)
print(a)
print(b)
tensor([2., 2., 2., 2., 2.])
[2. 2. 2. 2. 2.]

NumPy Array 转化成 Torch Tensor

使用from_numpy自动转化

import numpy as np
a = np.ones(5)
b = torch.from_numpy(a)
np.add(a, 1, out=a)
print(a)
print(b)
[2. 2. 2. 2. 2.]
tensor([2., 2., 2., 2., 2.], dtype=torch.float64)

所有的 Tensor 类型默认都是基于CPU, CharTensor 类型不支持到
NumPy 的转换.

CUDA 张量

使用.to 方法 可以将Tensor移动到任何设备中

# is_available 函数判断是否有cuda可以使用
# ``torch.device``将张量移动到指定的设备中
if torch.cuda.is_available():
device = torch.device("cuda") # a CUDA 设备对象
y = torch.ones_like(x, device=device) # 直接从GPU创建张量
x = x.to(device) # 或者直接使用``.to("cuda")``将张量移动到cuda中
z = x + y
print(z)
print(z.to("cpu", torch.double)) # ``.to`` 也会对变量的类型做更改
tensor([0.7632], device='cuda:0')
tensor([0.7632], dtype=torch.float64)

2. Autograd: 自动求导

本章是冲突的重灾区,建议阅读

%matplotlib inline

Autograd: 自动求导机制

PyTorch 中所有神经网络的核心是 autograd 包。
我们先简单介绍一下这个包,然后训练第一个简单的神经网络。

autograd包为张量上的所有操作提供了自动求导。
它是一个在运行时定义的框架,这意味着反向传播是根据你的代码来确定如何运行,并且每次迭代可以是不同的。

示例

张量(Tensor)

torch.Tensor是这个包的核心类。如果设置
.requires_gradTrue,那么将会追踪所有对于该张量的操作。
当完成计算后通过调用 .backward(),自动计算所有的梯度,
这个张量的所有梯度将会自动积累到 .grad 属性。

要阻止张量跟踪历史记录,可以调用.detach()方法将其与计算历史记录分离,并禁止跟踪它将来的计算记录。

为了防止跟踪历史记录(和使用内存),可以将代码块包装在with torch.no_grad():中。
在评估模型时特别有用,因为模型可能具有requires_grad = True的可训练参数,但是我们不需要梯度计算。

在自动梯度计算中还有另外一个重要的类Function.

Tensor and Function are interconnected and build up an acyclic
graph, that encodes a complete history of computation. Each tensor has
a .grad_fn attribute that references a Function that has created
the Tensor (except for Tensors created by the user - their
grad_fn is None).

TensorFunction互相连接并生成一个非循环图,它表示和存储了完整的计算历史。
每个张量都有一个.grad_fn属性,这个属性引用了一个创建了TensorFunction(除非这个张量是用户手动创建的,即,这个张量的
grad_fnNone)。

如果需要计算导数,你可以在Tensor上调用.backward()
如果Tensor是一个标量(即它包含一个元素数据)则不需要为backward()指定任何参数,
但是如果它有更多的元素,你需要指定一个gradient 参数来匹配张量的形状。

译者注:在其他的文章中你可能会看到说将Tensor包裹到Variable中提供自动梯度计算,Variable 这个在0.41版中已经被标注为过期了,现在可以直接使用Tensor,官方文档在这里:
https://pytorch.org/docs/stable/autograd.html#variable-deprecated

具体的后面会有详细说明

import torch

创建一个张量并设置 requires_grad=True 用来追踪他的计算历史

x = torch.ones(2, 2, requires_grad=True)
print(x)
tensor([[1., 1.],
[1., 1.]], requires_grad=True)

对张量进行操作:

y = x + 2
print(y)
tensor([[3., 3.],
[3., 3.]], grad_fn=<AddBackward0>)

结果y已经被计算出来了,所以,grad_fn已经被自动生成了。

print(y.grad_fn)
<AddBackward0 object at 0x000002004F7CC248>

对y进行一个操作

z = y * y * 3
out = z.mean() print(z, out)
tensor([[27., 27.],
[27., 27.]], grad_fn=<MulBackward0>) tensor(27., grad_fn=<MeanBackward0>)

.requires_grad_( ... ) 可以改变现有张量的 requires_grad属性。
如果没有指定的话,默认输入的flag是 False

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)
False
True
<SumBackward0 object at 0x000002004F7D5608>

梯度

反向传播
因为 out是一个纯量(scalar),out.backward() 等于out.backward(torch.tensor(1))

out.backward()

print gradients d(out)/dx

print(x.grad)
tensor([[4.5000, 4.5000],
[4.5000, 4.5000]])

得到矩阵 4.5.将 out叫做
Tensor

o

o

o”.

得到

o

=

1

4

i

z

i

o = \frac{1}{4}\sum_i z_i

o=41​∑i​zi​,

z

i

=

3

(

x

i

+

2

)

2

z_i = 3(x_i+2)^2

zi​=3(xi​+2)2 和

z

i

x

i

=

1

=

27

z_i\bigr\rvert_{x_i=1} = 27

zi​∣∣​xi​=1​=27.

因此,

o

x

i

=

3

2

(

x

i

+

2

)

\frac{\partial o}{\partial x_i} = \frac{3}{2}(x_i+2)

∂xi​∂o​=23​(xi​+2), 则

o

x

i

x

i

=

1

=

9

2

=

4.5

\frac{\partial o}{\partial x_i}\bigr\rvert_{x_i=1} = \frac{9}{2} = 4.5

∂xi​∂o​∣∣​xi​=1​=29​=4.5.

在数学上,如果我们有向量值函数

y

=

f

(

x

)

)

\vec{y} = f(\vec{x}))

y

​=f(x

)) ,且

y

\vec{y}

y

​ 关于

x

\vec{x}

x

的梯度是一个雅可比矩阵(Jacobian matrix):

J

=

(

y

1

x

1

y

1

x

n

y

m

x

1

y

m

x

n

)

J = \begin{pmatrix} \frac{\partial y_{1}}{\partial x_{1}} & \cdots & \frac{\partial y_{1}}{\partial x_{n}} \\ \vdots & \ddots & \vdots \\ \frac{\partial y_{m}}{\partial x_{1}} & \cdots & \frac{\partial y_{m}}{\partial x_{n}} \end{pmatrix}

J=⎝⎜⎛​∂x1​∂y1​​⋮∂x1​∂ym​​​⋯⋱⋯​∂xn​∂y1​​⋮∂xn​∂ym​​​⎠⎟⎞​

一般来说,torch.autograd就是用来计算vector-Jacobian product的工具。也就是说,给定任一向量

v

=

(

v

1

  

v

2

  


  

v

m

)

T

v=(v_{1}\;v_{2}\;\cdots\;v_{m})^{T}

v=(v1​v2​⋯vm​)T ,计算

v

T

J

v^{T}\cdot J

vT⋅J ,如果

v

v

v 恰好是标量函数

l

=

g

(

y

)

l=g(\vec{y})

l=g(y

​) 的梯度,也就是说

v

=

(

l

y

1

  


  

l

y

m

)

T

v=(\frac{\partial l}{\partial y_{1}}\;\cdots\;\frac{\partial l}{\partial y_{m}})^{T}

v=(∂y1​∂l​⋯∂ym​∂l​)T,那么根据链式法则,vector-Jacobian product 是

x

\vec{x}

x

l

l

l 的梯度:

J

T

v

=

(

y

1

x

1

y

m

x

1

y

1

x

n

y

m

x

n

)

(

l

y

1

l

y

m

)

=

(

l

x

1

l

x

n

)

J^{T}\cdot v = \begin{pmatrix} \frac{\partial y_{1}}{\partial x_{1}} & \cdots & \frac{\partial y_{m}}{\partial x_{1}} \\ \vdots & \ddots & \vdots \\ \frac{\partial y_{1}}{\partial x_{n}} & \cdots & \frac{\partial y_{m}}{\partial x_{n}} \end{pmatrix} \begin{pmatrix} \frac{\partial l}{\partial y_{1}}\\ \vdots \\ \frac{\partial l}{\partial y_{m}} \end{pmatrix} = \begin{pmatrix} \frac{\partial l}{\partial x_{1}}\\ \vdots \\ \frac{\partial l}{\partial x_{n}} \end{pmatrix}

JT⋅v=⎝⎜⎛​∂x1​∂y1​​⋮∂xn​∂y1​​​⋯⋱⋯​∂x1​∂ym​​⋮∂xn​∂ym​​​⎠⎟⎞​⎝⎜⎛​∂y1​∂l​⋮∂ym​∂l​​⎠⎟⎞​=⎝⎜⎛​∂x1​∂l​⋮∂xn​∂l​​⎠⎟⎞​

(注意,

v

T

J

v^{T}\cdot J

vT⋅J 给出了一个行向量,可以通过

J

T

v

J^{T}\cdot v

JT⋅v 将其视为列向量)

vector-Jacobian product 这种特性使得将外部梯度返回到具有非标量输出的模型变得非常方便。

现在让我们来看一个vector-Jacobian product的例子

x = torch.randn(3, requires_grad=True)

y = x * 2
while y.data.norm() < 1000:
y = y * 2 print(y)
tensor([ 293.4463,   50.6356, 1031.2501], grad_fn=<MulBackward0>)

在这个情形中,y不再是个标量。torch.autograd无法直接计算出完整的雅可比行列,但是如果我们只想要vector-Jacobian product,只需将向量作为参数传入backward

gradients = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float)
y.backward(gradients) print(x.grad)
tensor([5.1200e+01, 5.1200e+02, 5.1200e-02])

如果.requires_grad=True但是你又不希望进行autograd的计算,
那么可以将变量包裹在 with torch.no_grad()中:

print(x.requires_grad)
print((x ** 2).requires_grad) with torch.no_grad():
print((x ** 2).requires_grad)
True
True
False

稍后阅读:

autogradFunction 的官方文档 https://pytorch.org/docs/autograd

第一章:PyTorch 入门的相关教程结束。

《第一章:PyTorch 入门.doc》

下载本文的Word格式文档,以方便收藏与打印。