我们将介绍如何使用PyTorch构建神经网络的一些必备元素,带你进一步了解PyTorch。
之后我们会带领大家使用之前接触过的MNIST和Cifar10两个数据集做图像分类任务,这一次我们将使用PyTorch构建神经网络算法完成实验。
要点具体如下。
·PyTorch要点概述。
·PyTorch构建神经网络处理图像的分类问题。
PyTorch的使用
PyTorch如何构建神经网络的一些必备元素。如果大家对PyTorch有更多的学习需求,则请参考PyTorch官网https://pytorch.org/,其中的文档和教学案例都很全面。
1.1 Tensor 在PyTorch中,最核心的数据结构就是Tensor了,可以认为Tensor与Numpy中的ndarrays非常类似,但是Tensor可以使用GPU加速而ndarrays不可以。
我们在PyTorch下可以使用如下命令来进行GPU运算:
if torch.cuda.is_available():
x = x.cuda()
y = y.cuda()
print(x+y)
现在我们来列举几个小例子说明下Tensor是如何使用的。
例子一,Tensor和Numpy如何互相转换。
代码首先引入torch包(import torch),之后我们定义一个Numpy的二维数组,再使用torch.from_numpy(data)这个方法将Numpy数组转为PyTorch中的Tensor结构,另外,我们还可以使用numpy()方法将Tensor重新转为Numpy结构,具体代码如下:
import torch
import numpy as np
np_data = np.arange(8).reshape((2,4)) #定义一个numpy的二维数组
torch_data = torch.from_numpy(np_data)
print(np_data)
print(torch_data)
np_data2 = torch_data.numpy() #转回numpy
print(np_data2) 输出结果如下:
[[0 1 2 3]
[4 5 6 7]]
tensor([[0, 1, 2, 3],
[4, 5, 6, 7]])
[[0 1 2 3]
[4 5 6 7]] 上述输出结果中,第二个就是Tensor结构了,其他的都是Numpy中的ndarrays结构。 例子二,Tensor是如何做矩阵运算的。
下面的代码演示了一个比较重要的操作即矩阵相乘,我们可以看到,在Numpy中矩阵相乘使用的是dot这个方法,而在PyTorch中使用的是mm这个方法来表示,它们的结果是一样的,具体代码如下:
import torch
import numpy as np
np_data = np.array([[1,2],[3,5]])
torch_data = torch.from_numpy(np_data)
print(np_data)
print(np_data.dot(np_data))
print(torch_data.mm(torch_data))
输出结果如下: [[1 2]
[3 5]]
[[ 7 12]
[18 31]]
tensor([[ 7, 12],
[18, 31]])
1.2 Variable Tensor是PyTorch中的基础组件,但是构建神经网络还远远不够,我们需要能够构建计算图的Tensor,也就是Variable(简单理解就是Variable是对Tensor的一种封装)。
其操作与Tensor是一样的,但是每个Variable都包含了三个属性(data、grad以及creator):Variable中的Tensor本身(通过.data来进行访问)、对应Tensor的梯度(通过.grad进行访问)以及创建这个Variable的Function的引用(通过.grad_fn进行访问),该引用可用于回溯整个创建链路,如果是用户自己创建Variable,则其grad_fn为None Variable 如果我们需要使用Variable,则可在代码中输入如下语句:
from torch.autograd import Variable #导入Variable我们来看一个简单的小例子,示例代码如下:
from torch.autograd import Variable
import torch
x_tensor = torch.randn(10, 5) #从标准正态分布中返回多个样本值
#将Tensor变成Variable
x = Variable(x_tensor, requires_grad=True)
#默认Variable是不需要求梯度的,所以用这个方式申明需要对其进行求梯度的操作
print(x.data)
print(x.grad)
print(x.grad_fn)
返回的结果如下(值得注意的是,我们使用的是随机数,所以读者看到的结果与下面的输出值会不一样):
tensor([[-2.0649, 0.1842, 0.5331, -1.0484, 0.0831],
[ 1.7195, -1.0548, 2.1493, 0.0560, -1.0903],
[-1.0321, -1.8917, -0.5778, 0.0067, -0.0236],
[ 0.0899, -0.8397, 1.0165, 1.2902, -1.1621],
[ 1.5001, -0.6694, -0.4219, 1.1915, 0.3660],
[ 0.7689, -1.5318, -1.7156, -1.9283, -0.3875],
[ 1.1318, 0.7693, 1.8216, -0.3324, -0.8397],
[ 0.0843, 0.1739, 0.8270, 1.4916, 0.7978],
[ 1.4329, 0.0845, 0.0045, -0.7277, -0.2752],
[-1.3560, 0.2973, 1.8447, -0.5960, 1.8151]])
None
None
1.3 激活函数 我们来看下如何在PyTorch中加载常见的激活函数。
之前是通过
import torch.nn.functional as F来加载激活函数,随着PyTorch版本的更新,如今通过torch可以直接加载激活函数了。
下面我们通过一个示例代码段来看下如何使用PyTorch来构建激活函数,实现代码具体如下:
import torch
from torch.autograd import Variable
import matplotlib.pyplot as plt
tensor = torch.linspace(-6,6,200)
tensor = Variable(tensor)
np_data = tensor.numpy()
#定义激活函数
y_relu = torch.relu(tensor).data.numpy()
y_sigmoid =torch.sigmoid(tensor).data.numpy()
y_tanh = torch.tanh(tensor).data.numpy()
plt.figure(1, figsize=(8, 6))
plt.subplot(221)
plt.plot(np_data, y_relu, c='red', label='relu')
plt.legend(loc='best')
plt.subplot(222)
plt.plot(np_data, y_sigmoid, c='red', label='sigmoid')
plt.legend(loc='best')
plt.subplot(223)
plt.plot(np_data, y_tanh, c='red', label='tanh')
plt.legend(loc='best')
plt.show()
上述代码非常直观且易于理解,关于其解释就不多赘述了。代码的运行效果如图7-2所示。
1.4 损失函数 在之前我们已经对常用的损失函数做了一些讲解,本节中就不再赘述了。
PyTorch已经对这些常用的损失函数做好了封装,不必再向之前那样自己写代码来实现了。我们在本节中将主要介绍两个损失函数:
均方误差损失(MeanSquareErrorLoss)函数和交叉熵损失(CrossEntropyLoss)函数。
1.均方误差损失函数 PyTorch中均方差损失函数被封装成MSELoss函数,其调用方法如下:
torch.nn.MSELoss(size_average=None, reduce=None, reduction='mean') 调用方法中的参数及说明具体如下。 ·size_average(bool,optional):基本弃用(参见reduction)。
默认情况下,损失是批次(batch)中每个损失元素的平均值。请注意,对于某些损失,每个样本均有多个元 素。如果将字段size_average设置为False,则需要将每个batch的损失相加。
当reduce设置为False时忽略。默认值为True。 ·reduce(bool,optional):基本弃用(参见reduction)。
默认情况下,根据size_average,对每个batch中结果的损失进行平均或求和。当reduce为False时,返回batch中每个元素的损失并忽略size_average。默认值为True。
·reduction(string,optional):输出元素包含3种操作方式,即none、mean和sum。'none':不做处理。'mean':输出的总和除以输出中元素的数量。'sum':输出的和。
注意:size_average和reduce基本已被弃用,而且指定这两个args中的任何一个都将覆盖reduce。默认值为mean。 在PyTorch 0.4之后,参数size_average和reduce已被舍弃,最新版本是推荐使用re duction参数控制损失函数的输出行为,如果读者需要了解更具体的使用情况,则请参阅https://pytorch.org/docs/stable/nn.html#torch.nn.MSELoss。
2.交叉熵损失函数 PyTorch中的交叉熵损失函数将nn.LogSoftmax()和nn.NLLLoss()合并在一个类中,函数名为CrossEntropyLoss()。
CrossEntropyLoss是多分类任务中常用的损失函数,在PyTorch中其调用方法如下: torch.nn.CrossEntropyLoss(weight=None, size_average=None, ignore_index=-100, reduce=None, reduction='mean') 调用方法中的参数及其说明具体如下。
·weight(Tensor,optional):多分类任务中,手动给出每个类别权重的缩放量。如果给出,则其是一个大小等于类别个数的张量。
·size_average(bool,optional):已基本弃用(参见reduction)。
默认情况下,损失是batch中每个损失元素的平均值。请注意,对于某些损失,每个样本都包含了多个元素。
如果将字段size_average设置为False,则将每个小批量的损失相加。当reduce为False时则忽略。默认值为True。
·ignore_index(int,optional):指定被忽略且不对输入梯度做贡献的目标值。当size_average为True时,损失 则是未被忽略目标的平均。
·reduce(bool,optional):已基本弃用(参见reduction)。默认情况下,根据size_average,对每个batch中结果的损失进行平均或求和。当reduce为False时,返回batch中每个元素的损失并忽略size_average。默认值为True。
·reduction(string,optional):输出元素有3种操作方式,即none、mean和sum。'none':不做处理。'mean':输出的总和除以输出中的元素数量。'sum':输出的和。
注意:size_average和reduce正在被弃用,而且指定这两个args中的任何一个都将覆盖reduce。默认值为mean。 官方的示例代码如下:
>>> loss = nn.CrossEntropyLoss()
>>> input = torch.randn(3, 5, requires_grad=True)
>>> target = torch.empty(3, dtype=torch.long).random_(5)
>>> output = loss(input, target)
>>> output.backward()
值得注意的是,PyTorch是不支持one-hot编码类型的,输入的都是真实的target,所以如果输入的真实分类是one-hot编码的话则需要自行转换,即将target one_hot的编码格式转换为每个样本的类别,再传给CrossEntropyLoss。
完整的代码实现具体如下:
import torch
from torch import nn
import numpy as np
#编码one_hot
def one_hot(y):
'''
y: (N)的一维Tensor,值为每个样本的类别
out:
y_onehot:转换为one_hot编码格式
'''
y = y.view(-1, 1)
y_onehot = torch.FloatTen
sor(3, 5)
# In your for loop
y_onehot.zero_()
y_onehot.scatter_(1, y, 1)
return y_onehot
def cross_entropy_one_hot(target):
#解码
_, labels = target.max(dim=1)
return labels
#如果需要调用cross_entropy,则还需要传入一个in-put_
#return F.cross_entropy(input_, labels)
x = np.array([1,2,3])
x_tensor =torch.from_numpy(x)
print(one_hot(x_tensor))
x2 = np.array([[0,1,0,0,0]])
x2_tensor = torch.from_numpy(x2)
print(cross_entropy_one_hot(x2_tensor)) 输出结果具体如下:
tensor([[0., 1., 0., 0., 0.],
[0., 0., 1., 0., 0.],
[0., 0., 0., 1., 0.]]) #one-hot编码类型
tensor([1]) #truelabel类型