目录
1. 读取数据集 house_tiny.csv、boston_house_prices.csv、Iris.csv
一. 概念:张量、算子
张量:在深度学习框架中,数据经常用张量(Tensor)的形式来存储。张量是矩阵的扩展与延伸,可以认为是高阶的矩阵。1阶张量为向量,2阶张量为矩阵。如果你对Numpy熟悉,那么张量是类似于Numpy的多维数组(ndarray)的概念,可以具有任意多的维度(阶)。
算子:算子是构建复杂机器学习模型的基础组件,包含一个函数f(x)f(x)f(x)的前向函数和反向函数。可以认为是一块块基础的积木,最后用来组合完成一个复杂的机器人
二. 使用pytorch实现张量运算
1.2.1 创建张量
1.2.1.1 指定数据创建张量
import numpy as np
import torch
# 指定数据创建张量
a = np.array([1, 2, 3])
b = np.array([[1, 2, 3], [4, 5, 6]])
c = np.array([[[1, 2, 3], [4, 5, 6]],
[[7, 8, 9], [10, 11, 12]]])
# 需要注意的是,张量在任何一个维度上的元素数量必须相等。
t1 = torch.tensor(a)
t2 = torch.tensor(b)
t3 = torch.tensor(c)
print(t1)
print(t2)
print(t3)
运行结果:
1.2.1.2 指定形状创建张量
# 指定形状创建张量
# 创建一个3行2列的全0张量
t1 = torch.zeros([3,2])
print(t1)
# 创建一个3行2列的全1张量
t2 = torch.ones([3,2])
print(t2)
# 创建一个3行2列的随机值张量
t3 = torch.randint(1,10,size=[3,2])
print(t3)
运行结果:
1.2.1.3 指定区间创建
# 指定区间创建张量
# torch.arange不包含end,类型为int
t1= torch.arange(start=1, end=10,step=1)
# torch.arange包含end,steps是指一共取几个数
t2 = torch.linspace(start=1, end=5,steps=5)
print(t1)
print(t2)
运行结果:
1.2.2 张量的属性
1.2.2.1 张量的形状
张量具有如下形状属性:
Tensor.ndim
:张量的维度,例如向量的维度为1,矩阵的维度为2。Tensor.shape
: 张量每个维度上元素的数量。Tensor.shape[n]
:张量第n维的大小。第n维也称为轴(axis)。Tensor.size
:张量中全部元素的个数
t1 = torch.ones([3,4,5])
print('张量的维度是:',t1.ndim)
print('张量每个维度上元素的数量:',t1.shape)
print('张量第1维的大小:',t1.shape[1])
print('张量中全部元素的数量:',t1.numel())
运行结果:
1.2.2.2 形状的改变
t1 = torch.ones([2,2,3])
print(t1.shape)
print(t1)
t2 = torch.reshape(t1,[2,3,2])
print(t2.shape)
print(t2)
运行结果:
1.2.2.3 张量的数据类型
通过Tensor.dtype
来查看张量的数据类型,类型支持bool、float16、float32、float64、uint8、int8、int16、int32、int64和复数类型数据。
1)通过Python元素创建的张量,可以通过dtype来指定数据类型,如果未指定:
- 对于Python整型数据,则会创建int64型张量。
- 对于Python浮点型数据,默认会创建float32型张量。
print('Tensor dtype from python integers:', torch.tensor(1).dtype)
print('Tensor dtype from python floating point:', torch.tensor(1.0).dtype)
运行结果:
2)通过tensor.type()函数可以改变数组的数据类型。
t1 = torch.tensor(1)
t2 = t1.type(torch.float32)
print(t1.dtype)
print(t2.dtype)
运行结果:
1.2.2.4 张量的设备位置
初始化张量时可以通过place来指定其分配的设备位置,可支持的设备位置有三种:CPU、GPU和固定内存。
固定内存也称为不可分页内存或锁页内存,它与GPU之间具有更高的读写效率,并且支持异步传输,这对网络整体性能会有进一步提升,但它的缺点是分配空间过多时可能会降低主机系统的性能,因为它减少了用于存储虚拟内存数据的可分页内存。
例:创建了CPU上的张量
t1 = np.array([[1,0,0],[1,1,1]])
t1_cpu = torch.tensor(t1,device=torch.device("cpu"))
print("The position of num1_tensor(CPU):",t1_cpu.device)
运行结果:
1.2.3 张量与Numpy数组转换
t1 = torch.tensor([1., 2.])
# 将当前Tensor转化为numpy.ndarray
print('Tensor to convert:', t1.numpy())
运行结果:
1.2.4 张量的访问
1.2.4.1 索引和切片
我们可以通过索引或切片方便地访问或修改张量。飞桨使用标准的Python索引规则与Numpy索引规则,具有以下特点:
- 基于0−n0-n0−n的下标进行索引,如果下标为负数,则从尾部开始计算。
- 通过冒号“:”分隔切片参数start:stop:step来进行切片操作,也就是访问start到stop范围内的部分元素并生成一个新的序列。其中start为切片的起始位置,stop为切片的截止位置,step是切片的步长,这三个参数均可缺省。
运行结果:
1.2.4.2 访问张量
# 定义1个一维Tensor
ndim_1_Tensor = torch.tensor([0, 1, 2, 3, 4, 5, 6, 7, 8])
print("Origin Tensor:", ndim_1_Tensor)
print("First element:", ndim_1_Tensor[0])
print("Last element:", ndim_1_Tensor[-1])
print("All element:", ndim_1_Tensor[:])
print("Before 3:", ndim_1_Tensor[:3])
print("Interval of 3:", ndim_1_Tensor[::3])
# 定义1个二维Tensor
ndim_2_Tensor = torch.tensor([[0, 1, 2, 3],
[4, 5, 6, 7],
[8, 9, 10, 11]])
print("Origin Tensor:", ndim_2_Tensor)
print("First row:", ndim_2_Tensor[0])
print("First row:", ndim_2_Tensor[0, :])
print("First column:", ndim_2_Tensor[:, 0])
print("Last column:", ndim_2_Tensor[:, -1])
print("All element:", ndim_2_Tensor[:])
print("First row and second column:", ndim_2_Tensor[0, 1])
运行结果:
1.2.4.3 修改张量
ndim_2_Tensor = torch.ones([2, 3], dtype=torch.float32)
print('Origin Tensor:\n ', ndim_2_Tensor)
# 修改第1维为0
ndim_2_Tensor[0] = 0
print('change Tensor:\n ', ndim_2_Tensor)
# 修改第1维为2.1
ndim_2_Tensor[0:1] = 2.1
print('change Tensor: \n', ndim_2_Tensor)
# 修改全部Tensor
ndim_2_Tensor[...] = 3
print('change Tensor:\n ', ndim_2_Tensor)
运行结果:
1.2.5 张量的运算
张量支持包括基础数学运算、逻辑运算、矩阵运算等100余种运算操作,以加法为例,有如下两种实现方式:
1)使用pytorch torch.add(x,y)。
2)使用张量类成员函数x.add(y)
# 定义两个Tensor
x = torch.tensor([[1.1, 2.2], [3.3, 4.4]], dtype=torch.float64)
y = torch.tensor([[5.5, 6.6], [7.7, 8.8]], dtype=torch.float64)
# 第一种调用方法,paddle.add逐元素相加算子,并将各个位置的输出元素保存到返回结果中
print('Method 1: ', torch.add(x, y))
# 第二种调用方法
print('Method 2: ', x.add(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() # 指定维度上元素的和,默认为全部维度
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的全部元素是否接近
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) # 矩阵乘法
1.2.5.4 广播机制
pytorch的一些API在计算时支持广播(Broadcasting)机制,允许在一些运算时使用不同形状的张量。通常来讲,如果有一个形状较小和一个形状较大的张量,会希望多次使用较小的张量来对较大的张量执行某些操作,看起来像是形状较小的张量首先被扩展到和较大的张量形状一致,然后再做运算。
广播机制的条件
pytorch的广播机制主要遵循如下规则(参考Numpy广播机制):
1)每个张量至少为一维张量。
2)从后往前比较张量的形状,当前维度的大小要么相等,要么其中一个等于1,要么其中一个不存在。
x = torch.ones((2, 3, 4))
y = torch.ones((2, 3, 4))
z = x + y
print('broadcasting with two same shape tensor: ', z.shape)
x = torch.ones((2, 3, 1, 5))
y = torch.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 = torch.ones((2, 3, 4))
y = torch.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 = torch.ones([10, 1, 5, 2])
y = torch.ones([3, 2, 5])
z = torch.matmul(x, y)
print('After matmul:', z.shape)
运行结果:
从输出结果看,计算张量乘积时会使用到广播机制
三. 数据预处理
1. 读取数据集 house_tiny.csv、boston_house_prices.csv、Iris.csv
import pandas as pd
import torch
# 读入数据
data_iris = pd.read_csv('Iris.csv')
data_house_tiny = pd.read_csv('house_tiny.csv')
data_boston_house_prices = pd.read_csv('boston_house_prices.csv')
# 输出数据
print(data_iris)
print(data_house_tiny)
print(data_boston_house_prices)
2. 处理缺失值
# 处理缺失值与离散值
t1 = data_iris
t2 = data_house_tiny
t3 = data_boston_house_prices
# 使用均值处理缺失值
t1 = t1.fillna(value=t1.mean())
t2 = t2.fillna(value=t2.mean())
t3 = t3.fillna(value=t3.mean())
print(t1)
print(t2)
print(t3)
# 处理离散值
t1 = pd.get_dummies(t1)
t2 = pd.get_dummies(t2)
t3 = pd.get_dummies(t3)
print(t1)
print(t2)
print(t3)
运行结果:
Id SepalLengthCm ... PetalWidthCm Species
0 1 5.1 ... 0.2 Iris-setosa
1 2 4.9 ... 0.2 Iris-setosa
2 3 4.7 ... 0.2 Iris-setosa
3 4 4.6 ... 0.2 Iris-setosa
4 5 5.0 ... 0.2 Iris-setosa
.. ... ... ... ... ...
145 146 6.7 ... 2.3 Iris-virginica
146 147 6.3 ... 1.9 Iris-virginica
147 148 6.5 ... 2.0 Iris-virginica
148 149 6.2 ... 2.3 Iris-virginica
149 150 5.9 ... 1.8 Iris-virginica
[150 rows x 6 columns]
NumRooms Alley Price
0 3.0 Pave 127500
1 2.0 NaN 106000
2 4.0 NaN 178100
3 3.0 NaN 140000
CRIM ZN INDUS CHAS NOX ... RAD TAX PTRATIO LSTAT MEDV
0 0.00632 18.0 2.31 0 0.538 ... 1 296 15.3 4.98 24.0
1 0.02731 0.0 7.07 0 0.469 ... 2 242 17.8 9.14 21.6
2 0.02729 0.0 7.07 0 0.469 ... 2 242 17.8 4.03 34.7
3 0.03237 0.0 2.18 0 0.458 ... 3 222 18.7 2.94 33.4
4 0.06905 0.0 2.18 0 0.458 ... 3 222 18.7 5.33 36.2
.. ... ... ... ... ... ... ... ... ... ... ...
501 0.06263 0.0 11.93 0 0.573 ... 1 273 21.0 9.67 22.4
502 0.04527 0.0 11.93 0 0.573 ... 1 273 21.0 9.08 20.6
503 0.06076 0.0 11.93 0 0.573 ... 1 273 21.0 5.64 23.9
504 0.10959 0.0 11.93 0 0.573 ... 1 273 21.0 6.48 22.0
505 0.04741 0.0 11.93 0 0.573 ... 1 273 21.0 7.88 11.9
[506 rows x 13 columns]
Id SepalLengthCm ... Species_Iris-versicolor Species_Iris-virginica
0 1 5.1 ... 0 0
1 2 4.9 ... 0 0
2 3 4.7 ... 0 0
3 4 4.6 ... 0 0
4 5 5.0 ... 0 0
.. ... ... ... ... ...
145 146 6.7 ... 0 1
146 147 6.3 ... 0 1
147 148 6.5 ... 0 1
148 149 6.2 ... 0 1
149 150 5.9 ... 0 1
[150 rows x 8 columns]
NumRooms Price Alley_Pave
0 3.0 127500 1
1 2.0 106000 0
2 4.0 178100 0
3 3.0 140000 0
CRIM ZN INDUS CHAS NOX ... RAD TAX PTRATIO LSTAT MEDV
0 0.00632 18.0 2.31 0 0.538 ... 1 296 15.3 4.98 24.0
1 0.02731 0.0 7.07 0 0.469 ... 2 242 17.8 9.14 21.6
2 0.02729 0.0 7.07 0 0.469 ... 2 242 17.8 4.03 34.7
3 0.03237 0.0 2.18 0 0.458 ... 3 222 18.7 2.94 33.4
4 0.06905 0.0 2.18 0 0.458 ... 3 222 18.7 5.33 36.2
.. ... ... ... ... ... ... ... ... ... ... ...
501 0.06263 0.0 11.93 0 0.573 ... 1 273 21.0 9.67 22.4
502 0.04527 0.0 11.93 0 0.573 ... 1 273 21.0 9.08 20.6
503 0.06076 0.0 11.93 0 0.573 ... 1 273 21.0 5.64 23.9
504 0.10959 0.0 11.93 0 0.573 ... 1 273 21.0 6.48 22.0
505 0.04741 0.0 11.93 0 0.573 ... 1 273 21.0 7.88 11.9
[506 rows x 13 columns]
3. 转换为张量格式
t1 = np.array(t1)
t1 = torch.tensor(t1)
print(t1)
t2 = np.array(t2)
t2 = torch.tensor(t2)
print(t2)
t3 = np.array(t3)
t3 = torch.tensor(t3)
print(t3)
运行结果:
本文章参考神经网络与深度学习-案例与实践教程进行学习。