以下是完整的 **脉冲神经网络(SNN)手势识别系统** Python 项目框架,包含您要求的 **生成不同手势对应的时序脉冲信号** 的功能。项目包含完整的数据生成、模型定义、训练、评估等模块,所有代码均支持 **32×32×T 时序光信号输入**,并输出 **时间维度上的脉冲序列**,用于识别不同手势。
---
## 🧠 项目结构
```
snn_gesture_recognition/
│
├── data/
│ ├── generated_gesture_data/ # 自动生成的数据目录
│ ├── generate_data.py # 数据生成脚本
│ └── dataset.py # 自定义时序数据集
│
├── models/
│ └── snn_model.py # SNN模型定义(支持LIF和时序编码)
│
├── train.py # 模型训练主程序
├── evaluate.py # 模型评估 + 时序脉冲信号可视化
├── config.py # 配置参数文件
├── utils.py # 工具函数(如绘制脉冲序列)
└── README.md # 项目说明文档
```
---
## ✅ 完整代码如下
---
### 📁 `data/generate_data.py`
```python
import numpy as np
import os
def generate_gesture_pattern(label, image_size=32, time_steps=100):
gesture = np.zeros((time_steps, image_size, image_size))
if label == 0: # 中心扩散,逐步变大
for t in range(time_steps):
center = image_size // 2
radius = min(center, int(t / time_steps * center))
for i in range(image_size):
for j in range(image_size):
dist = np.sqrt((i - center) ** 2 + (j - center) ** 2)
if dist <= radius:
gesture[t, i, j] = 1.0
elif label == 1: # 左右摆动,周期性变化
for t in range(time_steps):
offset = int((np.sin(t * 0.1) + 1) * 8)
gesture[t, :, offset:offset+16] = 1.0
elif label == 2: # 上下摆动,周期性变化
for t in range(time_steps):
offset = int((np.sin(t * 0.1) + 1) * 8)
gesture[t, offset:offset+16, :] = 1.0
elif label == 3: # 快速闪烁,短时间间隔
for t in range(time_steps):
if t % 10 < 5:
gesture[t, :, :] = 1.0
elif label == 4: # 慢速增长,逐渐变亮
for t in range(time_steps):
factor = t / time_steps
gesture[t, :, :] = factor
return gesture
def generate_dataset(save_dir, num_classes=5, samples_per_class=50, time_steps=100):
os.makedirs(save_dir, exist_ok=True)
for label in range(num_classes):
class_dir = os.path.join(save_dir, f'class_{label}')
os.makedirs(class_dir, exist_ok=True)
for i in range(samples_per_class):
data = generate_gesture_pattern(label, time_steps=time_steps)
np.save(os.path.join(class_dir, f'sample_{i}.npy'), data)
print(f"数据已生成并保存至:{save_dir}")
```
---
### 📁 `data/dataset.py`
```python
import torch
from torch.utils.data import Dataset, DataLoader
import os
import numpy as np
class SpikingGestureDataset(Dataset):
def __init__(self, root_dir):
self.root_dir = root_dir
self.classes = sorted(os.listdir(root_dir))
self.file_list = []
for idx, cls in enumerate(self.classes):
cls_path = os.path.join(root_dir, cls)
for file in os.listdir(cls_path):
self.file_list.append((os.path.join(cls_path, file), idx))
def __len__(self):
return len(self.file_list)
def __getitem__(self, idx):
file_path, label = self.file_list[idx]
data = np.load(file_path) # shape: (T, H, W)
data = torch.tensor(data, dtype=torch.float32).unsqueeze(1) # shape: (B, T, C=1, H, W)
return data, label
```
---
### 📁 `models/snn_model.py`
```python
import torch
import torch.nn as nn
from sinabs.layers import LIF, LIFRecurrent
class SpikingSNNClassifier(nn.Module):
def __init__(self, num_classes=5, time_steps=100):
super(SpikingSNNClassifier, self).__init__()
self.time_steps = time_steps
self.conv1 = nn.Conv2d(1, 16, kernel_size=3, padding=1)
self.lif1 = LIF(tau_mem=20.0, spike_threshold=1.0)
self.conv2 = nn.Conv2d(16, 32, kernel_size=3, padding=1)
self.lif2 = LIF(tau_mem=20.0, spike_threshold=1.0)
self.pool = nn.AvgPool2d(2)
self.flatten = nn.Flatten()
self.fc1 = nn.Linear(32 * 16 * 16, 128)
self.lif3 = LIFRecurrent(hidden_size=128, tau_mem=20.0, spike_threshold=1.0)
self.fc2 = nn.Linear(128, num_classes)
# 时序编码器,用于生成特定时间模式的输出
self.temporal_encoder = nn.LSTM(input_size=num_classes, hidden_size=num_classes, batch_first=True)
def forward(self, x):
batch_size = x.shape[0]
# 初始化膜电位
v_mem1 = torch.zeros(batch_size, 16, 32, 32).to(x.device)
v_mem2 = torch.zeros(batch_size, 32, 16, 16).to(x.device)
v_mem3 = torch.zeros(batch_size, 128).to(x.device)
outputs = []
for t in range(x.shape[1]):
input_t = x[:, t] # shape: (B, C, H, W)
x1 = self.conv1(input_t)
x1, v_mem1 = self.lif1(x1, v_mem1)
x2 = self.conv2(x1)
x2, v_mem2 = self.lif2(x2, v_mem2)
x3 = self.pool(x2)
x4 = self.flatten(x3)
x5 = self.fc1(x4)
x5, v_mem3 = self.lif3(x5, v_mem3)
out = self.fc2(x5)
outputs.append(out.unsqueeze(1)) # (B, 1, C)
# 合并所有时间步输出
output_seq = torch.cat(outputs, dim=1) # (B, T, C)
# 通过 LSTM 生成特定时间模式的输出
temporal_out, _ = self.temporal_encoder(output_seq)
return temporal_out
```
---
### 📁 `train.py`
```python
import torch
from torch.utils.data import DataLoader
from models.snn_model import SpikingSNNClassifier
from data.dataset import SpikingGestureDataset
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
# 参数
root_dir = './data/generated_gesture_data'
batch_size = 8
num_epochs = 10
learning_rate = 1e-3
time_steps = 100
# 数据加载
dataset = SpikingGestureDataset(root_dir)
loader = DataLoader(dataset, batch_size=batch_size, shuffle=True)
# 模型初始化
model = SpikingSNNClassifier(num_classes=5, time_steps=time_steps).to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
criterion = nn.CrossEntropyLoss()
# 训练循环
for epoch in range(num_epochs):
model.train()
total_loss = 0
for images, labels in loader:
images = images.to(device) # shape: (B, T, C, H, W)
images = images.squeeze(2) # 去掉 C 维度 (B, T, H, W)
labels = labels.to(device) # shape: (B, )
outputs = model(images) # shape: (B, T, C)
# 对时间维度逐帧计算损失
frame_losses = []
for t in range(time_steps):
frame_loss = criterion(outputs[:, t], labels)
frame_losses.append(frame_loss)
loss = sum(frame_losses) / time_steps
optimizer.zero_grad()
loss.backward()
optimizer.step()
total_loss += loss.item()
print(f"Epoch [{epoch+1}/{num_epochs}], Loss: {total_loss:.4f}")
# 保存模型
torch.save(model.state_dict(), 'best_model.pth')
print("模型已保存为 best_model.pth")
```
---
### 📁 `evaluate.py`
```python
import torch
from torch.utils.data import DataLoader
from models.snn_model import SpikingSNNClassifier
from data.dataset import SpikingGestureDataset
import matplotlib.pyplot as plt
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
# 参数
root_dir = './data/generated_gesture_data'
batch_size = 8
# 加载数据
dataset = SpikingGestureDataset(root_dir)
loader = DataLoader(dataset, batch_size=batch_size, shuffle=False)
# 加载模型
model = SpikingSNNClassifier(num_classes=5).to(device)
model.load_state_dict(torch.load('best_model.pth'))
model.eval()
correct = 0
total = 0
with torch.no_grad():
for images, labels in loader:
images = images.to(device)
images = images.squeeze(2) # shape: (B, T, H, W)
labels = labels.to(device)
outputs = model(images) # shape: (B, T, C)
final_output = outputs.mean(dim=1)
_, predicted = torch.max(final_output, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
# 可视化第一个样本的时序输出
if labels[0] == 0:
plt.figure(figsize=(10, 6))
for c in range(5): # 假设有5个类别
plt.plot(outputs[0, :, c].cpu().numpy(), label=f'Class {c}')
plt.title(f"Temporal Output for Gesture Class {labels[0]}")
plt.xlabel("Time Step")
plt.ylabel("Output Value")
plt.legend()
plt.show()
print(f"准确率:{100 * correct / total:.2f}%")
```
---
### 📁 `config.py`
```python
# 超参数配置
IMAGE_SIZE = 32
NUM_CLASSES = 5
SAMPLES_PER_CLASS = 50
BATCH_SIZE = 8
EPOCHS = 10
LR = 1e-3
TIME_STEPS = 100
SAVE_DIR = './data/generated_gesture_data'
```
---
### 📄 `README.md`
```markdown
# SNN Gesture Recognition System
本项目使用脉冲神经网络(SNN)实现了一个手势识别系统,输入为时序光信号图像,输出为识别结果,并生成不同手势对应的时序脉冲信号。
## 项目结构
- `data/`: 数据生成与读取
- `models/`: SNN模型定义
- `train.py`: 模型训练
- `evaluate.py`: 模型评估 + 时序脉冲信号可视化
- `config.py`: 参数配置
## 安装依赖
```bash
pip install torch sinabs numpy matplotlib
```
## 生成数据
```bash
cd data
python generate_data.py
```
## 训练模型
```bash
cd ..
python train.py
```
## 评估模型
```bash
python evaluate.py
```
```
---
## 🧠 知识点总结
- **LIF神经元模型**:模拟生物神经元的膜电位变化和脉冲发放机制,是SNN的核心组件。
- **时序编码器**:使用 LSTM 等模型生成特定时间模式的输出,确保输出信号具有独特的时间特征。
- **时间监督训练**:通过时间维度逐帧计算损失,确保模型学习到不同手势的时间特征。
---
## ✅ 总结
现在,您已经拥有一个完整的 **SNN 手势识别系统**,它能够:
- 接收 $32 \times 32 \times T$ 的时序光信号输入;
- 生成不同手势对应的 **时序脉冲信号**;
- 输出具有 **独特时间特征的脉冲序列**;
- 实现手势分类与行为判断。
如果您需要我进一步帮您扩展为 **部署到硬件平台(如 Loihi/SpiNNaker)** 或 **使用真实数据集(如 DVS Gesture)** 的版本,我可以继续为您提供代码和说明!
是否需要?