教程 3: 分析与可视化方法

Note

阅读时间: 40-50 分钟

难度: 初级

先决条件: 教程 1教程 2

本教程介绍了 CANNs 分析器模块中的可视化与分析方法。


1. 分析器模块与 PlotConfigs 概览

canns.analyzer.plotting 模块为分析模拟结果提供可视化方法。所有绘图函数均使用 PlotConfigs 系统进行统一配置管理。

1.1 可用的绘图方法

1D 模型分析:

  • energy_landscape_1d_static——静态能量景观

  • energy_landscape_1d_animation——动画能量景观

  • raster_plot——脉冲光栅图

  • average_firing_rate_plot——随时间变化的平均放电率

  • tuning_curve——神经调谐曲线

2D 模型分析:

  • energy_landscape_2d_static——2D 静态能量景观

  • energy_landscape_2d_animation——2D 动画能量景观

1.2 PlotConfigs 系统

PlotConfigs 提供针对特定方法的配置构建器。每个绘图方法均对应一个配置构建器:

from canns.analyzer.visualization import (
    PlotConfigs,
    energy_landscape_1d_static,
    energy_landscape_1d_animation,
    raster_plot,
    average_firing_rate_plot,
    tuning_curve,
)

# 为每个方法创建配置
config_static = PlotConfigs.energy_landscape_1d_static(
    figsize=(10, 6),
    title='能量景观',
    show=True,        # 显示图表(默认)
    save_path=None    # 不保存至文件(默认)
)

# 将配置传递给绘图函数
energy_landscape_1d_static(
    data_sets={'r': (model.x, r_history)},
    config=config_static
)

Note

此为概念性示例。实际用法将在下文第 2 节中结合真实数据演示。

主要优势:

  • 统一接口: 所有绘图方法遵循相同模式

  • 配置复用: 一次创建,多次使用

  • 清晰默认值: show=True, save_path=None 适用于交互式可视化

Note

默认情况下,图表将显示(show=True)且不保存(save_path=None)。如需保存图表,请设置 save_path='filename.png'


2. 1D 分析方法

我们使用 SmoothTracking1D 任务演示所有 1D 分析方法。

2.1 准备工作

[1]:
import brainpy.math as bm
from canns.models.basic import CANN1D
from canns.task.tracking import SmoothTracking1D
from canns.analyzer.visualization import (
    PlotConfigs,
    energy_landscape_1d_static,
    energy_landscape_1d_animation,
    raster_plot,
    average_firing_rate_plot,
    tuning_curve,
)

# Setup environment
bm.set_dt(0.1)

# Create model
model = CANN1D(num=256, tau=1.0, k=8.1, a=0.5, A=10, J0=4.0)

# Create smooth tracking task
# Stimulus moves from -2.0 to 2.0, then to -1.0
task = SmoothTracking1D(
    cann_instance=model,
    Iext=[-4.0, 4.0, -2.0, 2.0],      # Keypoint positions
    duration=[20.0, 30.0, 20.0], # Duration for each segment
    time_step=bm.get_dt(),
)

# Get task data
task.get_data()

# Define simulation step
def run_step(t, inp):
    model.update(inp)
    return model.u.value, model.r.value, model.inp.value

# Run simulation
u_history, r_history, input_history = bm.for_loop(run_step, operands=(task.run_steps, task.data), progress_bar=10)
<SmoothTracking1D> Generating Task data: 700it [00:00, 1633.05it/s]

2.2 能量景观(静态)

energy_landscape_1d_static 绘制放电率随时间与神经元位置的变化:

[2]:
index = 200 # Time step to visualize

# Configure static energy landscape
config_static = PlotConfigs.energy_landscape_1d_static(
    figsize=(10, 6),
    title='Energy Landscape - Smooth Tracking',
    xlabel='Time Step',
    ylabel='Neuron Position',
    show=True,
    save_path=None
)

# Plot static energy landscape
energy_landscape_1d_static(
    data_sets={'u': (model.x, u_history[index]), 'stimlulus': (model.x, input_history[index])},
    config=config_static
)
../../../_images/zh_3_full_detail_tutorials_01_cann_modeling_03_analysis_visualization_7_0.png
[2]:
(<Figure size 1000x600 with 1 Axes>,
 <Axes: title={'center': 'Energy Landscape - Smooth Tracking'}, xlabel='Time Step', ylabel='Neuron Position'>)

