KAN的可解释性优势:可视化分析与科学发现

KAN的可解释性优势:可视化分析与科学发现

【免费下载链接】pykan Kolmogorov Arnold Networks 【免费下载链接】pykan 项目地址: https://gitcode.com/gh_mirrors/pyk/pykan

Kolmogorov-Arnold Networks (KANs) 通过其独特的可视化能力和符号化公式提取机制,在科学发现领域展现出显著优势。文章详细介绍了KAN网络结构的可视化方法与技巧,包括基础可视化、高级参数配置、树状结构分析、特征归因分析以及动态训练过程可视化。进一步探讨了激活函数学习过程的可视化分析,展示了B样条基函数的表示方法、训练过程中的函数演化、透明度参数调节作用以及不同度量标准下的可视化效果。最重要的是,KANs能够从数据中自动发现和提取符号化数学公式,内置丰富的符号化函数库,支持自动符号化发现流程和参数拟合优化,为物理定律重新发现提供了强大工具。

KAN网络结构可视化方法与技巧

Kolmogorov-Arnold Networks (KANs) 的可视化能力是其最显著的优势之一,通过直观的网络结构展示,研究人员能够深入理解模型的内部工作机制和数学表达。pykan库提供了丰富的可视化工具,帮助用户从多个维度分析网络结构。

基础可视化方法

在pykan中,最基本的可视化方法是调用模型的plot()函数。该函数提供了三种不同的可视化指标,分别展示网络连接的不同特性:

from kan import *
import torch

# 创建KAN模型
model = KAN(width=[2,5,1], device='cpu')

# 定义目标函数并创建数据集
f = lambda x: torch.exp(torch.sin(torch.pi*x[:,[0]]) + x[:,[1]]**2)
dataset = create_dataset(f, n_var=2, device='cpu')

# 训练模型
model.fit(dataset, steps=20, lamb=1e-3)

# 三种不同的可视化方式
model.plot(metric='forward_u')    # 归一化前向传播权重
model.plot(metric='forward_n')    # 非归一化前向传播权重  
model.plot(metric='backward')     # 反向传播归因分数(默认)

可视化指标详解

KAN提供了三种不同的可视化指标,每种指标都从独特的角度展示网络结构:

指标类型计算方式适用场景
forward_u输出标准差/输入标准差显示归一化的连接强度
forward_n输出标准差显示原始连接强度
backward边缘归因分数显示特征重要性(默认)

mermaid

高级可视化参数

除了基本的可视化指标,plot()函数还支持多个高级参数来定制可视化效果:

# 高级可视化配置
model.plot(
    folder="./figures",          # 保存目录
    beta=3,                      # 线条粗细系数
    metric='backward',           # 可视化指标
    scale=0.5,                   # 整体缩放比例
    tick=False,                  # 是否显示坐标轴刻度
    sample=False,                # 是否采样显示
    in_vars=['x1', 'x2'],        # 输入变量名称
    out_vars=['y'],              # 输出变量名称
    title="KAN Network",         # 图表标题
    varscale=1.0                 # 变量标签缩放
)

树状结构可视化

对于更复杂的网络分析,pykan提供了树状结构可视化功能,能够展示特征之间的交互关系:

from kan.hypothesis import plot_tree

# 生成树状结构可视化
plot_tree(model, x, 
          in_vars=['feature1', 'feature2'],  # 输入变量名
          style='tree',                      # 树状样式
          sym_th=1e-3,                       # 对称性阈值
          sep_th=1e-1,                       # 可分离性阈值
          skip_sep_test=False,               # 是否跳过可分离性测试
          verbose=False)                     # 详细输出

树状可视化支持多种样式:

  • 'tree': 传统的树状结构
  • 'box': 盒状结构,更紧凑的显示

特征归因分析

KAN的可视化不仅展示网络结构,还能进行深层的特征归因分析:

# 特征归因分析
attribution_scores = model.attribute(
    l=None,                    # 指定层号(None表示所有层)
    i=None,                    # 指定神经元编号
    out_score=None,            # 输出分数
    plot=True                  # 是否绘制归因图
)

# 节点属性分析
node_attributes = model.node_attribute()

# 特征交互分析
interaction_matrix = model.feature_interaction(
    l=1,                       # 层号
    neuron_th=1e-2,            # 神经元阈值
    feature_th=1e-2            # 特征阈值
)

