计算机系统应用教程网站

网站首页 > 技术文章 正文

程序员用PyTorch实现第一个神经网络前做好这9个准备,事半功倍

btikc 2024-10-14 08:50:21 技术文章 24 ℃ 0 评论

理解神经网络的基本组成部分,如张量、张量运算和梯度递减等,对构造复杂的神经网络至关重要。本章将构建首个神经网络的Hello world程序,并涵盖以下主题:

  • 安装PyTorch;
  • 实现第一个神经网络;

安装PyTorch

PyTorch可以作为Python包使用,用户可以使用pip或conda来构建,或者从源代码构建。本文推荐使用Anaconda Python 3发行版。要安装Anaconda,请参考Anaconda官方文档。强烈建议使用Jupyter Notebook,因为它允许进行交互。如果已经安装了Anaconda Python,那么可以继续PyTorch安装的后续步骤。

基于GPU的Cuda 8版安装:

conda install pytorch torchvision cuda80 -c soumith

基于GPU的Cuda 7.5版安装:

conda install pytorch torchvision -c soumith

非GPU版的安装:

conda install pytorch torchvision -c soumith

第一个神经网络

第一个神经网络,它将学习如何将训练示例(即输入数组)映射成目标(即输出数组)。假设我们为最大的在线公司之一Wondermovies工作(该公司按需提供视频服务),训练数据集包含了表示用户在平台上观看电影的平均时间的特征,网络将据此预测每个用户下周使用平台的时间。这是个假想出来的用例,不需要深入考虑。构建解决方案的主要分解活动如下。

  • 准备数据:get_data函数准备输入和输出张量(数组)。
  • 创建学习参数:get_weights函数提供以随机值初始化的张量,网络通过优化这些参数来解决问题。
  • 网络模型:simple_network函数应用线性规则为输入数据生成输出,计算时先用权重乘以输入数据,再加上偏差(y=wx+b)。
  • 损失:loss_fn函数提供了评估模型优劣的信息。
  • 优化器:optimize函数用于调整初始的随机权重,并帮助模型更准确地计算目标值。

如果大家刚接触机器学习,不用着急,到本文结束时将会真正理解每个函数的作用。下面这些从PyTorch代码抽取出来的函数,有助于更容易理解神经网络。我们将逐个详细讨论这些函数。前面提到的分解活动对大多数机器学习和深度学习问题而言都是相同的。接下来的章节会探讨为改进各项功能从而构建实际应用的各类技术。

神经网络的线性回归模型如下:

y= wx+b

用PyTorch编码如下:

x,y = get_data() #x – 表示训练数据,y – 表示目标变量
w,b = get_weights() #w,b – 学习参数
for i in range(500):
 y_pred = simple_network(x) # 计算wx + b的函数
 loss = loss_fn(y,y_pred) # 计算y和y_pred平方差的和
if i % 50 == 0:
 print(loss)
 optimize(learning_rate) # 调整 w,b,将损失最小化

准备数据

PyTorch提供了两种类型的数据抽象,称为张量和变量。张量类似于numpy中的数组,它们也可以在GPU上使用,并能够改善性能。数据抽象提供了GPU和CPU的简易切换。对某些运算,我们会注意到性能的提高,以及只有当数据被表示成数字的张量时,机器学习算法才能理解不同格式的数据。张量类似Python数组,并可以改变大小。例如,图像可以表示成三维数组(高,宽,通道(RGB)),深度学习中使用最多5个维度的张量表示也很常见。一些常见的张量如下:

  • 标量(0维张量);
  • 向量(1维张量);
  • 矩阵(2维张量);
  • 3维张量;
  • 切片张量;
  • 4维张量;
  • 5维张量;
  • GPU张量。

1.标量(0维张量)

包含一个元素的张量称为标量。标量的类型通常是FloatTensor或LongTensor。在本书写作时,PyTorch还没有特别的0维张量。因此,我们使用包含一个元素的一维张量表示:

x = torch.rand(10)
x.size()
Output - torch.Size([10])

2.向量(1维张量)

