接上文:。
本节大致有三部分,首先是PyTorch构建模型的一个概括性的了解;然后是使用PyTorch做一个CV的简单项目;最后尝试一下用CNN做Titanic的预测。
本部分主要来源:、、。
PyTorch:它是一个基于python的科学计算库,致力于为两类用户提供服务:
PyTorch中的张量(tensor)和Numpy中N维数组(ndarrays)的概念很相似,有了这个作为基础,张量也可以被运行在GPU上来加速计算。
张量、矩阵和向量区别:
首先,张量的维数等价于张量的阶数。
0维的张量就是标量,1维的张量就是向量,2维的张量就是矩阵,大于等于3维的张量没有名称,统一叫做张量。下面举例:
- 标量:很简单,就是一个数,1,2,5,108等等
- 向量:[1,2],[1,2,3],[1,2,3,4],[3,5,67,·······,n]都是向量
- 矩阵:[[1,3],[3,5]],[[1,2,3],[2,3,4],[3,4,5]],[[4,5,6,7,8],[3,4,7,8,9],[2,11,34,56,18]]是矩阵
- 3维张量:[[[1,2],[3,4]],[[1,2],[3,4]]]
但是混淆的地方来了,就是数学里面会使用3维向量,n维向量的说法,这其实指的是1维张量(即向量)的形状,即它所含分量的个数,
比如[1,3]这个向量的维数为2,它有1和3这两个分量;[1,2,3,······,4096]这个向量的维数为4096,它有1、2······4096这4096个分量,
都是说的向量的形状。你不能说[1,3]这个“张量”的维数是2,只能说[1,3]这个“1维张量”的维数是2。
维度要看张量的最左边有多少个左中括号,有n个,则这个张量就是n维张量
import torch
x = torch.empty(5, 3)
print(x)
'''
tensor([[2.7712e+35, 4.5886e-41, 7.2927e-04],
[3.0780e-41, 3.8725e+35, 4.5886e-41],
[4.4446e-17, 4.5886e-41, 3.9665e+35],
[4.5886e-41, 3.98e+35, 4.5886e-41],
[3.8722e+35, 4.5886e-41, 4.4446e-17]])
'''
torch.rand(*size, *, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)x = torch.rand(2, 3, 2)
print(x)
'''
tensor([[[0.7350, 0.1058],
[0.1558, 0.3330],
[0.9874, 0.9351]],
[[0.6613, 0.4773],
[0.9103, 0.2991],
[0.6107, 0.5941]]])
'''
torch.zeros(*size, *, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)x = torch.zeros(3, 2, 4, dtype=torch.long)
print(x)
'''
tensor([[[0, 0, 0, 0],
[0, 0, 0, 0]],
[[0, 0, 0, 0],
[0, 0, 0, 0]],
[[0, 0, 0, 0],
[0, 0, 0, 0]]])
'''
torch.tensor(data, *, dtype=None, device=None, requires_grad=False, pin_memory=False)x = torch.tensor([[5, 3], [6, 8], [7, 1]])
print(x)
'''
tensor([[5, 3],
[6, 8],
[7, 1]])
'''
Tensor.new_ones(size, dtype=None, device=None, requires_grad=False)x = torch.tensor([[2, 2, 2], [2, 2, 2]])
x = x.new_ones(2, 3)
print(x)
'''
tensor([[1, 1, 1],
[1, 1, 1]])
'''
torch.randn_like(input, *, dtype=None, layout=None, device=None, requires_grad=False, memory_format=torch.preserve_format)x = torch.tensor([[2, 2, 2], [2, 2, 2]])
x = torch.rand_like(x, dtype=torch.float)
print(x)
'''
tensor([[0.9673, 0.5070, 0.2757],
[0.0980, 0.1018, 0.4406]])
'''
此部分列举4个基础操作,详细链接。
Tensor.size(dim=None)x = torch.tensor([[2, 2, 2], [2, 2, 2]])
print(x.size())
'''
torch.Size([2, 3])
'''
x = torch.randn(1)
print(x.item())
y = torch.randn(4)
print(x[:2].item())
'''
-0.2167293280363083
-0.2167293280363083
'''
Tensor.view(*shape)返回一个新张量,其数据与tensor相同,但具有不同的形状x = torch.randn(4, 4)
y = x.view(16)
z = x.view(-1, 8) # -1是由别的维度推断出来的
f = x.view(2, 8)
print(x.size(), y.size(), z.size(), f.size())
'''
torch.Size([4, 4]) torch.Size([16]) torch.Size([2, 8]) torch.Size([2, 8])
'''
torch.add(input, other, *, alpha=1, out=None)print(x + y)x = torch.zeros(5, 3)
y = torch.ones_like(x)
z = torch.empty(5, 3)
torch.add(x, y, out=z)
print('-------------\n', z)
torch.add(x, 20, out=z)
print('-------------\n', z)
'''
-------------
tensor([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]])
-------------
tensor([[20., 20., 20.],
[20., 20., 20.],
[20., 20., 20.],
[20., 20., 20.],
[20., 20., 20.]])
Process finished with exit code 0
'''
或者采用加法的变体:Tensor.add_(other, *, alpha=1),注意有一个‘_’,这个符号在所有替换自身操作符的末尾都有。
另外,输出的方式还可以像python一样。
x.add_(y)
print(x)
'''
tensor([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]])
'''
print(x[:, 1])
'''
tensor([1., 1., 1., 1., 1.])
'''
Tensor.numpy()。torch.from_numpy(ndarray)。a = torch.ones(5) # torch.ones返回一个填充有标量值1的张量,其形状由变量参数size定义。
b = a.numpy()
print(a, '\n', b)
'''
tensor([1., 1., 1., 1., 1.])
[1. 1. 1. 1. 1.]
'''
c = torch.from_numpy(b)
print(b, '\n', c)
'''
[1. 1. 1. 1. 1.]
tensor([1., 1., 1., 1., 1.])
'''
在pytorch中,神经网络的核心是自动微分,在本节中我们会初探这个部分,也会训练一个小型的神经网络。
自动微分包会提供自动微分的操作,它是一个取决于每一轮的运行的库,你的下一次的结果会和你上一轮运行的代码有关,因此,每一轮的结果,有可能都不一样。
torch.Tensor是这个包的核心类,如果你设置了它的参数 .requires_grad=true 的话,它将会开始去追踪所有的在这个张量上面的运算。当你完成你得计算的时候,你可以调用backwward()来计算所有的微分。这个向量的梯度将会自动被保存在grad这个属性里面。
如果想要阻止张量跟踪历史数据,你可以调用detach()来将它从计算历史中分离出来,当然未来所有计算的数据也将不会被保存。或者你可以使用with torch.no_grad()来调用代码块,不光会阻止梯度计算,还会避免使用储存空间,这个在计算模型的时候将会有很大的用处,因为模型梯度计算的这个属性默认是开启的,而我们可能并不需要。
第二个非常重要的类是Function,Tensor和Function,他们两个是相互联系的并且可以搭建一个非循环的运算图。
每一个张量都有一个grad_fn的属性,它可以调用Function来创建Tensor,当然,如果用户自己创建了Tensor的话,那这个属性自动设置为None。
如果你想要计算引出量的话,你可以调用.backward()在Tensor上面,如果Tensor是一个纯数的话,那么你将不必要指明任何参数;如果它不是纯数的话,你需要指明一个和张量形状匹配的梯度的参数。下面来看一些例程。
import torch
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>)
"""
print(y.grad_fn)
"""
<AddBackward0 object at 0x7fc6bd199ac8>
"""
z = y * y * 3
out = z.mean()
print(z, out)
"""
tensor([[27., 27.],
[27., 27.]], grad_fn=<MulBackward0>) tensor(27., grad_fn=<MeanBackward0>)
"""
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 0x7fc6bd1b02e8>
"""
优化器(optimizer),可以理解为torch为我们封装的用来进行更新参数的方法,比如常见的随机梯度下降(stochastic gradient descent,SGD)。
优化器类都是由torch.optim提供的,例如:
注意:
model.parameters()来获取,获取模型中所有requires_grad=True的参数from torch import optim
optimizer = optim.SGD(model.parameters(), lr=1e-3) # 1. 实例化
optimizer.zero_grad() # 2. 梯度置为0
loss.backward() # 3. 计算梯度
optimizer.step() # 4. 更新参数的值
torch中也预测了很多损失函数,比如:均方误差:nn.MSELoss(),常用于回归问题;交叉熵损失:nn.CrossEntropyLoss(),常用于分类问题。
使用方法:
model = Lr() #1. 实例化模型
criterion = nn.MSELoss() # 2. 实例化损失函数
optimizer = optim.SGD(model.parameters(), lr=1e-3) #3. 实例化优化器类
for i in range(100):
y_predict = model(x_true) # 4. 向前计算预测值
loss = criterion(y_true,y_predict) # 5. 调用损失函数传入真实值和预测值,得到损失结果
optimizer.zero_grad() # 5. 当前循环参数梯度置为0
loss.backward() # 6. 计算梯度
optimizer.step() # 7. 更新参数的值
当模型太大,或者参数太多的情况下,为了加快训练速度,经常会使用GPU来进行训练。此时我们的代码需要稍作调整:
torch.cuda.is_available():import torch
print(torch.device("cuda:0" if torch.cuda.is_available() else "cpu"))
'''
输出:
cuda:0 # 是使用gpu
cpu # 是使用cpu
'''
model.to(device) # device是cpu或cuda
x_true.to(device)
predict = predict.cpu().detach().numpy()
构建一个深度学习模型也可以将其分为三步:数据集准备、模型定义、模型训练;
理论上,深度学习中的数据集准备与经典机器学习中的数据集准备并无本质性差别,大体都是基于特定的数据构建样本和标签的过程,其中这里的样本依据应用场景的不同而有不同的样式,比如CV领域中典型的就是图片,而NLP领域中典型的就是一段段的文本。
但无论原始样本如何,最终都要将其转化为数值型的Tensor。
当然,将数据集转化为Tensor之后理论上即可用于深度学习模型的输入和训练,但为了更好的支持模型训练以及大数据集下的分batch进行训练,PyTorch中提供了标准的数据集类型(Dataset),而我们则一般是要继承此类来提供这一格式。这里主要介绍3个常用的数据集相关的类:
Dataset是PyTorch中提供的一个数据集基类,首先查看Dataset的签名文档如下:
[docs]class Dataset(Generic[T_co]):
r"""An abstract class representing a :class:`Dataset`.
All datasets that represent a map from keys to data samples should subclass
it. All subclasses should overwrite :meth:`__getitem__`, supporting fetching a
data sample for a given key. Subclasses could also optionally overwrite
:meth:`__len__`, which is expected to return the size of the dataset by many
:class:`~torch.utils.data.Sampler` implementations and the default options
of :class:`~torch.utils.data.DataLoader`.
.. note::
:class:`~torch.utils.data.DataLoader` by default constructs a index
sampler that yields integral indi
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- gamedaodao.net 版权所有 湘ICP备2024080961号-6
违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务