该图显示了“波包”随时间的轨迹:x 轴为时间,y 轴为特征空间位置,颜色强度代表放电率。

2.3 能量景观(动画)

energy_landscape_1d_animation 生成动态动画,展示波包的演化过程:

[3]:
# Configure animation
config_anim = PlotConfigs.energy_landscape_1d_animation(
    time_steps_per_second=100,  # 100 time steps = 1 second of real time
    fps=20,                      # 20 frames per second
    title='Energy Landscape Animation',
    xlabel='Neuron Position',
    ylabel='Firing Rate',
    repeat=True,
    show=True,
    save_path=None  # Set to 'animation.gif' to save
)

# Generate animation
energy_landscape_1d_animation(
    data_sets={'u': (model.x, u_history), 'stimlulus': (model.x, input_history)},
    config=config_anim
)

动画呈现每个时间步的群体放电率分布,可视化波包如何在特征空间中移动。

动画参数: - time_steps_per_second: 每秒真实时间对应的模拟时间步数 - fps: 动画的每秒帧数 - repeat: 是否循环播放动画

2.4 光栅图

raster_plot 显示神经元的脉冲发放时间:

[4]:
from canns.analyzer.metrics.utils import firing_rate_to_spike_train

# Configure raster plot
config_raster = PlotConfigs.raster_plot(
    figsize=(10, 6),
    title='Raster Plot',
    xlabel='Time Step',
    ylabel='Neuron Index',
    show=True,
    save_path=None
)

# use u to generate spike train, because it has higher values
spike_train = firing_rate_to_spike_train(u_history, dt_spike=0.01, dt_rate=bm.get_dt())

# Plot raster
raster_plot(
    spike_train=spike_train,
    config=config_raster
)
../../../_images/zh_3_full_detail_tutorials_01_cann_modeling_03_analysis_visualization_11_0.png
[4]:
(<Figure size 1000x600 with 1 Axes>,
 <Axes: title={'center': 'Raster Plot'}, xlabel='Time Step', ylabel='Neuron Index'>)

每个点代表一个神经元在特定时刻的放电。该模式揭示了波包的空间结构及其时间演化。

2.5 平均放电率图

average_firing_rate_plot 显示群体平均放电率随时间的变化:

[5]:
# Configure average firing rate plot
config_avg = PlotConfigs.average_firing_rate_plot(
    figsize=(10, 4),
    title='Average Firing Rate',
    xlabel='Time (ms)',
    ylabel='Average Firing Rate',
    show=True,
    save_path=None
)

# Plot average firing rate
average_firing_rate_plot(
    spike_train=spike_train,
    dt=bm.get_dt(),
    config=config_avg
)
../../../_images/zh_3_full_detail_tutorials_01_cann_modeling_03_analysis_visualization_13_0.png
[5]:
(<Figure size 1000x400 with 1 Axes>,
 <Axes: title={'center': 'Average Firing Rate'}, xlabel='Neuron Index', ylabel='Average Firing Rate (Hz)'>)

该图展示网络在一段时间内的整体活动水平。

2.6 调谐曲线

tuning_curve 显示单个神经元对不同刺激位置的响应:

[6]:
# Configure tuning curve
config_tuning = PlotConfigs.tuning_curve(
    num_bins=50,          # Number of position bins
    pref_stim=model.x,    # Preferred stimuli for each neuron
    title='Tuning Curves of Selected Neurons',
    xlabel='Stimulus Position',
    ylabel='Average Firing Rate',
    show=True,
    save_path=None,
)

# Select neurons to plot
neuron_indices = [64, 128, 192]  # Left, center, right

# Plot tuning curves
tuning_curve(
    stimulus=task.Iext_sequence.squeeze(),
    firing_rates=r_history,
    neuron_indices=neuron_indices,
    config=config_tuning
)
../../../_images/zh_3_full_detail_tutorials_01_cann_modeling_03_analysis_visualization_15_0.png
[6]:
(<Figure size 1000x600 with 1 Axes>,
 <Axes: title={'center': 'Tuning Curves of Selected Neurons'}, xlabel='Stimulus Position', ylabel='Average Firing Rate'>)

调谐曲线揭示每个神经元的”偏好位置”——即引发最大响应的刺激位置。对于 CANN 模型,神经元通常具有以不同位置为中心的钟形调谐曲线。


3. 不同任务的能量景观

不同任务会产生特征性的能量景观模式。我们比较三种追踪任务:

3.1 PopulationCoding1D

