KAN:Kolmogorov–Arnold Networks分类模型实现

技术

picture.image

KAN是当前提出的一种全新的神经网络架构,传统的MLP多层感知器中,通常使用的激活函数是非线性的,例如ReLU、sigmoid或tanh,这些激活函数在大多数深度学习框架中都是不可学习的函数,只是应用于每个神经元的输出,MLP的线性层(全连接层)的权重是可学习的,但是KAN解决了激活函数在MLP中不可学习的问题,它把可学习的激活函数放在权重上,让其进行学习

picture.image

接下来作者将利用KAN进行对鸢尾花的分类实现,体现它相对于MLP无法比拟的可解释性、交互性特点,当然KAN也有其缺点就是目前版本训练速度较慢

代码实现

数据读取


          
import pandas as pd
          
from sklearn.datasets import load_iris
          
import matplotlib.pyplot as plt
          
import numpy as np
          
iris = load_iris()
          
iris_df = pd.DataFrame(data=iris.data, columns=iris.feature_names)
          
iris_df['target'] = iris.target
          
df = iris_df[iris_df['target'] != 2] # 只要01完成一个二分类问题
          
df.head()
      

picture.image

这里将数据简单梳理为二分类问题,并且将这个分类问题看作回归问题,去探讨不同输出维度下的KAN

KAN输出维度=1


          
from sklearn.model_selection import train_test_split
          
import torch
          
train_input, test_input, train_label, test_label = train_test_split(df.iloc[:, 0:4], df['target'], 
          
                                                                    test_size=0.2, random_state=42, stratify=df['target'])
          

          
# 将 DataFrame 和 Series 转换为 np.array
          
train_input = train_input.to_numpy()
          
test_input = test_input.to_numpy()
          
train_label = train_label.to_numpy()
          
test_label = test_label.to_numpy()
          
# 转换为pytorch张量
          
dataset = {}
          
dataset['train_input'] = torch.from_numpy(train_input)
          
dataset['test_input'] = torch.from_numpy(test_input)
          
dataset['train_label'] = torch.from_numpy(train_label[:,None])
          
dataset['test_label'] = torch.from_numpy(test_label[:,None])
      

分割数据集且将原始的 DataFrame 数据转换为适合在 PyTorch 中使用的张量形式


          
from kan import KAN
          
model = KAN(width=[4,1], grid=3, k=3)
          
# 初始化绘制KAN
          
model(dataset['train_input']);
          
model.plot(beta=100)
      

picture.image

这里创建一个KAN:4D输入,1D输出,没有隐藏的神经元,三次样条 (k=3),3个网格间隔 (grid=3),如果要添加隐藏的神经元在width中添加既可,它表示每层中的神经元数,例如,[2,5,5,3] 表示 2D 输入,3D 输出,具有 2 层 5 个隐藏神经元,创建这样的模型后对其可视化,当前这个模型还没有进行训练,接下来训练这个模型


          
# 定义训练集准确率计算函数
          
def train_acc():
          
    # 使用模型对训练输入进行预测,取预测值的第一个输出并四舍五入
          
    # 将预测值与训练标签进行比较,计算准确率
          
    return torch.mean((torch.round(model(dataset['train_input'])[:, 0]) == dataset['train_label'][:, 0]).float())
          

          
# 定义测试集准确率计算函数
          
def test_acc():
          
    # 使用模型对测试输入进行预测,取预测值的第一个输出并四舍五入
          
    # 将预测值与测试标签进行比较,计算准确率
          
    return torch.mean((torch.round(model(dataset['test_input'])[:, 0]) == dataset['test_label'][:, 0]).float())
          

          
# 训练模型,使用LBFGS优化器,训练20步,计算训练和测试集的准确率
          
results = model.train(dataset, opt="LBFGS", steps=20, metrics=(train_acc, test_acc))
          
model.plot()
      

picture.image

定义了两个函数 train_acc() 和 test_acc() 分别用于计算训练集和测试集上模型的准确率,然后使用 LBFGS 优化器对模型进行训练,训练步数为 20 步,并同时计算并输出训练和测试集的准确率,最后对模型进行可视化,对比模型初始可视化可以发现激活函数明显不一样了,这就是KAN对激活函数学习的一个结果,接下来我们把这个模型进行解释性输出


          
lib = ['x','x^2','x^3','x^4','exp','log','sqrt','tanh','sin','tan','abs']
          
model.auto_symbolic(lib=lib)
          
formula = model.symbolic_formula()[0][0]
          
formula
      

picture.image

