首页
/ Neuromatch Academy深度学习教程:从神经响应解码刺激信息

Neuromatch Academy深度学习教程:从神经响应解码刺激信息

2025-07-10 07:20:20作者:幸俭卉

教程目标

本教程将指导您使用深度学习技术从小鼠初级视觉皮层神经元的响应中解码刺激信息。具体来说,我们将分析约20,000个神经元对定向光栅刺激的响应数据,目标是构建一个能够从这些神经响应中预测刺激方向的深度学习模型。

通过本教程,您将学习:

  1. 使用PyTorch构建深度前馈神经网络
  2. 利用PyTorch内置损失函数评估网络输出
  3. 使用自动微分计算损失函数对网络参数的梯度
  4. 实现梯度下降优化网络参数

数据加载与预处理

数据来源

我们使用的数据来自Stringer等人(2019)的研究,记录了小鼠初级视觉皮层约20,000个神经元对不同方向光栅刺激的钙成像响应。这些数据已经过以下预处理:

  • 响应值相对于自发活动水平进行了归一化
  • 跨刺激进行了z-score标准化
  • 按刺激方向进行了分箱平均处理

数据加载

我们首先加载并准备数据:

# 加载数据
resp_all, stimuli_all = load_data('W3D4_stringer_oribinned1.npz')

# 将刺激方向转换为弧度(神经网络处理角度时通常使用弧度)
stimuli_all = stimuli_all * np.pi / 180

数据可视化

让我们先查看神经响应矩阵和几个神经元的调谐曲线:

# 绘制神经响应矩阵
fig, ax = plt.subplots(1, 1, figsize=(10, 5))
plot_data_matrix(resp_all, ax)
plt.title('Neural Response Matrix (stimuli × neurons)')

# 随机选择3个神经元绘制其调谐曲线
fig, axes = plt.subplots(1, 3, figsize=(15, 4))
neuron_indices = np.random.choice(resp_all.shape[1], 3, replace=False)
for i, ax in enumerate(axes):
    ax.plot(stimuli_all, resp_all[:, neuron_indices[i]])
    ax.set_xlabel('Stimulus orientation (rad)')
    ax.set_ylabel('Normalized response')
    ax.set_title(f'Neuron {neuron_indices[i]} tuning curve')
plt.tight_layout()

从调谐曲线可以看出,不同神经元对刺激方向的响应模式差异很大,这正是我们需要使用非线性方法进行解码的原因。

数据分割

我们将数据分为训练集和测试集:

# 设置随机种子保证可重复性
torch.manual_seed(42)

# 随机打乱数据
n_stimuli = resp_all.shape[0]
shuffled_indices = torch.randperm(n_stimuli)
resp_shuffled = resp_all[shuffled_indices]
stimuli_shuffled = stimuli_all[shuffled_indices]

# 80%训练集,20%测试集
split_idx = int(0.8 * n_stimuli)
train_data = resp_shuffled[:split_idx]
train_labels = stimuli_shuffled[:split_idx]
test_data = resp_shuffled[split_idx:]
test_labels = stimuli_shuffled[split_idx:]

构建解码模型

网络架构

我们将构建一个具有一个隐藏层的全连接神经网络:

  1. 输入层:神经元数量等于记录到的神经元数量(~20,000)
  2. 隐藏层:512个神经元,使用ReLU激活函数
  3. 输出层:1个神经元(预测的刺激方向),不使用激活函数(回归任务)
class OrientationDecoder(nn.Module):
    def __init__(self, n_neurons, hidden_size=512):
        super().__init__()
        self.fc1 = nn.Linear(n_neurons, hidden_size)  # 输入层到隐藏层
        self.fc2 = nn.Linear(hidden_size, 1)         # 隐藏层到输出层
        
    def forward(self, x):
        x = torch.relu(self.fc1(x))  # ReLU激活函数
        x = self.fc2(x)              # 输出层不使用激活函数
        return x

模型初始化

n_neurons = resp_all.shape[1]
model = OrientationDecoder(n_neurons)

训练模型

训练设置

# 损失函数 - 均方误差
criterion = nn.MSELoss()

# 优化器 - Adam
optimizer = optim.Adam(model.parameters(), lr=0.001)

# 训练参数
n_epochs = 50
batch_size = 32

训练循环

train_losses = []

for epoch in range(n_epochs):
    epoch_loss = 0
    for _ in range(len(train_data) // batch_size):
        # 获取小批量数据
        r, ori = get_data(batch_size, train_data, train_labels)
        
        # 前向传播
        outputs = model(r)
        loss = criterion(outputs, ori)
        
        # 反向传播和优化
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        
        epoch_loss += loss.item()
    
    # 记录平均损失
    avg_loss = epoch_loss / (len(train_data) // batch_size)
    train_losses.append(avg_loss)
    print(f'Epoch [{epoch+1}/{n_epochs}], Loss: {avg_loss:.4f}')

# 绘制训练损失曲线
plt.plot(train_losses)
plt.xlabel('Epoch')
plt.ylabel('Mean Squared Error')
plt.title('Training Loss')
plt.show()

模型评估

测试集性能

with torch.no_grad():
    test_outputs = model(test_data)
    test_loss = criterion(test_outputs, test_labels)
    print(f'Test MSE: {test_loss.item():.4f}')
    
    # 计算预测角度与真实角度的相关性
    corr = np.corrcoef(test_outputs.squeeze().numpy(), 
                      test_labels.squeeze().numpy())[0, 1]
    print(f'Correlation between predicted and true orientations: {corr:.3f}')

可视化预测结果

plt.scatter(test_labels.numpy(), test_outputs.numpy(), alpha=0.3)
plt.xlabel('True Orientation (rad)')
plt.ylabel('Predicted Orientation (rad)')
plt.title('Prediction vs Ground Truth')
plt.plot([-np.pi, np.pi], [-np.pi, np.pi], 'r--')  # 对角线
plt.show()

讨论与改进方向

  1. 模型性能分析

    • 观察训练损失曲线,判断模型是否收敛
    • 检查测试集性能,评估模型泛化能力
    • 分析预测值与真实值的相关性
  2. 可能的改进方向

    • 调整网络架构(增加层数、改变隐藏单元数量)
    • 尝试不同的激活函数
    • 使用学习率调度器
    • 增加正则化技术(如Dropout、权重衰减)
    • 对角度预测使用周期性损失函数(如余弦相似度)
  3. 神经科学意义

    • 成功的解码表明神经活动确实包含关于刺激方向的信息
    • 解码性能可以量化信息量
    • 可以分析网络学到的特征,理解神经编码策略

总结

本教程展示了如何使用深度学习从小鼠视觉皮层神经活动中解码刺激方向。我们构建了一个简单的全连接网络,并展示了完整的训练和评估流程。这种方法可以扩展到其他神经解码问题,为理解神经信息处理提供了有力工具。

通过调整模型架构和训练参数,您可以进一步探索如何优化解码性能,这有助于更深入地理解神经表征的性质和信息编码机制。