What is Pytorch?
Pytorch 是 torch 的 python 版本,是由 Facebook 开源的神经网络框架,专门针对 GPU 加速的深度神经网络 (DNN) 编程。简单说起来就是与 tensorflow 竞争的产品,不论使用哪一个,最终都能得到差不多的效果。
How to use Pytorch
了解一个框架(语言),最重要的环节便是熟悉语法、方法和接口。较为基础和重要的一些将列在下面。 首先默认你已经安装了 Pytorch 并且能够正常引入,并且已经学习并掌握了 numpy。
Numpy桥
同 tensorflow 一样,pytorch 的常用数据类型也是 Tensor,Tensor 是一种包含单一数据类型元素的多维矩阵,译作“张量”(张晟的弟弟)。 类比 numpy,一维 Tensor 叫 Vector,二维 Tensor叫 Matrix,三维及以上称为 Tensor。 而 numpy 和 Tensor 不仅仅有相似之处,还可以相互转换。
torch.from_numpy(ndarray) -> Tensor
import torch
np_data = np.array([7, 2, 3])
torch_data = torch.from_numpy(np_data)
此时得到的 torch_data 与 np_data 共享同一内存空间。修改其中一个另一个也会被修改,且返回的张量不能改变大小。
torch_data[0] = -1
print(np_data)
同时 Tensor 也可以转换为 numpy.ndarray。
torch.numpy() -> ndarray
tensor2array = torch_data.numpy()
Tensor 创建
对于 Python,常用的基本数据类型有 int、float、double 等,与之对应 Pytorch 也提供了多种类型的 tensor。
Pytorch 定了七种 CPU tensor 类型和八种 GPU tensor 类型:
数据类型 | CPU Tensor | GPU Tensor |
---|
32-bit floating point | torch.FloatTensor | torch.cuda.FloatTensor | 64-bit floating point | torch.DoubleTensor | torch.cuda.DoubleTensor | 16-bit floating point | N/A | torch.cuda.HalfTensor | 8-bit integer (unsigned) | torch.ByteTensor | torch.cuda.ByteTensor | 8-bit integer (signed) | torch.CharTensor | torch.cuda.CharTensor | 16-bit integer (signed) | torch.ShortTensor | torch.cuda.ShortTensor | 32-bit integer (signed) | torch.IntTensor | torch.cuda.IntTensor | 64-bit integer (signed) | torch.LongTensor | torch.cuda.LongTensor |
torch.Tensor是默认的tensor类型(torch.FloatTensor)的简称。
t1 = torch.Tensor(2,2)
一个张量还可以从 Python 的 list 或序列构建得到。
t1 = torch.FloatTensor([[1, 2, 3],
[4, 5, 6]])
其次还有许多创建特殊矩阵的方法:
- torch.ones(n,m): 创建n*m 维的张量,其元素都被填充了标量值1;
- torch.zeros(n,m): 创建n*m 维的张量,其元素都被填充了标量值0;
- torch.eye(n,m): 创建n*m 维的张量,其对角线为1,其余元素均为0;
- torch.linspace(start, end, steps=100) : 创建值start和 end之间等间距点的一维张量;
- torch.rand(sizes): 返回一个张量,包含了从区间[0,1)的均匀分布中抽取的一组随机数,其形状由整数序列sizes定义;
- torch.randn(sizes): 返回一个张量,包含了从标准正态分布(均值为0,方差为1,即高斯白噪声)中抽取一组随机数,其形状由整数序列sizes定义。
在实际应用中,常常使用 torch.size() 获取 Tensor 的大小。
a = torch.randn(2,2)
print(a)
print(a.size())
Tensor 索引及切片
索引
- 正序索引:Tensor 的索引值从 0 开始,范围从 0 到 size - 1。
t = torch.Tensor(range(5))
print(t)
print(t[1])
print(t[0:3])
- 逆序索引(tensor[ : , -1 ]): 最后一个索引为 -1。
- 负索引(tensor[ -3 ]):表示倒数第三个元素,注意索引值的大小,始终是小值在冒号的前面,[ -3, -1 ],大值在后。若写成[ -1, -3 ]将会报错。
切片 基本切片通过将 start, stop 和 step 参数提供给内置的 slice 函数来构造一个 Python slice 对象。此 slice 对象被传递给 Tensor 来提取 Tensor 的一部分。
t = torch.Tensor(range(5))
s = slice(2,5,2)
print("Slicing Tensor : {}".format(t[s]))
print(t[2 : 5 : 2])
在二维情况下,以逗号进行分割。
tensor = torch.Tensor([[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
[10, 11, 12]])
print(tensor[0 : 3 : 2, : ])
还有其他常用函数: torch.chunk(tensor, chunks, dim = 0) 将张量沿给定维度拆分成若干块。(将要拆分的张量,返回的块数,所沿拆分维度)
torch.cat(seq, dim = 0, out = None) -> Tensor 在给定维度上连接张量的给定序列。(Python 序列,张量连接的维度,输出参数)
torch.unsqueeze(input, dim, out = None) 返回在指定位置插入尺寸为1的新张量。(输入的张量,插入单个维度的索引,结果张量)
基本运算
相加
- x + y
- torch.add(x, y)
- y.add_(x)
x = torch.Tensor(2, 3)
y = torch.rand(2, 3)
print(x + y)
print(torch.add(x, y))
y.add_(x)
print(y)
类似的
函数 | 描述 |
---|
torch.sqrt(t) | 返回一个新张量,元素为输入的元素开方后的结果 | torch.round(t) | 返回一个新张量,元素为输入的元素四舍五入到最接近的整数 | torch.sign(t) | 返回一个新张量,元素为输入的元素的符号,正为1,负为-1 | torch.transpose(t) | 返回一个新张量,为原来张量的转置 | torch.abs(t) | 返回一个新张量,元素为输入元素的绝对值 | torch.ceil(t) | 返回一个新张量,元素为大于输入元素最小的整数 | torch.cos(t) | 返回一个新张量,元素为输入元素的 cos值 | torch.sin(t) | 返回一个新张量,元素为输入元素的sin值 |
Reshape
view 在处理数据时,由于不同的需求,我们常常需要将数据进行扩充或者在尺寸上进行变化以进行操作。
这里我们使用 view() 方法,返回具有相同数据但大小不同的新张量,从而达到了 reshape 的作用。
view(args) -> Tensor 返回具有相同数据但大小不同的张量。张量必须 contiguous() 才能被查看。 关于 contiguous(),可以参考下面这篇博客,讲的很不错!
https://blog.csdn.net/kdongyi/article/details/108180250
转置 由下面两种转置产生的结果张量,与输入张量共享存储。
torch.t(input, out = None) -> Tensor 将输入的二维张量转置其维度 0 和 1。(只适用于二维张量)
x = torch.randn(5, 10)
print(x.t().size())
torch.transpose(input, dim0, dim1, out = None) -> Tensor 返回一个输入转置后的张量,使两个维度相互交换。
y = torch.randn(5, 10, 15)
print(y.transpose(0, 1).size())
print(y.transpose(1, 2).size())
求导及梯度
在 0.4 版本以前,pytorch 使用 Variable 进行自动求导和梯度,可以参考这篇文章:
https://zhuanlan.zhihu.com/p/104519573
现在推荐使用的方法如下: 在 Tensor 中有一个参数 requires_grad,表示是否可以求导,即求梯度,默认值为 False。需要注意的是,当叶子结点有一个为可导,则根结点可导。
在使用中,我们通过: x.requires_grad_(True / False) 设置 tensor 可导与否。但是我们只能这样设置叶子变量,否则会报错!
我们针对一个函数求梯度:
x为 2 * 2 的值全为1的张量
y
i
=
(
x
i
+
4
)
2
y_i = (x_i + 4)^2
yi?=(xi?+4)2
z
i
=
y
i
2
+
x
i
+
2
z_i = y_i^2 + x_i + 2
zi?=yi2?+xi?+2
o
u
t
=
1
4
∑
i
=
1
4
z
i
out = \frac{1}{4}\sum_{i=1}^4z_i
out=41?∑i=14?zi?
下面对 out 求关于 x 的导数:
?
o
u
t
?
x
=
(
x
+
4
)
3
+
0.25
=
125.25
\frac{\partial{out}}{\partial{x}}=(x + 4)^3 + 0.25 = 125.25
?x?out?=(x+4)3+0.25=125.25
然后编程验证:
x = torch.ones(2, 2, requires_grad = True)
y = (x + 4) ** 2
z = y**2 + x + 2
out = z.mean()
out.backward()
print(x.grad)
我们可以使用 with torch.no_grad() 来停止梯度的计算:
print(x.requires_grad)
print((x ** 2).requires_grad)
with torch.no_grad():
print((x ** 2).requires_grad)
先到这儿吧,明天加油!
|