NNDL 实验二 pytorch入门

      在上次实验我们已经对python进行了简单的回顾,并且上次我们也安装了numpy库,并且对其进行了简单的应用。这次我们就来学习一下新的内容,掌握一些深度学习需要的基本内容,pytorch入门级别教学。

一. 概念:张量、算子

张量:张量是深度学习中表示和存储数据的主要形式,是类似于Numpy的多维数组的概念,张量是矩阵的扩展与延伸,可以认为是高阶的矩阵,1阶张量为向量,2阶张量为矩阵。

算子:算子是构建复杂机器学习模型和深度学习的基础组件,包含一个函数f(x)f(x)的前向函数和反向函数,在深度学习中,算子对应每一层中的计算逻辑。

二. 使用pytorch实现张量运算

1.2 张量

1.2.1 创建张量

1.2.1.1 指定数据创建张量

首先导入torch库

import torch as tc #导入torch库

创建一个一维张量

Tensor1 = tc.tensor([2, 3, 4]) #给定一个一维列表数据
print(Tensor1)

运行结果

 

 

创建一个二维张量

Tensor2 = tc.tensor([[1, 2, 3],
                    [4, 5, 6]]) #给定一个二维张量
print(Tensor2)

运行结果

 

 

创建一个三维张量

 

Tensor3 = tc.tensor([[[1, 2, 3],
                      [4, 5, 6]],
                      [[7, 8, 9],
                      [10, 11, 12]]]) #给定一个三维张量
print(Tensor3)

运行结果

 

 

1.2.1.2 指定形状创建

zeros_tensor = tc.zeros([3, 4])  # 创建形状为(3,4)的全0矩阵
ones_tensor = tc.ones([3, 4])  # 创建形状为(3,4)的全1矩阵
print(zeros_tensor)
print(ones_tensor)

运行结果

 

 

1.2.1.3 指定区间创建 

​
arange_tensor = tc.arange(start=1, end=5, step=1)  # 从1开始,到5结束(不包括5),步长为1
linspace_tensor = tc.linspace(start=1, end=5, steps=5)  # 从1开始, 到5结束(包括5), 平均分成五步
print(arange_tensor)
print(linspace_tensor)

​

运行结果

 

1.2.2 张量的属性

张量具有如下属性:

  • Tensor.ndim:张量的维度。
  • Tensor.shape: 张量每个维度上元素的数量。
  • Tensor.shape[n]:张量第n维的大小。第n维也称为轴。
  • Tensor.numel():张量中全部元素的个数。

1.2.2.1 张量的形状

输出张量的属性

Tensor4 = tc.ones([2, 3, 4, 5])

print("Number of dimensions:", Tensor4.ndim)
print("Shape of Tensor:", Tensor4.shape)
print("Elements number along axis 0 of Tensor:", Tensor4.shape[0])
print("Elements number along the last axis of Tensor:", Tensor4.shape[-1])
print('Number of elements in Tensor: ', Tensor4.numel())

运行结果

  

1.2.2.2 形状的改变

# 定义一个shape为[3,2,5]的三维Tensor
Tensor5 = tc.tensor([[[1, 2, 3, 4, 5],
                            [6, 7, 8, 9, 10]],
                           [[11, 12, 13, 14, 15],
                            [16, 17, 18, 19, 20]],
                           [[21, 22, 23, 24, 25],
                            [26, 27, 28, 29, 30]]])
print("the shape of Tensor5:", Tensor5.shape)
# torch.reshape 可以保持在输入数据不变的情况下,改变数据形状。这里我们设置reshape为[2,5,3]
reshape_Tensor = tc.reshape(Tensor5, [2, 5, 3])
print("After reshape:", reshape_Tensor)

运行结果

 

从输出结果看,将张量从[3, 2, 5]的形状reshape为[2, 5, 3]的形状时,张量内的数据不会发生改变,元素顺序也没有发生改变,只有数据形状发生了改变。 

分别对上文定义的Tensor5进行reshape为[-1]和reshape为[3, 5, 2]两种操作,观察新张量的形状。 

new_Tensor1 = Tensor5.reshape([-1])
print('new Tensor 1 shape: ', new_Tensor1.shape)
new_Tensor2 = Tensor5.reshape([3, 5, 2])
print('new Tensor 2 shape: ', new_Tensor2.shape)

运行结果

 

从输出结果看,第一行代码中的第一个reshape操作将张量reshape为元素数量为30的一维向量;第四行代码中的第二个reshape操作中,3对应的维度的元素个数与原张量在该维度上的元素个数相同。 

除使用torch.reshape进行张量形状的改变外,还可以通过torch.unsqueeze将张量中的一个或多个维度中插入尺寸为1的维度。 