可以发现KAN模型相对其其它深度学习框架,它可以输出一个具体的公式,当然这个KAN是单输出所以只有一个公式,通过这个公式它不在是一个黑箱模型,而是可以被我们所解释的模型,实际上把相应的X值输入公式并进行四舍五入返回的值就是0或1也就是我们的实际类别,接下来通过这个公式来输出在训练集、测试集上的模型精确度


          
def acc(formula, X, y):
          
    batch = X.shape[0]  # 获取批量大小
          
    correct = 0  # 初始化正确预测的数量
          
    for i in range(batch):
          
        # 构建替换字典,将 x_1, x_2, x_3, x_4 替换为当前样本的值
          
        subs_dict = {'x_1': X[i, 0], 'x_2': X[i, 1], 'x_3': X[i, 2], 'x_4': X[i, 3]}
          
        # 使用给定的公式对当前样本进行预测,并将结果转换为浮点数
          
        prediction = float(formula.subs(subs_dict))
          
        # 四舍五入预测值,与真实标签进行比较
          
        if np.round(prediction) == y[i, 0]:
          
            correct += 1
          
    # 计算准确率
          
    accuracy = correct / batch
          
    return accuracy
          
    
          
# 计算训练集和测试集的准确率
          
train_accuracy = acc(formula, dataset['train_input'], dataset['train_label'])
          
test_accuracy = acc(formula, dataset['test_input'], dataset['test_label'])
          
print('train acc of the formula:', train_accuracy)
          
print('test acc of the formula:', test_accuracy)
      

picture.image

通过准确率可知这个单输出的二分类KAN模型,表现的很好只是在训练集上出现了一点错误,接下来我们重新去构建一个二输出的KAN模型

KAN输出维度=2


          
dataset = {}
          
dataset['train_input'] = torch.from_numpy(train_input)
          
dataset['test_input'] = torch.from_numpy(test_input)
          
dataset['train_label'] = torch.from_numpy(train_label).type(torch.long)
          
dataset['test_label'] = torch.from_numpy(test_label).type(torch.long)
          

          
model = KAN(width=[4,2], grid=3, k=3)
          
model(dataset['train_input']);
          
model.plot(beta=100)
      

picture.image

这个模型相对于第一个模型只去修改了它的输出维数为二,同样还是把它看作是一个回归模型


          
def train_acc():
          
    return torch.mean((torch.argmax(model(dataset['train_input']), dim=1) == dataset['train_label']).float())
          

          
def test_acc():
          
    return torch.mean((torch.argmax(model(dataset['test_input']), dim=1) == dataset['test_label']).float())
          

          
results = model.train(dataset, opt="LBFGS", steps=20, metrics=(train_acc, test_acc), loss_fn=torch.nn.CrossEntropyLoss())
          
model.plot()
      

picture.image

同样是对激活函数进行学习,并可视化


          
lib = ['x','x^2','x^3','x^4','exp','log','sqrt','tanh','sin','abs']
          
model.auto_symbolic(lib=lib)
          
formula1, formula2 = model.symbolic_formula()[0]
          
formula1
      

picture.image


        
            

          formula2
        
      

picture.image

这是一个输出维数为二的KAN模型相应的它的输出都有与它一一对应的数学公式来进行解释


          
def acc(formula1, formula2, X, y):
          
    batch = X.shape[0]
          
    correct = 0
          
    for i in range(batch):
          
        logit1 = np.array(formula1.subs('x_1', X[i,0]).subs('x_2', X[i,1]).subs('x_3', X[i,2]).subs('x_4', X[i,3])).astype(np.float64)
          
        logit2 = np.array(formula2.subs('x_1', X[i,0]).subs('x_2', X[i,1]).subs('x_3', X[i,2]).subs('x_4', X[i,3])).astype(np.float64)
          
        correct += (logit2 > logit1) == y[i]
          
    return correct/batch
          

          
print('train acc of the formula:', acc(formula1, formula2, dataset['train_input'], dataset['train_label']))
          
print('test acc of the formula:', acc(formula1, formula2, dataset['test_input'], dataset['test_label']))
      

picture.image

相应的计算这个KAN模型的准确率,可以发现这个输出维数为二的KAN比输出维度为一的KAN要好,这个KAN模型在这个数据集上百分比预测正确,这里利用的是 预测结果(即 logit2 > logit1 的布尔值)与真实标签 y[i] 相等,则返回 True(1 ) ,否则返回 False(0 ),来进行准确率计算,到这里就完成了这个分类模型的构建,读者也可以尝试对所有数据集进行三分类KAN构建,下面是作者对完整鸢尾花数据进行构建的KAN模型可视化

picture.image

往期推荐

Pythorch框架构建Attention-lstm时序模型

Self-Attention原理详解

SHAP全解析:机器学习、深度学习模型解释保姆级教程

利用python meteostat库对全球气象数据访问,获取历史气象数据

Python桑基图可视化:揭示数据行为路径

梯度提升集成:LightGBM与XGBoost组合预测

特征工程——数据转换

回归任务常见评价指标解读以及Python实现

如果你对类似于这样的文章感兴趣。

欢迎关注、点赞、转发~

个人观点,仅供参考

0
0
0
0
关于作者

文章

0

获赞

0

收藏

0

相关资源
VikingDB:大规模云原生向量数据库的前沿实践与应用
本次演讲将重点介绍 VikingDB 解决各类应用中极限性能、规模、精度问题上的探索实践,并通过落地的案例向听众介绍如何在多模态信息检索、RAG 与知识库等领域进行合理的技术选型和规划。
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论