本文目录
环境安装
PyTorch官网
Jupyter NoteBook
PyTorch数据类型操作
import torch
x = torch.arange(12) # 使用arange创建一个行向量x tensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
x.shape # 通过张量的 shape 属性来访问张量的形状 torch.Size([12])
x.numel() # 张量中元素的总数 12
X = x.reshape(3, 4) # 要改变张量的形状
tensor([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
# reshape支持自动计算出一个维度用法 x.reshape(-1,4)或x.reshape(3,-1)等价于x.reshape(3,4)。
torch.zeros((2, 3, 4)) # 创建全0张量
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.]]])
torch.ones((2, 3, 4)) # 创建全1张量
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.]]])
torch.randn(3, 4) # 创建随机张量
tensor([[ 1.0962, 0.7937, -1.8389, -0.1989],
[ 1.5041, 0.2080, 1.4398, 1.8232],
[-1.3178, -0.8359, 1.8015, 0.4061]])
torch.tensor([[2, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]]) # 手动初始化张量
# 张量计算
x = torch.tensor([1.0, 2, 4, 8])
y = torch.tensor([2, 2, 2, 2])
x + y, x - y, x * y, x / y, x ** y # **运算符是求幂运算
(tensor([ 3., 4., 6., 10.]),
tensor([-1., 0., 2., 6.]),
tensor([ 2., 4., 8., 16.]),
tensor([0.5000, 1.0000, 2.0000, 4.0000]),
tensor([ 1., 4., 16., 64.]))
torch.exp(x) # 张量求幂
tensor([2.7183e+00, 7.3891e+00, 5.4598e+01, 2.9810e+03])
# 对张量分别按行和按列进行连结(concatenate)
X = torch.arange(12, dtype=torch.float32).reshape((3,4))
Y = torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
torch.cat((X, Y), dim=0), torch.cat((X, Y), dim=1)
(tensor([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[ 2., 1., 4., 3.],
[ 1., 2., 3., 4.],
[ 4., 3., 2., 1.]]),
tensor([[ 0., 1., 2., 3., 2., 1., 4., 3.],
[ 4., 5., 6., 7., 1., 2., 3., 4.],
[ 8., 9., 10., 11., 4., 3., 2., 1.]]))
# 对于每个位置,如果 X 和 Y 在该位置相等,则新张量中相应项的值为1,这意味着逻辑语句 X == Y 在该位置处为真,否则该位置为 0。
X == Y
tensor([[False, True, False, True],
[False, False, False, False],
[False, False, False, False]])
# 对张量中的所有元素进行求和会产生一个只有一个元素的张量。
X.sum()
tensor(66.)
# 在大多数情况下,我们将沿着数组中长度为1的轴进行广播
a = torch.arange(3).reshape((3, 1))
b = torch.arange(2).reshape((1, 2))
a, b
# 由于 a 和 b 分别是 3×1 和 1×2 矩阵,如果我们让它们相加,它们的形状不匹配。
# 我们将两个矩阵广播为一个更大的 3×2 矩阵,如下所示:矩阵 a将复制列,矩阵 b将复制行,然后再按元素相加。
a + b
tensor([[0, 1],
[1, 2],
[2, 3]])
# 索引和切片
X = torch.arange(12, dtype=torch.float32).reshape((3,4))
tensor([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.]])
X[-1], X[1:3]
(tensor([ 8., 9., 10., 11.]),
tensor([[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.]]))
# 写值
X[1, 2] = 9
tensor([[ 0., 1., 2., 3.],
[ 4., 5., 9., 7.],
[ 8., 9., 10., 11.]])
# 多元素写值
X[0:2, :] = 12
tensor([[12., 12., 12., 12.],
[12., 12., 12., 12.],
[ 8., 9., 10., 11.]])
# 节省内存写法一
Z = torch.zeros_like(Y)
print('id(Z):', id(Z)) # id(Z): 139674315734208
Z[:] = X + Y
print('id(Z):', id(Z)) # id(Z): 139674315734208
# 节省内存写法二
X[:] = X + Y
X += Y
# tensor与ndarray数据转换
tensor_cpu = torch.ones((2,2)) # 创建CPU类型的张量
tensor_gpu = tensor_cpu.cuda() # CPU转GPU
tensor_cpu = tensor_gpu.cpu() # GPU转CPU
np_array= tensor_cpu.numpy() # tensor转ndarray
torch.from_numpy(np.ones((2,2))) # ndarray转tensor(保留精度,ndarray默认64位精度,tensor默认32位。若通过from_numpy的方式,则会保留原来64位精度)
torch.Tensor(np.ones((2,2))) # ndarray转tensor方式二(丢失精度,64位浮点数截断为32位)
torch.ones((1,1)).item() # tensor cpu转scalar
pandas读写数据集
import os
# 写入数据集
os.makedirs(os.path.abspath('data'), exist_ok=True)
data_file = os.path.join(os.path.abspath('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')
# 读取数据集
import pandas as pd
data = pd.read_csv(data_file)
print(data) # type(data) = pandas.core.frame.DataFrame
# NumRooms Alley Price
0 NaN Pave 127500
1 2.0 NaN 106000
2 4.0 NaN 178100
3 NaN NaN 140000
# 读取第0行数据
data.loc[0]
NumRooms NaN
Alley Pave
Price 127500
Name: 0, dtype: object
# 读取第0行的Price字段
data.loc[0]["Price"]
127500
# 处理缺失值
inputs, outputs = data.iloc[:, 0:2], data.iloc[:, 2]
inputs = inputs.fillna(inputs.mean(numeric_only=True))
print(inputs)
NumRooms Alley
0 3.0 Pave
1 2.0 NaN
2 4.0 NaN
3 3.0 NaN
# 将NaN转换为0/1表示
# 对于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
# 转换为张量格式
X, y = torch.tensor(inputs.values), torch.tensor(outputs.values)
X, y
(tensor([[3., 1., 0.],
[2., 0., 1.],
[4., 0., 1.],
[3., 0., 1.]], dtype=torch.float64),
tensor([127500, 106000, 178100, 140000]))
# 导入库
import numpy as np
import pandas as pd
# 导入CSV或者xlsx文件:
df = pd.DataFrame(pd.read_csv('name.csv',header=1))
df = pd.DataFrame(pd.read_excel('name.xlsx'))
# 用pandas创建数据表:
df = pd.DataFrame({"id":[1001,1002,1003,1004,1005,1006],
"date":pd.date_range('20130102', periods=6),
"city":['Beijing ', 'SH', ' guangzhou ', 'Shenzhen', 'shanghai', 'BEIJING '],
"age":[23,44,54,32,34,32],
"category":['100-A','100-B','110-A','110-C','210-A','130-F'],
"price":[1200,np.nan,2133,5433,np.nan,4432]},
columns =['id','date','city','category','age','price'])
# 查看维度
df.shape
(6, 6)
# 数据表基本信息(维度、列名称、数据格式、所占空间等)
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 6 entries, 0 to 5
Data columns (total 6 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 id 6 non-null int64
1 date 6 non-null datetime64[ns]
2 city 6 non-null object
3 category 6 non-null object
4 age 6 non-null int64
5 price 4 non-null float64
dtypes: datetime64[ns](1), float64(1), int64(2), object(2)
memory usage: 416.0+ bytes
# 每一列数据的格式
df.dtypes
id int64
date datetime64[ns]
city object
category object
age int64
price float64
dtype: object
# 某一列格式
df['B'].dtype
# 空值
type(df.isnull())
df.isnull()
pandas.core.frame.DataFrame
id date city category age price
0 False False False False False False
1 False False False False False True
2 False False False False False False
3 False False False False False False
4 False False False False False True
5 False False False False False False
矩阵操作
# 创建矩阵
A = torch.arange(20).reshape(5, 4)
A
tensor([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15],
[16, 17, 18, 19]])
# 矩阵转置
A.T
tensor([[ 0, 4, 8, 12, 16],
[ 1, 5, 9, 13, 17],
[ 2, 6, 10, 14, 18],
[ 3, 7, 11, 15, 19]])
# 矩阵运算
A = torch.arange(20, dtype=torch.float32).reshape(5, 4)
B = A.clone() # 通过分配新内存,将A的一个副本分配给B
A, A + B, A * B
(tensor([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[12., 13., 14., 15.],
[16., 17., 18., 19.]]),
tensor([[ 0., 2., 4., 6.],
[ 8., 10., 12., 14.],
[16., 18., 20., 22.],
[24., 26., 28., 30.],
[32., 34., 36., 38.]]),
tensor([[ 0., 1., 4., 9.],
[ 16., 25., 36., 49.],
[ 64., 81., 100., 121.],
[144., 169., 196., 225.],
[256., 289., 324., 361.]]))
# 降维运算
x = torch.arange(4, dtype=torch.float32)
x, x.sum()
(tensor([0., 1., 2., 3.]), tensor(6.))
A.shape, A.sum()
(torch.Size([5, 4]), tensor(190.))
A
(tensor([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[12., 13., 14., 15.],
[16., 17., 18., 19.]]),
A_sum_axis0 = A.sum(axis=0)
A_sum_axis0, A_sum_axis0.shape
(tensor([40., 45., 50., 55.]), torch.Size([4]))
# 降维运算是一类操作的统称,例如求平均也是降维运算
A.sum(axis=[0, 1])
A.mean(), A.sum() / A.numel()
(tensor(9.5000), tensor(9.5000))
A.mean(axis=0), A.sum(axis=0) / A.shape[0]
(tensor([ 8., 9., 10., 11.]), tensor([ 8., 9., 10., 11.]))
# 非降维求和,使用广播机制保留维度
sum_A = A.sum(axis=1, keepdims=True)
sum_A
tensor([[ 6.],
[22.],
[38.],
[54.],
[70.]])
A / sum_A
tensor([[0.0000, 0.1667, 0.3333, 0.5000],
[0.1818, 0.2273, 0.2727, 0.3182],
[0.2105, 0.2368, 0.2632, 0.2895],
[0.2222, 0.2407, 0.2593, 0.2778],
[0.2286, 0.2429, 0.2571, 0.2714]])
# 点积
y = torch.ones(4, dtype = torch.float32)
x, y, torch.dot(x, y)
(tensor([0., 1., 2., 3.]), tensor([1., 1., 1., 1.]), tensor(6.))
torch.sum(x * y)
tensor(6.)
# 矩阵-向量积
A.shape, x.shape, torch.mv(A, x)
(torch.Size([5, 4]), torch.Size([4]), tensor([ 14., 38., 62., 86., 110.]))
# 矩阵-矩阵乘法
B = torch.ones(4, 3)
torch.mm(A, B)
tensor([[ 6., 6., 6.],
[22., 22., 22.],
[38., 38., 38.],
[54., 54., 54.],
[70., 70., 70.]])
# 范数
# 一个向量的范数告诉我们一个向量有多大。 这里考虑的大小(size)概念不涉及维度,而是分量的大小。
# 计算L2范数
u = torch.tensor([3.0, -4.0])
torch.norm(u)
tensor(5.)
# 计算L1范数
torch.abs(u).sum()
tensor(7.)
自动求导
# 对函数y=2x⊤x求导
# 创建输入值,包含四个元素的一维向量
x = torch.arange(4.0)
x
tensor([0., 1., 2., 3.])
# 共享内存,减少内存损耗
x.requires_grad_(True) # 等价于 `x = torch.arange(4.0, requires_grad=True)`
x.requires_grad # 默认值是False
# 计算y
# x是一个长度为4的向量,计算x和x的内积,得到了我们赋值给y的标量输出。
y = 2 * torch.dot(x, x)
y
tensor(28., grad_fn=<MulBackward0>)
# 可以通过调用反向传播函数来自动计算y关于x每个分量的梯度,并打印这些梯度。
y.backward()
x.grad
tensor([ 0., 4., 8., 12.])
# 函数y=2x⊤x关于x的梯度应为4x。让我们快速验证我们想要的梯度是否正确计算。
x.grad == 4 * x
tensor([True, True, True, True])
# 在默认情况下,PyTorch会累积梯度,我们需要清除之前的值
x.grad.zero_()
y = x.sum()
y.backward()
x.grad
# 非标量变量的反向传播
# 对非标量调用`backward`需要传入一个`gradient`参数,该参数指定微分函数关于`self`的梯度。
# 在我们的例子中,我们只想求偏导数的和,所以传递一个1的梯度是合适的
x.grad.zero_()
y = x * x
y.sum().backward() # 等价于y.backward(torch.ones(len(x)))
# 也可以y.backward(torch.ones_like(x))
x.grad
# 分离计算
# 将计算移动到记录的计算图之外
# 在这里,我们可以分离y来返回一个新变量u,该变量与y具有相同的值,但丢弃计算图中如何计算y的任何信息。换句话说,梯度不会向后流经u到x。因此,下面的反向传播函数计算z=u*x关于x的偏导数,同时将u作为常数处理,而不是z=x*x*x关于x的偏导数。
x.grad.zero_()
y = x * x
u = y.detach() # !Important
z = u * x
z.sum().backward()
x.grad == u
tensor([True, True, True, True])
# Python控制流的梯度计算
def f(a):
b = a * 2
while b.norm() < 1000:
b = b * 2
if b.sum() > 0:
c = b
else:
c = 100 * b
return c
a = torch.randn(size=(), requires_grad=True) # 创建一维随机向量,维度为0,即只有一个数据
d = f(a)
d.backward()
概率论
# 导入库
%matplotlib inline
import torch
from torch.distributions import multinomial
from d2l import torch as d2l
# 对丢色子进行抽样,众所周知每个面的概率是均分1/6
fair_probs = torch.ones([6]) / 6
# Multinomial函数第一参数为重复次数,第二参数为概率向量
multinomial.Multinomial(1, fair_probs).sample()