ones_Tensor = tc.ones([5, 10])
new_Tensor1 = tc.unsqueeze(ones_Tensor, dim=0)  # 在pytorch中,dim为插入维度的索引,即在第几维度插入
print('new Tensor 1 shape: ', new_Tensor1.shape)
new_Tensor2 = tc.unsqueeze(ones_Tensor, dim=1)
print('new Tensor 2 shape: ', new_Tensor2.shape)

运行结果

 

 

1.2.2.3 张量的数据类型

pytorch中可以通过Tensor.dtype来查看数据类型。 Tensor的最基本数据类型有:

32位浮点型:torch.float32 (最常用)
64位浮点型:torch.float64 (最常用)
32位整型:torch.int32
32位整型:torch.int32
16位整型:torch.int16
64位整型:torch.int64

1)通过Python元素创建的张量,如果未指定:

  • 对于Python整型数据,则会创建int64型张量。
  • 对于Python浮点型数据,默认会创建float32型张量。

 

print('Tensor dtype from python integers:', tc.tensor(1).dtype)
print('Tensor dtype from python floating point:', tc.tensor(1.0).dtype)

运行结果

 

2)而如果你要是想修改张量的数据类型可以通过下面

float32_tensor = tc.tensor(1.0)
int64_tensor = float32_tensor.type(tc.int64)
print('Tensor after cast to int64:', int64_tensor.dtype)

 运行结果
 

1.2.2.4 张量的设备位置

固定内存也称为不可分页内存或锁页内存,它与GPU之间具有更高的读写效率,并且支持异步传输,这对网络整体性能会有进一步提升,但它的缺点是分配空间过多时可能会降低主机系统的性能,因为它减少了用于存储虚拟内存数据的可分页内存。当未指定设备位置时,张量默认设备位置和安装的飞桨版本一致,如安装了GPU版本的飞桨,则设备位置默认为GPU。

 创建CPU上的张量,并通过Tensor.device查看张量所在的设备位置。

# 创建CPU上的Tensor
cpu_Tensor = tc.tensor(1, device='cpu')
# 通过Tensor.place查看张量所在设备位置
print('cpu Tensor: ', cpu_Tensor.device)

运行结果

 

 

1.2.3 张量与Numpy数组转换

Tensor6 = tc.tensor([1., 2.])# 将当前Tensor转化为numpy.ndarray
print('Tensor to convert:', Tensor6.numpy())

运行结果

 

 

1.2.4 张量的访问

1.2.4.1 索引和切片

我们可以通过索引或切片方便地访问或修改张量。飞桨使用标准的Python索引规则与Numpy索引规则,具有以下特点:

1)基于0−n的下标进行索引,如果下标为负数,则从尾部开始计算。
2)通过冒号“:”分隔切片参数start:stop:step来进行切片操作,也就是访问start到stop范围内的部分元素并生成一个新的序列。其中start为切片的起始位置,stop为切片的截止位置,step是切片的步长,这三个参数均可缺省。
 

1.2.4.2 访问张量

首先对一维张量进行索引切片

Tensor7 = tc.tensor([0, 1, 2, 3, 4, 5, 6, 7, 8])# 定义1个一维Tensor
print("Origin Tensor:", Tensor7)
print("First element:", Tensor7[0])
print("Last element:", Tensor7[-1])
print("All element:", Tensor7[:])
print("Before 3:", Tensor7[:3])
print("Interval of 3:", Tensor7[::3])

运行结果

 

 pytorch不支持负数步长,比如进行print(“Reverse:”, Tensor7[::-1])操作就会抛出错误。

 针对二维及以上维度的张量,在多个维度上进行索引或切片。索引或切片的第一个值对应第0维,第二个值对应第1维,以此类推,如果某个维度上未指定索引,则默认为“:”。

Tensor8 = tc.tensor([[0, 1, 2, 3],
                     [4, 5, 6, 7],
                     [8, 9, 10, 11]])# 定义1个二维Tensor
print("Origin Tensor:",Tensor8)
print("First row:",Tensor8[0])
print("First row:",Tensor8[0, :])
print("First column:",Tensor8[:, 0])
print("Last column:", Tensor8[:, -1])
print("All element:",Tensor8[:])
print("First row and second column:", Tensor8[0, 1])

运行结果

 

 

1.2.4.3 修改张量

与访问张量类似,可以在单个或多个轴上通过索引或切片操作来修改张量。

提醒

慎重通过索引或切片操作来修改张量,此操作仅会原地修改该张量的数值,且原值不会被保存。如果被修改的张量参与梯度计算,将仅会使用修改后的数值,这可能会给梯度计算引入风险。

Tensor9 = tc.ones([2, 3], dtype=tc.float32)
print('Origin Tensor:\n ', Tensor9)