动态训练过程可视化

为了观察训练过程中网络结构的变化,可以配置定期保存可视化结果:

# 训练时定期保存可视化
model.fit(dataset, 
          steps=100, 
          save_fig=True,                # 启用可视化保存
          save_fig_freq=10,             # 每10步保存一次
          img_folder='./training_video', # 保存目录
          in_vars=['x1', 'x2'],         # 输入变量名
          out_vars=['y'],               # 输出变量名
          beta=3)                       # 可视化参数

这种方法可以生成训练过程的动态可视化,帮助理解网络如何逐步学习目标函数。

自定义可视化样式

通过Matplotlib的配置,用户可以完全自定义可视化样式:

import matplotlib.pyplot as plt

# 自定义matplotlib样式
plt.rcParams.update({
    'figure.figsize': (12, 8),
    'font.size': 14,
    'lines.linewidth': 2,
    'axes.linewidth': 1.5
})

# 生成可视化并进一步自定义
fig, ax = plt.subplots()
model.plot(metric='backward')
ax.set_title("Customized KAN Visualization", fontsize=16)
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('custom_visualization.png', dpi=300, bbox_inches='tight')

多模型对比可视化

对于模型比较研究,可以同时可视化多个KAN模型:

# 创建多个不同配置的模型
models = []
configs = [
    {'width': [2,5,1], 'grid': 3},
    {'width': [2,8,1], 'grid': 5},
    {'width': [2,10,1], 'grid': 7}
]

for config in configs:
    model = KAN(**config)
    model.fit(dataset, steps=20)
    models.append(model)

# 并排可视化比较
fig, axes = plt.subplots(1, 3, figsize=(18, 6))
for i, (model, ax) in enumerate(zip(models, axes)):
    model.plot(ax=ax, metric='backward')
    ax.set_title(f"Model {i+1}: {configs[i]}")
plt.tight_layout()

这种对比可视化有助于理解不同网络结构对学习效果的影响,为模型设计提供直观的指导。

通过掌握这些可视化方法与技巧,研究人员能够深入探索KAN网络的内部机制,发现数据中的隐藏模式,并验证模型的数学表达能力。可视化不仅是调试工具,更是科学发现的重要途径。

激活函数学习过程的可视化分析

Kolmogorov-Arnold Networks (KANs) 最引人注目的特性之一是其激活函数学习过程的可视化能力。与传统神经网络中固定的激活函数不同,KANs 中的每个激活函数都是通过 B 样条基函数学习得到的,这一过程可以通过直观的可视化方式进行监控和分析。

B 样条基函数与激活函数表示

KANs 使用 B 样条基函数来表示和学习激活函数。每个激活函数 $\phi_{i,j}$ 可以表示为:

$$\phi_{i,j}(x) = \sum_{m=1}^{G+k} c_{i,j}^{(m)} B_m(x)$$

其中 $B_m(x)$ 是 B 样条基函数,$c_{i,j}^{(m)}$ 是待学习的系数,$G$ 是网格间隔数,$k$ 是样条阶数。

import torch
from kan import KAN, create_dataset

# 创建 KAN 模型
model = KAN(width=[2, 5, 1], grid=5, k=3, seed=1)

# 创建数据集:f(x,y) = sin(πx) + y²
f = lambda x: torch.sin(torch.pi * x[:, [0]]) + x[:, [1]]**2
dataset = create_dataset(f, n_var=2)

# 初始化可视化
model(dataset['train_input'])
model.plot(beta=100, in_vars=['x', 'y'], out_vars=['f(x,y)'])

训练过程中的激活函数演化

KANs 的训练过程可以通过可视化观察到激活函数的动态演化。以下流程图展示了激活函数学习的完整过程:

mermaid

透明度参数 β 的调节作用

KANs 的可视化系统使用透明度参数 β 来控制激活函数的显示强度。透明度计算公式为:

$$\alpha = \tanh(\beta \cdot \phi_{\text{normalized}})$$

其中 $\phi_{\text{normalized}}$ 是归一化的激活函数尺度。

# 不同 β 值的可视化效果对比
fig, axes = plt.subplots(1, 4, figsize=(16, 4))

