Bindsnet是一个基于pytorch实现的用于搭建SNN的框架。
关于网络构建:
(1)首先初始化一个网络:
import torch
import matplotlib.pyplot as plt
from bindsnet.network import Network, nodes, topology, monitors
#初始化一个网络
network = Network(dt=1.0)
(2)定义层,以及层与层之间的连接(其中moitor用于记录网络运行过程中各层的电压和脉冲)
X = nodes.Input(100) #输入层
Y = nodes.LIFNodes(100) #LiF神经元层
C = topology.Connection(source=X, target=Y, w = torch.rand(X.n, Y.n)#这边的n就是X和Y的维度
(3)将上述组件添加进网络
network.add_layer(layer=X, name='X')
network.add_layer(layer=Y, name='Y')
network.add_connection(connection=C, source='X', target='Y')
network.add_monitor(monitor=M1, name='X')
network.add_monitor(monitor=M2, name='Y')
(4)构建输入,运行网络
data = 15 * torch.rand(100)#随机输入
train = encoding.poisson(datum=data, time=5000)#possion编码,时间长度为5000
inputs = {'X' : train}
network.run(inputs=inputs, time=5000)#开始跑这个网络
spikes = {'X' : M1.get('s'), 'Y' : M2.get('s')}#得到输入层以及输出层的spike
对于BindsNet搭建的SNN的输入,与pytroch实现的ANN类似,但是在定义Dataset类时增加了输入样本和标签的脉冲编码(以手动下载MNIST数据集为例):
#定义函数用于加载原始数据
def load_data(data_folder, data_name, label_name):
"""
data_folder: 文件目录
data_name: 数据文件名
label_name:标签数据文件名
"""
with gzip.open(os.path.join(data_folder,label_name), 'rb') as lbpath: # rb表示的是读取二进制数据
y_train = np.frombuffer(lbpath.read(), np.uint8, offset=8)
with gzip.open(os.path.join(data_folder,data_name), 'rb') as imgpath:
x_train = np.frombuffer(
imgpath.read(), np.uint8, offset=16).reshape(len(y_train), 28, 28)
return (x_train, y_train)
#定义可以加载脉冲序列的类
class MNIST_Encode_Dataset(Dataset):
def __init__(self, folder, data_name, label_name,transform=None,image_encoder=None,label_encoder=None):
(train_set, train_labels) = load_data(folder, data_name, label_name) # 其实也可以直接使用torch.load(),读取之后的结果为torch.Tensor形式
self.train_set = train_set
self.train_labels = train_labels
self.transform = transform
if image_encoder is None:
image_encoder=NullEncoder()
if label_encoder is None:
label_encoder=NullEncoder()
self.image_encoder=image_encoder
self.label_encoder=label_encoder
def __getitem__(self, index):
image, label = self.train_set[index], int(self.train_labels[index])
if self.transform is not None:
image = self.transform(image)
output = {
"image": image,
"label": label,
"encoded_image": self.image_encoder(image),
"encoded_label": self.label_encoder(label),
}
return output
def __len__(self):
return len(self.train_set)
encode_train = MNIST_Encode_Dataset('/MNIST', "train-images-idx3-ubyte.gz","train-labels-idx1-ubyte.gz",
transform=transforms.Compose([transforms.ToTensor(),transforms.Lambda(lambda x: x * intensity)]),image_encoder=PoissonEncoder(time=50, dt=1),label_encoder=None)
dataloader = torch.utils.data.DataLoader(
encode_train, batch_size=batch_size, shuffle=True, num_workers=16, pin_memory=gpu
)