《动手学深度学习》——预备知识

参考资料:

2.1 数据操作

torch 里的 tensor 与 numpy 中的 ndarray 相比,能更好地支持 GPU 加速计算,且支持自动微分。

2.1.1 入门

创建一个张量:

# 全0张量
x = torch.zeros(2,3,4)
# 全1张量
x = torch.ones(2, 3, 4)
# 元素递增(reshape里的"-1"代表自动计算,即4)
x = torch.arange(12).reshape(3,-1)
# 从标准高斯分布中随机采样
x = torch.randn(3,4)
# 利用numpy的ndarray初始化张量
x = torch.tensor(numpty.arange(4))

输出张量的信息:

# 张量的形状
x.shape
# 张量中的元素总数(number of elements)
x.numel

2.1.2 运算符

常见的标准算术运算符(+-\*/\**)和逻辑运算符(==>=等)都可以被升级为按元素运算

# x = torch.tensor([1, 2, 4, 8])
# y = torch.tensor([2, 2, 2, 2])
x == y
# Out: tensor([False, True, False, False])

# 所有元素变为e的指数
torch.exp(x)

我们也可以把多个张量连结在一起:

# x,y同上
torch.cat((x,y),dim=0)
# Out: tensor([1, 2, 4, 8, 2, 2, 2, 2])
# 注:默认列向量

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=1)
# Out: 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.]])

2.1.3 广播机制

由于广播机制的存在,当参与运算的两个张量具有不同的形状时,也可用通过复制元素使得两个张量形状相同的方式得到运算结果:

a = torch.arange(3).reshape((3, 1))
b = torch.arange(2).reshape((1, 2))
a + b
# Out:tensor([[0, 1],
#             [1, 2],
#             [2, 3]])

个人感觉广播机制不必深究,在实际编程时的应用都比较基础。

2.1.4 索引和切片

这部分和 Python 相似:“起点:终点:步长”(左闭右开)。

2.1.5 节省内存

Y = Y+X 替换成 Y[:] = Y+XY += X

2.2 数据预处理

2.2.1 读取数据集

pandas 的部分操作见: pandas自学笔记__DataFrame_MaTF_的博客-CSDN博客

pd.get_dummies()可以用于实现独热编码:

print(inputs)
inputs = pd.get_dummies(inputs, dummy_na=True).astype("float64")
print(inputs)
#  NumRooms Alley
# 0       NaN  Pave
# 1       2.0   NaN
# 2       4.0   NaN
# 3       NaN   NaN
#    NumRooms  Alley_Pave  Alley_nan
# 0       NaN         1.0        0.0
# 1       2.0         0.0        1.0
# 2       4.0         0.0        1.0
# 3       NaN         0.0        1.0

2.2.2 转换为张量

如果 pd.DataFrame 中的所有条目均为数值类型,则可以转换成张量格式:

X, y = torch.tensor(inputs.values)

2.3 线性代数

2.3.1 张量

标量、向量、矩阵均可以看作特殊的张量。

# 得到张量的长度(第0维的长度)
len(x)
# 矩阵的转置(用在高维张量上会产生警告)
A.T
# 向量点积
torch.dot(x, y)
# 矩阵向量积
torch.mv(A, x)
# 矩阵乘法
torch.mm(A, B)
# 张量的矩阵乘法:用后面两维做矩阵乘法,前面的维度当作batch(可以广播)
a = torch.ones(2,1,3,4)
b = torch.ones(5,4,2)
c = torch.matmul(a,b)
c.shape
# Out: torch.size([2,5,3,2])

2.3.2 降维运算

降维运算包括 sum(),mean(),numel() 等,这里以 sum 为例:

# tensor([[ 0,  1,  2,  3],
#         [ 4,  5,  6,  7],
#         [ 8,  9, 10, 11],
#         [12, 13, 14, 15],
#         [16, 17, 18, 19]])
A_sum_axis1 = A.sum(axis=0)
A_sum_axis1, A_sum_axis1.shape
# Out: (tensor([40, 45, 50, 55]), torch.Size([4]))

sum() 中的 axis 代表沿哪个维度进行求和。

在某些情况下,我们希望使用 sum() 之类的函数,但却并不希望降维,则可以指定 keepdims=True

sum_A = A.sum(axis=1, keepdims=True)
print(sum_A.shape)
sum_A
# torch.Size([5, 1])
# tensor([[ 6],
#         [22],
#         [38],
#         [54],
#         [70]])

我们也可以使用 cumsum() 函数实现如“逐行相加”的操作:

# tensor([[ 0,  1,  2,  3],
#         [ 4,  5,  6,  7],
#         [ 8,  9, 10, 11],
#         [12, 13, 14, 15],
#         [16, 17, 18, 19]])
A.cumsum(axis=0)
# Out: tensor([[ 0,  1,  2,  3],
#             [ 4,  6,  8, 10],
#             [12, 15, 18, 21],
#             [24, 28, 32, 36],
#             [40, 45, 50, 55]])

