一、什么是范数
范数是一种将向量映射到非负实数的函数。对于一个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;
}