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()
# 以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,同时计算特征值和特征微量,否则只计算特征值。
  • 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 functionoptim)。

# 定义损失函数
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)

最后补充一篇解决模型超GPU显存的博客

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容