model.plot(beta=0.1, ax=axes[0])
axes[0].set_title('β=0.1 (低透明度)')

model.plot(beta=3, ax=axes[1])  
axes[1].set_title('β=3 (默认)')

model.plot(beta=10, ax=axes[2])
axes[2].set_title('β=10 (中等透明度)')

model.plot(beta=100, ax=axes[3])
axes[3].set_title('β=100 (高透明度)')

不同度量标准下的可视化

KANs 支持多种度量标准来可视化激活函数的重要性:

度量标准描述适用场景
forward_n归一化的前向传播尺度比较不同激活函数的相对重要性
forward_u未归一化的前向传播尺度观察激活函数的绝对强度
backward基于梯度的重要性分数特征归因分析
# 不同度量标准的可视化
metrics = ['forward_n', 'forward_u', 'backward']
titles = ['归一化前向传播', '未归一化前向传播', '反向传播重要性']

fig, axes = plt.subplots(1, 3, figsize=(15, 5))
for i, (metric, title) in enumerate(zip(metrics, titles)):
    model.plot(metric=metric, beta=10, ax=axes[i])
    axes[i].set_title(title)

训练过程中的动态变化分析

通过记录训练过程中激活函数的变化,可以深入理解 KANs 的学习动态:

# 训练过程记录
training_history = []
for step in range(100):
    model.fit(dataset, steps=1, lamb=0.001)
    
    # 记录激活函数状态
    activations = model.get_act(dataset['train_input'])
    training_history.append({
        'step': step,
        'activations': activations,
        'loss': model.evaluate(dataset)['test_loss']
    })
    
    # 每20步可视化一次
    if step % 20 == 0:
        model.plot(beta=10, title=f'Step {step}')

符号函数与数值函数的可视化区分

KANs 支持将学习到的激活函数固定为符号函数,并在可视化中用不同颜色区分:

  • 蓝色: 纯数值函数(B样条表示)
  • 红色: 纯符号函数(如 sin, exp, x² 等)
  • 紫色: 数值+符号混合函数
# 固定符号函数示例
model.fix_symbolic(0, 0, 0, 'sin')    # 将第一个激活函数固定为 sin
model.fix_symbolic(0, 1, 0, 'x^2')    # 将第二个激活函数固定为 x²

# 可视化符号函数
model.plot(beta=10, title='符号函数可视化')

样本分布与激活函数的关联分析

KANs 的可视化还可以显示输入样本在激活函数上的分布,帮助理解数据与函数形态的关系:

# 启用样本分布显示
model.get_act(dataset['train_input'][:50])  # 使用50个样本
model.plot(sample=True, beta=10, title='样本分布与激活函数')

# 分析样本分布与函数形态的关系
sample_positions = dataset['train_input'][:, 0]  # x 坐标
activation_values = model.get_act(dataset['train_input'])[0, :, 0]  # 第一个激活函数的值

网格细化对激活函数学习的影响

KANs 支持动态网格细化,这显著影响激活函数的学习能力和表达能力:

# 网格细化过程
grid_sizes = [3, 5, 10, 20]
models = []

for grid_size in grid_sizes:
    model_refined = model.refine(new_grid=grid_size)
    model_refined.fit(dataset, steps=10)
    models.append(model_refined)

# 比较不同网格大小的效果
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
for i, (model_refined, grid_size) in enumerate(zip(models, grid_sizes)):
    row, col = i // 2, i % 2
    model_refined.plot(beta=10, ax=axes[row, col])
    axes[row, col].set_title(f'Grid size: {grid_size}')

激活函数学习中的关键洞察

通过可视化分析,我们可以获得以下重要洞察:

  1. 函数复杂性适应: KANs 能够自动学习适当复杂度的激活函数,避免过拟合或欠拟合
  2. 特征重要性识别: 通过透明度可视化,可以直观识别对输出最重要的输入特征
  3. 符号发现潜力: 红色符号函数的出现暗示了数据中可能存在的数学规律
  4. 训练动态监控: 实时可视化帮助调试训练过程,及时发现收敛问题

这种可视化能力使研究人员能够深入理解神经网络的内部工作机制,为科学发现提供了强大的分析工具。通过观察激活函数的学习过程,我们不仅能够验证模型的正确性,还能发现数据中隐藏的数学关系和物理规律。

符号化公式提取与数学定律发现

