# 时间驱动：编码器

## 编码器基类

spikingjelly.clock_driven.encoding 中，存在2个基类编码器：

def forward(self, x: torch.Tensor):
if self.spike is None:
self.encode(x)

t = self.t
self.t += 1
if self.t >= self.T:
self.t = 0
return self.spike[t]


## 泊松编码器

import torch
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from PIL import Image
from spikingjelly.clock_driven import encoding
from spikingjelly import visualizing

# 读入lena图像
lena_img = np.array(Image.open('lena512.bmp')) / 255
x = torch.from_numpy(lena_img)

pe = encoding.PoissonEncoder()

# 仿真20个时间步长，将图像编码为脉冲矩阵并输出
w, h = x.shape
out_spike = torch.full((20, w, h), 0, dtype=torch.bool)
T = 20
for t in range(T):
out_spike[t] = pe(x)

plt.figure()
plt.imshow(x, cmap='gray')
plt.axis('off')

visualizing.plot_2d_spiking_feature_map(out_spike.float().numpy(), 4, 5, 30, 'PoissonEncoder')
plt.axis('off')
plt.show()


lena原灰度图和编码后20个脉冲矩阵如下：

# 仿真512个时间不长，将编码的脉冲矩阵逐次叠加，得到第1、128、256、384、512次叠加的结果并输出
superposition = torch.full((w, h), 0, dtype=torch.float)
superposition_ = torch.full((5, w, h), 0, dtype=torch.float)
T = 512
for t in range(T):
superposition += pe(x).float()
if t == 0 or t == 127 or t == 255 or t == 387 or t == 511:
superposition_[int((t + 1) / 128)] = superposition

# 归一化
for i in range(5):
min_ = superposition_[i].min()
max_ = superposition_[i].max()
superposition_[i] = (superposition_[i] - min_) / (max_ - min_)

# 画图
visualizing.plot_2d_spiking_feature_map(superposition_.numpy(), 1, 5, 30, 'PoissonEncoder')
plt.axis('off')

plt.show()


## 周期编码器

class PeriodicEncoder(BaseEncoder):
def __init__(self, spike: torch.Tensor):
super().__init__(spike.shape[0])
self.encode(spike)
def encode(self, spike: torch.Tensor):
self.spike = spike
self.T = spike.shape[0]


spike = torch.full((5, 3), 0)
spike[1, 0] = 1
spike[0, 1] = 1
spike[4, 2] = 1

pe = encoding.PeriodicEncoder(spike)

# 输出周期性编码器的编码结果
out_spike = torch.full((20, 3), 0)
for t in range(out_spike.shape[0]):
out_spike[t] = pe(spike)

visualizing.plot_1d_spikes(out_spike.float().numpy(), 'PeriodicEncoder', 'Simulating Step', 'Neuron Index',
plot_firing_rate=False)
plt.show()


## 延迟编码器

$t_f(x) = (T - 1)(1 - x)$

$t_f(x) = (T - 1) - ln(\alpha * x + 1)$

$(T - 1) - ln(\alpha * 1 + 1) = 0$

$\alpha = e^{T - 1} - 1$

$$\alpha$$ 会随着 $$T$$ 增大而指数增长，最终造成溢出。

import torch
import matplotlib.pyplot as plt
from spikingjelly.clock_driven import encoding
from spikingjelly import visualizing

# 随机生成6个神经元的刺激强度，设定最大脉冲时间为20
N = 6
x = torch.rand([N])
T = 20

# 将输入数据编码为脉冲序列
le = encoding.LatencyEncoder(T)

# 输出延迟编码器的编码结果
out_spike = torch.zeros([T, N])
for t in range(T):
out_spike[t] = le(x)

print(x)
visualizing.plot_1d_spikes(out_spike.numpy(), 'LatencyEncoder', 'Simulating Step', 'Neuron Index',
plot_firing_rate=False)
plt.show()


## 带权相位编码器

Phase (K=8)

1

2

3

4

5

6

7

8

Spike weight $$\omega(t)$$

2-1

2-2

2-3

2-4

2-5

2-6

2-7

2-8

192/256

1

1

0

0

0

0

0

0

1/256

0

0

0

0

0

0

0

1

128/256

1

0

0

0

0

0

0

0

255/256

1

1

1

1

1

1

1

1

1

Kim J, Kim H, Huh S, et al. Deep neural networks with weighted spikes[J]. Neurocomputing, 2018, 311: 373-386.