HFirst解读和复现心得

首先提供paper源码工具包的链接。
文章要点:事件相机输入、高斯核和赢者通吃(先到先赢)的池化方法。2020年AAAI上一篇文章:Effective AER Object Classification Using Segmented Probability-Maximization Learning in Spiking Neural Networks 前面的步骤也是这样,后面主要是训练部分提出了新方法。

首先介绍事件相机发放的示意图:
事件相机发放示意图
从图中可以看出log(I)变化超过阈值时才发放对应的脉冲。
并且,由公式: d I ( u , v , t ) d t = − d I ( u , v , t ) d u d u d t − d I ( u , v , t ) d v d v d t (1) \frac{d I(u, v, t)}{d t}=-\frac{d I(u, v, t)}{d u} \frac{d u}{d t}-\frac{d I(u, v, t)}{d v} \frac{d v}{d t} \tag{1} dtdI(u,v,t)=dudI(u,v,t)dtdudvdI(u,v,t)dtdv(1)
可推断,在横纵坐标u,v变化较大的地方发放的脉冲比较多,由此来检验事件的边缘。

然后介绍神经元模型。
这里我们约定所有的参数使用整数,模型公式可以这样表达:
 if  t i − t lastspike < t refr then  V m i ← V m i − 1 e l s e V m i ← { max ⁡ { V m i − 1 − I L C m ( t i − t i − 1 ) , 0 }  if  V m i − 1 ≥ 0 min ⁡ { V m i − 1 + I l C m ( t i − t i − 1 ) , 0 }  if  V m i − 1 < 0 V m i ← V m i + ω i e n d i f \begin{array}{l} \text { if } t_{i}-t_{\text {lastspike}}<t_{\text {refr}} \\ \text {then } \\ \qquad V m_{i} \leftarrow V m_{i-1} \end{array}\\ else \\ V m_{i} \leftarrow\left\{\begin{array}{ll}\max \left\{V m_{i-1}-\frac{I_{L}}{C_{m}}\left(t_{i}-t_{i-1}\right), 0\right\} & \text { if } V m_{i-1} \geq 0 \\ \min \left\{V m_{i-1}+\frac{I_{l}}{C_{m}}\left(t_{i}-t_{i-1}\right), 0\right\} & \text { if } V m_{i-1}<0\end{array}\right.\\ V m_{i} \leftarrow V m_{i}+\omega_{i}\\ end if  if titlastspike<trefrthen VmiVmi1elseVmimax{Vmi1CmIL(titi1),0}min{Vmi1+CmIl(titi1),0} if Vmi10 if Vmi1<0VmiVmi+ωiendif
i f V m i ≥ V t h r e s h t h e n V m i ← 0 t lastspike ← t i D o ( G e n e r a t e O u t p u t S p i k e ) e n d i f if V m_{i} \geq V_{t h r e s h}\\ then\\ V m_{i} \leftarrow 0\\ t_{\text {lastspike}} \leftarrow t_{i}\\ Do(Generate Output Spike) \\ end if ifVmiVthreshthenVmi0tlastspiketiDo(GenerateOutputSpike)endif

作者在源码中有注释,这样做有问题,但是效果更好。
我提出自己的想法:
1、这里没有采用负阈值。 V m i V_{m_i} Vmi直接加上的 w w w,而没有管事件的极性。(这一点应该是作者实验发现这样效果更好,虽然不符合理论推断,在源码中也可以看到并没有用上p,而是把正负数据输入然后再合并,感觉可能是提高了点火率所以效果更好)
2、复位操作15年这里还是减法和归零并存,文章中有陈述其他人有用减法,但是作者用的归零,目前而言已经普遍采用减法。20年还有一篇CVPR讲述的用减法做转换会更好。也可以看一下。(RMP-SNN: Residual Membrane Potential Neuron for Enabling Deeper High-Accuracy and Low-Latency Spiking Neural Network)
在这里插入图片描述

3、作者提到的横向抑制如上图,主要是类似于池化操作,即当前脉冲发放后给相邻脉冲的上次发放时间更新一下(这个操作感觉可以改),在图中有给相邻的电势置零的操作但是公式里只有更新最近发放时间。

然后是最大池化,选择的是先到者最大的方法,并且赢者通吃,即池化中选最先到的脉冲。(这里主要考虑的是未必就要把附近的都归零,因为脉冲点火率本来就低,信息浓缩的特别快,深层网络很难传递信号过去,感觉前面还是别降这么快)

接着作者分析了高斯核的反应,得到结论和运动方向夹角90°时电势变化较大。所谓的高斯核就是如下公式: F θ ( u , v ) = e ( − u 0 2 + γ 2 v 0 2 2 σ 2 ) cos ⁡ ( 2 π λ u 0 ) u 0 = u cos ⁡ θ + v sin ⁡ θ v 0 = − u sin ⁡ θ + v cos ⁡ θ (2) \begin{aligned} F_{\theta}(u, v) &=e^{\left(-\frac{u_{0}^{2}+\gamma^{2} v_{0}^{2}}{2 \sigma^{2}}\right)} \cos \left(\frac{2 \pi}{\lambda} u_{0}\right) \\ u_{0} &=u \cos \theta+v \sin \theta \\ v_{0} &=-u \sin \theta+v \cos \theta \end{aligned} \tag{2} Fθ(u,v)u0v0=e(2σ2u02+γ2v02)cos(λ2πu0)=ucosθ+vsinθ=usinθ+vcosθ(2)
其中 θ \theta θ从0°-165°,每次增加15°,共12个角度,也就是用它来提取12个角度的方向特征。看起来是经典操作了,参数也不用训练,用这个公式算就行了,其中的u,v这里用的是高斯核的相对位置。

接着介绍网络结构,示意图如下:
在这里插入图片描述
在这里插入图片描述
I l / C m I_l/C_m Il/Cm指的是衰减系数。
对于S1层:输入大小和S1大小一样,卷积核采用的策略其实是stride=1,padding=SAME的策略,单个事件过来后,会对S1的KernelSize * KernelSize这么多个神经元产生影响,把符合条件(没有超出边框,不在不应期)的找出来,更新电势,再看发不发放脉冲即可。
对于C1层,核是4x4,no padding, stride=4,即直接16对1,通过横向抑制采取先到通吃的策略,作者还加了一句这样也可以减少脉冲发放并且避免单个C1直接激活S2,但是目前来说脉冲是努力提高点火率的。
接着是S2层,C2层作者说是可有可无的,S2的连接系数是训练的,但是具体训练作者没提,代码也很简单。上面AER那篇也是后面接一层输出层,训练这一层。
训练前后代码如下:
`%load the C1 results
load(output_filename);

%initialize a filter
S2_Filter_temp = zeros(1,1);

%figure out what the filter size should be and increase the S2 size accordingly
max_x = max(C1out.x);
max_y = max(C1out.y);
max_p = max(C1out.p);
[S2FilterTemp_Sizey, S2FilterTemp_Sizex, S2FilterTemp_Sizep, ~] = size(S2_Filter_temp);
S2_Filter_temp = padarray(S2_Filter_temp, [max(max_y - S2FilterTemp_Sizey,0), max(max_x - S2FilterTemp_Sizex,0), max(max_p - S2FilterTemp_Sizep,0)], ‘post’);
%count the C1 spikes at each location
for eventNumber = 1:length(C1out.ts)
S2_Filter_temp(C1out.y(eventNumber), C1out.x(eventNumber), C1out.p(eventNumber)) = S2_Filter_temp(C1out.y(eventNumber), C1out.x(eventNumber), C1out.p(eventNumber))+1;
end
%normalize the filter
S2_Filter_temp = 100*S2_Filter_temp./sqrt(sum(sum(sum(S2_Filter_temp.^2)))); %set norm to 100
S2_Filters = S2_Filter_temp;
S2_Filters(S2_Filters == 0) = -1; %small inhibitory value
save(filter_filename, ‘S2_Filters’); %save the filter`

相当于是计数再归一化正则化啥的当权重了。
然后训练出来的权重就如下图:
在这里插入图片描述
颜色越深表明权重越大,右边是对应值的大小。

分类结果可以用谁的脉冲最多来决定。

最后作者在FPGA上实现,值得一提的是,为了实现,作者并没有img_size * img_size * num_orientations这么多个状态(最后一次发放时间,最后一次更新状态时间),只保持了img_size * img_size的大小,主要为了节约内存大小,由于计算量小,内存大小决定了固定FPGA板子上能放多大的网络,同时这也可以解释为对每个通道上的状态进行横向更新统一了。然后就分析了计算量,速度,功耗等。最后在poker和character上做了测试。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值