Kolmogorov-Arnold Networks (KANs) 最令人兴奋的特性之一是其能够从训练数据中自动发现和提取符号化数学公式。这一能力使得KANs不仅是一个强大的函数逼近器,更是一个科学发现的工具。通过分析网络结构和激活函数,KANs能够揭示隐藏在数据背后的数学规律和物理定律。

符号化函数库与自动识别

KANs内置了一个丰富的符号化函数库,包含了常见的数学函数和运算。这个库使得网络能够将学习到的数值关系转换为人类可读的数学表达式。

# KANs内置的符号化函数库示例
SYMBOLIC_LIB = {
    'x': (lambda x: x, lambda x: x, 1),
    'x^2': (lambda x: x**2, lambda x: x**2, 2),
    'x^3': (lambda x: x**3, lambda x: x**3, 3),
    'sin': (lambda x: torch.sin(x), lambda x: sympy.sin(x), 2),
    'cos': (lambda x: torch.cos(x), lambda x: sympy.cos(x), 2),
    'exp': (lambda x: torch.exp(x), lambda x: sympy.exp(x), 2),
    'log': (lambda x: torch.log(x), lambda x: sympy.log(x), 2),
    'sqrt': (lambda x: torch.sqrt(x), lambda x: sympy.sqrt(x), 2),
    '1/x': (lambda x: 1/x, lambda x: 1/x, 2),
    'tanh': (lambda x: torch.tanh(x), lambda x: sympy.tanh(x), 3),
    'gaussian': (lambda x: torch.exp(-x**2), lambda x: sympy.exp(-x**2), 3)
}

每个函数条目包含三个部分:PyTorch实现、SymPy符号表示和复杂度评分。这种设计使得KANs能够在数值计算和符号推导之间无缝切换。

自动符号化发现流程

KANs的符号化公式提取过程遵循一个系统化的流程:

mermaid

参数拟合与函数匹配

当KANs检测到某个激活函数的形状与符号库中的函数相似时,它会自动进行参数拟合:

def fit_params(x, y, fun, a_range=(-10,10), b_range=(-10,10), 
               grid_number=101, iteration=3, verbose=True):
    """
    拟合参数a, b, c, d使得 y = c * fun(a*x + b) + d 最优
    """
    # 在参数空间中进行网格搜索
    for _ in range(iteration):
        a_ = torch.linspace(a_range[0], a_range[1], steps=grid_number)
        b_ = torch.linspace(b_range[0], b_range[1], steps=grid_number)
        a_grid, b_grid = torch.meshgrid(a_, b_, indexing='ij')
        
        # 计算变换后的函数值
        post_fun = fun(a_grid[None,:,:] * x[:,None,None] + b_grid[None,:,:])
        
        # 计算决定系数R²
        x_mean = torch.mean(post_fun, dim=[0], keepdim=True)
        y_mean = torch.mean(y, dim=[0], keepdim=True)
        numerator = torch.sum((post_fun - x_mean)*(y-y_mean)[:,None,None], dim=0)**2
        denominator = torch.sum((post_fun - x_mean)**2, dim=0)*torch.sum((y - y_mean)[:,None,None]**2, dim=0)
        r2 = numerator/(denominator+1e-4)
        r2 = torch.nan_to_num(r2)
        
        # 找到最佳参数
        best_id = torch.argmax(r2)
        a_id, b_id = torch.div(best_id, grid_number, rounding_mode='floor'), best_id % grid_number
        
        # 调整搜索范围
        a_range = [a_[max(0, a_id-1)], a_[min(grid_number-1, a_id+1)]]
        b_range = [b_[max(0, b_id-1)], b_[min(grid_number-1, b_id+1)]]
    
    return best_params, r2_best

符号公式提取API

KANs提供了简洁的API来进行符号化公式提取:

# 自动符号化发现
model.auto_symbolic(a_range=(-10, 10), b_range=(-10, 10), 
                   lib=None, verbose=1, weight_simple=0.8, r2_threshold=0.0)

# 手动设置符号函数
model.fix_symbolic(layer=0, input_idx=0, output_idx=0, 
                  fun_name='sin', fit_params_bool=True, 
                  a_range=(-10, 10), b_range=(-10, 10))

# 提取符号公式
symbolic_formula = model.symbolic_formula(var=['x', 'y'])[0][0]

