文章目录

  • 1、概述
  • 2、课程学习
    • 2.1、深度学习介绍
    • 2.2、安装
    • 2.3、数据操作
    • 2.4、数据预处理
    • 2.5、线性代数
    • 2.6、微积分
    • 2.7、自动微分
    • 2.8、概率
      • 2.8.1、基本概率论
      • 2.8.2、处理多个随机变量
      • 2.8.3、期望和方差
    • 2.9、查阅文档

1、概述

本篇博客用来记录我学习深度学习的学习笔记,本篇博客主要深度学习所需的一些预备知识,
包括数据操作,线性代数,微积分,概率论等

在这里插入图片描述


2、课程学习

2.1、深度学习介绍

在这里插入图片描述

深度学习是机器学习的一种

深度学习在广告推荐中的案例

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


2.2、安装

在这里插入图片描述

Conda 是一个开源的 软件包管理系统 和 环境管理系统,专为数据科学、机器学习、生物信息学等领域设计。它允许用户高效地安装、管理和切换多个版本的软件包及其依赖项,同时支持多种编程语言(如 Python、R、Ruby、Java 等)和跨平台(Linux、macOS、Windows)。
Jupyter Notebook 是一个功能强大的交互式计算工具,广泛应用于数据科学、教育、研究和开发领域。作用包括:数据分析与可视化,机器学习与建模,教育与教学,科研与报告,合作与共享
D2L 是一个面向中文读者的深度学习开源项目,由 李沐博士 等人开发,旨在通过 可运行代码、数学公式和实践案例 的结合,帮助用户系统性地学习深度学习。
PyTorch 是一个开源的深度学习框架,由 Facebook 的 AI 研究团队开发。它基于 Python 语言,支持动态计算图(Dynamic Computation Graph),广泛应用于计算机视觉、自然语言处理等领域。
TorchVision 是 PyTorch 生态中专注于 计算机视觉 的核心库


2.3、数据操作

N 维数组样例
N维数组是机器学习和神经网络的主要数据结构。

张量表示一个由数值组成的数组,这个数组可能有多个维度。
具有一个轴的张量对应数学上的向量(vector)
具有两个轴的张量对应数学上的矩阵(matrix)

具有两个轴以上的张量没有特殊的数学名称。

N 维数组样例
N 维数组是机器学习和神经网络的主要数据结构

在这里插入图片描述

在这里插入图片描述

创建数组的前提条件

  • 形状:例如 3 * 4 矩阵
  • 每个元素的数据类型:例如 32 位浮点数
  • 每个元素的值:例如全是0,或者随机数

在这里插入图片描述

访问元素

在这里插入图片描述


首先,我们可以使用 arange 创建一个行向量 x
这个行向量包含以0开始的前12个整数,它们默认创建为整数。
也可指定创建类型为浮点数。张量中的每个值都称为张量的 元素(element)

import torchA = torch.arange(5, dtype=torch.float32)
print(A)   # tensor([0., 1., 2., 3., 4.])

我们导入torch。请注意,虽然它被称为PyTorch,但是代码中使用torch而不是pytorch


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

import torchA = torch.arange(5, dtype=torch.float32)
print(A)        # tensor([0., 1., 2., 3., 4.])
print(A.shape)  # torch.Size([5])

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

import torchA = torch.arange(5, dtype=torch.float32)
print(A)          # tensor([0., 1., 2., 3., 4.])
print(A.numel())  # 5

改变一个张量的形状而不改变元素数量和元素值,我们可以调用 reshape 函数

import torchA = torch.arange(20, dtype=torch.float32).reshape(5, 4)
print(A)         
# tensor([[ 0.,  1.,  2.,  3.],
#         [ 4.,  5.,  6.,  7.],
#         [ 8.,  9., 10., 11.],
#         [12., 13., 14., 15.],
#         [16., 17., 18., 19.]])

使用全0全1,其他常量或者从特定分布中随机采样的数字

在这里插入图片描述

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

在这里插入图片描述

操作符运算
常见的标准算术运算符(+,-,*,/,**)都可以按升级为按照元素运算

在这里插入图片描述

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

dim=0 表示将 X 和 Y 按照行进行合并
dim=1 表示将 X 和 Y 按照列进行合并

在这里插入图片描述


我们也可以通过逻辑运算符构建二元张量
在这里插入图片描述
对张量中的所有元素进行求和会产生一个只有一个元素的张量。
在这里插入图片描述

广播机制

即使形状不同,依然可以进行张量的加减法

广播(Broadcasting)是 PyTorch 中一种允许不同形状张量进行逐元素运算的机制。
核心思想是:自动扩展较小的张量,使其形状与较大的张量兼容,从而避免手动复制数据,节省内存并简化代码。

即使形状不同,我们任然可以通过调用广播机制来执行按元素操作

在这里插入图片描述

特殊元素获取

可以使用 X[-1] 取出最后一行
使用 X[1:3] 取出第二行和第三行

注意:
行和列都是从 0 开始

在这里插入图片描述

除读取外,我们还可以通过指定索引来将元素写入矩阵。

在这里插入图片描述

按照区域赋值
为多个元素赋值相同的值,我们只需要索引所有元素,然后为他们赋值
在这里插入图片描述

python 使用 id()获取变量的地址(类似 C 中的指针)
在 PyTorch 中,id() 是 Python 内置函数,用于返回对象的 唯一标识符(即内存地址)。

运行一些操作可能会导致为新结果分配内存
在这里插入图片描述

执行原地操作

在这里插入图片描述

其中上图第二个样例中,Z 的内存没有发生变化,前后是一致的

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

