Pytorch
Pytorch 是一个基于 Python 的深度学习框架,它提供了最大的灵活性和速度,以及强大的计算能力。
导入
import torch
张量(Tensor)
张量表示一个由数值组成的数组,这个数组可能有多个维度。张量可以用来存储数据和进行数学运算。
创建张量
# 行向量
x = torch.arange(12)
print(x)
# tensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
通过 shape 属性可以获取张量的形状。
print(x.shape)
# torch.Size([12])
可以使用 reshape 方法改变张量的形状。
x = x.reshape(3, 4)
print(x)
# tensor([[ 0, 1, 2, 3],
# [ 4, 5, 6, 7],
# [ 8, 9, 10, 11]])
如果希望创建全 0 或全 1 的张量,可以使用 zeros 和 ones 函数。
x = torch.zeros(2, 3)
print(x)
# tensor([[0., 0., 0.],
# [0., 0., 0.]])
x = torch.ones(2, 3)
print(x)
# tensor([[1., 1., 1.],
# [1., 1., 1.]])
可以使用 randn 函数创建一个张量,其中的元素是从均值为 0,标准差为 1 的标准高斯(正态)分布中随机采样而来。
x = torch.randn(2, 3)
print(x)
# tensor([[ 0.3365, -0.1132, -0.6787],
# [ 0.3177, -0.0755, -0.2871]])
也可以直接提供张量的数值来创建张量。
x = torch.tensor([[1, 2, 3], [4, 5, 6]])
print(x)
# tensor([[1, 2, 3],
# [4, 5, 6]])
运算
可以对张量进行标准的数学运算。
加法
张量的运算遵循按元素操作的原则。
x = torch.tensor([1, 2, 3])
y = torch.tensor([4, 5, 6])
print(x + y)
# tensor([5, 7, 9])
减法
print(x - y)
# tensor([-3, -3, -3])
乘法
print(x * y)
# tensor([ 4, 10, 18])
除法
print(x / y)
# tensor([0.2500, 0.4000, 0.5000])
求幂
x = torch.tensor([1, 2, 3])
print(x ** 2)
# tensor([1, 4, 9])
拼接
x = torch.tensor([[1, 2, 3], [4, 5, 6]])
y = torch.tensor([[7, 8, 9], [10, 11, 12]])
print(torch.cat((x, y), dim=0)) # dim=0 表示按行拼接,即增加行数
# tensor([[ 1, 2, 3],
# [ 4, 5, 6],
# [ 7, 8, 9],
# [10, 11, 12]])
print(torch.cat((x, y), dim=1)) # dim=1 表示按列拼接,即增加列数
# tensor([[ 1, 2, 3, 7, 8, 9],
# [ 4, 5, 6, 10, 11, 12]])
求和
x = torch.tensor([1, 2, 3])
print(x.sum())
# tensor(6)
广播机制
当对两个形状不同的张量进行按元素运算时,可能会触发广播机制。
x = torch.arange(3).reshape(3, 1)
y = torch.arange(2).reshape(1, 2)
print(x)
# tensor([[0],
# [1],
# [2]])
print(y)
# tensor([[0, 1]])
广播机制会先将 x 和 y 扩展到相同的形状,然后再按元素运算。
x' = [[0, 0],
[1, 1],
[2, 2]] # 复制 x 原有的列,扩展到和 y 的列数相同
y' = [[0, 1],
[0, 1],
[0, 1]] # 复制 y 原有的行,扩展到和 x 的行数相同
print(x + y)
# tensor([[0, 1],
# [1, 2],
# [2, 3]])
索引和切片
可以使用索引来访问张量的元素。
x = torch.arange(12).reshape(3, 4)
print(x)
# tensor([[ 0, 1, 2, 3],
# [ 4, 5, 6, 7],
# [ 8, 9, 10, 11]])
print(x[1, 2]) # 表示第 2 行,第 3 列的元素
# tensor(6)
print(x[1:3]) # 表示第 2 行和第 3 行
# tensor([[ 4, 5, 6, 7],
# [ 8, 9, 10, 11]])
print(x[1:3, 0:2]) # 表示第 2 行和第 3 行,第 1 列和第 2 列
# tensor([[ 4, 5],
# [ 8, 9]])
节省内存
运行一些操作可能会导致为新结果分配内存。例如,如果我们用 y = x + y,我们将取消对 y 的引用,以便开始使用 y 指向的新张量。我们可以使用索引运算符将结果分配给先前分配的数组,例如:
x = torch.tensor([1, 2, 3])
y = torch.tensor([4, 5, 6])
y[:] = x + y
print(y)
# tensor([2, 4, 6])
转换为其他 Python 对象
可以使用 numpy 方法将张量转换为 numpy 数组。
x = torch.tensor([1, 2, 3])
y = x.numpy()
print(y)
# [1 2 3]
数据预处理
读取数据集
首先创建一个人工数据集。
import os
os.makedirs(os.path.join('..', 'data'), exist_ok=True) # 保存在上一级目录下的 data 文件夹
data_file = os.path.join('..', 'data', 'house_tiny.csv') # 保存在上一级目录下的 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')
其中每行表示一个数据样本。在这个数据集中,有两个特征,即 'NumRooms' 和 'Alley',以及一个标签,即 'Price'。NA
表示缺失值。
NumRooms | Alley | Price |
---|---|---|
NA | Pave | 127500 |
2 | NA | 106000 |
4 | NA | 178100 |
NA | NA | 140000 |
如果要从 CSV 文件中读取数据,可以使用 pandas 库。
# !pip install pandas
import pandas as pd
data = pd.read_csv(data_file)
print(data)
# NumRooms Alley Price
# 0 NaN Pave 127500
# 1 2.0 NaN 106000
# 2 4.0 NaN 178100
# 3 NaN NaN 140000
处理缺失值
通常,缺失值可能是数据预处理中的一个问题。为了处理缺失的数据,我们经常使用插值法或者删除法。
插值法是指用已知的值估计未知的值。常用的插值方法有:最近邻插值、线性插值、多项式插值、样条插值等。
删除法是指删除缺失值所在的行或列。
在上述数据中,我们的目的是为了预测房价,因此我们把数据分为 input 和 output。其中 input 是特征,output 是标签。
inputs, outputs = data.iloc[:, 0:2], data.iloc[:, 2]
对于 inputs 中的缺失值,我们使用插值法。我们使用同一列的非缺失值的平均值来替换缺失值。
inputs = inputs.fillna(inputs.mean()) # mean() 方法返回每一列的平均值
print(inputs)
# NumRooms Alley
# 0 3.0 Pave
# 1 2.0 NaN
# 2 4.0 NaN
# 3 3.0 NaN
但是对于缺少的非数值特征呢?我们可以将非数值特征替换为一个指示特征。因为在这里,'Alley' 只有两个可能的取值 'Pave' 和 'NA',我们可以将 'Alley' 变为两个特征 'Alley_Pave' 和 'Alley_nan',如果 'Alley' 为 'Pave',则 'Alley_Pave' 为 1,'Alley_nan' 为 0;如果 'Alley' 为 'NA',则 'Alley_Pave' 为 0,'Alley_nan' 为 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
现在,所有输入数据都是数值类型,且没有缺失值。我们可以将 inputs 和 outputs 转换为张量。
x, y = torch.tensor(inputs.values), torch.tensor(outputs.values)
print(x)
# tensor([[3., 1., 0.],
# [2., 0., 1.],
# [4., 0., 1.],
# [3., 0., 1.]], dtype=torch.float64)
print(y)
# tensor([127500, 106000, 178100, 140000])