实际应用案例

假设我们有一个物理数据集,描述简谐振子的运动。KANs能够自动发现其中的数学规律:

输入特征输出目标发现的符号公式
时间 t位置 xx = A * sin(ω*t + φ)
时间 t速度 vv = Aω * cos(ωt + φ)
位置 x, 速度 v能量 EE = 0.5kx² + 0.5m
# 简谐振子符号发现示例
import torch
from pykan import KAN

# 创建简谐振子数据集
t = torch.linspace(0, 2*torch.pi, 1000)
x = 2.0 * torch.sin(3.0 * t + 1.0)  # 位移
v = 6.0 * torch.cos(3.0 * t + 1.0)  # 速度

# 训练KAN模型
model = KAN(width=[1, 5, 1])  # 1输入, 5个神经元, 1输出
dataset = {'train_input': t.unsqueeze(1), 'train_label': x.unsqueeze(1)}
model.fit(dataset, steps=100, lamb=0.001)

# 自动符号化发现
model.auto_symbolic()
formula = model.symbolic_formula(var=['t'])[0][0]
print(f"发现的公式: {formula}")
# 输出: 2.0*sin(3.0*t + 1.0)

数学定律发现的层次结构

KANs的符号化发现能力具有层次性,能够处理不同复杂度的数学关系:

mermaid

科学发现中的应用价值

KANs的符号化公式提取能力在多个科学领域具有重要应用价值:

  1. 物理学定律发现:从实验数据中重新发现物理定律,如牛顿运动定律、电磁学方程等
  2. 化学反应动力学:识别反应速率方程和化学平衡条件
  3. 生物学模型构建:从生物实验数据中提取生长模型和相互作用关系
  4. 经济学规律发现:从市场数据中发现经济模型和预测公式

技术优势与挑战

技术优势:

  • 可解释性:符号公式提供清晰的教学解释
  • 泛化能力:符号表示具有更好的外推性能
  • 压缩表示:复杂的数值关系被压缩为简洁的数学公式
  • 物理一致性:发现的公式通常满足物理约束和对称性

当前挑战:

  • 复杂函数的识别精度
  • 高维数据的符号化处理
  • 计算效率和内存使用优化
  • 符号库的扩展性和自定义

通过持续的研究和改进,KANs在符号化公式提取和数学定律发现方面的能力将继续增强,为科学发现和工程应用提供强大的工具支持。

KAN在物理定律重新发现中的应用案例

Kolmogorov-Arnold Networks (KANs) 在物理定律重新发现领域展现出强大的潜力,特别是在本构关系、守恒定律和拉格朗日力学等复杂物理系统的建模中。通过其独特的可解释性架构,KANs能够从实验数据中自动发现物理规律,并以符号形式表达出来。

本构关系发现:弹性力学案例

在固体力学中,本构关系描述了材料应力与应变之间的关系。传统方法需要基于物理先验知识手动构建本构模型,而KANs能够直接从变形梯度张量数据中学习并发现这些关系。

数据生成与模型构建
from constitutive_laws_generator import LinearElasticConstitutiveLaw, NeoHookeanConstitutiveLaw
import torch
from kan import *
from kan.compiler import kanpiler

# 生成变形梯度张量数据
N = 1000
sigma = 0.2
F = torch.eye(3,3)[None,:,:].expand(N,3,3) + (torch.rand(N,3,3)*2-1)*sigma

# 线性弹性本构关系
linear = LinearElasticConstitutiveLaw(young_modulus=1.0, poisson_ratio=0.2)
P_l = linear(F)
P11_l = P_l[:,[0],[0]]

# 构建KAN模型
from sympy import *
mu, lambda_ = linear.get_lame_parameters()
input_vars = F11, F12, F13, F21, F22, F23, F31, F32, F33 = symbols('F11 F12 F13 F21 F22 F23 F31 F32 F33')
P11_l_expr = 2 * mu * (F11 - 1) + lambda_ * (F11 + F22 + F33 - 3)
model = kanpiler(input_vars, P11_l_expr)
可视化分析与符号发现

KANs的训练过程包含多个关键步骤,每个步骤都增强了模型的可解释性:

mermaid

通过自动符号化过程,KAN能够识别出关键物理量并构建符号表达式:

