神经网络基础知识
二分类任务(Binary Classification)
-
在二分类问题中,目标是将输入(如图片、文本或其他数据)分为两类之一,通常使用标签0和1来表示不同的类别。以图像识别为例,假设我们需要判断一张图片中是否包含猫。我们可以将包含猫的图片标记为标签1,不包含猫的图片标记为标签0。模型的任务是学习图片的特征,以便根据这些特征准确地预测图片的类别,即是“猫”还是“非猫”。二分类模型经过训练后,可以对未见过的图片进行推断,输出0或1来表示是否检测到猫。
-
在视觉任务中,图像通常表示为矩阵,其中每个像素点包含颜色信息。如果图片大小为 \(64 \times 64\) 像素,并且是 RGB 彩色图像,那么这张图片可以表示为三个 \(64 \times 64\) 的矩阵,分别对应红、绿、蓝三个通道中每个像素的强度值。为了将这张图片转换为一个特征向量,可以将这三个矩阵中的所有像素值按顺序展开为一个列向量,即将所有红、绿、蓝通道的像素强度值依次排成一个长向量。这样得到的特征向量维度为 \([1, 64 \times 64 \times 3]\) ,也就是 \([1, 12288]\) ,可以记作 \(n_x = 12288\) 。在二分类问题中,目标是通过学习一个分类器,将特征向量作为输入,从而预测输出 \(y\) 的类别,即图片是否为“猫”( \(y=1\) )或“非猫”( \(y=0\) )。
-
符号定义
\(n_x\):表示每个样本的特征数
\(x\):表示一个 \(n_x\)维的输入特征向量,维度为 \((n_x,1)\)
\(y\):表示输出结果,在二分类问题中取值为 \((0,1)\)
\(m\):表示训练样本总数
\(M_{train}\):表示训练集样本总数
\(M_{test}\):表示测试集样本总数
\((x,y)\):表示一个单独的样本,包含输入与输出
\((x^{(i)},y^{(i)})\):表示第 \(i\) 组训练样本,包含输入与输出
\(X=[x^{(1)},x^{(2)},...,x^{(m)}]\):表示训练集所有样本的输入,维度为 \((n_x,m)\),每个样本自成一列
\(Y=[y^{(1)},y^{(2)},...,y^{(n)}]\):表示训练集所有样本的输出,维度为 \((1,m)\),每个样本自成一列
逻辑回归(Logistic Regression)
-
在二分类任务中,目标是训练一个分类器,使其能够输出预测值 \(\hat{y}\),其中 \(\hat{y}\)表示 \(y=1\) 的概率,即 \(\hat{y}=P(y=1|x)\)。在逻辑回归模型中,有一个权重向量 \(\omega\) 和一个偏置参数 \(b\)。这里,\(\omega\) 是一个与输入特征向量 \(x\) 维度相同的列向量,大小为 \((n_x,1)\),用于表示特征的权重。偏置参数 \(b\) 则是一个标量(实数),表示模型的偏移量。
-
在逻辑回归中,我们通过计算特征向量 \(x\) 和权重向量 \(\omega\) 的内积并加上偏置 \(b\),然后将结果传入 Sigmoid 函数,以得到预测值 \(\hat{y}\)。该假设函数(Hypothesis Function)定义如下:
\[z=\omega^Tx+b \\ \hat{y}=\sigma(z)=\frac{1}{1+e^{-z}} \]其中, \(\sigma(z)\) 是 Sigmoid 函数,它将 \(z\) 的值域映射到 \([0,1]\) 的范围,从而使 \(\hat{y}\) 表示预测为类别 \(y=1\) 的概率。逻辑回归模型的目标是通过训练学习参数 \(\omega\) 和 \(b\),使得 \(\hat{y}\) 能够很好地估计 \(y=1\) 的概率。
在实际训练过程中,通过最小化损失函数,逻辑回归不断调整参数 \(\omega\) 和 \(b\),以最大化模型在训练数据上的预测准确性。
-
在机器学习中,损失函数 \(L(\hat{y},y)\) 用于衡量模型预测值与实际值之间的差距。通常情况下,我们可能会使用预测值与实际值的平方差作为损失函数,但在逻辑回归中,使用平方差损失会导致优化目标不是凸函数,因此可能会出现多个局部最优值,从而难以找到全局最优解。为了解决这一问题,逻辑回归采用了交叉熵损失函数,定义如下:
\[L(\hat{y},y)=-y\text{log}(\hat{y})-(1-y)\text{log}(1-\hat{y}) \]该损失函数有如下性质:
- 当 \(y=1\)时,损失函数变为 \(L=-log(\hat{y})\)。在这种情况下,为了使损失函数尽可能小, \(\hat{y}\) 需要尽可能大。而由于 Sigmoid 函数的输出范围是 \([0,1]\), \(\hat{y}\) 会尽可能接近于 1。
- 当 \(y=0\)时,损失函数变为 \(L=-log(1-\hat{y})\)。在这种情况下,为了使损失函数尽可能小, \(\hat{y}\) 需要尽可能小。同样由于 Sigmoid 函数的限制, \(\hat{y}\) 会尽可能接近于0。
交叉熵损失在逻辑回归中有重要作用,因为它是一个凸函数,这意味着损失函数在参数空间中有唯一的全局最优解,因此可以通过梯度下降等优化方法有效地找到最佳参数 \(\omega\) 和 \(b\),从而提高模型的预测性能。
-
在逻辑回归中,损失函数 \(L(\hat{y},y)\) 定义在单个训练样本上,用于衡量模型在该样本上的预测误差,反映了模型对该样本预测的准确性。然而,为了衡量模型在整个训练集上的表现,我们定义代价函数 \(J(\omega,b)\),它是所有训练样本的平均损失。代价函数的定义如下:
\[J(\omega,b)=\frac{1}{m}\sum_{i=1}^{m}L(\hat{y}^{(i)},y^{(i)}) \]其中, \(m\) 是训练样本的总数,\(L(\hat{y},y)\) 表示第 \(i\) 个样本的损失。
损失函数和代价函数之间的区别在于,损失函数只适用于单个训练样本,而代价函数是所有样本损失的平均值,衡量模型在整个训练集上的总体表现。训练逻辑回归模型的目标是找到合适的参数 \(\omega\) 和 \(b\),使得代价函数 \(J(\omega,b)\) 达到最小值,从而让模型的整体预测误差降到最低。
-
在逻辑回归模型中,我们的目标是预测二分类变量 \(y \in \{0, 1\}\) 的概率。预测结果可以表示为:
\[\hat{y} = \sigma(\omega^T x + b) \]因此,模型输出 \(\hat{y}\) 表示 \(y = 1\) 的概率, \(1 - \hat{y}\) 表示 \(y = 0\) 的概率。可以用如下条件概率表达式描述模型预测:
\[p(y | x) = \begin{cases} \hat{y}, & \text{if } y = 1 \\ 1 - \hat{y}, & \text{if } y = 0 \end{cases} \]上述公式可以进一步合并为一个统一的表达式:
\[p(y|x)={\hat{y}}^{y}{(1-\hat{y})}^{(1-y)} \]此公式可以解释为:当 \(y = 1\) 时, \(p(y | x) = \hat{y}\) ;当 \(y = 0\) 时, \(p(y | x) = 1 - \hat{y}\) 。
为了训练模型,我们希望最大化所有样本的联合概率,即对数似然函数。因为对数函数是单调递增的,最大化 \(p(y | x)\) 等价于最大化其对数:
\[log(p(y|x))=y\text{log}(\hat{y})+(1-y)\text{log}(1-\hat{y}) \]这样,我们就得到了逻辑回归的对数似然函数。
在逻辑回归中,我们通过最小化负对数似然损失(即交叉熵损失)来训练模型。负对数似然损失函数 \(L(\hat{y}, y)\) 可以定义为:
\[L(\hat{y},y)=-\text{log}(p(y|x)) \]代入合并的概率公式后,可以得到具体的损失函数形式:
\[L(\hat{y}, y) = -\left( y \log(\hat{y}) + (1 - y) \log(1 - \hat{y}) \right) \] -
在逻辑回归中,我们的目标是找到一组模型参数 \(\omega\) 和 \(b\) ,使得给定训练样本的观测结果概率最大。由于假设所有训练样本是独立同分布的,因此所有样本的联合概率可以表示为每个样本条件概率的乘积。
假设训练集中共有 \(m\) 个样本 \((x^{(i)}, y^{(i)})\),每个样本的观测标签条件概率为 \(P(y^{(i)} | x^{(i)})\)。对于所有样本,联合概率可以表示为:
\[P(\text{labels in training set}) = \prod_{i =1}^{m}{P(y^{(i)}|x^{(i)})} \]最大似然估计的目标是找到一组参数 \(\omega\) 和 \(b\) ,使得这个联合概率最大。
为了简化计算,我们通常取联合概率的对数,因为对数函数是单调递增的,因此最大化联合概率与最大化其对数是等价的。将联合概率的对数表示为:
\[\log P(\text{labels in training set}) = \log \prod_{i=1}^{m} P(y^{(i)} | x^{(i)}) \]根据对数乘法法则,转化为求和形式:
\[\log P(\text{labels in training set}) = \sum_{i=1}^{m} \log P(y^{(i)} | x^{(i)}) \]我们已知每个样本的概率可以写成:
\[P(y^{(i)} | x^{(i)}) = \hat{y}^{(i) y^{(i)}} (1 - \hat{y}^{(i)})^{(1 - y^{(i)})} \]于是,对数似然函数就可以表示为:
\[\log P(\text{labels in training set}) = \sum_{i=1}^{m} ( y^{(i)} \log(\hat{y}^{(i)}) + (1 - y^{(i)}) \log(1 - \hat{y}^{(i)}) ) \]在逻辑回归中,我们通常希望最小化一个损失函数而不是直接最大化似然。因此,定义损失函数为对数似然的负值(因为最大化对数似然等价于最小化负对数似然):
\[\text{负对数似然} = -\sum_{i=1}^{m} ( y^{(i)} \log(\hat{y}^{(i)}) + (1 - y^{(i)}) \log(1 - \hat{y}^{(i)}) ) \]进一步定义平均损失函数,这样可以在样本量 \(m\) 变化时保证损失函数的稳定性。我们在前面加上一个因子 \(\frac{1}{m}\):
\[J(\omega, b) = \frac{1}{m} \sum_{i=1}^{m} L(\hat{y}^{(i)}, y^{(i)}) \]其中,单个样本的损失函数(即交叉熵损失)为:
\[L(\hat{y}^{(i)}, y^{(i)}) = -( y^{(i)} \log(\hat{y}^{(i)}) + (1 - y^{(i)}) \log(1 - \hat{y}^{(i)}) ) \]这样一来,我们得到了逻辑回归的代价函数。模型训练的目标是通过优化算法(如梯度下降)最小化这个代价函数 ,使得模型对所有训练样本的预测误差尽量小。
最终,逻辑回归的代价函数形式为:
\[J(\omega, b) = -\frac{1}{m} \sum_{i=1}^{m} ( y^{(i)} \log(\hat{y}^{(i)}) + (1 - y^{(i)}) \log(1 - \hat{y}^{(i)}) ) \]其中, \(\hat{y}^{(i)} = \sigma(\omega^T x^{(i)} + b)\) 是第 \(i\) 个样本的预测概率。这个函数度量了模型在所有训练样本上的预测误差。
梯度下降(Gradient Descent)
-
在测试集上寻找最佳参数 \(\omega\) 和 \(b\),目标是最小化代价函数 \(J(\omega,b)\)。由于代价函数 \(J(\omega,b)\) 是凸函数,因此可以使用梯度下降算法来找到其全局最小值。
梯度下降的过程如下:
-
随机初始化:首先,随机初始化参数 \(\omega\) 和 \(b\)。由于凸函数只有一个全局最小值,所以无论初始位置如何,梯度下降都可以收敛到全局最优解或其附近。
-
计算梯度:在每次迭代中,计算代价函数 \(J(\omega,b)\) 对参数 \(\omega\) 和 \(b\) 的偏导数,即梯度。梯度指示了代价函数在当前参数位置上变化最快的方向。
-
更新参数:沿着代价函数下降最快的方向(即负梯度方向)更新参数。更新公式如下:
\[ \omega := \omega - \alpha \frac{\partial J(\omega, b)}{\partial \omega} \\ b := b - \alpha \frac{\partial J(\omega, b)}{\partial b} \]其中, \(\alpha\) 是学习率,决定了每一步更新的幅度。
-
迭代:重复计算梯度和更新参数的步骤,直到代价函数的值不再显著下降,即达到收敛条件,此时 \(\omega\) 和 \(b\) 接近全局最优解。
通过梯度下降算法,我们可以使代价函数 收敛到其最小值,从而找到最佳参数 \(\omega\) 和 \(b\),使得模型在测试集上表现良好。
-
-
在处理复杂的计算表达式时,计算图是一种有效的工具,它将函数分解为一系列简单的操作,从而简化求导过程。计算图的前向计算用于得到代价函数的值,而反向传播用于根据链式法则计算每个变量的梯度,便于优化模型参数。
以以下计算过程为例:
\[J=3(a+bc) \]我们可以将其分解为多个简单的计算步骤:
- 定义中间变量:
\[u = bc ,\; v = a + u, \; J = 3v \]-
前向计算:按照计算图,从输入开始一步步计算出代价函数 \(J\) 的值。
-
反向传播与链式法则:通过链式法则,从输出向输入逐步求导,以计算出 \(J\) 对每个中间变量的偏导数。链式法则如下:
\[\frac{dJ}{du}=\frac{dJ}{dv}\frac{dv}{du} \]在计算图中,通常用符号
dvar
表示最终输出 \(J\) 对某个中间变量var
的偏导数结果,例如 \(da\) 表示 \(\frac{dJ}{da}\)。这种分步骤的计算图方法使复杂函数的导数计算更为系统化和简洁,尤其适用于反向传播算法。 -
在单样本逻辑回归中,目标是通过梯度下降法来最小化损失函数,以更新模型参数 \(\omega\) 和 \(b\)。以下是整个梯度下降过程的详细步骤:
前向计算
-
线性组合:计算输入特征的加权和,加上偏置项 \(b\)。
\[z = \omega^T x + b =\omega_1 x_1 + \omega_2x_2 + b \] -
激活函数:将 \(z\) 输入到 Sigmoid 函数中,得到模型的预测输出 \(\hat{y}\)(即 \(a\)),表示预测为正类的概率。
\[\hat{y} = a = \sigma(z) = \frac{1}{1+e^{-x}} \] -
损失函数:使用交叉熵损失函数计算预测值 \(a\) 和真实标签 \(y\) 之间的误差。
\[L(a,y) = -y\text{log}(a) - (1-y)\text{log}(1-a) \]- 计算图流向:前向计算的流向依次为
\[\omega,x \rightarrow z \rightarrow a \rightarrow L(a,y) \]反向传播
在反向传播中,通过链式法则依次计算损失 \(L\)对每个参数的梯度。
-
损失函数的导数:计算损失 \(L\) 对输出 \(a\) 的偏导数。
\[da = \frac{dL(a,y)}{da}= -\frac{y}{a} + \frac{1-y}{1-a} \] -
Sigmoid 导数:计算 \(a\) 对 \(z\) 的导数。
\[ \frac{da}{dz} = \frac{e^{-x}}{(1+e^{-x})^2}=a^2 \times (\frac{1}{a}-1)=a-a^2 \] -
链式法则:将上述两步结合,得到损失函数 \(L\) 对 \(z\) 的导数。
\[dz = \frac{dL(a,y)}{dz} = \frac{dL(a,y)}{da} \times \frac{da}{dz} = a-y \] -
参数梯度计算:根据链式法则计算 \(L\) 对 \(\omega_1\)、 \(\omega_2\) 和 \(b\) 的偏导数。
\[\frac{dz}{d\omega_1} = x_1,\; \frac{dz}{d\omega_x} = x_x,\; \frac{dz}{db} = 1 \\ d\omega_1=\frac{dL(a,y)}{d\omega1} = \frac{dL(a,y)}{dz} \times \frac{dz}{d\omega_1} = x_1(a-y) \\ d\omega_2=\frac{dL(a,y)}{d\omega2} = \frac{dL(a,y)}{dz} \times \frac{dz}{d\omega_2} = x_2(a-y) \\ db=\frac{dL(a,y)}{db} = \frac{dL(a,y)}{dz} \times \frac{dz}{db} = a-y \]参数更新
利用学习率 \(\alpha\) 更新参数 \(\omega_1\)、 \(\omega_2\) 和 \(b\):
\[\omega_1=\omega_1-\alpha d\omega_1 = \omega_1 -\alpha \cdot x_1(a-y) \\ \omega_2=\omega_2-\alpha d\omega_2 = \omega_2 -\alpha \cdot x_2(a-y) \\ b=b-\alpha db = b-\alpha \cdot (a-y) \]通过不断迭代上述步骤,梯度下降会逐步调整参数,使得代价函数 \(J(\omega, b)\) 收敛到最小值,从而提高模型的预测准确性。
-
-
在多样本逻辑回归中,为了最小化损失函数,我们使用梯度下降来更新模型参数 \(\omega\) 和 \(b\)。对于包含 \(m\) 个训练样本的数据集,逻辑回归的代价函数定义为所有样本损失的平均值:
\[J(\omega,b)=\frac{1}{m}\sum_{i=1}^mL(a^{(i)},y^{(i)}) \]梯度下降的目的是最小化这个全局代价函数 \(J(\omega, b)\)。因此,对于 \(\omega_1\) 的梯度,可以表示为:
\[ \frac{dJ(\omega,b)}{d\omega_1}=\frac{1}{m}\sum_{i=1}^m\frac{dL(a^{(i)},y^{(i)}}{d\omega_1}) \]这意味着全局代价函数对 \(\omega_1\) 的导数等于每个样本损失对 \(\omega_1\) 的导数的平均。因此,在计算全局梯度时,可以通过对每个样本的梯度累加,最后取平均值来求出最终的梯度,从而更新参数。
梯度计算步骤
- 初始化
\[J=0,\; d\omega_1=0,\; d\omega_2=0,\; db=0 \]- 遍历每个样本 \(i(i \in [1,m])\):
-
计算 \(z^{(i)}\):线性组合输入特征和参数:
\[z^{(i)}=\omega^Tx^{(i)}+b \] -
计算 \(a^{(i)}\):通过 Sigmoid 函数得到预测概率:
\[ a^{(i)} = \sigma(z^{(i)}) \] -
累加代价函数:
\[ J += -y^{(i)}\text{log}(a^{(i)})-(1-y^{(i)})\text{log}(1-a^{(i)}) \] -
累加梯度:
\[ d\omega_1+=x_1^{(i)}(a^{(i)}-y^{(i)}) \\ d\omega_2+=x_2^{(i)}(a^{(i)}-y^{(i)}) \\ db += a^{(i)}-y^{(i)} \]- 计算全局平均
\[J /= m \\ d\omega_1/=m,\;d\omega_2/=m,\;db/=m \]- 参数更新
\[\omega_1:=\omega_1-\alpha d\omega_1 \\ \omega_2:=\omega_2-\alpha d\omega_2 \\ b:=b-\alpha db \]以上过程为对 \(m\) 个样本的一次梯度下降,因此需要重复该过程多次(迭代),以便逐步逼近代价函数的最小值。
-
上述算法存在一个主要的计算效率问题:多重for循环。这种显式的 for 循环会使得算法在处理大型数据集和高维特征时非常低效。
- 第一个循环用于多次执行梯度下降。
- 第二个循环遍历 \(m\) 个训练样本。
- 第三个循环遍历所有特征(在例子中为两个特征 \(\omega_1\)和 \(\omega_2\);若有更多特征,则要计算从 \(\omega_1\)到 \(\omega_n\))。
向量化(vectorization)
-
向量化是一种将标量运算转换为向量或矩阵运算的技术。对于深度学习和数据科学中的大量计算任务,向量化的使用能够极大地提高计算效率。原因在于向量化可以让计算直接在矩阵级别上操作,而不是通过循环逐一处理元素。
在逻辑回归中需要计算 \(z={{w}^{T}}x+b\) ,这里的 \(\omega\) , \(x\)都是 \((n_x,1)\)维的列向量,如果用非向量化的方式计算 \({w}^{T}x\),代码如下
z = 0 for i in range(nx):z += w[i] * x[i] z += b
如果是向量化方法,代码如下
z = np.dot(w, x) + b
并且向量化方式运行速度会快很多,代码及其运行结果如下
import time import numpy as np# 随机生成两个数组 a = np.random.rand(1000000) b = np.random.rand(1000000)# 向量化的版本 tic = time.time() c = np.dot(a, b) toc = time.time() print(c) print("Vectorized version: " + str(1000*(toc-tic)) + "ms")# 非向量化的版本 c = 0 tic = time.time() for i in range(1000000):c += a[i]*b[i] toc = time.time() print(c) print("For loop: " + str(1000*(toc-tic)) + "ms")
250325.66409073974 Vectorized version: 5.634069442749023ms 250325.66409074445 For loop: 419.6150302886963ms
使用向量化和内置函数(例如 NumPy 的
np.dot
)能够让 Python 代码在 CPU 和 GPU 上都高效运行,因为这些函数在底层已经优化为 SIMD 指令,充分利用并行化。相比之下,显式的for
循环逐一操作每个元素,无法利用 SIMD 的性能优势。CPU 和 GPU 均支持并行化,但方式有所不同:
- CPU 的并行化依赖 SIMD 指令(单指令多数据),适合执行多个简单指令流。CPU 的并行化核心较少,但每个核心相对强大,因此非常适合处理任务量小但复杂的运算。
- GPU 是为了处理图像和视频渲染而设计的,具有大量核心(通常是 CPU 的数百倍),擅长在大规模数据上进行简单的并行计算,因此在深度学习中的矩阵计算尤为高效。GPU 的大规模并行架构非常适合深度学习中的大规模矩阵运算。
-
在计算向量 \(u=Av\) 时,矩阵乘法的定义是 \(u_i=\sum_jA_{ij}v_j\),而非向量化的实现方式通常使用嵌套循环来遍历矩阵的行和列:
for i in range(n):for j in range(m):u[i] = A[i][j] * v[j]
这种方式虽然直接,但嵌套循环的开销较大,尤其是在矩阵规模较大时会影响性能。而向量化的实现方式可以通过
np.dot()
函数计算矩阵与向量的乘积,将循环交给底层的高效实现来处理,大大提高了代码运行速度:v = np.dot(A, v)
不难看出,向量化的实现方式消除了两层循环,使得代码运行速度更快。这种向量化方式适用于大量的矩阵和向量操作,因此在数据处理和机器学习中被广泛采用。
在 Numpy 中,还可以直接对向量 \(v\) 使用一些函数,操作 \(v\) 中的所有元素,避免写显式循环。例如:
u = np.exp(v)
计算\(e^x\);np.log(v)
计算 \(\text{log}(x)\);np.abs(v)
计算绝对值;np.maximum(v, 0)
计算 \(v\) 中每个元素和0比的最大值;v**2
计算 \(v\) 中每个元素的平方;1/v
计算 \(v\) 中每个元素的倒数。
这些操作都能自动应用于 \(v\) 的每一个元素,避免了显式循环,使代码更加简洁高效。
-
在逻辑回归梯度下降中,如果有多个特征,需要分别计算每个特征的梯度更新。传统的非向量化方法需要为每个特征分别计算梯度,例如:
\[ d\omega_1+=x_1^{(i)}(a^{(i)}-y^{(i)}) \\ d\omega_2+=x_2^{(i)}(a^{(i)}-y^{(i)}) \]其中 \(a^{(i)}\) 是预测值, \(y^{(i)}\) 是真实值。对于 \(n\) 个特征,这种方法需要进行 \(n\) 次循环。
使用向量化方法,我们可以将这些特征的梯度更新整合为一个向量,避免多次循环,通过一次计算完成所有梯度的更新:
\[d\omega=d\omega+x^{(i)}(a^{(i)}-y^{(i)}) \]这样一来,向量化方法通过在矩阵或向量层面直接计算,实现了批量更新,提高了梯度下降的效率。这种优化方式不仅在逻辑回归中适用,在其他机器学习算法的梯度计算中也同样高效。
-
在逻辑回归的前向传播中,我们需要对多个样本进行预测。对于每个样本 \(i\),计算如下:
\[z^{(i)}=\omega^Tx^{(i)}+b \\ a^{(i)} = \sigma(z^{(i)}) \]其中:
- \(x^{(i)} \in \mathbb{R}^{n_x}\) 是第 \(i\) 个样本的输入特征向量。
- \(\omega \in \mathbb{R}^{n_x}\) 是模型的参数向量(权重)。
- \(b \in \mathbb{R}\) 是偏置项。
- \(a^{(i)}\) 是第 \(a^{(i)}\) 个样本的预测输出。
为了对 \(m\) 个样本进行批量计算,我们可以将输入数据和计算过程向量化。
令 \(X = [x^{(1)},x^{(2)},...,x^{(m)}] \in \mathbb{R}^{n_x \times m}\),每一列代表一个样本的特征向量。参数向量 \(\omega\) 保持为 \(\mathbb{R}^{n_x}\) 的列向量。
\[Z = [z^{(1)},z^{(2)}\;... \;z^{(m)}] \\ = \omega^TX+b \\ = [\omega^Tx^{(1)}+b,\omega^Tx^{(2)}+b\;... \;\omega^Tx^{(n)}+b] \]- \(\omega^T \in \mathbb{R}^{1 \times n_x}\),所以 \(\omega^T X \in \mathbb{R}^{1 \times m}\) 。
- \(b\) 是标量,通过广播机制加到 \(Z\) 的每个元素上。
- 最终 \(Z \in \mathbb{R}^{1 \times m}\),每个元素对应一个样本的线性组合结果。
对 \(Z\) 中的每个元素应用 Sigmoid 函数,得到预测值向量 \(A\):
Sigmoid激活函数也可以进行向量化计算,在同一时间内可以完成一个所有 \(m\) 个训练样本的前向传播向量化计算。
\[A=\sigma(Z)=[a^{(1)},a^{(2)}\;... \;a^{(m)}] \]- \(A \in \mathbb{R}^{1 \times m}\),每个元素是对应样本的预测概率。
向量化的前向传播过程可以用 Python 和 NumPy 实现:
import numpy as npdef sigmoid(z):return 1 / (1 + np.exp(-z))# 假设 W 是形状为 (n_x, 1) 的列向量,X 是形状为 (n_x, m) 的输入矩阵 Z = np.dot(W.T, X) + b # Z 的形状为 (1, m) A = sigmoid(Z) # A 的形状为 (1, m)
-
在逻辑回归的梯度下降过程中,我们可以利用向量化计算批量训练数据的梯度,以提高效率和简化代码。在这种情况下,对于每个样本 \(i\),模型的预测输出 \(a^{(i)}\) 与真实标签 \(y^{(i)}\) 的误差可以表示为:
\[dZ=A-Y=[a^{(1)}-y^{(1)},a^{(2)}-y^{(2)}\;...\;a^{(m)}-y^{(m)}]\in \mathbb{R}^{1\times m} \]其中:
- \(A \in \mathbb{R}^{1 \times m}\) 是模型对 \(m\) 个样本的预测结果。
- \(Y \in \mathbb{R}^{1 \times m}\) 是实际标签的向量。
- \(dZ \in \mathbb{R}^{1 \times m}\) 表示每个样本的误差(损失的导数)。
偏置项 \(b\) 的梯度 \(db\) 是 \(dZ\) 的平均值,可以计算为:
\[db=\frac{1}{m}\sum_{i=1}^{m}dz^{(i)} \]在代码中,可以利用 Numpy 的
np.sum()
函数对 \(dZ\) 的所有元素求和,并除以 \(m\) 来计算 \(db\) 。dZ = A - Y db = np.sum(dZ) / m
权重向量 \(\omega\) 的梯度 \(d\omega\) 可以表示为:
\[d\omega = \frac{1}{m}\sum_{i=1}^mx^{(i)}dz^{(i)} \]将所有样本的输入数据 \(X \in \mathbb{R}^{n_x \times m}\) 和误差 \(dZ \in \mathbb{R}^{1 \times m}\) 进行矩阵乘法,可以得到 \(d\omega\) 的向量化表示:
\[d\omega = \frac{1}{m}XdZ^T \]- \(X \in \mathbb{R}^{n_x \times m}\) 表示所有样本的输入数据,每列代表一个样本的特征向量。
- \(dZ^T \in \mathbb{R}^{m \times 1}\) 是误差向量的转置。
- \(X dZ^T \in \mathbb{R}^{n_x \times 1}\) 是每个特征的梯度,表示为一个列向量。
在代码中,可以通过 Numpy 的矩阵乘法
np.dot()
来实现:dw = np.dot(X, dZ.T) / m
-
向量化逻辑回归总结
在逻辑回归的训练中,我们可以利用向量化操作来简化前向传播和梯度计算过程。
- \(X \in \mathbb{R}^{n_x \times m}\):输入矩阵,其中每列为一个样本的特征向量,总共 \(m\) 个样本,每个样本有 \(n_x\) 个特征。
- \(\omega \in \mathbb{R}^{n_x}\):权重向量(列向量),用于模型的线性组合。
- \(Y \in \mathbb{R}^{1 \times m}\):实际标签向量,其中每个元素为一个样本的标签。
前向传播
\[Z = \omega^TX+b \in \mathbb{R}^{1\times m} \\ A = \sigma(Z) \in \mathbb{R}^{1\times m} \]反向传播
\[dZ = A - Y \in \mathbb{R}^{1\times m} \\ d\omega = \frac{1}{m} XdZ^T \in \mathbb{R}^{n_x} \\ db =\frac{1}{m}\sum dZ \in \mathbb{R} \]参数更新
\[\omega = \omega - \alpha d\omega \in \mathbb{R}^{n_x} \\ b = b - \alpha db \in \mathbb{R} \]向量化后的逻辑回归梯度更新可以用以下代码实现:
import numpy as np# 前向传播 Z = np.dot(W.T, X) + b A = sigmoid(Z) # 假设已定义 sigmoid 函数# 反向传播 dZ = A - Y dw = np.dot(X, dZ.T) / m db = np.sum(dZ) / m# 参数更新 W = W - alpha * dw b = b - alpha * db