2.3.3 范数

# 1范数
torch.abs(x).sum()
# 2范数
torch.norm(x)

2.4 自动微分

2.4.1 一个简单的例子

y = 2 x T x y=2x^Tx y=2xTx 对列向量 x x x 求导为例:

x = torch.arange(4.0)
x.requires_grad_(True)  # 等价于x=torch.arange(4.0,requires_grad=True)
y = 2 * torch.dot(x, x)
y.backward()
x.grad
# Out: tensor([ 0.,  4.,  8., 12.])

# 注意:在默认情况下,PyTorch会累积梯度,我们需要清除之前的值
x.grad.zero_()

2.4.2 向量的反向传播

参考 ARTS-S pytorch中backward函数的gradient参数作用 - 荷楠仁 - 博客园 (cnblogs.com)

backward() 中有一个参数 gradient ,我们可以这样理解:原本 backward() 函数只能作用于向量,使用 gradient 参数可以化张量为向量:
y 1 = x 1 x 2 x 3 y 2 = x 1 + x 2 + x 3 y 3 = x 1 + x 2 x 3 y = f ( y 1 , y 2 , y 3 ) [ ∂ y ∂ x 1 , ∂ y ∂ x 2 , ∂ y ∂ x 3 ] = [ ∂ y ∂ y 1 , ∂ y ∂ y 2 , ∂ y ∂ x 3 ] [ ∂ y 1 ∂ x 1 ∂ y 1 ∂ x 2 ∂ y 1 ∂ x 3 ∂ y 2 ∂ x 1 ∂ y 2 ∂ x 2 ∂ y 2 ∂ x 3 ∂ y 3 ∂ x 1 ∂ y 3 ∂ x 2 ∂ y 3 ∂ x 3 ] y_1=x_1x_2x_3\\ y_2=x_1+x_2+x_3\\ y_3=x_1+x_2x_3\\ y=f(y_1,y_2,y_3)\\ [\frac{\partial y}{\partial x_1},\frac{\partial y}{\partial x_2},\frac{\partial y}{\partial x_3}]=[\frac{\partial y}{\partial y_1},\frac{\partial y}{\partial y_2},\frac{\partial y}{\partial x_3}] \left[\begin{array}{l} \frac{\partial y_1}{\partial x_1} & \frac{\partial y_1}{\partial x_2} & \frac{\partial y_1}{\partial x_3}\\ \frac{\partial y_2}{\partial x_1} & \frac{\partial y_2}{\partial x_2} & \frac{\partial y_2}{\partial x_3}\\ \frac{\partial y_3}{\partial x_1} & \frac{\partial y_3}{\partial x_2} & \frac{\partial y_3}{\partial x_3}\\ \end{array}\right] y1=x1x2x3y2=x1+x2+x3y3=x1+x2x3y=f(y1,y2,y3)[x1y,x2y,x3y]=[y1y,y2y,x3y] x1y1x1y2x1y3x2y1x2y2x2y3x3y1x3y2x3y3
在上面的公式中, [ ∂ y ∂ y 1 , ∂ y ∂ y 2 , ∂ y ∂ x 3 ] [\frac{\partial y}{\partial y_1},\frac{\partial y}{\partial y_2},\frac{\partial y}{\partial x_3}] [y1y,y2y,x3y] 就是 gradient y y y 就是转换后的标量。

# tensor([0., 1., 2., 3.])
x.grad.zero_()
y = x * x
# 等价于y.backward(torch.ones(len(x)))
y.backward(gradient=torch.tensor([1 ,2, 3, 4]))
x.grad
# tensor([ 0.,  4., 12., 24.])

2.4.3 分离计算

设想这样一种情况: z = g ( x , y ) ,   y = f ( x ) z=g(x,y),\ y=f(x) z=g(x,y), y=f(x) ,假如我们希望在计算 ∂ z ∂ x \frac{\partial z}{\partial x} xz 先将 y y y 看作常数,可以采用如下操作:

y = x * x
u = y.detach()
z = u * x
z.sum().backward()

2.4.4 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)
d = f(a)
d.backward()

2.5 概率

2.5.1 基本概率论

import torch
from torch.distributions import multinomial
from d2l import torch as d2l

使用 multinomial.Multinomial ,我们可以传入一个概率向量,输出是另一个相同长度的向量:它在索引 i 处的值是采样结果中 i 出现的次数:

multinomial.Multinomial(10, fair_probs).sample()	# 10代表采样次数
# Out: tensor([2., 4., 1., 0., 1., 2.])

猜你喜欢

转载自blog.csdn.net/MaTF_/article/details/131523937
今日推荐