今天你学习了没?没学习就学下边的。Now please start your study!
pytorch入门
前言
在这之前,我们学习了numpy的基操,学习了在深度学习中用到的python语法。今天的精神粮食是pytorch的入门操作,掌握这些基本操作才能在往后的深度学习中如鱼得水。
一、张量(Tensor)是什么?
课本上的defination是这样的: 张量是矩阵的扩展与延伸,可以认为是高阶的矩阵。
emmm,可能确实不是很好理解,那就用我蹩脚的语言形容一下。
my comprehension: 张量的感觉像是一个无形的容器,他可以容纳任意维的向量和矩阵,也可以容纳多个向量和矩阵,张量的出现是为了数据运算更加方便和快捷。
二、算子(Operator)是什么?
讲完tensor了,得谈谈什么是算子吧。看它的英文单词,不难理解,从广义上讲对于函数的任何一项操作就叫做算子,而在深度学习中,我们常用到的卷积算法、一些求值求和过程也可以抽象的理解为一组操作,也可以叫做算子。毕竟,操作+操作也等于操作嘛。
三、尝试创建张量
我们可以采用Anaconda3下的Jupyter记事本进行实践。
引入torch库
这里就不详细介绍torch的安装,不会的可以参考大佬博客:pytorch安装
import torch
尝试创建张量
1.1指定数据创建张量
#1.2.1 创建张量
#1.2.1.1 指定数据创建张量
#(1)通过指定的Python列表数据[2.0, 3.0, 4.0],创建一个一维张量
tensor1 = torch.tensor([2.0,3.0,4.0])
print(tensor1)
#(2)通过指定的Python列表数据来创建类似矩阵(matrix)的二维张量。
matrix_tensor = torch.tensor([[1.0,2.0,3.0],[4.0,5.0,6.0]])
print(matrix_tensor)
#(3)同样地,还可以创建维度为3、4...N等更复杂的多维张量。
tensor_3_matrix = torch.tensor([[[1.0,2.0,3.0],[4.0,5.0,6.0]],[[7.0,8.0,9.0],[1.0,2.0,3.0]],[[4.0,5.0,6.0],[7.0,8.0,9.0]]])
print(tensor_3_matrix)
代码解释:
①其中tensor1为指定数据的一维张量的创建,我们使用torch.tensor([数据])
②matrix_tensor为指定数据的二维张量的创建,同①。
③tensor_3_matrix为指定数据的三维张量的创建,同①。
Jupyter运行结果示意:
1.2指定形状创建张量
#1.2.1.2 指定形状创建
m, n = 2, 3
# 使用troch.zeros创建数据全为0,形状为[m, n]的Tensor
zeros_tensor = torch.zeros([m,n])
print(zeros_tensor)
# 使用torch.ones创建数据全为1,形状为[m, n]的Tensor
ones_Tensor = torch.ones([m, n])
print(ones_Tensor)
# 使用torch.full创建数据全为指定值,形状为[m, n]的Tensor,这里我们指定数据为10
full_Tensor = torch.full([m, n], 10)
print(full_Tensor)
代码解释:
①zeros_tensor为m行n列的全为0的张量
②ones_Tensor为m行n列的全为1的张量
③full_Tensor为m行n列的全为10的张量
运行结果示意:
1.3 指定区间创建
#1.2.1.3 指定区间创建
# 使用torch.arange创建以步长step均匀分隔数值区间[start, end)的一维Tensor
arange_tensor = torch.arange(start=2,end=5,step=1)
print(arange_tensor)
# 使用torch.linspace创建以元素个数steps均匀分隔数值区间[start, end]的Tensor
linspace_Tensor = torch.linspace(start=1, end=7, steps=5)#paddle则使用(start=1,stop=7,num=5)的参数格式
print(linspace_Tensor)
代码解释:
①torch.arange(start,end,step),创建从start开始,end结束,中间步长为step的一维张量。
②torch.linspace(start,end,steps),创建从start开始,end结束,以steps作为总个数均分的一维张量。
运行结果示意:
四、张量的属性
张量的基本属性
2.1张量的形状
#1.2.2 张量的属性
#1.2.2.1 张量的形状
ndim_4_tensor = torch.tensor([2.0,3.0,4.0,5.0])#转为张量
print("Number of dimensions:",ndim_4_tensor.ndim)
print("Shape of Tensor:",ndim_4_tensor.shape)
print("Elements number along axis 0 of Tensor:",ndim_4_tensor.shape[0])
print("Elements number along the last axis of Tensor:", ndim_4_tensor.shape[-1])
print('Number of elements in Tensor: ', ndim_4_tensor.size)
代码解释:
①ndim_4_tensor.ndim: 即ndim_4_tensor这个张量的维度。
②ndim_4_tensor.shape: 即ndim_4_tensor这个张量的大小。
③ndim_4_tensor.shape[0]: 即ndim_4_tensor这个张量的大小中的第一个数。(当张量是多维时,会出现张量的大小是一个一维张量,从而确定每个维度下的个数和多少个维度。)
④ndim_4_tensor.shape[0]: 即ndim_4_tensor这个张量的大小中的最后一个数。
运行结果示意:
2.2形状的改变
#1.2.2.2 形状的改变
# 定义一个shape为[3,2,5]的三维Tensor
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("the shape of ndim_3_Tensor:", ndim_3_Tensor.shape)
# torch.reshape 可以保持在输入数据不变的情况下,改变数据形状。这里我们设置reshape为[2,5,3]
reshape_Tensor = torch.reshape(ndim_3_Tensor, [2, 5, 3])
print("After reshape:\n", reshape_Tensor)
"""
paddle使用reshape的一些技巧:
①-1表示这个维度的值是从张量的元素总数和剩余维度推断出来的。因此,有且只有一个维度可以被设置为-1。
②0表示实际的维数是从张量的对应维数中复制出来的,因此shape中0所对应的索引值不能超过张量的总维度。
"""
#在这里用pytorch对reshape实现的两个example:
new_Tensor1 = ndim_3_Tensor.reshape([-1])
print('new Tensor 1 shape: ', new_Tensor1.shape)
#reshape表示的是转成[1,5,6]的三维张量的大小
new_Tensor2 = ndim_3_Tensor.reshape((1, 5, 6))
print('new Tensor 2 shape: ', new_Tensor2.shape)
#torch.unsqueeze的参数解析:(input,dim,out=None)
#torch.unsqueeze作用是用来扩展维度的,其中:
#input表示输入的参数即某个张量
#dim表示插入维度的索引(在哪儿插入维度1?)
#out表示结果张量
ones_Tensor = torch.ones([5, 10])
new_Tensor1 = torch.unsqueeze(ones_Tensor, dim=0)
print('new Tensor 1 shape: ', new_Tensor1.shape)
new_Tensor2 = torch.unsqueeze(ones_Tensor, dim=1)
print('new Tensor 2 shape: ', new_Tensor2.shape)
代码解释:
①ndim_3_tensor是一个定义了的三维张量。
②torch.reshape(tensor,shape)将tensor的形状变为规定的shape的形状。
③torch.unsqueeze(input,dim)的作用是用来扩展维度的,其中input输入为一个tensor.dim则表示插入维度的索引值(即在哪儿插入?),插入维度1
运行结果示意:
2.3张量的数据类型
#1.2.2.3 张量的数据类型
# 使用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)
# 定义dtype为float32的Tensor
float32_Tensor = torch.tensor(1.0)
print(float32_Tensor)
# 在torch中某个tensor.int()或者tensor.float()可以将输入数据的数据类型转换为int/float并输出。支持输出和输入数据类型相同。
int64_Tensor = float32_Tensor.int()
print("Tensor after cast to int64:",int64_Tensor)
代码解释:
①torch.tensor().dtype:返回tensor中元素的类型
②转化类型可以使用.int()、.float()、.double()
运行结果示意:
2.4张量的设备位置
#1.2.2.4 张量的设备位置
# 创建CPU上的Tensor
cpu_Tensor = torch.tensor(1, dtype=torch.int32, device = torch.device('cpu'))
# 通过Tensor.device查看张量所在设备位置
print('cpu Tensor: ', cpu_Tensor.device)
# 创建GPU上的Tensor
gpu_Tensor = torch.tensor(1, dtype=torch.int32, device = torch.device('cuda',0))
print('gpu Tensor: ', gpu_Tensor.device)
# 创建固定内存上的Tensor
pin_memory_Tensor = torch.tensor(1, dtype=torch.int32, device = torch.device('cuda'))
print('pin memory Tensor: ', pin_memory_Tensor.device)
代码解释:
①torch.tensor(input,dtype,device):input表示输入,dtype表示类型,device表示存放位置,采用torch.device(‘cpu’)放入cpu中。
②放入cuda中同上
运行结果示意:
一个特别说明
由于我这个电脑是比较菜的(人比较菜计算了,电脑还菜,你说这这这找谁说理去?我真的栓Q,所以你们凑合看吧。),电脑未配置CUDA所以这里会报错,如果安装了CUDA就不会报错了。这里就放一个反面例子吧。
五、张量与Numpy数组转换
张量与Numpy数组之间的转换
#1.2.3 张量与Numpy数组转换
ndim_1_Tensor = torch.tensor([1., 2.])
# 将当前 Tensor 转化为 numpy.ndarray
print('Tensor to convert: ', ndim_1_Tensor.numpy())
代码解释:
直接使用ndim_1_Tensor.numpy()转为numpy数组。
运行结果示意:
六、张量的访问
张量的访问方法
3.1 索引和切片
“”"
通过冒号“:”分隔切片参数start:stop:step来进行切片操作,也就是访问start到stop范围内的部分元素并生成一个新的序列。
其中start为切片的起始位置,stop为切片的截止位置,step是切片的步长,这三个参数均可缺省。
“”"
3.2 访问张量
#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)#打印tensor
print("First element:", ndim_1_Tensor[0])#获取tensor中的第0个位置上的索引
print("Last element:", ndim_1_Tensor[-1])#获取tensor中最后一个位置上的索引
print("All element:", ndim_1_Tensor[:])#获取tensor的全部值序列
print("Before 3:", ndim_1_Tensor[:3])#获取从开始到位置3(不包括位置3)的全部值序列
print("Interval of 3:", ndim_1_Tensor[::3])#从开始到结束,从0开始,每次位置+3获取值序列
print("Reverse:", ndim_1_Tensor.flip(dims=[0]))#函数flip可以实现对某一维的数据进行翻转其中,dims=[x1,x2,...]控制的哪一维进行翻转
print("**************分割线**************")
# 定义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)#打印tensor
print("First row:", ndim_2_Tensor[0])#获取二维张量的第一行
print("First row:", ndim_2_Tensor[0, :])#获取二维张量中第一行的全部值序列
print("First column:", ndim_2_Tensor[:, 0])#获取所有行中的第一个值,作为值序列的tensor输出
print("Last column:", ndim_2_Tensor[:, -1])#获取所有行中的最后一个值,作为值序列的tensor输出
print("All element:", ndim_2_Tensor[:])#获取所有行
print("First row and second column:", ndim_2_Tensor[0, 1])#获取tensor中第一行第二列的某个值
代码解释:这里直接看代码注释即可(可能是UP累了。)
运行结果示意:
3.3 修改张量
#1.2.4.3 修改张量
# 定义1个二维Tensor
ndim_2_Tensor = torch.ones([2,3], dtype=torch.float)
print('Origin Tensor: ', ndim_2_Tensor)#获取ndim_2_Tensor
# 修改第1维为0
ndim_2_Tensor[0] = 0#将第一位的值改为0
print('change Tensor: ', ndim_2_Tensor)
# 修改第1维为2.1
ndim_2_Tensor[0:1] = 2.1#将第从0到1行(不包括一行)的值
print('change Tensor: ', ndim_2_Tensor)
# 修改全部Tensor
ndim_2_Tensor[...] = 3#将全部值改为3
print('change Tensor: ', ndim_2_Tensor)
代码解释:看注释即可。
运行结果示意:
七、张量的运算
张量的运算
4.1基本运算
# 定义两个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))
print("***********分割线*************")
print(x.abs()) # 逐元素取绝对值
print(x.ceil()) # 逐元素向上取整
print(x.floor()) # 逐元素向下取整
print(x.round()) # 逐元素四舍五入
print(x.exp()) # 逐元素计算自然常数为底的指数
print(x.log()) # 逐元素计算x的自然对数
print(x.reciprocal()) # 逐元素求倒数
print(x.square()) # 逐元素计算平方
print(x.sqrt()) # 逐元素计算平方根
print(x.sin()) # 逐元素计算正弦
print(x.cos()) # 逐元素计算余弦
print(x.add(y)) # 逐元素加
print(x.subtract(y)) # 逐元素减
print(x.multiply(y)) # 逐元素乘(积)
print(x.divide(y)) # 逐元素除
print(x.fmod(y)) # 逐元素除并取余
print(x.pow(y)) # 逐元素幂
print(x.max()) # 指定维度上元素最大值,默认为全部维度
print(x.min()) # 指定维度上元素最小值,默认为全部维度
print(x.prod()) # 指定维度上元素累乘,默认为全部维度
print(x.sum()) # 指定维度上元素的和,默认为全部维度
print("***********分割线*************")
print(x + y);print(x.add(y)) # 逐元素加
print(x - y);print(x.subtract(y)) # 逐元素减
print(x * y);print(x.multiply(y)) # 逐元素乘(积)
print(x / y);print(x.divide(y)) # 逐元素除
print(x % y);print(x.fmod(y)) # 逐元素除并取余
print(x ** y);print(x.pow(y)) # 逐元素幂
print("***********分割线*************")
print(x.isfinite()) # 判断Tensor中元素是否是有限的数字,即不包括inf与nan
print(x.equal(y)) # 判断两个Tensor的全部元素是否相等,并返回形状为[1]的布尔类Tensor
print(x.equal(y)) # 判断两个Tensor的每个元素是否相等,并返回形状相同的布尔类Tensor
print(x.not_equal(y)) # 判断两个Tensor的每个元素是否不相等
print(x.gt(y)) # 判断Tensor x的元素是否小于Tensor y的对应元素
print(x.less_equal(y)) # 判断Tensor x的元素是否小于或等于Tensor y的对应元素
print(x.gt(y)) # 判断Tensor x的元素是否大于Tensor y的对应元素
print(x.greater_equal(y)) # 判断Tensor x的元素是否大于或等于Tensor y的对应元素
print(x.allclose(y)) # 判断两个Tensor的全部元素是否接近
代码解释:见注释
运行结果:
4.2矩阵运算
#1.2.5.3 矩阵运算
print(x.t()) # 矩阵转置
print(x.transpose(1, 0)) # 交换第 0 维与第 1 维的顺序
print(x.norm('fro')) # 矩阵的弗罗贝尼乌斯范数
print(x.dist(y, p=2)) # 矩阵(x-y)的2范数
print(x.matmul(y)) # 矩阵乘法
代码解释:
x.transpose(dim0,dim1):交换dim0和dim1这两个维度。
运行结果示意:
4.3 广播机制
#1.2.5.4 广播机制
# 当两个Tensor的形状一致时,可以广播
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 = torch.ones((2, 3, 4))
y = torch.ones((2, 3, 6))
z = x + y
#会输出关于dimension mismatch的错误"""
x = torch.ones([10, 1, 5, 2])
y = torch.ones([3, 2, 5])
z = torch.matmul(x, y)
print('After matmul: ', z.shape)
运行结果示意:
八、数据预处理
操作一个简单的数据集
5.1写一个简单的数据集
import os
os.makedirs(os.path.join('C:\\Users\\86155', 'data'), exist_ok=True)
data_file = os.path.join('C:\\Users\\86155', 'data', 'house_tiny.csv')
with open(data_file, 'w') as f:
f.write('NumRooms,Alley,Price\n') # 列名
f.write('NA,Pave,127500\n') # 每行表示一个数据样本
f.write('2,NA,106000\n')
f.write('4,NA,178100\n')
f.write('NA,NA,140000\n')
5.2处理数据集中的缺失值
import pandas as pd
data = pd.read_csv(data_file)
print(data)
#因为自制数据的数据量较小,所以我们使用插值法处理缺失值
inputs,outputs = data.iloc[:,0:2],data.iloc[:,2]#将数据集划分为属性和标签
inputs = inputs.fillna(inputs.mean())#将连续属性中取值为NaN的值取值为该属性的均值
print(inputs)
inputs = pd.get_dummies(inputs, dummy_na=True)#将离散属性中的属性值分开来写,化为Alley_Pave和Alley_NaN的形式
print(inputs)
5.3数据转化为张量格式
#将数据转化为张量格式
X, y = torch.tensor(inputs.values), torch.tensor(outputs.values)
X, y
全部Code结果:
读入两个数据集
读入数据集boston_house_prices.csv和Iris.csv
#读入数据集boston_house_prices.csv
datafile_boston = os.path.join("C:\\Users\\86155",'data','boston_house_prices.csv')
data_boston = pd.read_csv(datafile_boston)
#读入数据集Iris.csv
datafile_iris = os.path.join("C:\\Users\\86155",'data','Iris.csv')
data_iris = pd.read_csv(datafile_iris)
九、总结
首先,我们知道了什么是张量,什么是算子。
其次,我们知道了如何用torch去创建张量,并讲了一下张量有什么属性。
然后,我们应该打好对于张量运算的基本操作,我觉得这部分应该是深度学习的基础,所以要扎实一些。
最后,我们讲了数据集的预处理,然后对于缺失值的处理和如何将数据转化为张量格式,方便以后进行数据运算。
这就是day02的全部内容,简单总结一下,就是pytorch的基本操作还是要扎实一些,就比如pytorch的张量的数据类型转化用的则是torch.float32这种,而之前则只是直接int()。
老师的出题博客:NNDL 实验二 pytorch入门可以关注一下。