Tensor9[0] = 0 # 修改第1维为0
print('change Tensor:\n ', Tensor9)

Tensor9[0:1] = 2.1 # 修改第1维为2.1
print('change Tensor: \n', Tensor9)

Tensor9[...] = 3 # 修改全部Tensor
print('change Tensor:\n ', Tensor9)

运行结果

 

 

1.2.5 张量的运算

张量支持包括基础数学运算、逻辑运算、矩阵运算等100余种运算操作,以加法为例,有如下两种实现方式:
1)使用pytorch torch.add(x,y)。
2)使用张量类成员函数x.add(y)。

# 定义两个Tensor
x = tc.tensor([[1.1, 2.2], [3.3, 4.4]], dtype=tc.float64)
y = tc.tensor([[5.5, 6.6], [7.7, 8.8]], dtype=tc.float64)
# 第一种调用方法,paddle.add逐元素相加算子,并将各个位置的输出元素保存到返回结果中
print('Method 1: ', tc.add(x, y))
# 第二种调用方法
print('Method 2: ', x.add(y))

运行结果

 

 从输出结果看,使用张量类成员函数x.add(y)和torch.add(x,y)具有相同的效果。

1.2.5.1 数学运算

张量类的基础数学函数如下:
x.abs()                       # 逐元素取绝对值
x.ceil()                      # 逐元素向上取整
x.floor()                     # 逐元素向下取整
x.round()                     # 逐元素四舍五入
x.exp()                       # 逐元素计算自然常数为底的指数
x.log()                       # 逐元素计算x的自然对数
x.reciprocal()                # 逐元素求倒数
x.square()                    # 逐元素计算平方
x.sqrt()                      # 逐元素计算平方根
x.sin()                       # 逐元素计算正弦
x.cos()                       # 逐元素计算余弦
x.add(y)                      # 逐元素加
x.subtract(y)                 # 逐元素减
x.multiply(y)                 # 逐元素乘(积)
x.divide(y)                   # 逐元素除
x.mod(y)                      # 逐元素除并取余
x.pow(y)                      # 逐元素幂
x.max()                       # 指定维度上元素最大值,默认为全部维度
x.min()                       # 指定维度上元素最小值,默认为全部维度
x.prod()                      # 指定维度上元素累乘,默认为全部维度
x.sum()                       # 指定维度上元素的和,默认为全部维度

同时,为了更方便地使用张量,pytorch对Python数学运算相关的魔法函数进行了重写,以下操作与上述结果相同。

x + y  -> x.add(y)            # 逐元素加
x - y  -> x.subtract(y)       # 逐元素减
x * y  -> x.multiply(y)       # 逐元素乘(积)
x / y  -> x.divide(y)         # 逐元素除
x % y  -> x.mod(y)            # 逐元素除并取余
x ** y -> x.pow(y)            # 逐元素幂

1.2.5.2 逻辑运算

张量类的逻辑运算函数如下:

x.isfinite()                  # 判断Tensor中元素是否是有限的数字,即不包括inf与nan
x.equal_all(y)                # 判断两个Tensor的全部元素是否相等,并返回形状为[1]的布尔类Tensor
x.equal(y)                    # 判断两个Tensor的每个元素是否相等,并返回形状相同的布尔类Tensor
x.not_equal(y)                # 判断两个Tensor的每个元素是否不相等
x.less_than(y)                # 判断Tensor x的元素是否小于Tensor y的对应元素
x.less_equal(y)               # 判断Tensor x的元素是否小于或等于Tensor y的对应元素
x.greater_than(y)             # 判断Tensor x的元素是否大于Tensor y的对应元素
x.greater_equal(y)            # 判断Tensor x的元素是否大于或等于Tensor y的对应元素
x.allclose(y)                 # 判断两个Tensor的全部元素是否接近

同样地,pytorch对Python逻辑比较相关的魔法函数也进行了重写,这里不再赘述。

1.2.5.3 矩阵运算

张量类还包含了矩阵运算相关的函数,如矩阵的转置、范数计算和乘法等。

x.t()                         # 矩阵转置
x.transpose([1, 0])           # 交换第 0 维与第 1 维的顺序
x.norm('fro')                 # 矩阵的弗罗贝尼乌斯范数
x.dist(y, p=2)                # 矩阵(x-y)的2范数
x.matmul(y)                   # 矩阵乘法

有些矩阵运算中也支持大于两维的张量,比如matmul函数,对最后两个维度进行矩阵乘。比如x是形状为[j,k,n,m]的张量,另一个y是[j,k,m,p]的张量,则x.matmul(y)输出的张量形状为[j,k,n,p]。

1.2.5.4 广播机制

广播机制的条件

pytorch的广播机制主要遵循如下规则(参考Numpy广播机制):

