第一次在最优化学课上看到共轭函数的定义时,我的反应和大多数人一样:这玩意儿到底在干嘛?f*(y) = sup(x·y - f(x)),一个莫名其妙的 sup,一个负号,看起来像是在做某种诡异的变换。直到后来做对偶理论、写优化算法时反复使用它,才逐渐意识到——共轭函数其实是理解对偶性、次梯度、近端算子这些东西的一把总钥匙。如果你也在学凸优化、在看对偶问题推导、或者想搞清楚 Lasso 里那个软阈值算子到底怎么来的,这篇文章应该能帮你把碎片拼接起来。
我会从最直观的几何直觉讲起,逐步拆解为什么是这种形式、核心性质怎么用、以及它在实际算法里到底扮演什么角色。整个过程会讲透“为什么”,而不仅仅是罗列公式。
1. 共轭函数要解决的三个实在问题
1.1 用一条直线重新编码一个函数
我接触共轭函数时最初的一个困惑是:f明明已经是个函数了,为什么还要再构造一个f*?这不是多此一举吗?后来才明白,共轭函数本质上是在换一种方式描述同样的信息——就像同一个物体,你可以用笛卡尔坐标描述,也可以用极坐标描述。坐标变了,但信息不减。
具体来说,对于一个函数f: R^n → R,共轭函数f*的定义是:
f*(y) = sup{ x·y - f(x) | x ∈ dom f }
其中x·y是内积。注意,定义中的f(x)不需要可微,也不需要光滑,但它必须是凸函数才有一系列好的性质。换句话说,共轭变换做的事情是:给定一个方向y,找出在这个方向上“夹住”原函数f的最佳支撑超平面所对应的截距。
为什么要这样做?因为在很多优化问题中,我们关心的不是函数在每个点上的取值,而是“全局信息”——比如某个线性函数在什么位置能最好地逼近它、下界能撑得多高。共轭函数恰好就是把这些全局信息压缩成另一个函数。等你看完支撑超平面那部分,这种“信息等价变换”的感觉会更强烈。
1.2 为什么引入定义里的那个“最优点”
再看一眼定义式。对固定的y,x·y - f(x)是在给定斜率y的前提下,寻找一个x让这个量达到最大。它其实是在问一个问题:在所有斜率为y的直线(更准确地说,是方向为y的仿射函数)中,哪一条放在函数f的下方时,整体位置最高?
你可能已经发现,这跟“求极大值”有关。在凸分析里,sup 和 max 的区别很重要。如果最大值达不到,sup 依然存在且有意义,但 max 就不行。共轭函数在很多情况下对应的那个“最优 x”并不存在,所以必须用 sup 而不是 max。这一点在很多证明里会反复用到。
从信息编码的角度看,f*存取的并不是f在某个点上的值,而是f在“每个斜率方向上的最紧凑的支撑位置”。当所有方向的信息都齐了,f的形状就能被重构出来——这就是为什么双共轭在某些条件下能恢复原函数。这类比于傅里叶变换:f是时域信号,f*是频域表示,两者是同一个对象的两种视角。
1.3 不止是凸优化的工具
很多初学者会觉得共轭函数只在对偶证明里出现,离实际算法很远。实际上,它的身影遍布多个领域:经济学中的效用函数与费用函数互为共轭,统计物理中的配分函数与自由能之间就是共轭关系,概率论中的矩母函数、大偏差速率函数也与共轭概念紧密相连。甚至连 Legendre 变换——力学里从拉格朗日量到哈密顿量的经典操作——本质上就是光滑情形下的共轭函数特例。
所以,花时间理解共轭函数不是“纯数学自娱自乐”。它一旦掌握,你看很多公式的眼界会完全不一样:对偶间隙、KKT 条件、近端梯度法、ADMM……背后都是同一个原理在不同场景下的反复应用。
2. 从二维图像看懂共轭函数
2.1 一个具体的几何操作
假设f(x) = (1/2)x²,这是最简单的凸函数。我们来看f*(y)到底是什么。按定义:
f*(y) = sup{ x·y - (1/2)x² }
对固定的y,把括号里的表达式看成关于x的二次函数:-1/2 x² + yx。这是一个开口向下的抛物线,最大值在x = y处取得,代回得到:
f*(y) = y·y - (1/2)y² = (1/2)y²
所以(1/2)x²的共轭是它自己。这个例子虽然简单,但非常经典:二次函数的共轭保留了相同的二次形态,只是变量换成了对偶变量。这也是为什么许多算法在处理二次项时特别舒服的原因之一。
再画个图感受一下几何过程。对固定的y,这些直线L(x) = y·x - c是一组斜率为y的平行线。f*(y)要找的是其中某条直线的截距c的最大值。这条最优直线不仅斜率固定,而且在某个点与f的曲线恰好相切。换句话说,f*(y)截获的是函数f的切线族的包络信息。
如果你在纸面上画出f(x) = (1/2)x²的曲线,再画出几条不同y值的切线,会发现每条切线的截距正好对应一个f*(y)值。把所有(y, f*(y))点连起来,就得到一条与原函数形状一致的新曲线。这个“切线族包络”的视角,比单纯背公式有用得多。
2.2 支撑超平面与凸集的等价描述
从几何上看,一个凸函数f的上图(epigraph),也就是集合{(x, t) | t ≥ f(x)},是一个凸集。共轭函数f*(y)的几何含义是:用斜率为(y, -1)的超平面去支撑这个凸集,并以某种方式记录支撑点的高度信息。这就把函数的问题转化为了集合的支撑超平面问题。
凸集的支撑超平面是凸分析的核心工具。粗略地说,支撑超平面是在凸集边界上“轻轻接触”但不穿过它的超平面。从外部看,凸集完全位于支撑超平面的一侧。f*正是在枚举所有可能的超平面斜率,记录每个斜率下支撑“位置”的信息。
用生活类比来理解:想象你用手电筒从一个角度照射一个物体,光照在墙上会投下影子。光的方向变了,影子的形状也变了。如果你把“所有角度下影子的投影长度”都记录下来,反过来其实可以重构物体的形状。共轭函数做的事很类似——它记录的是凸函数在所有方向下的“投影信息”。不同方向的光照图像合在一起,就能完整还原原函数的几何结构。
2.3 为什么叫“共轭”而不是“变换”
这个名字其实带有强烈的对称意味。对凸函数套一次共轭,得到一个新函数;如果原函数是闭凸函数(closed convex),再套一次共轭就会回到原来的函数,即f** = f。这一来一回的对称性跟共轭在数学里其他分支中的含义一脉相承。
了解了这种对称性,你会自然理解为什么很多对偶问题长得那么“漂亮”:原问题里的变量转换成对偶变量,对偶问题里的变量转回原变量,信息往返不丢失。这种“转换→返回原状”的性质,让共轭成为一个非常优雅的数学工具。
2.4 一个容易被忽略的点:f*的定义域
f*(y)可能在某个y处取到无穷大。比如f(x) = x²,对任意y,sup{xy - x²}都是有限的;但如果f(x) = e^x,对y > 0时,xy - e^x在x → +∞时会趋于正无穷,这时f*(y) = +∞。因此,共轭函数的值域扩到了R ∪ {+∞},它的有效定义域是那些让 sup 取到有限值的y的集合。
这是个特别容易忽视的细节。很多初学者拿到一个函数就硬套公式,结果算出+∞还以为自己算错了。实际上,+∞本身就是共轭函数的一个合法输出——它表示这个方向下没有有限支撑超平面。这个性质在后面讲指示函数的共轭时会变得尤其重要。
3. 几个核心例子的共轭计算
3.1 绝对值函数的共轭
来看f(x) = |x|。对任意y:
f*(y) = sup{ xy - |x| }
对x ≥ 0,表达式为x(y - 1);对x ≤ 0,表达式为x(y + 1)(因为|x| = -x)。
当|y| ≤ 1时,无论x怎么取,xy - |x|的最大值都是 0(在x = 0处取到);当y > 1时,取x → +∞,表达式趋于正无穷;当y < -1时,取x → -∞,同样趋于正无穷。因此:
f*(y) = 0, 如果 |y| ≤ 1;否则为 +∞
也就是说,绝对值函数的共轭正好是区间[-1, 1]的指示函数。这个例子非常漂亮地展示了共轭如何把“非光滑但有界”的函数变成“光滑但受限”的指示函数。它也解释了为什么很多稀疏优化问题中的约束可以表示为指示函数——两者互为共轭,对偶关系天然成立。
3.2 二次型与范数的共轭
对正定矩阵Q,f(x) = (1/2)x^T Q x的共轭是:
f*(y) = sup{ x^T y - (1/2)x^T Q x }
对x求导置零得y = Qx,即x = Q^{-1}y。代回得:
f*(y) = (1/2)y^T Q^{-1} y
注意这里Q^{-1}出现了。原函数越“陡峭”(Q大),共轭函数就越“平坦”(Q^{-1}小);反过来也一样。这种逆变关系在数学上对应强凸性与光滑性的对偶,在算法分析中到处可见。
再看泛化的范数情形。考虑f(x) = ‖x‖,其中‖·‖是一般范数。它的共轭是:
f*(y) = sup{ x·y - ‖x‖ }
如果‖y‖_* ≤ 1(其中‖·‖_*是对偶范数),则x·y ≤ ‖x‖·‖y‖_* ≤ ‖x‖,所以 sup 最大为 0;否则可以取到正无穷。结果:
f*(y) = 0, 如果 ‖y‖_* ≤ 1;否则为 +∞
这是单位对偶范数球的指示函数。这解释了为什么带有范数惩罚项的优化问题在转换到对偶形式后会变成一个约束优化问题:范数的共轭天然是指示函数,那个隐含的“约束”其实是范数对偶球的界。
3.3 指数函数与负熵
再看两个常用例子。对f(x) = e^x,有:
f*(y) = sup{ xy - e^x }
当y < 0时,令e^x = -y,得f*(y) = -y ln(-y) + y;当y = 0时,sup 为 0;当y > 0时,无上界。整理后这个式子跟信息论里的负熵(u ln u - u的形式)很像。
另一个经典例子是负熵f(x) = x ln x(定义在x > 0),它的共轭是f*(y) = e^{y-1}。在最大熵问题、指数族分布、变分推断等场景中,负熵与其共轭之间的 Legendre 型关系非常关键。理解了这些例子,你在读相关文献时看到“Legendre 对偶”、“势函数”这些词就不会再发怵了。
3.4 指示函数与支撑函数
这组例子很多人一开始会绕晕,但它是打开对偶问题的最后一扇门。对一个集合C,指示函数定义是:
I_C(x) = 0, x ∈ C;= +∞, x ∉ C
它的共轭是:
I_C*(y) = sup{ x·y - I_C(x) } = sup{ x·y | x ∈ C }
这个函数叫集合C的支撑函数(support function),记作σ_C(y)。任何凸集的信息都编码在它的支撑函数中:给定方向y,它告诉你这个集合在y方向上的“延伸极限”。
支撑函数是制造对偶约束的核心工具。很多看起来复杂的约束集合,只要换成支撑函数,就能以极清晰的方式进入共轭表达式。反过来,σ_C的共轭又回到I_C的闭包。这组互逆关系在凸分析里是最常用的操作之一。
4. 共轭与次梯度、闭凸性的深层关系
4.1 Fenchel 不等式:一个最基础的下界
从定义直接可得一个简单但威力巨大的不等式:
f(x) + f*(y) ≥ x·y
这被称为 Fenchel 不等式(也叫 Fenchel-Young 不等式)。它的直观意思是:任意线性函数x·y必然被f(x)与f*(y)之和所控制。这个不等式在构造算法停机条件、分析对偶间隙时经常充当核心工具。
几何上,Fenchel 不等式说的就是定义式里 sup 的那个性质:对所有x,x·y - f(x) ≤ f*(y),移项即得。看似是平凡放缩,但最优性条件往往就是把某个不等式取到等号。
在共轭函数的最优点处,这个不等式取等号。也就是说,如果x*是f*(y)定义式中的最优点,那么:
f(x*) + f*(y) = x*·y
这就是所谓“共轭配对点”的性质。对可微函数来说,这个等号条件等价于∇f(x*) = y。
4.2 次梯度视角下的共轭配对
凸函数未必可微,但我们有次梯度工具。g ∈ ∂f(x)的定义是:对所有z,有f(z) ≥ f(x) + g·(z - x)。这个定义跟共轭的配对条件近乎完美地吻合。
具体来说,以下三条等价:
y ∈ ∂f(x)x是f*(y)定义式中 sup 的最优点f(x) + f*(y) = x·y
从图像上看,次梯度y就是对原函数在x处的一个支撑超平面的斜率;而共轭函数记录的是所有这种支撑超平面的“截距”。两者配合,相当于用无穷多个线性不等式重构了凸函数本身。
这个视角在优化算法里尤其重要。比如用次梯度法或近端梯度法时,每次迭代本质上是找到一个满足这种配对关系的(x, y)对。KKT 条件的核心,就是让原变量和对偶变量在共轭配对的意义下“对齐”。
4.3 双共轭与闭凸函数
前面提到,对一个闭凸函数,双共轭恒等式成立:f** = f。如果不是闭凸函数,双共轭得到的是它的凸包闭包。这相当于函数版本里的“凸包”:先取凸包,再取闭包,得到的就是一个闭凸函数。
这个性质在优化中意义重大。很多时候我们构造的惩罚项或约束并不天然是闭凸的,但我们可以放心地替换为它的双共轭,因为优化问题的最优值和最优解都不会因此改变(在适当条件下)。这背后正是“闭凸函数与双共轭一一对应”的保证。
需要注意,这里的“闭”并不是拓扑学里的抽象概念,它对应一个很具体的判定:一个凸函数是闭的,当且仅当它的上图是闭集,并且它在定义域内任意点处不取-∞。在实际判断中,大多数你遇到的凸函数都满足这个条件,但总有个别反例。比如定义在区间(0, +∞)上但端点不取有限的函数,就需要仔细检查。
4.4 光滑性-强凸性的对偶关系
这是我个人认为共轭理论中最优雅的一对性质:函数f是μ-强凸的,当且仅当它的共轭f*是1/μ-光滑的(即梯度 Lipschitz 连续)。强凸和光滑这两类看似不同的“正则性”,在共轭变换下竟然是一体两面。
这个结论不只是纯理论。在优化算法里,如果你能把一个强凸问题通过共轭转成光滑问题,或者反过来,就可以用不同的算法工具。比如近端梯度法对光滑项的要求比较高,如果目标函数里有强凸的项但不好求梯度,考虑一下它的共轭形式可能更顺畅。
证明思路也不复杂:如果f强凸,则对足够小的α,f(x) - (α/2)‖x‖²仍是凸函数。这种“减去二次项仍凸”的性质在共轭域里等价于“加上二次项仍凹”,而这正是光滑性的刻画。具体推演在不少凸分析教材里有详细展示,这里不展开。
5. 在优化算法中的落地应用
5.1 从共轭到对偶问题的核心等式
假设我们要最小化f(x) + g(Ax),其中f和g都是闭凸函数。利用共轭的定义,可以把g(Ax)改写为:
g(Ax) = sup{ (Ax)·z - g*(z) }
于是原问题变成:
min_x f(x) + sup_z { (Ax)·z - g*(z) }
在合适的约束规格下交换 min 和 sup,就能推导出对偶问题。这个过程看起来简单,但每一步都依赖共轭的定义和闭凸性的保证。
为什么这个操作如此重要?因为在很多情况下,原问题不好解(比如带有复杂的非光滑项),但它的对偶问题却结构清晰。掌握了这个从共轭出发的推导路径后,你可以自己动手构造任意优化问题的对偶形式,而不是死记硬背别人给的结果。
更实用的一点是,这个过程还揭示了原变量和对偶变量之间的配对关系。对偶变量z对应的正是原问题中约束条件的“影子价格”。如果你能理解共轭函数的定义是在选方向和找支撑,那这个配对关系就有了直觉基础:z是支撑超平面的斜率,而最优的x是切点位置。
5.2 近端算子与共轭的隐藏关联
近端算子(proximal operator)是现代一阶优化算法的基础组件,它的定义是:
prox_f(v) = argmin_x { f(x) + (1/2)‖x - v‖² }
它和共轭函数之间有一条很重要的恒等式(Moreau 分解):
prox_f(v) + prox_{f*}(v) = v
这条式子导出的结论是:算prox_f和算prox_{f*}本质上是一回事,只是变量方向不同。实际应用中,如果f的近端算子不好算,可以转而算f*的近端算子,有时反而简单得多。
举个例子。设f(x) = ‖x‖_1,它的共轭f*(y)是对偶范数球的指示函数。f的近端算子是软阈值操作,而f*的近端算子是向对偶球的投影。这两个操作表面看起来完全不同,但 Moreau 分解告诉我们它们之间只差一个“镜像”关系。这个结论帮助我在设计算法时多了一个备用方案:当某项近端算子困难时,就去看看它在共轭空间里是不是更友好。
5.3 实际案例:Lasso 的对偶视角
用 Lasso 问题来收拢所有概念。Lasso 的目标是:
min_x (1/2)‖Ax - b‖² + λ‖x‖_1
利用‖x‖_1 = sup{ (x·z) | ‖z‖_∞ ≤ 1 },或者从共轭角度(‖·‖_1的共轭是L∞球指示函数),我们可以推导出它的对偶问题。这个对偶问题在很多教材里都有,但关键点在于:λ‖x‖_1中的λ在对偶里变成了约束半径。这也是为什么对偶视角能解释“Lasso 的解为什么稀疏”——因为对应的对偶变量被限制在一个L∞球内,而它的活动集恰好对应原变量中的非零位置。
这类分析很有工程价值。当你写算法时,如果发现原问题收敛慢,可以换个思路:去分析对偶残差、判断哪些约束处于活动状态,或者直接交替优化原变量和对偶变量。我对 ADMM 的理解,也是通过共轭函数把“交替方向”拆成两步来看——每一步本质上都在做某种近端更新,而近端更新又和共轭互为镜像。这样看问题是完整的闭环。
6. 学习共轭函数时容易踩的几个坑
6.1 定义域为空的情况
不是每个函数都有有效的共轭。如果f在某个方向上不存在任何有限下界,那么f*在那个方向上的值就是+∞。比如f(x) = -x²(这是个凹函数,并不是凸函数),对任何y取x → -∞时xy + x²都趋于+∞,所以共轭处处为+∞。这里问题出在f本身不是凸函数。
使用共轭前一定要确认函数的凸性,还有是否满足闭条件。否则会推导出一堆+∞或空定义域的怪结论,而你还很难察觉问题出在第一步。
6.2 共轭并不能让非凸函数变凸
一个常见误解是:对非凸函数取共轭,再取共轭,就变成凸函数了。虽然双共轭f**确实是凸函数,但它对应的是原函数的凸包闭包,不是原函数本身。如果你在一个非凸问题上利用双共轭做松弛,得到的是原问题的凸松弛——这很有用,但要注意它和原问题的最优解可能并不一致。
很多全局优化方法会把非凸问题松弛成凸问题再求解,但你必须清醒地知道松弛的代价是什么。共轭工具的“还原”承诺是有前提的:对象必须是闭凸函数。
6.3 光滑与不可微的处理差异
很多人以为“共轭要求函数可微”,这是错的。次梯度的存在性不需要整体可微性,|x|就是一个典型例子,它在0处不可导,但共轭照样有简洁的闭式表达式。真正重要的是共轭定义中的 sup 是否能算出来。
实际操作中,不可微函数的共轭往往比可微函数更干净(比如范数的共轭是指示函数)。学习时不要因为“不可微”就回避它,恰恰相反,这类例子才是优化里最常见的。
6.4 计算时混淆变量与对偶变量
初学阶段,在求共轭的解析式时,最容易犯的错误是:求导后直接把x代回,但忘了x和y的关系本身依赖y。比如f(x) = (1/2)ax²,求导ax = y得x = y/a,代回后是(1/2)a(y/a)² = y²/(2a),而不是(1/2)ay²。这个步骤虽然简单,但在复杂函数中很容易因为中途变量混用而出错。
建议每个例子都用“先求导、再解出x(y)、最后代回”的标准三步流程,能显著降低计算错误率。涉及多个变量或矩阵的情况尤其要小心,矩阵求导时的转置位置也容易出错。
6.5 忽略闭凸条件的检验
如果你在做研究或读论文,可能会看到“对任意函数取双共轭”的写法,这时要特别留意作者是否默认了闭凸性。如果不满足闭凸条件,f** = f并不成立,后续推导可能就是无效的。最常见的情况是定义域是开区间,或函数在边界点取-∞这类奇葩情形。遇到不熟悉的函数,花一分钟检查一下它的上图是否闭,比推导到一半才发现问题要省时得多。
在我自己的经验里,把共轭函数当作“视角转换器”来用,比当作“需要背诵定义的抽象对象”来学,效率高很多。它就像一个坐标系变换:有些问题在原坐标下很复杂,换到对偶坐标系下反而一目了然。学共轭函数的最终目的,不是会背公式,而是建立起这种“换坐标系”的自觉。当你下次再遇到某个问题在对偶域里意外地简单时,就会理解我在说什么。