群体编码展示了短暂刺激呈现后的记忆维持能力。

[7]:
from canns.task.tracking import PopulationCoding1D

model = CANN1D(num=256, tau=1.0, k=8.1, a=0.5, A=10, J0=4.0)

# Population coding task
task_pc = PopulationCoding1D(
    cann_instance=model,
    before_duration=10.0,
    after_duration=10.0,
    Iext=0.0,
    duration=20.0,
    time_step=bm.get_dt(),
)

# Get data and run simulation
task_pc.get_data()

u_pc, r_pc, inp_pc = bm.for_loop(run_step, operands=(task_pc.run_steps, task_pc.data), progress_bar=10)

# Visualize
config_anim = PlotConfigs.energy_landscape_1d_animation(
    time_steps_per_second=100,  # 100 time steps = 1 second of real time
    fps=20,                      # 20 frames per second
    title='Energy Landscape Animation - Population Coding',
    xlabel='Neuron Position',
    ylabel='Firing Rate',
    repeat=True,
    show=True,
    save_path=None  # Set to 'animation.gif' to save
)

# Generate animation
energy_landscape_1d_animation(
    data_sets={'u': (model.x, u_pc), 'stimlulus': (model.x, inp_pc)},
    config=config_anim
)
<PopulationCoding1D>Generating Task data(No For Loop)

特征模式: 波包在刺激呈现期间(中间部分)形成,并在刺激结束后仍保持在原位(右侧部分)。这体现了吸引子的稳定性与记忆维持能力。

3.2 TemplateMatching1D

模板匹配展示了从噪声输入中完成模式重建的能力。

[8]:
from canns.task.tracking import TemplateMatching1D

model = CANN1D(num=256, tau=1.0, k=8.1, a=0.5, A=10, J0=4.0)


# Template matching task
task_tm = TemplateMatching1D(
    cann_instance=model,
    Iext=1.0,
    duration=50.0,
    time_step=bm.get_dt(),
)

# Get data and run simulation
task_tm.get_data()

u_tm, r_tm, inp_tm = bm.for_loop(run_step, operands=(task_tm.run_steps, task_tm.data), progress_bar=10)

# Visualize
config_anim = PlotConfigs.energy_landscape_1d_animation(
    time_steps_per_second=100,  # 100 time steps = 1 second of real time
    fps=20,                      # 20 frames per second
    title='Energy Landscape Animation - Template Matching',
    xlabel='Neuron Position',
    ylabel='Firing Rate',
    repeat=True,
    show=True,
    save_path=None  # Set to 'animation.gif' to save
)

# Generate animation
energy_landscape_1d_animation(
    data_sets={'u': (model.x, u_tm), 'stimlulus': (model.x, inp_tm)},
    config=config_anim
)
<TemplateMatching1D>Generating Task data: 100%|██████████| 500/500 [00:00<00:00, 10877.85it/s]

特征模式: 初始的分散活动(噪声输入产生广泛而微弱的激活)收敛为一个尖锐的波包。这体现了吸引子通过收敛”清理”噪声输入的能力。

3.3 SmoothTracking1D

平滑追踪展示了波包跟随移动刺激的能力。

[9]:
from canns.task.tracking import SmoothTracking1D

model = CANN1D(num=256, tau=1.0, k=8.1, a=0.5, A=10, J0=4.0)


# Smooth tracking task
task_st = SmoothTracking1D(
    cann_instance=model,
    Iext=[-2.0, 2.0],
    duration=[50.0],
    time_step=bm.get_dt(),
)

# Get data and run simulation
task_st.get_data()

u_st, r_st, inp_st = bm.for_loop(run_step, operands=(task_st.run_steps, task_st.data), progress_bar=10)

# Visualize
config_anim = PlotConfigs.energy_landscape_1d_animation(
    time_steps_per_second=100,  # 100 time steps = 1 second of real time
    fps=20,                      # 20 frames per second
    title='Energy Landscape Animation - Smooth Tracking',
    xlabel='Neuron Position',
    ylabel='Firing Rate',
    repeat=True,
    show=True,
    save_path=None  # Set to 'animation.gif' to save
)

# Generate animation
energy_landscape_1d_animation(
    data_sets={'u': (model.x, u_st), 'stimlulus': (model.x, inp_st)},
    config=config_anim
)
<SmoothTracking1D> Generating Task data: 500it [00:00, 6982.24it/s]

