pykan 正则化实战指南:用 reg_metric 与 lamb 让 KAN 更稀疏、更可解释
【免费下载链接】pykanKolmogorov Arnold Networks项目地址: https://gitcode.com/GitHub_Trending/pyk/pykan
本篇技术指南以 pykan(Kolmogorov-Arnold Networks)的 API 8 正则化教程为主体,系统讲解如何通过 L1/熵(entropy)正则化让 KAN 网络变稀疏、从而获得更强的可解释性。你将掌握 pykan 中五种reg_metric选择的具体含义与适用场景、fit()中lamb等超参数对训练的影响方式,以及如何用model.plot()的不同metric直观检验稀疏化效果,为后续的剪枝(pruning)与公式提取(symbolic regression)打下基础。
一、为什么 KAN 需要正则化:稀疏性是可解释性的前提
KAN 将网络表示为可学习的样条(spline)激活函数,其可解释性建立在"结构足够简单"之上:如果网络里每个边、每个激活都处于活跃状态,很难判断哪些输入真正驱动了输出。正则化(Regularization)的核心目标就是通过惩罚项迫使大部分边/节点的贡献趋近于零,让网络自动"长成"一个稀疏图——只保留真正有作用的连接,其余边在可视化中近乎透明,从而帮助研究者解读模型学到的函数关系。
pykan 官方文档指出:"Regularization helps interpretability by making KANs sparser. This may require some hyperparameter tuning."也就是说,稀疏化效果与超参数(尤其是lamb与正则化度量方式reg_metric)强相关,需要针对具体任务做调优,这正是本篇要解决的核心问题。
二、准备数据:构造二输入回归数据集
正则化实验的第一步与普通 KAN 训练一致:导入kan包,确定计算设备,并借助create_dataset生成训练/测试数据。以下代码来自原教程:
from kan import * import torch device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') print(device) f = lambda x: torch.exp(torch.sin(torch.pi*x[:,[0]]) + x[:,[1]]**2) dataset = create_dataset(f, n_var=2, device=device) dataset['train_input'].shape, dataset['train_label'].shape输出结果:
cuda (torch.Size([1000, 2]), torch.Size([1000, 1]))这里选择的目标函数为f(x) = exp(sin(π·x₁) + x₂²),自变量维度n_var=2。create_dataset会按默认规模生成 1000 个训练样本与同等规模的测试样本,输入形状为(1000, 2)、标签形状为(1000, 1)(具体生成逻辑可查看 kan/utils.py 中的create_dataset实现)。后续所有正则化实验都在这份数据集上进行。
三、五种 reg_metric:对"哪个张量"施加 L1 正则?
正则化的第一步是明确对什么施加惩罚。pykan 并不直接对网络权重做 L1,而是对"边的强度度量(edge attribution / activation scale)"做惩罚。fit()的reg_metric参数提供了五种选择(见 kan/MultKAN.py 中reg()方法的实现):
| reg_metric | 含义 | 底层张量 | 说明 |
|---|---|---|---|
edge_forward_spline_n(默认) | 边的"范数",归一化(输出 std / 输入 std),仅考虑 spline 部分(忽略 symbolic) | acts_scale_spline | 训练时最常用,只惩罚样条部分的归一化强度 |
edge_forward_sum | 边的"范数",归一化(输出 std / 输入 std),同时包含 spline + symbolic | acts_scale | 把符号函数(symbolic)的贡献也计入边的强度 |
edge_forward_spline_u | 边的"范数",未归一化(输出 std),仅考虑 spline 部分 | edge_actscale | 不除以输入 std,量纲为原始输出标准差 |
edge_backward | 边的归因分数(edge attribution score) | edge_scores | 基于反向传播的归因得分,与可视化中的 backward 一致 |
node_backward | 节点的归因分数(node attribution score) | node_attribute_scores | 对节点(神经元)层面做归因惩罚 |
源码依据:在 kan/MultKAN.py 中,reg()方法根据reg_metric把acts_scale指向对应的强度张量:
if reg_metric == 'edge_forward_spline_n': acts_scale = self.acts_scale_spline elif reg_metric == 'edge_forward_sum': acts_scale = self.acts_scale elif reg_metric == 'edge_forward_spline_u': acts_scale = self.edge_actscale elif reg_metric == 'edge_backward': acts_scale = self.edge_scores elif reg_metric == 'node_backward': acts_scale = self.node_attribute_scores else: raise Exception(f'reg_metric = {reg_metric} not recognized!')而这些张量是在前向传播forward()中缓存得到的(kan/MultKAN.py):input_range = std(preacts) + 0.1、output_range_spline = std(postacts_numerical)(仅样条部分)、output_range = std(postacts)(含符号部分),由此分别构造出acts_scale_spline(归一化、仅 spline)、acts_scale(归一化、spline+symbolic)与edge_actscale(未归一化)。理解这一链路有助于判断:当你的模型大量使用符号函数(如x²、sin)时,edge_forward_spline_n会"看不见"符号层的贡献,此时改用edge_forward_sum更合理。
需要说明的是,edge_backward与node_backward两种模式在训练时还会额外触发归因计算(fit()内部在reg_metric为这两者时分别调用self.attribute()与self.node_attribute(),见 kan/MultKAN.py),计算开销相对更高,但能直接对"解释性得分"做惩罚,语义上与最终可视化目标最一致。
四、实战训练:在 fit 中启用正则化
原教程使用KAN(width=[2,5,1], grid=3, k=3, seed=1)初始化一个 2 输入、单隐层 5 神经元、单输出的 KAN,并用 LBFGS 优化器训练 20 步:
# train the model model = KAN(width=[2,5,1], grid=3, k=3, seed=1, device=device) model.fit(dataset, opt="LBFGS", steps=20, lamb=0.01, reg_metric='edge_forward_spline_n'); # default #model.fit(dataset, opt="LBFGS", steps=20, lamb=0.01, reg_metric='edge_forward_sum'); #model.fit(dataset, opt="LBFGS", steps=20, lamb=0.01, reg_metric='edge_forward_spline_u'); #model.fit(dataset, opt="LBFGS", steps=20, lamb=0.01, reg_metric='edge_backward'); #model.fit(dataset, opt="LBFGS", steps=20, lamb=0.01, reg_metric='node_backward'); model.plot()训练过程输出(含 checkpoint 与进度条信息):
checkpoint directory created: ./model saving model version 0.0 | train_loss: 4.57e-02 | test_loss: 4.35e-02 | reg: 7.15e+00 | : 100%|█| 20/20 [00:04<00:00, 4.58it saving model version 0.1关键超参数说明(源自fit()的完整签名,见 kan/MultKAN.py):
lamb:正则化总强度,最终优化目标为objective = train_loss + lamb * reg_(见 kan/MultKAN.py)。lamb=0表示完全关闭正则化;原教程取0.01作为温和的惩罚强度。reg_metric:正则化度量方式,取值即第三节表格中的五种,默认edge_forward_spline_n。lamb_l1(默认 1.0):L1 惩罚强度,作用于边强度向量的元素求和。lamb_entropy(默认 2.0):熵惩罚强度,作用于边强度按行/列归一化后的熵,用于鼓励"均匀"或"集中"的结构。lamb_coef(默认 0.0):样条系数幅度惩罚强度,鼓励 spline 系数整体趋近于零。lamb_coefdiff(默认 0.0):相邻样条系数差值的 L1 惩罚(平滑性),鼓励系数曲线光滑。- 其余参数如
opt("LBFGS"或"Adam")、steps、lr、update_grid、grid_update_num等与常规训练一致,不在正则化讨论范围内。
训练机制细节:从fit()源码可以看到,正则化项的累计方式为对每一层边强度向量vec计算lamb_l1 * sum(vec) + lamb_entropy * (entropy_row + entropy_col),其中行/列熵基于p_row = vec / (sum(vec, dim=1) + 1)、p_col = vec / (sum(vec, dim=0) + 1)计算,再叠加样条系数的lamb_coef与lamb_coefdiff惩罚(kan/MultKAN.py)。这意味着lamb并不是唯一的旋钮——即使lamb固定,调节lamb_l1、lamb_entropy也会显著改变稀疏化的"形态"。
五、解读训练指标:train_loss / test_loss / reg
训练进度条展示的三项指标分别来自results字典(kan/MultKAN.py):
train_loss:训练集上的 RMSE(sqrt(mean((pred - label)²))),本示例为4.57e-02,说明 20 步内已能较好拟合目标函数;test_loss:测试集上的 RMSE,本示例为4.35e-02,与训练损失接近,未出现明显过拟合;reg:正则化项reg_的数值,本示例为7.15e+00。
fit()返回的results字典中这三项均为按步记录的一维数组,可用来观察"损失下降与稀疏化推进"的权衡曲线:若reg下降过慢,说明惩罚不足,图仍会显得稠密;若train_loss明显劣于无正则化训练,则说明lamb过大、过度压缩了模型容量,需要下调。
六、用 plot 可视化稀疏化效果(三种 metric)
model.plot()在绘图时同样提供了与正则化度量对应的选项(原教程说明 + 源码 kan/MultKAN.py 双重印证):
| plot 的 metric | 对应张量 | 语义 |
|---|---|---|
forward_u | edge_actscale | 同reg_metric='edge_forward_spline_u':未归一化输出 std |
forward_n | acts_scale | 归一化输出 std / 输入 std(含 spline+symbolic),对应edge_forward_sum |
backward(默认) | edge_scores | 同reg_metric='edge_backward':边的归因分数 |
绘图时各边透明度由alpha = tanh(beta * score)决定(beta默认 3,kan/MultKAN.py):分数越低,边越透明;正则化做得越好,可视化图中弱边越"隐去",网络结构越清晰。运行:
model.plot(metric='forward_u') #model.plot(metric='forward_n') #model.plot(metric='backward') # default以下是使用默认reg_metric='edge_forward_spline_n'、lamb=0.01训练 20 步后绘制的 KAN 结构图(默认 backward metric):
改用metric='forward_u'重新绘制同一模型,边的不透明度改为基于未归一化输出 std,可以交叉验证不同强度定义下的稀疏结构是否一致:
一个值得注意的细节:原教程注释中写有 "forward_n: same asedge_forward_spline_u",但从 kan/MultKAN.py 的源码看,forward_n实际读取的是self.acts_scale(归一化、含 spline+symbolic),与edge_forward_sum对应;而forward_u才对应edge_forward_spline_u。对比源码后可以推断原注释此处存在笔误,实际使用时应以源码映射为准。
七、超参数调优建议与注意事项
- 从默认组合起步:
reg_metric='edge_forward_spline_n'+lamb=0.01是一个稳妥的起点。若发现网络仍稠密,可逐步增大lamb(如 0.01 → 0.1 → 1),观察reg项下降与train_loss上升的平衡点。 - 符号函数参与时切换度量:当模型中 symbolic 部分占比高时,
edge_forward_spline_n会忽略符号层贡献,建议改用edge_forward_sum让惩罚覆盖全量贡献。 - 区分归一化与未归一化:
edge_forward_spline_u(未归一化)对不同输入尺度的边一视同仁地按原始标准差惩罚,可能偏向压制输出幅值大的边;归一化版本则更能反映边的"相对重要性"。 - 归因类度量的代价:
edge_backward/node_backward与最终可视化语义一致,但训练中每步都要额外做归因计算(attribute()/node_attribute()),训练更慢,适合对可解释性有高要求的小规模任务。 lamb=0时的行为:fit()中当lamb=0时会自动关闭激活缓存与符号层(见disable_symbolic_in_fit,kan/MultKAN.py),此时正则项恒为 0;如需启用正则化,请保持lamb > 0并确认模型处于可缓存激活的状态。- 与其他 API 串联:稀疏化是剪枝(pruning,见 API 7)与公式提取(symbolic regression,见 API 12 等)的前置步骤——剪枝正是基于
edge_scores等强度张量按阈值掩码实现的(kan/MultKAN.py),正则化先把弱边"压下去",剪枝再将其"删干净",二者配合可获得极简的可解释模型。
八、小结
正则化是 pykan 可解释性工作流中的关键一环:通过reg_metric选定"对哪类边强度做惩罚",通过lamb(及其细分项lamb_l1、lamb_entropy、lamb_coef、lamb_coefdiff)控制惩罚力度,训练后用plot()的forward_u/forward_n/backward三种视图检验稀疏化效果。本教程示例在 20 步 LBFGS 训练内将回归损失压到4.57e-02(train)/4.35e-02(test),同时让reg项参与优化,为后续剪枝与公式提取铺平了道路。实践时建议结合训练输出的reg曲线与结构图透明度,反复微调lamb,找到"拟合精度"与"结构稀疏性"的最佳平衡。
延伸阅读:本教程对应的可运行 Notebook 位于 docs/API_demo/API_8_regularization.ipynb;reg()、fit()、plot()、attribute()的完整实现参见 kan/MultKAN.py;与正则化配套的剪枝、符号化等后续流程可参考 docs/API_demo 下的 API 7、API 12 教程。
【免费下载链接】pykanKolmogorov Arnold Networks项目地址: https://gitcode.com/GitHub_Trending/pyk/pykan
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考