在这里插入图片描述

numPytorch 使用不一样的数据类型

在这里插入图片描述

numPytorch 可以互相转换

torch 转化为 NumPy 张量
在这里插入图片描述

将大小为 1 的张量转换为 Python 标量

在这里插入图片描述


2.4、数据预处理

为了能用深度学习来解决现实世界的问题,我们经常从预处理原始数据开始, 而不是从那些准备好的张量格式数据开始。

读取数据集
我们首先创建一个人工数据集,并存储在CSV(逗号分隔值)文件 ../data/house_tiny.csv

要从创建的CSV文件中加载原始数据集,我们导入pandas包并调用read_csv函数。

import os
import pandas as pdos.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')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

“NaN”项代表缺失值。

处理缺失值

对于缺失值的处理,有两种处理办法,插值法删除法

  • 插值法用一个替代值弥补缺失值
  • 删除法则直接忽略缺失值。

通过位置索引iloc,我们将data分成inputsoutputs, 其中前者为data的前两列,而后者为data的最后一列。
对于inputs中缺少的数值,我们用同一列的均值替换“NaN”项。

在这里插入图片描述

对于inputs中的类别值或离散值,我们将“NaN”视为一个类别。 由于“巷子类型”(“Alley”)列只接受两种类型的类别值“Pave”和“NaN”, pandas可以自动将此列转换为两列“Alley_Pave”和“Alley_nan”。 巷子类型为“Pave”的行会将“Alley_Pave”的值设置为1,“Alley_nan”的值设置为0。 缺少巷子类型的行会将“Alley_Pave”和“Alley_nan”分别设置为0和1。

在这里插入图片描述

转换为张量格式
现在inputsoutputs中的所有条目都是数值类型,它们可以转换为张量格式。

在这里插入图片描述


2.5、线性代数

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

  • 确定的数值被称为标量值
  • 不确定的符号被称为变量

标量由只有一个元素的张量表示。

在这里插入图片描述

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

通过一维张量表示向量。

在这里插入图片描述

在数学中,我们可以使用下标来引用向量的任一元素
在这里插入图片描述
在代码中,我们通过张量的索引来访问任一元素。
在这里插入图片描述

长度,维度和形状
向量的长度通常称为向量的维度(dimension)
在这里插入图片描述
当用张量表示一个向量(只有一个轴)时,我们也可以通过.shape属性访问向量的长度。
形状(shape)是一个元素组,列出了张量沿每个轴的长度(维数)。 对于只有一个轴的张量,形状只有一个元素。

在这里插入图片描述

矩阵
正如向量将标量从零阶推广到一阶,矩阵将向量从一阶推广到二阶。
我们可以将任意矩阵 A ∈ R m × n A \in \mathbb{R}^{m \times n} ARm×n
视为一个表格,其中每个元素 aij 属于第 i 行,第 j
在这里插入图片描述

当矩阵具有相同数量的行和列时,其形状将变为正方形; 因此,它被称为方阵(square matrix)

当调用函数来实例化张量时, 我们可以通过指定两个分量mn来创建一个形状为m * n的矩阵。

在这里插入图片描述

当我们交换矩阵的行和列时,结果称为矩阵的转置(transpose)

在这里插入图片描述

作为方阵的一种特殊类型,对称矩阵(symmetric matrix)等于其转置

在这里插入图片描述

张量

就像向量是标量的推广,矩阵是向量的推广一样,我们可以构建具有更多轴的数据结构。 张量(本小节中的“张量”指代数对象)是描述具有任意数量轴的n维数组的通用方法。

在这里插入图片描述

张量算法的基本形式

同样,给定具有相同形状的任意两个张量,任何按元素二元运算的结果都将是相同形状的张量。
例如,将两个相同形状的矩阵相加,会在这两个矩阵上执行元素加法。

在这里插入图片描述
具体而言,两个矩阵的按元素乘法称为Hadamard积(Hadamard product)

在这里插入图片描述

将张量乘以或加上一个标量不会改变张量的形状,其中张量的每个元素都将与标量相加或相乘。

在这里插入图片描述

降维
我们可以对任意张量进行的一个有用的操作是计算其元素的和
在代码中,求和的函数

import torchx = torch.arange(4, dtype=torch.float32)
print(x)         # tensor([0., 1., 2., 3.])
print(x.sum())   # tensor(6.)

我们可以表示任意形状张量的元素和。

在这里插入图片描述

import torchA = torch.arange(20).reshape(5, 4)
print(A)
# tensor([[ 0,  1,  2,  3],
#         [ 4,  5,  6,  7],
#         [ 8,  9, 10, 11],
#         [12, 13, 14, 15],
#         [16, 17, 18, 19]])print(A.shape)  # torch.Size([5, 4])
print(A.sum())  # tensor(190)