特征模式: 波包平滑地从左向右移动,追踪运动刺激。这体现了吸引子在整合外部输入的同时保持稳定波包结构的能力。

3.4 对比总结

任务

输入模式

能量景观特征

演示能力

PopulationCoding

短暂刺激

波包形成并原地持续

记忆维持

TemplateMatching

噪声连续输入

分布式活动 → 尖锐波包

模式补全

SmoothTracking

运动刺激

波包平滑跟随轨迹

刺激追踪

这三种模式揭示了连续吸引子网络的三大核心计算能力:记忆去噪追踪


4. 2D 分析方法

对于 CANN2D 模型,分析器提供相应的 2D 可视化方法。PlotConfigs 模式在 2D 可视化中完全一致。

4.1 准备 CANN2D 模拟

[ ]:
from canns.models.basic import CANN2D
from canns.task.tracking import SmoothTracking2D
from canns.analyzer.visualization import (
    PlotConfigs,
    energy_landscape_2d_static,
    energy_landscape_2d_animation,
)

# Create 2D model
model_2d = CANN2D(
    length=32,      # 32x32 neuron grid
    tau=1.0,
    k=8.1,
    a=0.3,
    A=10,
    J0=4.0,
)

# Create 2D tracking task
# Move from (-1, -1) to (1, 1) to (-1, 1)
task_2d = SmoothTracking2D(
    cann_instance=model_2d,
    Iext=[(-1.0, -1.0), (1.0, 1.0), (-1.0, 1.0)],
    duration=[30.0, 30.0],
    time_step=0.1,
)

# Get data and run simulation
task_2d.get_data()

def run_step_2d(t, inp):
    model_2d.update(inp)
    return model_2d.u.value, model_2d.r.value

u_history_2d, r_history_2d = bm.for_loop(run_step_2d, operands=(task_2d.run_steps, task_2d.data), progress_bar=10)
<SmoothTracking2D> Generating Task data: 600it [00:00, 1153.29it/s]

4.2 能量景观 2D(静态)

[11]:
# Select a time point to visualize
time_idx = 300

# Configure 2D static landscape
config_2d_static = PlotConfigs.energy_landscape_2d_static(
    figsize=(8, 8),
    title=f'2D Energy Landscape at t={time_idx * 0.1:.1f}',
    xlabel='X Position',
    ylabel='Y Position',
    show=True,
    save_path=None
)

# Plot 2D energy landscape at specific time
energy_landscape_2d_static(
    z_data=u_history_2d[time_idx],
    config=config_2d_static
)
../../../_images/zh_3_full_detail_tutorials_01_cann_modeling_03_analysis_visualization_27_0.png
[11]:
(<Figure size 800x800 with 2 Axes>,
 <Axes: title={'center': '2D Energy Landscape at t=30.0'}, xlabel='X Position', ylabel='Y Position'>)

2D 静态图显示单个时间点的放电率空间分布,揭示二维波包结构。

4.3 能量景观 2D(动画)

[12]:
# Configure 2D animation
config_2d_anim = PlotConfigs.energy_landscape_2d_animation(
    time_steps_per_second=100,
    fps=20,
    figsize=(8, 8),
    title='2D Energy Landscape Animation',
    xlabel='X Position',
    ylabel='Y Position',
    repeat=True,
    show=True,
    save_path=None  # Set to 'animation_2d.gif' to save
)

# Generate 2D energy landscape animation
energy_landscape_2d_animation(
    zs_data=u_history_2d,
    config=config_2d_anim
)

2D 动画展示波包在二维特征空间中沿任务定义轨迹移动的过程。


5. 下一步

恭喜完成教程 3!您现已掌握: - 如何使用 PlotConfigs 实现统一的可视化配置 - CANNs 中所有主要的 1D 与 2D 可视化方法 - 不同任务如何产生特征性的能量景观模式 - 三大核心计算能力:记忆、去噪与追踪

继续学习

  • 下一步: 教程 4:参数效应——探索参数如何系统性影响模型行为

  • 高级应用: 继续学习教程 5-7,了解分层模型与类脑网络

关键要点

  1. PlotConfigs 模式: 始终使用 PlotConfigs.method_name() 创建配置,再传递给绘图函数

  2. 默认行为: 图表默认显示(show=True, save_path=None

  3. 数据集: 所有绘图函数均接受 data_sets 字典以支持灵活的数据输入

  4. 任务模式: 不同任务揭示吸引子的不同属性(稳定性、收敛性、追踪能力)