向量只不过是一个元素序列的数组。例如,可以使用向量存储上周的平均温度:

temp = torch.FloatTensor([23,24,24.5,26,27.2,23.0])
temp.size()
Output - torch.Size([6])

3.矩阵(2维向量)

大多数结构化数据都可以表示成表或矩阵。我们使用波士顿房价(Boston House Prices)的数据集,它包含在Python的机器学习包scikit-learn中。数据集是一个包含了506个样本或行的numpy数组,其中每个样本用13个特征表示。Torch提供了一个工具函数from_numpy(),它将numpy数组转换成torch张量,其结果张量的形状为506行×13列:

boston_tensor = torch.from_numpy(boston.data)
boston_tensor.size()
Output: torch.Size([506, 13])
boston_tensor[:2]
Output:
Columns 0 to 7
 0.0063 18.0000 2.3100 0.0000 0.5380 6.5750 65.2000 4.0900
 0.0273 0.0000 7.0700 0.0000 0.4690 6.4210 78.9000 4.9671
Columns 8 to 12
 1.0000 296.0000 15.3000 396.9000 4.9800
 2.0000 242.0000 17.8000 396.9000 9.1400
[torch.DoubleTensor of size 2x13]

4.3维张量

当把多个矩阵累加到一起时,就得到了一个3维张量。3维张量可以用来表示类似图像这样的数据。图像可以表示成堆叠到一起的矩阵中的数字。一个图像形状的例子是(224,224,3),其中第一个数字表示高度,第二个数字表示宽度,第三个表示通道数(RGB)。我们来看看计算机是如何识别大熊猫的,代码如下:

from PIL import Image
# 使用PIL包从磁盘读入熊猫图像并转成numpy数组
panda = np.array(Image.open('panda.jpg').resize((224,224)))
panda_tensor = torch.from_numpy(panda)
panda_tensor.size()
Output - torch.Size([224, 224, 3])
# 显示熊猫
plt.imshow(panda)

由于显示大小为(224,224,3)的张量会占用本书的很多篇幅,因此将把图2.1所示的图像切片成较小的张量来显示。



5.切片张量

张量的一个常见操作是切片。举个简单的例子,我们可能选择一个张量的前5个元素,其中张量名称为sales。我们使用一种简单的记号sales[:slice_index],其中slice_index表示要进行切片的张量位置:

sales = 
torch.FloatTensor([1000.0,323.2,333.4,444.5,1000.0,323.2,333.4,444.5])
sales[:5]
 1000.0000
 323.2000
 333.4000
 444.5000
 1000.0000
[torch.FloatTensor of size 5]
sales[:-5]
 1000.0000
 323.2000
 333.4000
[torch.FloatTensor of size 3]

对熊猫图像做些更有趣的处理,比如只选择一个通道时熊猫图像的样子,以及如何选择熊猫的面部。

下面,只选择熊猫图像的一个通道:

plt.imshow(panda_tensor[:,:,0].numpy()) #0表示RGB中的第一个通道

输出如图1.2所示。



现在裁剪图像,假设要构造一个熊猫的面部检测器,我们只需要熊猫图像的面部部分。我们来裁剪张量图像,让它只包含熊猫面部。

plt.imshow(panda_tensor[25:175,60:130,0].numpy())

输出如图1.3所示。

另一个常见的例子是需要获取张量的某个特定元素:

# torch.eye(shape)生成一个对角线元素为1的对角矩阵
sales = torch.eye(3,3)
sales[0,1]
Output- 0.00.0


PyTorch的大多数张量运算都和NumPy运算非常类似。

6.4维张量

4维张量类型的一个常见例子是批图像。为了可以更快地在多样例上执行相同的操作,现代的CPU和GPU都进行了专门优化,因此,处理一张或多张图像的时间相差并不大。因而,同时使用一批样例比使用单样例更加常见。对批大小的选择并不一目了然,它取决于多个因素。不使用更大批尺寸或完整数据集的主要因素是GPU的内存限制,16、32和64是通常使用的批尺寸。

