Pytorch的基本使用
本篇内容参考官方文档自己总结而来仅供自学自查,详细需求请查阅官方文档。
数据类型
-
张量(
Tnsor
)
什么是张量?简单来说就可以看成是向量。一阶张量,就是一维向量,如此如此。
1. torch自己的方法构造的数据都是默认为Tensor的张量,比如:
- 定值构造
定值构造方法还有很多,如下:
import torch
torch.Tensor(list/ndarray)#---->将列表转为,数组转为tensor
torch.eye(3)#---->生成3行3列的值为1的对角矩阵
torch.linspace(start, end, steps=100, out=None)#---->等差数列矩阵
torch.logspace(start, end, steps=100, out=None)#---->对数等差数列矩阵
torch.zeros()、ones()、等等方法和numpy类似,不一一举例。
- 随机构造
这类构造方法也不少,如下:
import torch
torch.rand(2,2)# ----->生成2X2的矩阵,数值再0-1之间
torch.randn(2,2)# ---->生服从标准正态分布的2X2
torch.arange(1,20,2)# ---->序列数组
2. numpy的array或者list数组转换而来。
这里介绍一下numpy的array和torch的tensor的区别,numpy的array是不支持GPU的,只支持CPU。而torch的tensor是两个都支持的。
- array转tensor-----
orch.from_numpy()
>>> a = numpy.array([1, 2, 3])
>>> t = torch.from_numpy(a)
>>> t
torch.LongTensor([1, 2, 3])
>>> t[0] = -1
>>> a
array([-1, 2, 3])
这个方法有一个缺点也是优点,生成的tensor和array指向同一个内存地址,一个变了都会变。
- tensor转array
tensor转成其他的数据的方法有很多,如下:
import torch
a = torch.rand(2,2)
# to numpy.ndarray
a.numpy()
# 转换成支持CPU
a.cpu()
# 转换成支持GPU
a.cuda()
3. tensor的属性
- 数据类型
32位浮点型:torch.FloatTensor。也是pyorch.Tensor()的默认类型。
64位整型:torch.LongTensor。
32位整型:torch.IntTensor。
16位整型:torch.ShortTensor。
64位浮点型:torch.DoubleTensor。 - 张量的大小
tensor.size()
tensor.shape
>>> tt1
tensor([[0.1372, 0.6473, 0.6765],
[0.3346, 0.1886, 0.4174]])
>>> tt1.shape
torch.Size([2, 3])
>>> tt1.size()
torch.Size([2, 3])
- 张量的元素个数
torch.numel(input)
>>> tt1.numel()
6
>>> torch.numel(tt1)
6
基本上张量的简介就差不多了,更多内容参考pytorch中文文档。
-
变量(
Variable
)
Variable类型数据是张量的升级版,给tensor加了装备:前向传播
、反向传播
、自动求导
等功能,在计算图的构建中起的很重要的作用。有一个图能很形象的说明:
其中最重要的两个属性是:data和grad。.data表示该变量保存的实际数据,通过该属性可以访问到它所保存的原始张量类型,而关于该 variable(变量)的梯度会被累计到.grad 上去。与tensor不同,Variable在另一个模块内----torch.autograd。
不过,pytorch 0.4之后的版本,好像把Tensor和Variabel合并了。requires_grad变成了Tensor本来的一个属性了。
这里给一片博客可以参考
import torch
from torch.autograd import Variable
# 定义三个Variable变量
# requires_grad 是设置是否需要计算梯度
x = Variable(torch.Tensor([1, 2, 3]), requires_grad=True)
w = Variable(torch.Tensor([2, 3, 4]), requires_grad=True)
b = Variable(torch.Tensor([3, 4, 5]), requires_grad=True)
# 构建计算图,公式为:y = w * x^2 + b
y = w * x * x + b
# 自动求导,计算梯度
# 这里传入的torch.Tensor([1,1,1])是用来表示每个梯度的权重的
y.backward(torch.Tensor([1, 1, 1]))
print(x.grad)# 2*w*x
print(w.grad)# x*x
print(b.grad)# 常量的导数为1
数据操作
- 索引 ---- 和numpy
的索引相同
>>> tt1
tensor([[0.1372, 0.6473, 0.6765],
[0.3346, 0.1886, 0.4174]])
>>> tt1[1,1]
tensor(0.1886)
>>> tt1[:,2]
tensor([0.6765, 0.4174])
- 切片---- 和numpy
的切片相同
>>> tt1
tensor([[-0.3623, -0.6115, 0.7283],
[ 0.4699, 2.3261, 0.1599]])
>>> tt1[:,1:2]
tensor([[-0.6115],
[ 2.3261]])
>>> tt1[:,:]
tensor([[-0.3623, -0.6115, 0.7283],
[ 0.4699, 2.3261, 0.1599]])
- 连接 ---- torch.cat()
>>> tt1 = torch.rand(2,3)
>>> tt2 = torch.rand(2,3)
>>> torch.cat((tt1,tt2),0)
tensor([[0.1372, 0.6473, 0.6765],
[0.3346, 0.1886, 0.4174],
[0.8388, 0.7322, 0.7819],
[0.4745, 0.2260, 0.7371]])
>>> torch.cat((tt1,tt2),1)
tensor([[0.1372, 0.6473, 0.6765, 0.8388, 0.7322, 0.7819],
[0.3346, 0.1886, 0.4174, 0.4745, 0.2260, 0.7371]])
- reshape ---- torch.view()、torch.reshape()
# view()
>>> tt1
tensor([[-0.3623, -0.6115, 0.7283],
[ 0.4699, 2.3261, 0.1599]])
>>> tt1.view(-1)
tensor([-0.3623, -0.6115, 0.7283, 0.4699, 2.3261, 0.1599])
>>> tt1.view(3,2)
tensor([[-0.3623, -0.6115],
[ 0.7283, 0.4699],
[ 2.3261, 0.1599]])
# reshape()
>>> tt1
tensor([[-0.7242, 0.6419, -1.2202],
[-0.7509, -0.9206, 0.9566]])
>>> tt1.reshape(3,2)
tensor([[-0.7242, 0.6419],
[-1.2202, -0.7509],
[-0.9206, 0.9566]])
- 最后补充一个增加和去除无用维度的操作
- 去除-----
torch.squeeze(input, dim=None, out=None)
- 增加-----
torch.unsqueeze(input, dim=None, out=None)
- 去除-----
>>> tt1
tensor([[-0.7242, 0.6419, -1.2202],
[-0.7509, -0.9206, 0.9566]])
>>> tt = tt1.view(2,1,3)
>>> tt
tensor([[[-0.7242, 0.6419, -1.2202]],
[[-0.7509, -0.9206, 0.9566]]])
>>> tt.shape
torch.Size([2, 1, 3])
>>> ttt = tt.squeeze()
>>> ttt
tensor([[-0.7242, 0.6419, -1.2202],
[-0.7509, -0.9206, 0.9566]])
>>> ttt.shape
torch.Size([2, 3])
二者用法类似,返回张量与输入张量共享内存,所以改变其中一个的内容会改变另一个。
数学运算
- 基本四则运算-----
python自带的四则运算符 " +、-、*、/ "
都是对应位置的操作。
>>> tt1 = torch.randn(2,3)
>>> tt2 = torch.randn(2,3)
>>> tt1
tensor([[-0.7242, 0.6419, -1.2202],
[-0.7509, -0.9206, 0.9566]])
>>> tt2
tensor([[-0.7343, -2.0070, 1.1552],
[ 0.1351, -0.5211, 0.7543]])
>>> tt1+tt2
tensor([[-1.4585, -1.3651, -0.0649],
[-0.6158, -1.4417, 1.7109]])
>>> tt1-tt2
tensor([[ 0.0100, 2.6489, -2.3754],
[-0.8859, -0.3995, 0.2023]])
>>> tt1*tt2
tensor([[ 0.5318, -1.2883, -1.4096],
[-0.1014, 0.4797, 0.7215]])
>>> tt1/tt2
tensor([[ 0.9863, -0.3198, -1.0562],
[-5.5598, 1.7666, 1.2683]])
torch的:
加法torch.add(input, value, out=None)
乘法-----torch.mul(input, value, out=None)
除法-----torch.div(input, value, out=None)
# input是"被操作数",必须是tensor,value是"操作数"。
# 两个张量相加,对应位置相加
>>> torch.add(tt1,tt2)
tensor([[-1.4585, -1.3651, -0.0649],
[-0.6158, -1.4417, 1.7109]])
# tensor+标量,为每个位置加上这个标量
>>> torch.add(tt1,1)
tensor([[ 0.2758, 1.6419, -0.2202],
[ 0.2491, 0.0794, 1.9566]])
这三个方法类似,不一一举例。
- 高级运算
- 求对数(e为底)-----
torch.log(input, out=None)
- 求指数(e为底)-----
torch.exp(tensor, out=None)
- 其他2、10为低的指数-----
torch.log2(),torch.log10()
- 求次幂-----
torch.pow(input, exponent, out=None)
- 求绝对值-----
torch.abs(input, out=None)
- 三角函数-----
torch.cos()、torch.sin()、torch.tan()
- 反三角函数-----
torch.acos()、torch.asin()、torch.atan()
- 均值、求和、方差、标准差-----
torch.mean()、torch.sum()、torch.var()、torch.std()
- 求对数(e为底)-----
# 以tt1为底,0为指数
>>> torch.pow(tt1,0)
tensor([[1., 1., 1.],
[1., 1., 1.]])
# 以2.7为底,tt1为指数
>>> torch.pow(2.7,tt1)
tensor([[0.4871, 1.8919, 0.2976],
[0.4743, 0.4008, 2.5861]])
# e为底
>>> torch.exp(tt1)
tensor([[0.4847, 1.9001, 0.2952],
[0.4720, 0.3983, 2.6029]])
基本上够用了,方法不熟悉就边查遍用。
最后补充一点矩阵方面的东西:
-
torch.dot(tensor1, tensor2) -> float
计算两个一阶张量的点积 -
torch.eig(input, eigenvectors=False, out=None) -> (Tensor, Tensor)
- 计算input
(方阵:n行n列)
的特征值和特征向量。 - eigenvectors=True,同时计算特征值和特征微量,否则只计算特征值。
- 计算input
-
torch.inverse(input, out=None) -> Tensor
对方阵input求逆 -
torch.mm(mat1, mat2, out=None) -> Tensor
对矩阵mat1和mat2进行相乘。 -
torch.mv(mat, vec, out=None) -> Tensor
对矩阵mat和向量vec进行相乘。 -
torch.t(input, out=None)
输入一个矩阵(2维张量),并转置0,1维,可以被视为torch.transpose(input, 0, 1)
的简写函数。torch.transpose()
可以多维转置。
流程结构
这里主要介绍模型的搭建流程。
1. 构建网络
-
class Net(torch.nn.Module)
方式:
import torch
import torch.nn.functional as F
class Net(torch.nn.Module):
def __init__(self, n_feature, n_hidden, n_output):
super(Net, self).__init__()
self.hidden = torch.nn.Linear(n_feature, n_hidden)
self.predict = torch.nn.Linear(n_hidden, n_output)
def forward(self, x):
x = F.relu(self.hidden(x))
x = self.predict(x)
return x
# 实例化
net = Net(10,3,2)
torch.nn.Sequential()
# 直接在Sequential类中初始化
net = torch.nn.Sequential(
torch.nn.Linear(1, 10),
torch.nn.ReLU(),
torch.nn.Linear(10, 1)
)
2. 定义优化器、损失函数
反向传播的流程是借助损失函数,优化器来实现的(更多函数请参考loss function和optim)。
# 定义损失函数
loss_func = torch.nn.CrossEntropyLoss()
# 定义优化器
optimizer = torch.optim.SGD(net.parameters(), lr=0.02)
3. 前向传播
上面两个方法的前向传播都是如此
predict = net(input)
4. 更新参数
使用优化器通过优化损失函数,得到梯度,反向更新模型参数。
# 1. 计算loss
loss = loss_func(predict,y_true)
# 2. 计算梯度
optimizer.zero_grad() # 梯度清空
loss.backward() # 反向传播-->给优化器
optimizer.step() # 单步更新-->给参数
如此一个网络搭建和一次训练就完成了!
- 最后补充一点如何决定使用CPU
还是GPU
在训练网络之前,我们可以决定是通过CPU还是GPU来进行训练。
- 默认的方式是CPU,无需任何操作。
- 选择GPU
第一种、实例化的时候使用.cuda()
第二种、使用类似tensorflow的方式指定CUDA_VISIBLE_DEVICES
net = Net(10,3,2).cuda()
loss_func = torch.nn.CrossEntropyLoss().cuda()
#================================================
import os
os.environ["CUDA_VISIBLE_DEVICES"] = "0"
- 智能选择,可以用以下代码来决定:
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
对应的我们在实例化网络和损失函数的时候都需要.to(device)
。即:
net = Net(10,3,2).to(device)
loss_func = torch.nn.CrossEntropyLoss().to(device)