默认情况下,调用求和函数会沿所有的轴降低张量的维度,使它变为一个标量。
我们还可以指定张量沿哪一个轴来通过求和降低维度。
以矩阵为例,为了通过求和所有行的元素来降维(轴0)

  • 可以在调用函数时指定axis=0。 由于输入矩阵沿0轴降维以生成输出向量,因此输入轴0的维数在输出形状中消失。(只保留一行
  • 指定axis=1将通过汇总所有列的元素降维(轴1)。因此,输入轴1的维数在输出形状中消失。(只保留一列
import torchA = torch.arange(20).reshape(5, 4)
print(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)
print(A_sum_axis0)         # tensor([40, 45, 50, 55])
print(A_sum_axis0.shape)   # torch.Size([4])# 对所有列进行降维,只保留一列
A_sum_axis1 = A.sum(axis=1)
print(A_sum_axis1)         # tensor([ 6, 22, 38, 54, 70])
print(A_sum_axis1.shape)   # torch.Size([5])

torch.Size([4]) 表示一个 一维张量(向量),其形状(shape)为 (4,),即该张量只有一个维度,且该维度的长度为 4。
维度(Dimensions):张量的维度数由 torch.Size 中的元素个数决定。例如:

  • torch.Size([]):0 维张量(标量)。
  • torch.Size([4]):1 维张量(向量)。
  • torch.Size([2, 3]):2 维张量(矩阵)。
  • torch.Size([2, 3, 4]):3 维张量。

沿着行和列对矩阵求和(A.sum(axis=[0, 1])),等价于对矩阵的所有元素进行求和(A.sum())。

import torchA = torch.arange(20).reshape(5, 4)
print(A)
# tensor([[ 0,  1,  2,  3],
#         [ 4,  5,  6,  7],
#         [ 8,  9, 10, 11],
#         [12, 13, 14, 15],
#         [16, 17, 18, 19]])print(A.sum(axis=[0, 1]))  # tensor(190)
print(A.sum())             # tensor(190)

一个与求和相关的量是平均值(mean或average)。 我们通过将总和除以元素总数来计算平均值。

import torchA = torch.arange(20, dtype=torch.float32).reshape(5, 4)
print(A)
# tensor([[ 0,  1,  2,  3],
#         [ 4,  5,  6,  7],
#         [ 8,  9, 10, 11],
#         [12, 13, 14, 15],
#         [16, 17, 18, 19]])print(A.mean())              # tensor(9.5000)
print(A.sum() / A.numel())   # tensor(9.5000)

numel()PyTorch 中的一个方法,用于返回张量(Tensor)中 所有元素的总数(即 number of elements 的缩写)。
它通过将张量的所有维度大小相乘,计算出总元素数量。


同样,计算平均值的函数也可以沿指定轴降低张量的维度。

import torchA = torch.arange(20, dtype=torch.float32).reshape(5, 4)
print(A)
# tensor([[ 0,  1,  2,  3],
#         [ 4,  5,  6,  7],
#         [ 8,  9, 10, 11],
#         [12, 13, 14, 15],
#         [16, 17, 18, 19]])print(A.mean())              # tensor(9.5000)
print(A.mean(axis=0))        # tensor([ 8.,  9., 10., 11.])
print(A.mean(axis=1))        # tensor([ 1.5000,  5.5000,  9.5000, 13.5000, 17.5000])

非降维求和
有时在调用函数来计算总和或均值时保持轴数不变会很有用。

import torchA = torch.arange(20, dtype=torch.float32).reshape(5, 4)
print(A)
# tensor([[ 0,  1,  2,  3],
#         [ 4,  5,  6,  7],
#         [ 8,  9, 10, 11],
#         [12, 13, 14, 15],
#         [16, 17, 18, 19]])# 降维求和
sum_A_old = A.sum(axis=1)
print(sum_A_old)         # tensor([ 6., 22., 38., 54., 70.])
print(sum_A_old.shape)   # torch.Size([5])# 非降维求和
sum_A = A.sum(axis=1, keepdims=True)
print(sum_A)             
# tensor([[ 6.],
#         [22.],
#         [38.],
#         [54.],
#         [70.]])
print(sum_A.shape)       # torch.Size([5, 1])

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

import torchA = torch.arange(20, dtype=torch.float32).reshape(5, 4)
print(A)
# tensor([[ 0,  1,  2,  3],
#         [ 4,  5,  6,  7],
#         [ 8,  9, 10, 11],
#         [12, 13, 14, 15],
#         [16, 17, 18, 19]])print(A.cumsum(axis=0))
# tensor([[ 0.,  1.,  2.,  3.],
#         [ 4.,  6.,  8., 10.],
#         [12., 15., 18., 21.],
#         [24., 28., 32., 36.],
#         [40., 45., 50., 55.]])

点积

给定两个向量,他们的点积是相同位置的元素乘积的和

import torchx = torch.arange(4, dtype=torch.float32)
y = torch.ones(4, dtype = torch.float32)print(x)              # tensor([0., 1., 2., 3.])
print(y)              # tensor([1., 1., 1., 1.])
print(torch.dot(x,y)) # tensor(6.)

矩阵-向量积

矩阵向量积 Ax 是一个长度为 m 的列向量, 其第 i 个元素是点积 aiTx
在这里插入图片描述

在代码中使用张量表示矩阵-向量积,我们使用mv函数。
当我们为矩阵A和向量x调用torch.mv(A, x)时,会执行矩阵-向量积。

import torchA = torch.arange(20, dtype=torch.float32).reshape(5, 4)
x = torch.arange(4, dtype=torch.float32)print(A)
# tensor([[ 0.,  1.,  2.,  3.],
#         [ 4.,  5.,  6.,  7.],
#         [ 8.,  9., 10., 11.],
#         [12., 13., 14., 15.],
#         [16., 17., 18., 19.]])
print(x)              # tensor([0., 1., 2., 3.])print(torch.mv(A, x)) # tensor([ 14.,  38.,  62.,  86., 110.])

注意,A的列维数(沿轴1的长度)必须与x的维数(其长度)相同。


矩阵-矩阵乘法

我们可以将矩阵-矩阵乘法 AB 看作简单地执行 m 次矩阵-向量积,并将结果拼接在一起,形成一个 n * m 矩阵。
在这里插入图片描述

import torchA = torch.arange(20, dtype=torch.float32).reshape(5, 4)
B = torch.ones(4, 3)print(A)
# tensor([[ 0.,  1.,  2.,  3.],
#         [ 4.,  5.,  6.,  7.],
#         [ 8.,  9., 10., 11.],
#         [12., 13., 14., 15.],
#         [16., 17., 18., 19.]])
print(B)
# tensor([[1., 1., 1.],
#         [1., 1., 1.],
#         [1., 1., 1.],
#         [1., 1., 1.]])
print(torch.mm(A, B))
# tensor([[ 6.,  6.,  6.],
#         [22., 22., 22.],
#         [38., 38., 38.],
#         [54., 54., 54.],
#         [70., 70., 70.]])

范数
向量的范数是表示一个向量有多大。 这里考虑的大小(size)概念不涉及维度,而是分量的大小。

范数的常见性质

  1. 按照常量因子缩放
    在这里插入图片描述

  2. 三角不等式
    在这里插入图片描述

  3. 范数的非负性
    在这里插入图片描述


L2范数
向量元素平方和的平方根
在这里插入图片描述

import torchu = torch.tensor([3.0, -4.0])
print(torch.norm(u))    # tensor(5.)

L1范数
向量元素的绝对值之和
在这里插入图片描述

import torchu = torch.tensor([3.0, -4.0])
print(torch.abs(u).sum())  # tensor(7.)

Lp 范数
在这里插入图片描述


Frobenius范数
Frobenius范数(Frobenius norm)是矩阵元素平方和的平方根

在这里插入图片描述

import torchA = torch.arange(20, dtype=torch.float32).reshape(5, 4)
print(A)   
# tensor([[ 0.,  1.,  2.,  3.],
#         [ 4.,  5.,  6.,  7.],
#         [ 8.,  9., 10., 11.],
#         [12., 13., 14., 15.],
#         [16., 17., 18., 19.]])
print(torch.norm(A))  # tensor(49.6991)

2.6、微积分

在2500年前,古希腊人把一个多边形分成三角形,并把它们的面积相加,才找到计算多边形面积的方法。 为了求出曲线形状(比如圆)的面积,古希腊人在这样的形状上刻内接多边形。
如下图所示,内接多边形的等长边越多,就越接近圆。 这个过程也被称为逼近法(method of exhaustion)

在这里插入图片描述

逼近法就是积分(integral calculus)的起源。

在深度学习中,我们“训练”模型,不断更新它们,使它们在看到越来越多的数据时变得越来越好。 通常情况下,变得更好意味着最小化一个损失函数(loss function), 即一个衡量“模型有多糟糕”这个问题的分数。 最终,我们真正关心的是生成一个模型,它能够在从未见过的数据上表现良好。 但“训练”模型只能将模型与我们实际能看到的数据相拟合。
因此,我们可以将拟合模型的任务分解为两个关键问题:

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

导数和微分
在深度学习中,我们通常选择对于模型参数可微的损失函数。
简而言之,对于每个参数, 如果我们把这个参数增加或减少一个无穷小的量,可以知道损失会以多快的速度增加或减少,

导数的定义:
在这里插入图片描述

如果 f ′ ( α ) f'(\alpha) f(α) 存在,则 f f f α \alpha α 处是可微的
如果 f f f在一个区间内的每个数上都是可微的,则此函数在此区间中是可微的。


微分常见法则
在这里插入图片描述


绘制图及其切线

import numpy as np
from matplotlib_inline import backend_inline
from d2l import torch as d2ldef use_svg_display():  #@save"""使用svg格式在Jupyter中显示绘图"""backend_inline.set_matplotlib_formats('svg')def set_figsize(figsize=(3.5, 2.5)):  #@save"""设置matplotlib的图表大小"""use_svg_display()d2l.plt.rcParams['figure.figsize'] = figsize#@save
def set_axes(axes, xlabel, ylabel, xlim, ylim, xscale, yscale, legend):"""设置matplotlib的轴"""axes.set_xlabel(xlabel)axes.set_ylabel(ylabel)axes.set_xscale(xscale)axes.set_yscale(yscale)axes.set_xlim(xlim)axes.set_ylim(ylim)if legend:axes.legend(legend)axes.grid()#@save
def plot(X, Y=None, xlabel=None, ylabel=None, legend=None, xlim=None,ylim=None, xscale='linear', yscale='linear',fmts=('-', 'm--', 'g-.', 'r:'), figsize=(3.5, 2.5), axes=None):"""绘制数据点"""if legend is None:legend = []set_figsize(figsize)axes = axes if axes else d2l.plt.gca()# 如果X有一个轴,输出Truedef has_one_axis(X):return (hasattr(X, "ndim") and X.ndim == 1 or isinstance(X, list)and not hasattr(X[0], "__len__"))if has_one_axis(X):X = [X]if Y is None:X, Y = [[]] * len(X), Xelif has_one_axis(Y):Y = [Y]if len(X) != len(Y):X = X * len(Y)axes.cla()for x, y, fmt in zip(X, Y, fmts):if len(x):axes.plot(x, y, fmt)else:axes.plot(y, fmt)set_axes(axes, xlabel, ylabel, xlim, ylim, xscale, yscale, legend)def f(t):return 3 * t ** 2 - 4 * tx = np.arange(0, 3, 0.1)
plot(x, [f(x), 2 * x - 3], 'x', 'f(x)', legend=['f(x)', 'Tangent line (x=1)'])
d2l.plt.show()

在这里插入图片描述


偏导数
到目前为止,我们只讨论了仅含一个变量的函数的微分。
在深度学习中,函数通常依赖于许多变量。
因此,我们需要将微分的思想推广到多元函数(multivariate function上。

  • 导数:在一元函数 y = f ( x ) y=f(x) y=f(x)中,导数 f ′ ( x ) f'(x) f(x)表示曲线在点 ( x , f ( x ) ) (x, f(x)) x,f(x)处的切线斜率
  • 偏导数:在多元函数 z = f ( x , y ) z=f(x, y) z=f(x,y)中,偏导数 ∂ f ∂ x \frac{\partial f}{\partial x} xf表示曲面在点 ( x , y , f ( x , y ) ) (x,y,f(x,y)) (x,y,f(x,y))处沿着x轴方向的切线斜率(固定y不变)

在这里插入图片描述


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

在这里插入图片描述


链式法则
然而,上面方法可能很难找到梯度。
这是因为在深度学习中,多元函数通常是复合(composite)的, 所以难以应用上述任何规则来微分这些函数。
幸运的是,链式法则可以被用来微分复合函数。

链式法则是微积分中用于求解复合函数导数的核心工具
其核心思想是:复合函数的导数等于外层函数的导数乘以内层函数的导数,层层传递,如同链条一样。

在这里插入图片描述


2.7、自动微分

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

反向传播:反向传播(Back Propagation, BP) 是神经网络训练的核心算法之一,主要用于计算损失函数对网络参数的梯度,并通过梯度下降等优化方法更新参数,从而最小化损失函数。


计算图
PyTorch 中的 计算图(Computational Graph)是深度学习框架中用于描述数学运算的 有向无环图(DAG)
它通过节点记录张量(Tensor)之间的运算关系,是 PyTorch 实现 自动求导(Autograd)的核心机制。

  • 节点(Node)
    叶子节点(Leaf Node):用户直接创建的张量(如 x = torch.tensor(..., requires_grad=True)),grad_fnNone
    中间节点:由运算生成的张量(如 y = x + 2),grad_fn 记录生成该张量的操作(如 <AddBackward0>)。
  • 边(Edge)
    表示张量之间的依赖关系,即数据流。例如,y = x * x 中,边连接 x 和 y,表示 y 的计算依赖于 x。

在这里插入图片描述


一个简单的例子
一个简单的例子,假设我们想要对函数 y = 2 ∗ x T ∗ x y=2*x^T*x y=2xTx关于列向量 x x x求导。首先,我们创建变量 x x x并为其分配一个初始值。
在我们计算 y y y关于 x x x的梯度之前,需要一个地方来存储梯度。(避免每次都用新的内存来存储梯度,造成内存耗尽)

PyTorch 中,x.requires_grad = Truex.requires_grad_(True) 的作用是启用对张量 x 的梯度追踪,这是自动求导(Autograd)的核心机制之一。

PyTorch 默认不会追踪张量的操作,以节省内存
启用后的作用

  • PyTorch 会记录所有对 x 的操作(如加法、乘法、矩阵运算等),构建一个动态计算图
  • 在调用 backward() 进行反向传播时,可以自动计算 x 的梯度(x.grad)。
import torchx = torch.arange(4.0)
print(x)               # tensor([0., 1., 2., 3.])# 启动对张量 x 的梯度追踪
x.requires_grad_(True)
print(x.grad)          # 默认值是 None# 计算 y = 2x^2
y = 2 * torch.dot(x, x)
print(y)               # tensor(28., grad_fn=<MulBackward0>)# 调用反向传播函数来自动计算 y 关于 x 每个分量的梯度,并打印
y.backward()
print(x.grad)          # tensor([ 0.,  4.,  8., 12.])# 验证梯度是否正确
print(x.grad == 4 * x) # tensor([True, True, True, True])

grad_fn=<MulBackward0>

  • 含义grad_fn 是张量的一个属性,表示生成该张量的操作对应的梯度函数(Gradient Function)。
  • <MulBackward0> 表示该张量是通过 乘法操作(*)生成的,并且在反向传播时会使用乘法的反向传播规则(即乘法的导数)。
  • 动态计算图:PyTorch 使用动态计算图记录操作历史。grad_fn 是计算图中的一部分,用于追踪该张量是如何从其他张量(叶子节点或中间节点)生成的。

非标量变量的反向传播
y不是标量时,向量y关于向量x的导数的最自然解释是一个矩阵。
对于高阶和高维的y和x,求导的结果可以是一个高阶张量。

import torchx = torch.arange(4.0)
print(x)               # tensor([0., 1., 2., 3.])# 启动对张量 x 的梯度追踪
x.requires_grad_(True)
print(x.grad)          # 默认值是 None# 对非标量调用backward需要传入一个gradient参数,该参数指定微分函数关于self的梯度。
# 本例只想求偏导数的和,所以传递一个1的梯度是合适的
y = x * x
# 等价于y.backward(torch.ones(len(x)))
y.sum().backward()
print(x.grad)          # tensor([0., 2., 4., 6.])

为什么需要 .sum()
backward() 默认处理标量。若 y 是向量,需通过 .sum()提供梯度权重(gradient 参数)将其转换为标量。
对于 y = x²,其导数为 dy/dx = 2x。由于 y.sum()x₁² + x₂² + x₃²,其对 x 的梯度是 [2x₁, 2x₂, 2x₃]


分离计算
有时,我们希望将某些计算移动到记录的计算图之外。
例如,假设 y y y是作为 x x x的函数计算的,而 z z z则是作为 y y y x x x的函数计算的。
想象一下,我们想计算 z z z关于 x x x的梯度,但由于某种原因,希望将 y y y视为一个常数, 并且只考虑到 x x x y y y被计算后发挥的作用。
这里可以分离 y y y来返回一个新变量 u u u,该变量与 y y y具有相同的值, 但丢弃计算图中如何计算 y y y的任何信息。

import torchx = torch.arange(4.0)
print(x)               # tensor([0., 1., 2., 3.])# 启动对张量 x 的梯度追踪
x.requires_grad_(True)
print(x.grad)          # 默认值是 Noney = x * x
# 创建新张量,与原张量数据相同,但不记录梯度,防止梯度传播
u = y.detach()
z = u * xz.sum().backward()
print(x.grad == u)     # tensor([True, True, True, True])

u u u 作为常数处理
随后可以单独计算 y y y 关于 x x x 的导数


Python 控制梯度流的计算
使用自动微分的一个好处是: 即使构建函数的计算图需要通过 Python 控制流(例如,条件、循环或任意函数调用),我们仍然可以计算得到的变量的梯度
在下面的代码中,while循环的迭代次数和 if 语句的结果都取决于输入 a 的值。

import torchdef f(a):b = a * 2while b.norm() < 1000:b = b * 2if b.sum() > 0:c = belse:c = 100 * breturn c# 创建一个标量张量(scalar tensor),
# 其数值从标准正态分布(均值为 0,标准差为 1)中随机生成,
# 并且启用了梯度追踪功能。
a = torch.randn(size=(), requires_grad=True)
d = f(a)
d.backward()print(a.grad == d / a)    # tensor(True)

我们现在可以分析上面定义的 f 函数。 请注意,它在其输入 a 中是分段线性的。 换言之,对于任何 a,存在某个常量标量 k,使得 f(a)=k*a,其中 k 的值取决于输入 a,因此可以用 d/a 验证梯度是否正确。


2.8、概率

简单地说,机器学习就是做出预测。

2.8.1、基本概率论

大数定律(law of large numbers): 将出现的次数除以投掷的总次数, 即此事件(event)概率的估计值。随着投掷次数的增加,估计值会越来越接近真实的潜在概率。
在统计学中,我们把从概率分布中抽取样本的过程称为抽样(sampling)

import torch
from torch.distributions import multinomial
from d2l import torch as d2l# torch.ones([6]):生成一个形状为 (6,) 的张量,所有元素初始化为 1,即 [1, 1, 1, 1, 1, 1]。
fair_probs = torch.ones([6]) / 6        # tensor([0.1667, 0.1667, 0.1667, 0.1667, 0.1667, 0.1667])# total_count 实验的总次数, fair_probs 指定每个类别的概率分布
# sample 从分布中采样一次,返回一个形状为 (6, )的张量(one-hot 向量)
# 返回一个 one-hot 向量,其中只有一个元素为 1(表示该类别被选中),其余为 0。
res = multinomial.Multinomial(10000, fair_probs).sample()print(res / 10000)                      # tensor([0.1629, 0.1630, 0.1709, 0.1685, 0.1623, 0.1724])# 绘图  看到这些概率如何随着时间的推移收敛到真实概率。 
counts = multinomial.Multinomial(10, fair_probs).sample((500,))
cum_counts = counts.cumsum(dim=0)
estimates = cum_counts / cum_counts.sum(dim=1, keepdims=True)d2l.set_figsize((6, 4.5))
for i in range(6):d2l.plt.plot(estimates[:, i].numpy(),label=("P(die=" + str(i + 1) + ")"))
d2l.plt.axhline(y=0.167, color='black', linestyle='dashed')
d2l.plt.gca().set_xlabel('Groups of experiments')
d2l.plt.gca().set_ylabel('Estimated probability')
d2l.plt.legend()
d2l.plt.show()

在这里插入图片描述


概率论公理
我们将集合 S = { 1 , 2 , 3 , 4 , 5 , 6 } S = \{1, 2, 3,4,5,6\} S={1,2,3,4,5,6}称为样本空间(sample space)结果空间(outcome space)
事件(event)是一组给定样本空间的随机结果。
在这里插入图片描述


随机变量
随机变量几乎可以是任何数量,并且它可以在随机实验的一组可能性中取一个值。
我们可以将 P ( X ) P(X) P(X)表示为随机变量 X X X上的分布(distribution): 分布告诉我们 X X X获得某一值的概率。
另一方面,我们可以简单用 P ( a ) P(a) P(a)表示随机变量取值 a a a的概率。
离散(discrete)随机变量(如骰子的每一面) 和连续(continuous)随机变量(如人的体重和身高)之间存在微妙的区别。
如果我们进行足够精确的测量,最终会发现这个星球上没有两个人具有完全相同的身高。 在这种情况下,询问某人的身高是否落入给定的区间,比如是否在1.79米和1.81米之间更有意义。 在这些情况下,我们将这个看到某个数值的可能性量化为密度(density)

2.8.2、处理多个随机变量

联合概率
P ( A = a , B = b ) P(A=a, B=b) P(A=a,B=b)表示: A = a A=a A=a B = b B=b B=b同时满足的概率

条件概率
P ( B = b ∣ A = a ) P(B=b | A=a) P(B=bA=a)表示:在 a a a已经发生的条件下, A = a A=a A=a B = b B=b B=b同时满足的概率
P ( B = b ∣ A = a ) = P ( A = a , B = b ) P ( A = a ) P(B=b | A=a) = \frac{P(A=a, B=b)}{P(A = a)} P(B=bA=a)=P(A=a)P(A=a,B=b)

贝叶斯定理
P ( B = b ∣ A = a ) = P ( A = a ∣ B = b ) ∗ P ( B = b ) P ( A = a ) P(B=b | A=a) = \frac{P(A=a | B=b) * P(B=b)}{P(A = a)} P(B=bA=a)=P(A=a)P(A=aB=b)P(B=b)

边际化
B B B的概率相当于计算 A A A的所有可能选择,并将所有选择的联合概率聚合在一起
P ( B ) = ∑ A P ( A , B ) P(B) = \sum_{A} P(A,B) P(B)=AP(A,B)

独立性
如果两个随机变量 A A A B B B独立的,意味着事件 A A A的发生跟事件 B B B的发生无关。
P ( B = b ∣ A = a ) = P ( B = b ) P(B=b | A=a) =P(B=b) P(B=bA=a)=P(B=b)
P ( B = b , A = a ) = P ( B = b ) ∗ P ( A = a ) P(B=b, A=a) =P(B=b) * P(A=a) P(B=b,A=a)=P(B=b)P(A=a)


2.8.3、期望和方差

一个随机变量 X X X期望(expectation,或平均值(average))表示为
E [ X ] = ∑ x x ∗ P ( X = x ) E[X] = \sum_{x} x * P(X = x) E[X]=xxP(X=x)

衡量随机变量 X X X与其期望值的偏置。这可以通过方差来量化
V a r [ X ] = E [ ( X − E [ X ] ) 2 ] Var[X]=E[(X-E[X])^2] Var[X]=E[(XE[X])2]

方差的平方根就是标准差


2.9、查阅文档

查找指定函数的方法的作用

help(torch.ones)

返回结果

Help on built-in function ones in module torch:ones(...)ones(*size, *, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) -> TensorReturns a tensor filled with the scalar value `1`, with the shape definedby the variable argument :attr:`size`.Args:size (int...): a sequence of integers defining the shape of the output tensor.Can be a variable number of arguments or a collection like a list or tuple.Keyword arguments:out (Tensor, optional): the output tensor.dtype (:class:`torch.dtype`, optional): the desired data type of returned tensor.Default: if ``None``, uses a global default (see :func:`torch.set_default_dtype`).layout (:class:`torch.layout`, optional): the desired layout of returned Tensor.Default: ``torch.strided``.device (:class:`torch.device`, optional): the desired device of returned tensor.Default: if ``None``, uses the current device for the default tensor type(see :func:`torch.set_default_device`). :attr:`device` will be the CPUfor CPU tensor types and the current CUDA device for CUDA tensor types.requires_grad (bool, optional): If autograd should record operations on thereturned tensor. Default: ``False``.Example::>>> torch.ones(2, 3)tensor([[ 1.,  1.,  1.],[ 1.,  1.,  1.]])>>> torch.ones(5)tensor([ 1.,  1.,  1.,  1.,  1.])

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/87657.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/87657.shtml
英文地址,请注明出处:http://en.pswp.cn/web/87657.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

瑞盟MS4554N/MS4554N1双向电平转换器重新定义混合电压系统连接

在电子设备的“心脏”——电路系统里&#xff0c;不同功能模块常因性能需求差异&#xff0c;采用差异化的供电电压&#xff1a;传感器用1.8V低功耗运行&#xff0c;主控芯片选3.3V高效处理&#xff0c;传统接口保留5V稳定传输……当这些“电压孤岛”需要互联时&#xff0c;一个…

二叉树题解——验证二叉搜索树【LeetCode】后序遍历

98. 验证二叉搜索树 一、算法逻辑&#xff08;逐步通顺讲解每一步思路&#xff09; 这段算法使用了一种递归的思路&#xff1a; 每个节点返回它所在子树的 最小值和最大值&#xff0c;并在返回的过程中检查 BST 的合法性。 ✅ 1️⃣ 定义递归函数 dfs(node)&#xff0c;其含…

Flink-Source算子点位提交问题(Earliest)

背景 最近在做 Flink 任务数据源切换时遇到 offset 消费问题&#xff0c;遂写篇文章记录下来。 切换时只修改了 source 算子的 topic&#xff0c;uid 等其他信息保持不变&#xff1a; 发布时&#xff0c;发现算子的消费者点位重置为earliest&#xff0c;导致消息积压。消息积…

如何录制带备注的演示文稿(LaTex Beamer + Pympress)

参考文献&#xff1a; Pympress 官网Avidemux 官网Audacity 官网FFmpeg 官网2025年度25大视频剪辑软件推荐2025最新音频降噪软件盘点&#xff0c;从入门到专业的6个高效工具如何用一段音频替换mp4视频格式的原有音频&#xff1f;免费简单易用的视频剪切编辑工具—AvidemuxFFmp…

VS Code 的 Copilot Chat 扩展程序

安装与启用 Copilot Chat 扩展 在 VS Code 中打开扩展市场&#xff08;快捷键 CtrlShiftX 或点击左侧活动栏的扩展图标&#xff09;。搜索“GitHub Copilot Chat”&#xff0c;点击安装。安装完成后需登录 GitHub 账户并授权 Copilot 权限。确保已订阅 GitHub Copilot 服务&am…

bash 脚本比较 100 个程序运行时间,精确到毫秒,脚本

脚本如下&#xff1a; #!/bin/bash# 设置测试次数 NUM_TESTS100 # 设置要测试的程序路径 PROGRAM"./your_program" # 替换为你的程序路径 # 设置程序参数&#xff08;如果没有参数则留空&#xff09; ARGS"" # 例如: "input.txt output.txt"#…

【Linux学习】Linux安装并配置Redis

安装Redis在Linux系统上安装Redis可以通过包管理器或源码编译两种方式进行。以下是两种方法的详细步骤。使用包管理器安装Redis&#xff08;以Ubuntu为例&#xff09;&#xff1a;sudo apt update sudo apt install redis-server通过源码编译安装Redis&#xff1a;wget https:/…

redis每种数据结构对应的底层数据结构原理

Redis 的每种数据结构(String、List、Hash、Set、Sorted Set)在底层都采用了不同的实现方式,根据数据规模和特性动态选择最优的编码(encoding)以节省内存和提高性能。以下是详细原理分析: 1. String(字符串) 底层实现: int:当存储整数值且可用 long 表示时,直接使用…

WPF控件大全:核心属性详解

WPF常用控件及核心属性 以下是WPF开发中最常用的控件及其关键属性&#xff08;按功能分类&#xff09;&#xff1a; 基础布局控件 Grid&#xff08;网格布局&#xff09; RowDefinitions&#xff1a;行定义集合&#xff08;如Height"Auto"&#xff09;ColumnDefinit…

马斯克脑机接口(Neuralink)技术进展,已经实现瘫痪患者通过BCI控制电脑、玩视频游戏、学习编程,未来盲人也能恢复视力了

目录 图片总结文字版总结1. 核心目标与愿景1.1 增强人类能力1.2 解决脑部疾病1.3 理解意识1.4 应对AI风险 2. 技术进展与产品2.1 Telepathy&#xff08;意念操控&#xff09;功能与目标技术细节参与者案例 2.2 Blindsight&#xff08;视觉恢复&#xff09;**功能与目标**技术细…

Vuex身份认证

虽说上一节我们实现了登录功能&#xff0c;但是实际上还是可以通过浏览器的地址来跳过登录访问到后台&#xff0c;这种可有可无的登录功能使得系统没有安全性&#xff0c;而且没有意义 为了让登录这个功能有意义&#xff0c;我们应该&#xff1a; 应当在用户登录成功之后给用户…

springboot中使用线程池

1.什么场景下使用线程池&#xff1f; 在异步的场景下&#xff0c;可以使用线程池 不需要同步等待&#xff0c; 不需要管上一个方法是否执行完毕&#xff0c;你当前的方法就可以立即执行 我们来模拟一下&#xff0c;在一个方法里面执行3个子任务&#xff0c;不需要相互等待 …

Flask+LayUI开发手记(十):构建统一的选项集合服务

作为前端最主要的组件&#xff0c;无论是layui-table表格还是layui-form表单&#xff0c;其中都涉及到选项列的处理。如果是普通编程&#xff0c;一个任务对应一个程序&#xff0c;自然可以就事论事地单对单处理&#xff0c;前后端都配制好选项&#xff0c;手工保证两者的一致性…

redis的数据初始化或增量更新的方法

做系统开发的时候&#xff0c;经常需要切换环境&#xff0c;做一些数据的初始化的工作&#xff0c;而redis的初始化&#xff0c;假如通过命令来执行&#xff0c;又太复杂&#xff0c;因为redis有很多种数据类型&#xff0c;全部通过敲击命令来初始化的话&#xff0c;打的命令实…

【PaddleOCR】OCR表格识别数据集介绍,包含PubTabNet、好未来表格识别、WTW中文场景表格等数据,持续更新中......

&#x1f9d1; 博主简介&#xff1a;曾任某智慧城市类企业算法总监&#xff0c;目前在美国市场的物流公司从事高级算法工程师一职&#xff0c;深耕人工智能领域&#xff0c;精通python数据挖掘、可视化、机器学习等&#xff0c;发表过AI相关的专利并多次在AI类比赛中获奖。CSDN…

sparkjar任务运行

mainclass&#xff1a; test.sparkjar.SparkJarTest

Web攻防-文件下载文件读取文件删除目录遍历路径穿越

知识点&#xff1a; 1、WEB攻防-文件下载&读取&删除-功能点&URL 2、WEB攻防-目录遍历&穿越-功能点&URL 黑盒分析&#xff1a; 1、功能点 文件上传&#xff0c;文件下载&#xff0c;文件删除&#xff0c;文件管理器等地方 2、URL特征 文件名&#xff1a; d…

使用LIMIT + OFFSET 分页时,数据重复的风险

在使用 LIMIT OFFSET 分页时&#xff0c;数据重复的风险不仅与排序字段的唯一性有关&#xff0c;还与数据变动&#xff08;插入、删除、更新&#xff09;密切相关。以下是详细分析&#xff1a; 一、数据变动如何导致分页异常 1. 插入新数据 场景&#xff1a;用户在浏览第 1 页…

Excel 数据透视表不够用时,如何处理来自多个数据源的数据?

当数据透视表感到“吃力”时&#xff0c;我们该怎么办&#xff1a; 数据量巨大&#xff1a;Excel工作表有104万行的限制&#xff0c;当有几十万行数据时&#xff0c;透视表和公式就会变得非常卡顿。数据来源多样&#xff1a;数据分散在多个Excel文件、CSV文件、数据库甚至网页…

cf(1034)Div3(补题A B C D E F)

哈&#xff0c;这个比赛在开了不久之后&#xff0c;不知道为啥卡了差不多20来分钟&#xff0c;后面卡着卡着就想睡觉了。实在是太困了.... 题目意思&#xff1a; Alice做一次操作&#xff0c;删除任意数字a,而Bob做一次操作删除b使得ab对4取余是3。 获胜条件&#xff0c;有人…