与ANN能够直接接收图像的像素值不同,SNN的输入是异步脉冲序列。因此将二维图像输入SNN之前,需要对图像进行脉冲化。常用的一种脉冲化方法为泊松编码。
一、原理
泊松编码:将输入数据编码为发放次数分布符合泊松过程的脉冲序列
对于二维图像,每一个像素都能生成相互独立的泊松编码:
- 预先设定总时间 T;
- 每一个时间步,每一个像素产生脉冲的概率与该像素值成比例;
- 执行 T个时间步,分别得到各个像素对应的脉冲序列;
- 将每个像素产生的脉冲序列输入到对应神经元 / SNN输入层异步接收到各个像素的脉冲。
理解:
- 根据像素值设定每个时间步产生脉冲的概率,模拟一段时间,得到脉冲序列;
- 这段时间内可能产生的脉冲数量符合泊松分布 / 该脉冲产生过程是泊松过程;
- 这段时间平均脉冲发放数对应泊松分布公式中的
;
- 通过将多个时间步的脉冲矩阵叠加,可以还原出原图像。

二、实例
测试代码实现了PNG图像的泊松编码(这里仅对RGB三通道进行了脉冲化)。
import numpy as np
from PIL import Image
image = Image.open('PIC/WOODSTOCK.png')
data_ori = np.array(image) # original
print('SHAPE:', data_ori.shape)
x = data_ori.shape[0]
y = data_ori.shape[1]
data_pro = data_ori.astype('float')[:] # probability
data_new = data_ori[:] # reconducted
frames_new = [] # to gif
data_poisson = data_ori.tolist() # code
for i in range(x):
for j in range(y):
for k in range(3):
data_poisson[i][j][k] = ''
t_simu = 255
# probability matrix
for row in data_pro:
for pixel in row:
pixel[:3] /= 255
# generate poisson code
for t in range(t_simu):
print('Proccessing %d/%d' % (t+1, t_simu))
for i in range(x):
for j in range(y):
for k in range(3):
if np.random.random() < data_pro[i][j][k]:
data_poisson[i][j][k] += '1'
else:
data_poisson[i][j][k] += '0'
# add temporary png to gif
if not (t % 15):
for i in range(x):
for j in range(y):
for k in range(3):
data_new[i][j][k] = data_poisson[i][j][k].count('1')
Image.fromarray(data_new).save('temp/temp_%d.png' % t)
frames_new.append(Image.open('temp/temp_%d.png' % t))
# output poisson code
with open('Poison.out', 'w') as file:
for i in range(x):
for j in range(y):
for k in range(3):
file.write(data_poisson[i][j][k] + '\n')
data_new[i][j][k] = data_poisson[i][j][k].count('1')
file.write('\n')
img = Image.fromarray(data_new)
img.save('reconduct.png')
frames_new[0].save('reconduct.gif', save_all=True, append_images=frames_new, duration=500, loop=1)
该实例中,首先将像素值归一化作为脉冲发放概率,模拟255个时间步,每个像素各个通道产生的泊松编码保存在文件Poisson.out中。

重建图像reconduct.png能够较准确地还原图像,说明得到的编码较好地保留了原图像信息;reconduct.gif复现了编码过程中不同时间步下的重建图像。