pytorch预备知识
学习pytorch前的一些基础知识
1数据操作和数据预处理操作
1.1 张量
张量(tensor):n维数组
张量表示由一个数值组成的数组,这个数组可以又多个维度。具有一个轴的张量对应数学上的向量(vector)。具有两个轴的张量对应数学上的矩阵(matrix)。具有两个轴以上的张量没有特殊的数学名称。
arange()函数的使用
import torch #导入torch包
x=torch.arange(12)
print(x)
tensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
- 张量相关函数
- shape函数 可以通过shape属性来访问张量的形状
print(x.shape) # 获取张量的形状
torch.Size([12])
- numel函数 所有元素个数的和
print(x.numel())
12
- reshape()函数 改变一个张量的形状而不改变元素数量和元素值
X=x.reshape(3,4) #将x转化为一个行为3,列为4的张量
print(X)
print(X.shape)
tensor([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
torch.Size([3, 4])
可以使用自动推断维度-1,在上⾯的例⼦中,我们可以⽤x.reshape(-1,4)或x.reshape(3,-1)来
取代x.reshape(3,4)
- torch.zeros()函数和torch.ones()函数 张量元素初始化为0或者1
y=torch.zeros(2,3,4) #三维的,2层,3行,4列
print(y)
z=torch.ones(2,3,4)
print(z)
tensor([[[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]],
[[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]]])
tensor([[[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]],
[[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]]])
有时想通过某个特定的概率分布中随机采样来得到张量中的每个元素的值,例如,当我们构造数组来为神经网络中的参数时,我们通常会随机初始化参数的值。以下代码创建⼀个形状为(3,4)的张量。其中的每个元素都从均值为0、标准差为1的标准⾼斯(正态)分布中随机采样。
a=torch.randn(3,4)
print(a)
tensor([[-0.2418, -1.4962, -0.9822, -0.6629],
[-0.0987, -0.2770, 0.4597, -1.0751],
[-0.9014, 1.6390, -2.2285, -0.5725]])
初始化赋予想要的值
b=torch.tensor([[1,2,3,4],[5,6,7,8],[9,10,11,12]])
print(b)
tensor([[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12]])
1.1.2 运算
常见的标准算术运算符(+ ,- ,* ,/ ,**)
- 按元素操作
x=torch.tensor([1.0,2,4,8])
y=torch.tensor([2,2,2,2])
print(x+y)
print(x-y)
print(x*y)
print(x**y)
tensor([ 3., 4., 6., 10.])
tensor([-1., 0., 2., 6.])
tensor([ 2., 4., 8., 16.])
tensor([ 1., 4., 16., 64.])
除了按元素计算外,还可以执行线性代数运算
- 连结(concatenate) 把多个张量连接在一起 函数 torch.cat()
a=torch.arange(12,dtype=torch.float32,).reshape((3,4))
b=torch.tensor([[2.0,1,3,4],[1,2,3,4],[4,3,2,1]])
print(torch.cat((a,b),dim=0)) # dim等于0从行连接 dim=1,从列连接
print(torch.cat((a,b),dim=1))
tensor([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[ 2., 1., 3., 4.],
[ 1., 2., 3., 4.],
[ 4., 3., 2., 1.]])
tensor([[ 0., 1., 2., 3., 2., 1., 3., 4.],
[ 4., 5., 6., 7., 1., 2., 3., 4.],
[ 8., 9., 10., 11., 4., 3., 2., 1.]])
- 两个张量的比较会形成一个逻辑符号构成的张量
print(a==b)
tensor([[False, True, False, False],
[False, False, False, False],
[False, False, False, False]])
- 对张量内所有元素求和
print(a.sum())
tensor(66.)
1.2.2广播机制
上面的按元素操作都是形状相同的时候执行操作,证某些情况下,即使形状不用,我们仍然可以通过广播机制(broadcasting mech)来执行按元素操作这种机制的工作方式如下:首先,通过适当复制元素来扩展一个或两个数组,以便转化之后,两个张量有相同的形状。其次,对生成的数组执行按元素操作。
大多数情况下,我们将沿着数组中长度为1的轴进行广播,如下例子:
import torch
a=torch.arange(3).reshape(3,1)
b=torch.arange(2).reshape(1,2)
print(a,"\n",b)
print(a+b)
由于a和b分别是3 × 1和1 × 2矩阵,如果我们让它们相加,它们的形状不匹配。我们将两个矩阵⼴播为⼀个更
⼤的3 × 2矩阵,如下所⽰:矩阵a将复制列,矩阵b将复制⾏,然后再按元素相加。
tensor([[0],
[1],
[2]])
tensor([[0, 1]])
tensor([[0, 1],
[1, 2],
[2, 3]])
1.2.3索引和切片
和python数组一样,张量的元素可以通过索引过来进行访问。索引第一个坐标为0;可以指定范围进行访问;可以通过使用负索引根据元素带裂表尾部的相对位置访问元素。
x=torch.arange(12)
print(x)
print(x[-1]) # 最后一个元素
print(x[2:7]) # 第三到七个元素
x[0]=10 # 对张量的元素进行赋值
print(x)
tensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
tensor(11)
tensor([2, 3, 4, 5, 6])
tensor([10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
当多维度的张量时,会出现访问制定维度的元素的情况,如2维张量,[0:2, :]访问第1⾏和第2⾏,其中“:”代表沿轴1(列)的所有元素。虽然我们讨论的是矩阵的索引,但这也适⽤于向量和超过2个维度的张量。
y=x.reshape(3,4)
print(y)
y[0:2,:]=9 # 0:2 表示0到2行, :表示所有列
print(y)
tensor([[10, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
tensor([[ 9, 9, 9, 9],
[ 9, 9, 9, 9],
[ 8, 9, 10, 11]])
1.2.4节省内存
运⾏⼀些操作可能会导致为新结果分配内存。例如,如果我们⽤Y = X + Y,我们将取消引⽤Y指向的张量,
而是指向新分配的内存处的张量。
import torch
x=torch.arange(12)
y=torch.tensor([1,1,1,1,1,1,1,1,1,1,1,1])
before=id(y)
print(id(x))
print(id(y))
y=y+x
print(id(y))
print(before==id(y))
1942692739976
1942737774696
1942696363976
False
这是我们很多时候不希望的操作,这个时候需要执行原地操作,切片法表示法将操作的结果分配给先前分配的数组,如Y[:] = < expression> 。
z=torch.zeros_like(y)
print(id(z))
z[:]=y+z
print(id(z))
1994398623928
1994398623928
使用x[:]=x+y即可简绍内存开销
1.2.5转化为其他python对象
转化为NumPy张量,使用numpy()函数
import torch
x=torch.arange(12)
y=x.numpy()
print(type(x),type(y))
<class 'torch.Tensor'> <class 'numpy.ndarray'>
将大小为1的张量转化为python标量,我们可以调用item函数或者python的内置函数
a=torch.tensor([3.5])
print(a)
print(a.item())
print(float(a))
print(int(a))
tensor([3.5000])
3.5
3.5
3
1.2.6数据预处理
预处理原始数据时,数据很多并不是准备好的张量格式数据,所以要转化为张量数据。在python中常用的数据分析工具中,通常使用pandas软件包。
- 将数据集写入csv文件当中
import os
os.makedirs(os.path.join('..','data'),exist_ok=True)
data_file=os.path.join('..','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')
- 将数据从csv文件中读出来
导入pandas包,调用read_csv函数
import pandas as pd
from Test.数据预处理 import data_file
data=pd.read_csv(data_file)
print(data)
- 处理缺少值
注意,“NaN”项代表缺失值。为了处理缺失的数据,典型的方法包括插值和删除,其中插值用替代值代替缺失值。而删除则忽略缺失值。
插值法,通过位置索引iloc,我们将data分成inputs和outputs,其中前者为data的前两列,儿女后者为打他的最后一列。对于inputs中缺少的数值,我们用同一列的均值替换“NaN”项。
inputs,outputs=data.iloc[:,0:2],data.iloc[:,2]
inputs=inputs.fillna(inputs.mean())
print(inputs)
NumRooms Alley
0 3.0 Pave
1 2.0 NaN
2 4.0 NaN
3 3.0 NaN
对于inputs中的类别值或离散值,我们将“NaN”视为一个类别。由于“巷子”(“Alley”)列值接受两种类别的类别值“Pave”和“NaN”,pandas可以自动将此列转化为两列“Alley_Pave”和“Alley_nan”。巷子类型为"Pave"的行会将"Alley_Pave"的值设置为1,“Alley_nan”的值设置为0.缺少巷子类型的行会将“Alley_pave”和“Alley_nan”分别设置为0和1。
inputs=pd.get_dummies(inputs,dummy_na=True)
print(inputs)
NumRooms Alley_Pave Alley_nan
0 3.0 1 0
1 2.0 0 1
2 4.0 0 1
3 3.0 0 1
1.2.7转化为张量格式
上述inputs和outputs中的所有条目都是数值类型,他们可以转化为张量格式。当数据转化为张量格式后,方便进一步操作。
x,y=torch.tensor(inputs.values),torch.tensor(outputs.values)
print(x,"\n",y)
tensor([[3., 1., 0.],
[2., 0., 1.],
[4., 0., 1.],
[3., 0., 1.]], dtype=torch.float64)
tensor([127500, 106000, 178100, 140000])
删除缺失值