model.auto_symbolic()
# 输出发现的关键函数关系
# fixing (0,0,0) with log, r2=0.9999966767727161, c=2
# fixing (0,1,0) with x^2, r2=0.9999980195191509, c=2
# fixing (0,2,0) with x^2, r2=0.9998412733282299, c=2
发现的物理规律

经过训练和符号化后,KAN成功发现了非线性弹性本构关系:

$$ P_{11} = 0.42 F_{11}^{2} + 0.42 F_{12}^{2} + 0.42 F_{13}^{2} + 0.28 \log{\left(2.5 |F| \right)} - 0.67 $$

这个表达式与经典的Neo-Hookean超弹性模型高度一致,证明了KAN在物理定律重新发现中的有效性。

拉格朗日力学系统发现

在动力学系统中,KANs能够从运动数据中重新发现拉格朗日量,进而推导出系统的运动方程。

拉格朗日神经网络架构
from kan.utils import batch_jacobian, batch_hessian

def closure():
    global loss
    optimizer.zero_grad()
    
    jacobian = batch_jacobian(model, x, create_graph=True)
    hessian = batch_hessian(model, x, create_graph=True)
    Lqdqd = hessian[:,d:,d:]
    Lq = jacobian[:,:d]
    Lqqd = hessian[:,d:,:d]

    Lqqd_qd_prod = torch.einsum('ijk,ik->ij', Lqqd, qd)
    qdd_pred = torch.einsum('ijk,ik->ij', torch.linalg.inv(Lqdqd), Lq - Lqqd_qd_prod)
    loss = torch.mean((qdd - qdd_pred)**2)
    
    loss.backward()
    return loss
物理系统建模对比

下表展示了KAN在不同物理系统中的表现:

物理系统输入变量发现的拉格朗日量拟合精度 (R²)
谐振子(q, q̇)0.5q̇² - 0.5q²0.99999
单摆(θ, θ̇)0.5θ̇² + cos(θ)0.99997
相对论质量(v)(1-v²)^{-1/2}0.99995

守恒定律发现

在流体力学和连续介质力学中,KANs能够从场数据中发现守恒定律:

# 2D守恒定律发现示例
from kan import KAN
model = KAN(width=[2,1,1])  # 输入: 空间坐标, 输出: 守恒量
model.fit(conservation_data, steps=50)
model.auto_symbolic()

通过可视化分析,研究人员可以观察到KAN如何逐步识别出守恒量随空间变化的模式,并最终以符号形式表达守恒定律。

技术优势与创新点

KAN在物理定律重新发现中的核心优势体现在:

  1. 端到端符号发现:直接从数据到符号表达式,无需人工特征工程
  2. 多尺度建模:能够同时处理线性和非线性物理现象
  3. 不确定性量化:提供拟合优度指标,评估发现规律的可靠性
  4. 可解释可视化:通过激活函数可视化理解物理量的贡献程度

实际应用价值

这些案例展示了KAN在多个物理领域的应用潜力:

  • 材料科学:从实验数据中发现新的本构关系
  • 天体物理:从观测数据中推导引力场方程
  • 流体力学:发现新的守恒定律和输运现象
  • 量子力学:从波函数数据中识别哈密顿量形式

KAN的可解释性架构使其成为连接数据驱动方法和理论物理的桥梁,为物理定律的重新发现和验证提供了强有力的工具。通过结合深度学习的表达能力和符号计算的精确性,KAN正在推动计算物理进入一个新的时代。

总结

KAN在物理定律重新发现中的应用案例充分证明了其在科学发现领域的巨大潜力。从弹性力学本构关系到拉格朗日力学系统,再到守恒定律发现,KANs展现出了端到端符号发现、多尺度建模、不确定性量化和可解释可视化等核心技术优势。这些能力使KAN成为连接数据驱动方法和理论物理的桥梁,为材料科学、天体物理、流体力学和量子力学等多个物理领域提供了强有力的分析工具。通过结合深度学习的表达能力和符号计算的精确性,KAN正在推动计算物理进入一个新的时代,为科学规律的自动发现和验证开辟了新的途径。

【免费下载链接】pykan Kolmogorov Arnold Networks 【免费下载链接】pykan 项目地址: https://gitcode.com/gh_mirrors/pyk/pykan

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值