《动手学深度学习》第二版(2.预备知识)笔记

本文介绍了机器学习中的基础知识,包括数据存储和操作、张量概念及其操作(如reshape、广播机制、索引、切片和内存管理),以及线性代数中的向量、矩阵运算和微积分概念,如梯度、点积和矩阵乘法。还提到了自动微分在深度学习中的应用,如梯度计算和反向传播。
摘要由CSDN通过智能技术生成

前言

学习笔记,仅供学习,不做商用,如有侵权,联系我删除即可

所有机器学习方法都涉及从数据中提取信息。因此,我们先学习一些关于数据的实用技能,包括存储、操作和预处理数据。

机器学习通常需要处理大型数据集。我们可以将某些数据集视为一个表,其中表的行对应样本,列对应属性。

深度学习是关于优化的学习。对于一个带有参数的模型,我们想要找到其中能拟合数据的最好模型。

一、数据操作

张量(tensor):n维数组

张量表示一个由数值组成的数组,这个数组可能有多个维度。

  • 具有一个轴的张量对应数学上的向量(vector);
  • 具有两个轴的张量对应数学上的矩阵(matrix);
  • 具有两个轴以上的张量没有特殊的数学名称。

1.1 入门

张量中的每个值都称为张量的元素(element)。

除非额外指定,新的张量将存储在内存中,并采用基于CPU的计算。

可以通过张量的shape属性来访问张量(沿每个轴的长度)的形状。

如果只想知道张量中元素的总数,即形状的所有元素乘积,可以检查它的大小(size)。

要想改变一个张量的形状而不改变元素数量和元素值,可以调用reshape函数。例如,可以把张量x从形状为 (12,)的行向量转换为形状为(3,4)的矩阵。

我们不需要通过手动指定每个维度来改变形状。也就是说,如果我们的目标形状是(高度,宽度),那么在知道宽度后,高度会被自动计算得出,不必我们自己做除法。

可以通过-1来调用此自动计算出维度的功能。即我们可以用x.reshape(-1,4)或x.reshape(3,-1)来取代x.reshape(3,4)

创建一个形状为(2,3,4)的张量(两个通道,每个通道是3行4列的矩阵,即CHW的类型),其中所有元素都设置为0。

 创建一个形状为(2,3,4)的张量,其中所有元素都设置为1。

有时我们想通过从某个特定的概率分布中随机采样来得到张量中每个元素的值。

以下代码创建一个形状为(3,4)的张量。其中的 每个元素都从均值为0、标准差为1的标准高斯分布(正态分布)中随机采样。

还可以通过提供包含数值的Python列表(或嵌套列表),来为所需张量中的每个元素赋予确定值。

1.2 运算符

“按元素”方式可以应用更多的计算,包括像求幂这样的一元运算符. 

把多个张量连结(concatenate)在一起,把它们端对端地叠起来形成一个更大的张量。我们只需要提供张量列表,并给出沿哪个轴连结。

下面的例子分别演示了当我们沿行(轴‐0,形状的第一个元素)按列(轴‐1,形状的第二个元素)连结两个矩阵时,会发生什么情况。我们可以看到,第一个输出张量的轴‐0长度(6)是两个输入张量轴‐0长度的总和(3+3);第二个输出张量的轴‐1长度(8)是两个输入张量轴‐1长度的总和(4+4)。

 对张量中的所有元素进行求和,会产生一个单元素张量。

1.3 广播机制

在某些情况下,即使形状不同,我们仍然可以通过调用广播机制(broadcasting mechanism)来执行按元素操作。

这种机制的工作方式如下:

  1. 通过适当复制元素来扩展一个或两个数组,以便在转换之后,两个张量具有相同的形状;
  2. 对生成的数组执行按元素操作。

1.4 索引和切片

张量中的元素可以通过索引访问。

与任何Python数组一样:第一个元素的索引是0,最后一个元素索引是‐1;可以指定范围以包含第一个元素和最后一个之前的元素。

可以用[-1]选择最后一个元素可以用[1:3]选择第二个和第三个元素([a,b]-->从索引a到索引b-1(从第a+1个元素到第b个元素)):

还可以通过指定索引来将元素写入矩阵。 

 如果我们想为多个元素赋值相同的值,我们只需要索引所有元素,然后为它们赋值。例如,[0:2, :]访问第1行和第2行,其中“:”代表沿轴1(列)的所有元素。虽然我们讨论的是矩阵的索引,但这也适用于向量和超过2个维度的张量

 1.5 节省内存

运行一些操作可能会导致为新结果分配内存。

例如,Y = X + Y,我们将取消引用Y指向的张量, 而是指向新分配的内存处的张量。运行Y = Y + X后,我们会发现id(Y)指向另一个位置。这是因为Python首先计算Y + X,为结果分配新的内存,然后使Y指向内存中的这个新位置。

但这是不可取的,原因有两个:

  1. 首先,我们不想总是不必要地分配内存。在机器学习中,我们可能有数百兆的参数,并且在一秒内多次更新所有参数。通常情况下,我们希望原地执行这些更新;
  2. 如果我们不原地更新,其他引用仍然会指向旧的内存位置,这样我们的某些代码可能会无意中引用旧的参数 

可以使用切片表示法将操作的结果分配给先前分配的数组,例如Y[:] = <expression>。

 如果在后续计算中没有重复使用X,我们也可以使用X[:] = X + Y或X += Y来减少操作的内存开销。

1.6 转换为其他Python对象

torch张量和numpy数组将共享它们的底层内存,就地操作更改一个张量也会同时更改另一个张量。

