设计哲学与架构概览

本文档阐述了 CANNs 库的核心设计原则和模块组织结构。

核心设计原则

CANNs 库基于两个基本原则构建,这些原则指导着其架构和实现。

关注点分离

该库严格将不同的功能职责分离到独立的模块中:

:🏗️ 模型 (canns.models):

定义神经网络动力学和状态演化

:📊 任务 (canns.task):

生成实验范式和输入数据

:📈 分析器 (canns.analyzer):

可视化和分析仿真结果

:🧠 训练器 (canns.trainer):

为脑启发模型实现学习规则

:🔗 流水线 (canns.pipeline):

编排完整的实验工作流

每个模块专注于单一职责。模型不生成自己的输入数据。任务不分析结果。分析器不修改模型参数。这种分离使代码库易于维护、测试和扩展。

通过基类实现可扩展性

每个主要组件都继承自抽象基类,这些基类定义了标准接口:

  • canns.models.basic.BasicModel 用于基本 CANN 模型

  • canns.models.brain_inspired.BrainInspiredModel 用于脑启发模型

  • canns.trainer.Trainer 用于训练算法

这些基类建立了契约,确保所有实现都能与库的其余部分无缝协作。用户可以通过继承这些基类并实现所需方法来创建自定义模型、任务或训练器。

模块架构

四个核心应用场景

CANNs 库支持四种不同的工作流,每种工作流针对不同的研究需求。这些场景展示了架构的模块化设计和灵活性。

../../_images/canns_scenarios_custom.png

CANNs 四个核心应用场景

🔬 场景 1:CANN 建模与仿真

研究连续吸引子动力学的最常见工作流

模型构建 → 任务数据生成 → 仿真实验 → 模型分析

📊 场景 2:数据分析

分析实验或虚拟神经记录

真实/虚拟实验数据 → 数据分析 → 吸引子/动力学分析 → 结果

🧠 场景 3:脑启发学习

使用生物学上合理的学习规则训练网络

任务数据集 → 脑启发建模 → 脑启发训练 → 评估

🔗 场景 4:端到端流水线

从配置到结果的自动化实验工作流

输入配置 → 流水线编排 → 自动执行 → 输出报告

模块交互模式

数据流模式

在所有场景中,模块遵循关注点分离原则进行交互:

  • 🟡 输入阶段:数据进入系统(模型、数据集、配置)

  • 处理阶段:核心计算(仿真、训练、分析)

  • 🟢 输出阶段:结果可视化和解释

这种一致的结构使库直观易用,同时支持多样化的研究工作流。

BrainPy 集成

CANNs 库基于 BrainPy [])构建,这是一个强大的脑动力学编程框架。BrainPy 提供:

:⚙️ 动力学抽象

bp.DynamicalSystem 神经系统基类

:💾 状态管理

bm.Variable 容器用于所有状态变量(替代独立的 State、HiddenState、ParamState)

:⏱️ 时间步控制

bm.set_dt(...)bm.get_dt() 用于统一的时间管理

:⚡ JIT 编译

bm.for_loop 用于高性能仿真

:🎲 随机数管理

bm.random 用于可重复的随机性

借助 BrainPy [18],CANN 模型只需定义变量和更新方程。时间步进、并行化和编译都自动处理——显著降低了实现复杂度。

模块关系

模块如何交互

模型 ↔ 任务耦合

某些任务需要模型实例来访问刺激生成方法。例如,SmoothTracking1D 需要访问 model.get_stimulus_by_pos() 来将位置坐标转换为神经输入模式。这种耦合是为了用户便利而有意设计的,但仅限于跟踪任务。

模型 ↔ 分析器独立性

分析器处理模型输出(放电率、膜电位)但不修改模型状态。它们接受 NumPy 数组形式的仿真结果并生成可视化。这种独立性使得同一个分析器可以处理任何产生兼容输出的模型。

模型 ↔ 训练器协作

训练器根据学习规则修改模型参数——特别是连接权重。它们通过约定的属性与模型交互,如 model.W 用于权重,model.s 用于状态向量。训练器框架专为使用局部、活动依赖可塑性的脑启发模型而设计。

流水线编排

canns.pipeline 模块将所有其他模块协调成完整的实验工作流。它管理从模型设置到任务执行再到结果分析的完整周期,为常见用例提供高级接口。

设计权衡

灵活性 vs. 便利性

🔧 灵活性

高级用户可以覆盖任何组件或创建自定义实现

🚀 便利性

标准工作流应该只需要最少的样板代码

该库通过合理的默认值和丰富的自定义选项来实现这种平衡。例如,CANN1D() 使用适用于大多数情况的默认参数,但每个参数都可以显式指定。

性能 vs. 简洁性

该库通过多层策略实现高性能:

Python 层(BrainPy/JAX [17]

基于 JAX [17] 的编译提供 GPU/TPU 加速,但需要函数式编程模式。该库通过以下方式抽象了这种复杂性:

  • 在 BrainPy 的 bm.for_loop 中封装 JIT 编译

  • 通过 bm.Variable 容器管理状态

  • 提供处理常见模式的实用函数

用户无需直接编写 JAX 特定代码即可受益于 GPU/TPU 加速。

原生层(canns-lib)

Important

对于 Python 开销显著的性能关键操作,该库通过 canns-lib 提供可选的 Rust 驱动后端:

  • Ripser 模块:拓扑数据分析 [15, 16],相比纯 Python 平均加速 1.13 倍(最高 1.82 倍)

  • 空间导航:加速的 RatInABox 环境,长轨迹积分速度提升约 700 倍

  • 未来模块:计划支持近似最近邻、动力学计算

canns-lib 集成遵循相同的原则:它提供简单的 Python API,同时利用原生性能处理瓶颈操作。用户可以选择使用这些加速功能而无需更改代码结构。

扩展库

创建自定义模型

要添加新模型,请继承适当的基类并实现所需方法。

必需方法:

  • make_conn():生成连接矩阵

  • get_stimulus_by_pos():将位置转换为输入模式

  • init_state():注册状态变量

  • update():定义单步动力学

必需方法:

  • init_state():注册状态和权重参数

  • update():定义状态演化

  • energy:返回网络能量的属性

创建自定义任务

Tip

任务应该生成与模型期望兼容的输入序列。关键考虑因素:

  • 使用 bm.get_dt() 保持时间步一致性

  • 以模型期望的格式返回数据

  • 提供用于分析的轨迹信息

创建自定义训练器

Note

训练器继承自 canns.trainer.Trainer 并实现:

  • train():参数更新策略

  • predict():单样本推理

  • 标准进度和编译配置

总结

CANNs 库通过精心的架构选择实现其目标:

1️⃣

关注点分离 保持模块专注且独立

2️⃣

基类继承 确保一致的接口

3️⃣

BrainPy 集成 提供性能而不增加复杂性

4️⃣

灵活耦合 在便利性和模块化之间取得平衡

这些原则使快速原型开发和严谨研究成为可能,同时保持代码质量和可扩展性。