举例来说,加载一批64×224×224×3的猫咪图片,其中64表示批尺寸或图片数量,两个224分别表示高和宽,3表示通道数:

#从磁盘读取猫咪图片
cats = glob(data_path+'*.jpg')
#将图片转换成numpy数组
cat_imgs = np.array([np.array(Image.open(cat).resize((224,224))) for cat in
cats[:64]])
cat_imgs = cat_imgs.reshape(-1,224,224,3)
cat_tensors = torch.from_numpy(cat_imgs)
cat_tensors.size()
Output - torch.Size([64, 224, 224, 3])

7.5维张量

可能必须使用5维张量的一个例子是视频数据。视频可以划分为帧,例如,熊猫玩球的长度为30秒的视频,可能包含30帧,这可以表示成形状为(1×30×224×224×3)的张量。一批这样的视频可以表示成形状为(32×30×224×224×3)的张量——例中的30表示每个视频剪辑中包含的帧数,32表示视频剪辑的个数。

8.GPU上的张量

我们已学习了如何用张量表示法表示不同形式的数据。有了张量格式的数据后,要进行一些常见运算,比如加、减、乘、点积和矩阵乘法等。所有这些操作都可以在CPU或GPU上执行。PyTorch提供了一个名为cuda()的简单函数,将张量从CPU复制到GPU。我们来看一下其中的一些操作,并比较矩阵乘法运算在CPU和GPU上的性能差异。

张量的加法运算用如下代码实现:

#执行张量加法运算的不同方式
a = torch.rand(2,2)
b = torch.rand(2,2)
c = a + b
d = torch.add(a,b)
#和自身相加
a.add_(5)
#不同张量之间的乘法 
a*b
a.mul(b)
#和自身相乘
a.mul_(b)

对于张量矩阵乘法,我们比较一下代码在CPU和GPU上的性能。所有张量都可以通过调用cuda()函数转移到GPU上。

GPU上的乘法运算运行如下:

a = torch.rand(10000,10000)
b = torch.rand(10000,10000)
a.matmul(b)
Time taken: 3.23 s
#将张量转移到GPU
a = a.cuda()
b = b.cuda()
a.matmul(b)
Time taken: 11.2 μs

加、减和矩阵乘法这些基础运算可以用于构建复杂运算,如卷积神经网络(CNN)和递归神经网络(RNN),本书稍后的章节将进行相关讲解。

9.变量

深度学习算法经常可以表示成计算图。图2.4所示为一个在示例中构建的变量计算图的简单例子。



在图1.4所示的计算图中,每个小圆圈表示一个变量,变量形成了一个轻量封装,将张量对象、梯度,以及创建张量对象的函数引用封装起来。图1.5所示为Variable类的组件。



梯度是指loss函数相对于各个参数(W, b)的变化率。例如,如果a的梯度是2,那么a值的任何变化都会导致Y值变为原来的两倍。如果还不清楚,不要着急——大多数数深度学习框架都会为我们代为计算梯度值。本章中,我们将学习如何使用梯度来改善模型的性能。

除了梯度,变量还引用了创建它的函数,相应地也就指明了每个变量是如何创建的。例如,变量a带有的信息表明它是由X和W的积生成的。

让我们看个例子,创建变量并检查梯度和函数引用:

x = Variable(torch.ones(2,2),requires_grad=True)
y = x.mean()
y.backward()
x.grad
Variable containing:
 0.2500 0.2500
 0.2500 0.2500
[torch.FloatTensor of size 2x2]
x.grad_fn
Output – None
x.data
 1 1
 1 1
[torch.FloatTensor of size 2x2]
y.grad_fn
<torch.autograd.function.MeanBackward at 0x7f6ee5cfc4f8>

在上面的例子中,我们在变量上调用了backward操作来计算梯度。默认情况下,变量的梯度是none。

变量中的grad_fn指向了创建它的函数。变量被用户创建后,就像例子中的x一样,其函数引用为None。对于变量y,它指向的函数引用是MeanBackward。

属性Data用于获取变量相关的张量。

本文摘自《PyTorch深度学习》

END

喜欢的朋友请转发到朋友圈

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表