
本文介绍一种基于平滑近似函数 $l_a(x) = \frac{1}{1 + (a/x)^2}$ 的可微分 l0 正则化方法,使其能无缝集成到 keras 层中,支持端到端训练,并保持正则强度与参数量无关。
本文介绍一种基于平滑近似函数 $l_a(x) = \frac{1}{1 + (a/x)^2}$ 的可微分 l0 正则化方法,使其能无缝集成到 keras 层中,支持端到端训练,并保持正则强度与参数量无关。
在深度学习中,L0 正则化(即直接惩罚非零参数个数)具有极强的稀疏诱导能力,但因其不可导、非连续,在标准梯度下降框架下无法直接优化。Keras 原生仅支持 L1/L2 等可微正则器,而真实 L0 需要借助光滑近似实现可微分替代。
一个简洁有效的选择是使用如下软阈值函数:
$$
L_a(x) = \frac{1}{1 + \left(\frac{a}{|x| + \varepsilon}\right)^2}
$$
其中:
- $a > 0$ 是可学习或预设的阈值(控制“多小算零”),例如 $a = 0.01$;
- $\varepsilon = 10^{-8}$ 防止除零;
- 当 $|x| \ll a$ 时,$L_a(x) \approx 0$;当 $|x| \gg a$ 时,$L_a(x) \approx 1$;且 $L_a(a) = 0.5$,语义清晰。
该函数在全体实数域上连续、可导(除 $x=0$ 外,但因加 $\varepsilon$ 已规避),且其输出可被解释为“每个权重近似贡献的‘非零概率’”,因此对整个张量求和即可得可微分 L0 近似计数:
import tensorflow as tf
from tensorflow import keras
class DifferentiableL0Regularizer(keras.regularizers.Regularizer):
def __init__(self, a=0.01):
self.a = tf.cast(a, tf.float32)
def __call__(self, x):
eps = 1e-8
# 平滑 L0 近似:每个元素贡献 [0, 1] 区间内的“非零程度”
l0_approx = 1.0 / (1.0 + tf.square(self.a / (tf.abs(x) + eps)))
# 返回标量正则损失(总和,非均值)——与 Keras 内置 L1/L2 一致
return tf.reduce_sum(l0_approx)
def get_config(self):
return {'a': float(self.a)}
使用时,将其传入任意 Keras 层的 kernel_regularizer 或 bias_regularizer 参数即可:
model = keras.Sequential([
keras.layers.Conv2D(32, 3, kernel_regularizer=DifferentiableL0Regularizer(a=0.02)),
keras.layers.ReLU(),
keras.layers.Dense(10, kernel_regularizer=DifferentiableL0Regularizer(a=0.01))
])
⚠️ 关键注意事项:
-
不建议取均值:Keras 所有内置正则器(L1、L2)均返回
sum,而非mean。若改为mean,将导致不同尺寸层的正则强度失衡(如大卷积核被过度抑制),破坏超参一致性。应保持tf.reduce_sum。 -
梯度稳定性:
a值不宜过小(如 a=0.01 起调参,必要时可设为可训练变量(需在__call__中用tf.Variable并加入self.add_loss)。 -
与主损失融合方式:Keras 自动将正则损失加到总 loss 中(通过
model.add_loss()机制),无需手动相加;训练时只需编译时指定loss=,其余由框架统一处理。
综上,该实现兼顾数学合理性、工程鲁棒性与框架兼容性,是部署结构化剪枝、神经架构搜索(NAS)或稀疏训练任务的理想基础组件。