1)每个张量至少为一维张量。
2)从后往前比较张量的形状,当前维度的大小要么相等,要么其中一个等于1,要么其中一个不存在。

x = tc.ones((2, 3, 4))
y = tc.ones((2, 3, 4))
z = x + y
print('broadcasting with two same shape tensor: ', z.shape)

x = tc.ones((2, 3, 1, 5))
y = tc.ones((3, 4, 1))
# 从后往前依次比较:
# 第一次:y的维度大小是1
# 第二次:x的维度大小是1
# 第三次:x和y的维度大小相等,都为3
# 第四次:y的维度不存在
# 所以x和y是可以广播的
z = x + y
print('broadcasting with two different shape tensor:', z.shape)

运行结果

 从输出结果看,x与y在上述两种情况中均遵循广播规则,因此在张量相加时可以广播。我们再定义两个shape分别为[2, 3, 4]和[2, 3, 6]的张量,观察这两个张量是否能够通过广播操作相加。

x = tc.ones((2, 3, 4))
y = tc.ones((2, 3, 6))
z = x + y

运行结果

 

 运行结果会抛出错误,从输出结果看,此时x和y是不能广播的,因为在第一次从后往前的比较中,4和6不相等,不符合广播规则。

广播机制的计算规则

现在我们知道在什么情况下两个张量是可以广播的。两个张量进行广播后的结果张量的形状计算规则如下:

1)如果两个张量shape的长度不一致,那么需要在较小长度的shape前添加1,直到两个张量的形状长度相等。

2) 保证两个张量形状相等之后,每个维度上的结果维度就是当前维度上较大的那个。

以张量x和y进行广播为例,x的shape为[2, 3,
1,5],张量y的shape为[3,4,1]。首先张量y的形状长度较小,因此要将该张量形状补齐为[1, 3, 4,
1],再对两个张量的每一维进行比较。从第一维看,x在一维上的大小为2,y为1,因此,结果张量在第一维的大小为2。以此类推,对每一维进行比较,得到结果张量的形状为[2,
3, 4, 5]。

由于矩阵乘法函数paddle.matmul在深度学习中使用非常多,这里需要特别说明一下它的广播规则:

1)如果两个张量均为一维,则获得点积结果。

2) 如果两个张量都是二维的,则获得矩阵与矩阵的乘积。

3) 如果张量x是一维,y是二维,则将x的shape转换为[1, D],与y进行矩阵相乘后再删除前置尺寸。

4) 如果张量x是二维,y是一维,则获得矩阵与向量的乘积。

5) 如果两个张量都是N维张量(N >
2),则根据广播规则广播非矩阵维度(除最后两个维度外其余维度)。比如:如果输入x是形状为[j,1,n,m]的张量,另一个y是[k,m,p]的张量,则输出张量的形状为[j,k,n,p]。
 

x = tc.ones([10, 1, 5, 2])
y = tc.ones([3, 2, 5])
z = tc.matmul(x, y)
print('After matmul:', z.shape)

 运行结果

从输出结果看,计算张量乘积时会使用到广播机制。 

三. 数据预处理

1. 读取数据集 house_tiny.csv、boston_house_prices.csv、Iris.csv

1)读取数据集 house_tiny.csv

import pandas as pd
import numpy as np
import torch

data = pd.read_csv('house_tiny.csv')
print(data)

运行结果

 

2)读取数据集 boston_house_prices.csv

 

import pandas as pd
import numpy as np
import torch

data = pd.read_csv('boston_house_prices.csv')
print(data)

运行结果

 

 

3)读取数据集 Iris.csv

 

import pandas as pd
import numpy as np
import torch

data = pd.read_csv('Iris.csv')
print(data)

运行结果

 

 

2. 处理缺失值

对上面的house_tiny.csv数据集进行处理

# 处理缺失值和离散值
x = data
# 使用均值处理缺失值
x = x.fillna(value=x.mean())
print(x)
# 处理离散值
x = pd.get_dummies(x)
print(x)

 运行结果

 

3. 转换为张量格式

对上面的house_tiny.csv数据集进行处理

#  转换为张量形式
x = np.array(x)
x = torch.tensor(x)
print(x)

 运行结果

 

小结

本次实验内容大部分都是根据NNDL实验1中的内容完成,链接中的实验所使用的是paddle完成,而经过一段时间的学习pytorch,我们只是将paddle改写为用pytorch编程。其实好多内容在学习机器学习时有所涉及,奈何自己当时没有学好,只好自己再重现边查边学,在做完实验后更加深刻理解了张量和量子,同时对数据的处理读取,预处理等等都有了更加深刻了解,这次相对于上次来说难度有所增加,有难度就会有挑战,有挑战才会有动力,要好好加油啦!

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值