您的位置:

范数求导

一、什么是范数

范数是一种将向量映射到非负实数的函数。对于一个n维向量x,其p范数定义为:$$\left\lVert x \right\rVert_{p} = \sqrt[p]{\sum_{i=1}^{n} {{\left\lvert x_i \right\rvert}^p}}$$ 其中,p为范数的阶数,向量中每个元素的绝对值取p次方后求和再开p次方。

通常情况下,常用的范数如下:

  • L1范数:$$\left\lVert x \right\rVert_{1}=\sum_{i=1}^{n} {\left\lvert x_i \right\rvert}$$
  • L2范数:$$\left\lVert x \right\rVert_{2}=\sqrt{\sum_{i=1}^{n} {\left\lvert x_i \right\rvert}^2}$$
  • L∞范数:$$\left\lVert x \right\rVert_{\infty}=\max_{1\leq i\leq n}{\left\lvert x_i \right\rvert}$$

二、范数的导数

范数的导数表示为范数的梯度向量,即向量各分量的导数向量。对于一个向量x,其p范数的导数为:

  • L1范数的导数:$$\frac{\partial{\left\lVert x \right\rVert_{1}}}{\partial{x_i}}=\frac{x_i}{\left\lVert x \right\rVert_{1}}$$
  • L2范数的导数:$$\frac{\partial{\left\lVert x \right\rVert_{2}}}{\partial{x_i}}=\frac{x_i}{\left\lVert x \right\rVert_{2}}$$
  • L∞范数的导数:$$\frac{\partial{\left\lVert x \right\rVert_{\infty}}}{\partial{x_i}}=\begin{cases} 1,\left\lvert x_i \right\rvert=\left\lVert x \right\rVert_{\infty} \\0,\left\lvert x_i \right\rvert\neq\left\lVert x \right\rVert_{\infty} \end{cases}$$

具体来说,L1范数可视为L2范数在原点与目标点的曼哈顿距离,而L2范数则是在原点与目标点的欧几里得距离。因此,L1范数的导数在原点的分量不唯一,而L2范数则有唯一的梯度向量。L∞范数则是在各分量差值中取最大值作为距离,其导数在最大值处分量为1,其他处为0。

三、范数求导的应用

范数求导在优化问题中有着广泛的应用,主要用于对目标函数的求导。一些常用的应用如下:

  • 正则化:在模型训练中引入范数正则化可以使得模型的泛化性能更好。例如,L1正则化可以实现特征选择,L2正则化可以防止过拟合。
  • 稀疏表示:通过使问题的解具有更大的结构性,使得问题变得更加容易求解。例如,对于二次规划问题C(x)的目标函数,一个常见的目标是最小化L1范数,即:$$\min \left\lVert x \right\rVert_{1}\quad \text{s.t.}\quad C(x)\leq0$$

四、代码示例

<?php
/**
 * 计算向量的Lp范数
 *
 * @param array $vector 向量数组
 * @param int $p 范数的阶数
 *
 * @return float
 */
function norm(array $vector, int $p = 2): float
{
    $sum = 0;
    foreach ($vector as $item) {
        $sum += pow(abs($item), $p);
    }
    return pow($sum, 1 / $p);
}

/**
 * 计算向量的导数
 *
 * @param array $vector 向量数组
 * @param int $p 范数的阶数
 *
 * @return array
 */
function grad(array $vector, int $p = 2): array
{
    $g = [];
    $n = norm($vector, $p);
    foreach ($vector as $i => $item) {
        switch ($p) {
            case 1:
                $g[$i] = $item === 0 ? 0 : $item / $n;
                break;
            case 2:
                $g[$i] = $item / $n;
                break;
            default:
                $g[$i] = abs($item) === $n ? ($item > 0 ? 1 : -1) : 0;
        }
    }
    return $g;
}