关于深度学习的基础的Python知识(PyTorch)
文章目录
关于深度学习的基础的Python知识(PyTorch)
一、概念:张量
1、张量的定义:
张量是矩阵的扩展与延伸,可以认为是高阶的矩阵。1阶张量为向量,2阶张量为矩阵。张量是类似于Numpy的多维数组(ndarray)的概念,可以具有任意多的维度。
(图片来自邱锡鹏老师和飞桨的《神经网络与深度学习:案例与实践》)
2、个人理解:
张量是用向量组成的维度空间的实体,可以很方便地存放各式各样的信息。
二.、使用PyTorch实现张量运算
首先导入torch
:
import torch
1、创建张量
(1)以指定数据创建张量(以三阶张量为例)
# 创建一个三阶张量(指定数据创建张量)
ndim_1_Tensor = torch.tensor([[[1, 9], [6, 3]], [[0, 1], [2, 8]]])
print(ndim_1_Tensor)
运行结果:
(2)指定形状创建张量
# 指定形状创建
size = ndim_1_Tensor.size()
zero_Tensor = torch.zeros(size) # 全零张量
print(zero_Tensor)
one_Tensor = torch.ones(size) # 全一张量
print(one_Tensor)
full_Tensor = torch.full(size, 10) #指定数据
print(full_Tensor)
运行结果:
2、张量的属性
(1)张量的形状属性
张量具有如下形状属性:
Tensor.ndim
:张量的维度,例如向量的维度为1,矩阵的维度为2。Tensor.shape
: 张量每个维度上元素的数量。Tensor.shape[n]
:张量第n维的大小。第n维也称为轴(axis)。Tensor.numel()
:张量中全部元素的个数。(paddle
中为Tensor.size
)(图片来自邱锡鹏老师和飞桨的《神经网络与深度学习:案例与实践》)
创建如图张量:
ndim_4_Tensor = torch.ones([2, 3, 4, 5]) # 创建一个每个维度的宽度分别为2,3,4,5的4维张量
打印出此向量的shape
、ndim
、shape[n]
、numel()
属性:
# 打印出此向量的`shape`、`ndim`、`shape[n]`、`numel()`属性
print("shape:", ndim_4_Tensor.shape)
print("ndim:", ndim_4_Tensor.ndim)
print("shape[2]:", ndim_4_Tensor.shape[1])
print("numel:", ndim_4_Tensor.numel())
运行结果:
(2)张量形状的改变
在实际使用中,还可以通过使用torch.reshape
接口来改变张量的形状:
ndim_3_Tensor = torch.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("shape:", ndim_3_Tensor.shape)
# 改变数据形状
reshape_Tensor = torch.reshape(ndim_3_Tensor, [2, 5, 3])
print("After reshape:", reshape_Tensor)
运行结果:
可以看到,通过此接口改变张量的形状后,张量内部的数据顺序是不变的。
除使用torch.reshape
进行张量形状的改变外,还可以通过torch.unsqueeze
将张量中的某一维度中插入尺寸为1的维度:
ones_Tensor = torch.ones([5, 10])
new_Tensor1 = torch.unsqueeze(ones_Tensor, dim=0)
print('new shape: ', new_Tensor1.shape)
运行结果
其他技巧:
将reshape
值设为-1
,使张量变为一维:
new_Tensor1 = ndim_3_Tensor.reshape(-1)
print('new shape: ', new_Tensor1.shape)
运行结果:
(3)张量的数据类型
通过Tensor.dtype
可以查看张量的数据类型:
Tensor1 = torch.ones([2, 3, 4, 5])
print("data type: ", Tensor1.dtype)
运行结果:
通过Numpy数组创建的张量,则与其原来的数据类型保持相同。通过torch.tensor()
函数可以将Numpy数组转化为张量:
# 使用torch.tensor通过已知数据来创建一个Tensor
print("Tensor dtype from Python integers:", torch.tensor(1).dtype)
print("Tensor dtype from Python floating point:", torch.tensor(1.0).dtype)
运行结果:
如果想改变张量的数据类型,可以通过Tensor.to
或者Tensor.type
来实现:
# 定义dtype为float32的Tensor
float32_Tensor = torch.tensor(1.0)
# Tensor.to或Tensor.type可以将输入数据的数据类型转换为指定的dtype并输出。支持输出和输入数据类型相同。
float32_Tensor = float32_Tensor.to(torch.int64)
print("Tensor after change to int64:", float32_Tensor.dtype)
float32_Tensor = float32_Tensor.type(torch.float32)
print("Tensor after change to float32:", float32_Tensor.dtype)
运行结果:
(4)张量的设备位置
初始化张量时可以通过device来指定其分配的设备位置。
如下代码分别创建了CPU和GPU上的张量,并通过Tensor.device
查看张量所在的设备位置:
# 创建CPU上的Tensor
cpu_Tensor = torch.tensor(1, device=torch.device('cpu'))
# 通过Tensor.device查看张量所在设备位置
print('cpu Tensor: ', cpu_Tensor.device)
# 创建GPU上的Tensor
gpu_Tensor = torch.tensor(1, device=torch.device('cuda'))
# 通过Tensor.device查看张量所在设备位置
print('gpu Tensor: ', gpu_Tensor.device)
运行结果:
此外,通过通过Tensor.to
还可以改变张量所在的设备位置:
gpu_Tensor2 = cpu_Tensor.to('cuda')
print('gpu Tensor: ', gpu_Tensor2.device)
运行结果:
3、张量与Numpy数组转换
张量和Numpy数组可以相互转换。使用Numpy数组生成张量之前就已经使用过,现在主要探讨将张量转化为Numpy数组:
ndim_1_Tensor = torch.tensor([1., 2.])
# 将当前 Tensor 转化为 numpy.ndarray
print('Tensor to convert: ', ndim_1_Tensor.numpy())
print('Type: ', type(ndim_1_Tensor.numpy()))
运行结果:
4、张量的访问
(1)索引和切片
在PyTorch中,我们可以通过索引或切片方便地访问或修改张量。PyTorch使用标准的Python索引规则与NumPy索引规则,具有以下特点:
(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])
运行结果:
注意,PyTorch不允许以这种方式来进行翻转操作:
print("Reverse:", ndim_1_Tensor[::-1])
报错:
翻转操作应该使用torch.flip
:
print("Reverse:", torch.flip(ndim_1_Tensor, dims=[0]))
运行结果:
dims
指的是翻转的维度。
针对二维及以上维度的张量,在多个维度上进行索引或切片。索引或切片的第一个值对应第0维,第二个值对应第1维,以此类推,如果某个维度上未指定索引,则默认为“:”:
# 定义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])
运行结果:
(3)修改张量
与访问张量类似,可以在单个或多个轴上通过索引或切片操作来修改张量:
# 定义1个二维Tensor
ndim_2_Tensor = torch.ones([2, 3], dtype=torch.float32)
print('Origin Tensor: ', ndim_2_Tensor)
# 修改第1维为0
ndim_2_Tensor[0] = 0
print('change Tensor: ', ndim_2_Tensor)
# 修改第1维为2.1
ndim_2_Tensor[0:1] = 2.1
print('change Tensor: ', ndim_2_Tensor)
# 修改全部Tensor
ndim_2_Tensor[...] = 3
print('change Tensor: ', ndim_2_Tensor)
运行结果:
5、张量的运算
张量支持包括基础数学运算、逻辑运算、矩阵运算等100余种运算操作,以加法为例,有如下两种实现方式:
1)使用PyTorch API torch.add(x,y)
。
2)使用张量类成员函数x.add(y)
。
# 定义两个Tensor
x = torch.tensor([[1.1, 2.2], [3.3, 4.4]], dtype=torch.float32)
y = torch.tensor([[5.5, 6.6], [7.7, 8.8]], dtype=torch.float64)
# 第一种调用方法,torch.add逐元素相加算子,并将各个位置的输出元素保存到返回结果中
print('Method 1: ', torch.add(x, y))
# 第二种调用方法
print('Method 2: ', x.add(y))
运行结果:
(1)数学运算
张量类的基础数学函数如下:
x.abs() # 逐元素取绝对值
x.ceil() # 逐元素向上取整
x.floor() # 逐元素向下取整
x.round() # 逐元素四舍五入
x.exp() # 逐元素计算自然常数为底的指数
x.log() # 逐元素计算自然对数
x.reciprocal() # 逐元素求倒数
x.square() # 逐元素计算平方
x.sqrt() # 逐元素计算平方根
x.sin() # 逐元素计算正弦
x.cos() # 逐元素计算余弦
x.add(y) # 逐元素加
x.sub(y) # 逐元素减
x.mul(y) # 逐元素乘(积)
x.div(y) # 逐元素除
x.fmod(y) # 逐元素除并取余
x.pow(y) # 逐元素幂
x.max() # 指定维度上元素最大值,默认为全部维度
x.min() # 指定维度上元素最小值,默认为全部维度
x.prod() # 指定维度上元素累乘,默认为全部维度
x.sum() # 指定维度上元素的和,默认为全部维度
同时,为了更方便地使用张量,PyTorch 对 Python 数学运算相关的魔法函数进行了重写,以下操作与上述结果相同:
x + y -> x.add(y) # 逐元素加
x - y -> x.sub(y) # 逐元素减
x * y -> x.mul(y) # 逐元素乘(积)
x / y -> x.div(y) # 逐元素除
x % y -> x.fmod(y) # 逐元素除并取余
x ** y -> x.pow(y) # 逐元素幂
测试代码:
# 创建张量x和y
x = torch.tensor([[1, 1], [4, 5], [1, 4]], dtype=torch.float32)
y = torch.tensor([[1, -2], [3, -4], [5, -6]], dtype=torch.float64)
# 打印张量x和y
print("x : ", x)
print("y : ", y)
# 测试逐元素取绝对值
print("x.abs() : ", x.abs())
# 测试逐元素向上取整
print("x.ceil() : ", x.ceil())
# 测试逐元素向下取整
print("x.floor() : ", x.floor())
# 测试逐元素四舍五入
print("x.round() : ", x.round())
# 测试逐元素计算自然常数为底的指数
print("x.exp() : ", x.exp())
# 测试逐元素计算自然对数
print("x.log() : ", x.log())
# 测试逐元素求倒数
print("x.reciprocal() : ", x.reciprocal())
# 测试逐元素计算平方
print("x.square() : ", x.square())
# 测试逐元素计算平方根
print("x.sqrt() : ", x.sqrt())
# 测试逐元素计算正弦
print("x.sin() : ", x.sin())
# 测试逐元素计算余弦
print("x.cos() : ", x.cos())
# 测试逐元素加法
print("x + y : ", x + y)
# 测试逐元素减法
print("x - y : ", x - y)
# 测试逐元素乘法
print("x * y : ", x * y)
# 测试逐元素除法
print("x / y : ", x / y)
# 测试逐元素取余
print("x % y : ", x % y)
# 测试逐元素幂运算
print("x ** y : ", x ** y)
# 测试指定维度上的元素最大值
print("x.max(dim=1) : ", x.max(dim=1))
# 测试指定维度上的元素最小值
print("x.min(dim=1) : ", x.min(dim=1))
# 测试指定维度上的元素均值
print("x.mean(dim=1) : ", x.mean(dim=1))
# 测试指定维度上的元素和
print("x.sum(dim=1) : ", x.sum(dim=1))
# 测试指定维度上的元素乘积
print("x.prod(dim=1) : ", x.prod(dim=1))
运行结果:
(2)逻辑运算
在 PyTorch 中,张量类的逻辑运算和矩阵运算函数如下:
# 逻辑运算函数
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的全部元素是否接近
# 矩阵运算函数
x.t() # 矩阵转置
x.transpose([1, 0]) # 交换第 0 维与第 1 维的顺序
x.norm('fro') # 矩阵的弗罗贝尼乌斯范数
x.dist(y, p=2) # 矩阵(x-y)的2范数
x.matmul(y) # 矩阵乘法
# 对于多维张量的矩阵乘法,例如x是形状为[j, k, n, m]的张量,另一个y是[j, k, m, p]的张量
# 则x.matmul(y)输出的张量形状为[j, k, n, p]
三、数据预处理
1、读取数据集 house_tiny.csv、boston_house_prices.csv、Iris.csv
# 1. 读取数据集 house_tiny.csv
house_tiny_path = 'house_tiny.csv'
process_dataset(house_tiny_path)
# 2. 读取数据集 boston_house_prices.csv
boston_house_prices_path = 'boston_house_prices.csv'
process_dataset(boston_house_prices_path)
# 3. 读取数据集 Iris.csv
iris_path = 'Iris.csv'
process_dataset(iris_path)
2、处理缺失值
# 读取数据集
df = pd.read_csv(file_path)
# 打印原始数据
print(f"{file_path} 原始数据:")
print(df)
# 处理缺失值,填充为每列的均值
# 首先将不能转换为数值类型的数据转换为 NaN
df = df.apply(pd.to_numeric, errors='coerce')
# 然后填充缺失值
df.fillna(df.mean(), inplace=True)
# 打印处理后的数据
print(f"\n{file_path} 处理缺失值后的数据:")
print(df)
3、转换为张量格式
# 转换为张量格式
tensor = torch.tensor(df.values, dtype=torch.float32)
# 打印张量
print(f"\n{file_path} 张量:")
print(tensor)
print("\n")
运行结果:
作者:Asitwas