如何构建 CANN 模型?¶
目标:完成本指南后,您将能够创建并运行一个基础的 CANN 模型。
预计阅读时间:10 分钟
介绍¶
在本库中构建 CANN 模型非常简单,这得益于与 BrainPy 的集成,BrainPy 是基于 JAX 构建的动力系统框架。本指南将向您展示如何:
设置 BrainPy 环境
创建 CANN1D 模型实例
初始化模型状态
运行简单的前向传播
基础知识:BrainPy 框架¶
CANN 模型使用 BrainPy 构建,它提供:
通过
bm.set_dt()的统一时间步管理用于管理神经动力学的状态容器(
bm.Variable)通过
bm.for_loop的 JIT 编译以获得高性能梯度分析的自动微分支持
所有 CANN 模型都继承自 bp.DynamicalSystem,这意味着它们在库中遵循一致的接口。
逐步指南:创建您的第一个 CANN¶
1. 设置时间步¶
在创建任何模型之前,您必须设置模拟时间步:
[ ]:
import brainpy.math as bm
# 设置时间步为 0.1 ms(或您偏好的值)
bm.set_dt(0.1)
为什么这很重要:时间步 dt 控制您模拟的粒度。您会话中的所有模型都将使用此值进行其动力学更新。
2. 导入并创建模型¶
[2]:
from canns.models.basic import CANN1D
# 创建有 512 个神经元的 1D CANN
cann = CANN1D(num=512)
这里发生了什么:
num=512指定网络中的神经元数量该模型自动设置连接权重、神经元位置和动力学参数
使用默认参数(例如连接强度
k、时间常数tau),除非您指定其他参数
4. 运行前向传播¶
现在您可以调用模型来更新其状态:
[4]:
import jax.numpy as jnp
# 创建简单的外部输入(在位置 0 的刺激)
external_input = jnp.zeros(512)
# 运行一个时间步
cann(external_input)
# 访问模型的当前状态
print("突触输入:", cann.u.value)
print("神经活动:", cann.r.value)
突触输入: [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0.]
神经活动: [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0.]
发生了什么:
模型接收外部输入并更新其内部动力学
cann.u存储突触输入(膜电位)cann.r存储神经放电速率(活动)每次调用
cann(...)将模型推进一个时间步(dt)
完整的工作示例¶
这是一个最小的、可运行的示例,将它们全部整合在一起:
[ ]:
import brainpy.math as bm
import jax.numpy as jnp
from canns.models.basic import CANN1D
# 步骤 1:设置时间步
bm.set_dt(0.1)
# 步骤 2:创建模型
cann = CANN1D(num=512)
# 步骤 3:创建以位置 0 为中心的高斯凸起刺激
positions = cann.x # 来自 -pi 到 pi 的神经元位置
stimulus = jnp.exp(-0.5 * (positions - 0.0)**2 / 0.25**2)
# 步骤 4:运行多个前向传播
cann(stimulus)
cann(stimulus)
cann(stimulus)
# 步骤 6:检查输出
print(f"活动形状:{cann.r.value.shape}")
print(f"最大活动:{jnp.max(cann.r.value)}")
[6]:
cann = CANN1D(
num=512, # 神经元数量
k=1.0, # 全局连接强度
tau=1.0, # 时间常数(毫秒)
a=0.5, # 兴奋性连接宽度
A=10.0, # 兴奋性连接幅度
J0=1.0, # 外部输入强度
)
关键参数:
num:神经元数量(更高 = 更精细的空间分辨率,但速度更慢)k:控制总体连接强度(更高 = 更强的自组织)tau:动力学的时间常数(更高 = 变化更慢)a:连接核的宽度(控制凸起宽度)A:连接的幅度(影响稳定性)
对于大多数应用,默认值表现很好。我们将在核心概念部分探索参数调整。
运行多个时间步¶
在实践中,您将在循环中运行许多时间步。BrainPy 为此提供了优化的工具:
[ ]:
# 初始化状态
def step_function(t, stimulus):
"""运行模型的一个时间步。"""
cann(stimulus)
return cann.r.value # 返回每个步骤的活动
# 为 100 个时间步创建刺激(这里是恒定刺激)
stimuli = jnp.tile(stimulus, (100, 1))
# 使用进度条运行优化循环
activities = bm.for_loop(
step_function,
operands=(jnp.arange(0, 100), stimuli),
pbar=bm.ProgressBar(10) # 显示进度
)
print(f"记录的活动形状:{activities.shape}") # (100, 512)
❌ 错误 1:未设置时间步¶
[10]:
from canns.models.basic import CANN1D
cann = CANN1D(num=512) # 使用之前设置的任何 dt(或默认值)
✅ 解决方案:在脚本开始时显式设置 dt:
[ ]:
import brainpy.math as bm
bm.set_dt(0.1) # 首先设置 dt
cann = CANN1D(num=512)
❌ 错误 2:输入维度错误¶
[12]:
cann = CANN1D(num=512)
try:
cann(jnp.zeros(256)) # 错误!输入大小与神经元数量不匹配
except Exception as e:
print(f"按预期捕获错误:{e}")
按预期捕获错误:add got incompatible shapes for broadcasting: (512,), (256,).
✅ 解决方案:输入必须与 num 大小相同:
[13]:
cann = CANN1D(num=512)
cann(jnp.zeros(512)) # 正确的大小
关于 2D CANN?¶
相同的原理也适用于 2D 模型:
[ ]:
from canns.models.basic import CANN2D
bm.set_dt(0.1)
# 创建有 32x32 个神经元的 2D CANN
cann2d = CANN2D(32)
# 输入必须是 (32, 32) 形状
stimulus_2d = jnp.zeros((32, 32))
cann2d(stimulus_2d)
print(f"2D 活动形状:{cann2d.r.value.shape}") # (32, 32)
API 几乎相同——只需调整您的输入维度!
后续步骤¶
现在您知道如何创建和运行 CANN 模型,您已准备好:
生成任务数据 - 学习如何创建平滑跟踪输入、导航任务等
探索模型集合 - 发现其他模型变体(SFA-CANN、分层网络、脑启发模型)
学习 BrainPy 基础 - 如果您想构建自定义模型或深入理解框架
快速参考:
[ ]:
# 创建任何 CANN 模型的模板
import brainpy.math as bm
from canns.models.basic import CANN1D
bm.set_dt(0.1) # 1. 设置时间步
cann = CANN1D(num=512) # 2. 创建模型
cann(stimulus) # 4. 运行前向传播
result = cann.r.value # 5. 访问活动
有疑问?查看FAQ或打开GitHub Discussion。