要将大小为1的张量转换为Python标量,我们可以调用item函数或Python的内置函数。

二、线性代数

2.1 标量

仅包含一个数值被称为标量(scalar)。

2.2 向量

向量可以被视为标量值组成的列表。这些标量值被称为向量的元素(element)或分量(component)。

大量文献认为列向量是向量的默认方向,本书也是如此。

向量的长度通常称为向量的维度(dimension)。我们可以通过调用Python的内置len()函数来访问张量的长度。

当用张量表示一个向量(只有一个轴)时,我们也可以通过.shape属性访问向量的长度。形状(shape)是一个元素组,列出了张量沿每个轴的长度(维数)。对于只有一个轴的张量,形状只有一个元素。

向量或轴的维度被用来表示向量或轴的长度,即向量或轴的元素数量。然而,张量的维度用来表示张量具有的轴数。在这个意义上,张量的某个轴的维数就是这个轴的长度

2.3 张量及其计算方法

张量(本小节中的“张量”指代数对象)是描述具有任意数量轴的n维数组的通用方法。

两个矩阵的按元素乘法称为Hadamard积(Hadamard product)(数学符号⊙)

 2.4 降维

调用求和函数会沿所有的轴降低张量的维度,使它变为一个标量。

非降维求和可以选择在某个轴上附加:keepdims=True,例如

如果想沿某个轴计算A元素的累积总和,比如axis=0(按行计算),可以调用cumsum函数。此函数不会沿任何轴降低输入张量的维度

2.5 点积(Dot Product)

点积(dotproduct)x^{T}y(或〈x,y〉)是相同位置按元素乘积

可以通过执行按元素乘法,然后进行求和来表示两个向量的点积: 

2.6 矩阵‐向量积

使用张量表示矩阵‐向量积,我们使用mv函数。当我们为矩阵A和向量x调用torch.mv(A,x)时,会执 行矩阵‐向量积。注意,A的列维数(沿轴1的长度)必须与x的维数(其长度)相同。

2.7 矩阵-矩阵乘法

可以将矩阵‐矩阵乘法AB看作简单地执行m次矩阵‐向量积,并将结果拼接在一起,形成一个n×m矩阵。

2.8 范数

L1范数:向量元素的绝对值之和,

L2范数:向量元素平方和的平方根,

矩阵的Frobenius范数:矩阵元素平方和的平方根,

目标,或许是深度学习算法最重要的组成部分(除了数据),通常被表达为范数。

三、微积分

在深度学习中,我们“训练”模型,不断更新它们,使它们在看到越来越多的数据时变得越来越好。通常情况下,变得更好意味着最小化一个损失函数(loss function)。

可以把拟合模型的任务分解为两个关键问题:

  • 优化(optimization):用模型拟合观测数据的过程;
  • 泛化(generalization):数学原理和实践者的智慧,能够指导我们生成出有效性超出用于训练的数据集本身的模型。

注释#@save是一个特殊的标记,会将对应的函数、类或语句保存在包中。因此,以后无须重新定义就可以直接调用它们

3.1 梯度

可以连结一个多元函数对其所有变量的偏导数,以得到该函数的梯度(gradient)向量。

 梯度对于设计深度学习中的优化算法有很大用处。

四、 自动微分

深度学习框架通过自动计算导数,即自动微分(automatic differentiation)来加快求导。实际中,根据设计好的模型,系统会构建一个计算图(computational graph),来跟踪计算是哪些数据通过哪些操作组合起来产生输出。自动微分使系统能够随后反向传播梯度。这里,反向传播(back propagate)意味着跟踪整个计算图,填充关于每个参数的偏导数。

4.1 一个示例

import torch
x = torch.arange(4.0)  # tensor([0., 1., 2., 3.])

x.requires_grad_(True) # 等价于x=torch.arange(4.0,requires_grad=True)
x.grad # 默认值是None

y = 2 * torch.dot(x, x) # tensor(28., grad_fn=<MulBackward0>)

# 调用反向传播函数来自动计算y关于x每个分量的梯度,并打印这些梯度。
y.backward()
x.grad      # tensor([ 0., 4., 8., 12.])

# 验证这个梯度是否计算正确
x.grad == 4 * x    # tensor([True, True, True, True])

# 在默认情况下,PyTorch会累积梯度,我们需要清除之前的值
x.grad.zero_()
y = x.sum()
y.backward()
x.grad        # tensor([1., 1., 1., 1.])

小结:

  1. 梯度会保存在x.grad里,默认值是None,并且默认情况下Pytorch会累积梯度,需要清除之前的值。
  2. 在调用反向传播.backward()之后,会自动计算y关于x的每个分量的梯度,并把梯度保存在x.grad里。

4.2 分离计算 

希望将某些计算移动到记录的计算图之外。

例如,假设y是作为x的函数计算的,而z则是作为y和x的函数计算的。想象一下,我们想计算z关于x的梯度,但由于某种原因,希望将y视为一个常数,并且只考虑到x在y被计算后发挥的作用。 这里可以分离y来返回一个新变量u,该变量与y具有相同的值,但丢弃计算图中如何计算y的任何信息。换句话说,梯度不会向后流经u到x。因此,下面的反向传播函数计算z=u*x关于x的偏导数,同时将u作为常数处理,而不是z=x*x*x关于x的偏导数。

由于记录了y的计算结果,我们可以随后在y上调用反向传播,得到y=x*x关于的x的导数,即2*x。 

五、概率

基本的概率论的相关知识,没有太多需要额外记录的笔记。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值