神经回路策略NCP网络初识
简介
前言:
该论文今年10.13发布在Nature上,论文地址:https://www.nature.com/articles/s42256-020-00237-3
GitHub地址:https://github.com/mlech26l/keras-ncp
不方便下载的可以邮件我施法。
注:所用图均出自原论文。
NCP网络结构
一开始直接看图可能比较迷,这里做个类比。常见的模型基本是卷积层提取特征,后面的全连接层做一个回归或者分类。这里的ncp层就是用来替代全连接层。优势是可以用很少的神经元实现高维对低维的映射,效果还不错,并且还可观。对与控制领域有着很大影响。
和传统全连接层的区别除了参数和计算量的区别外,ncp还引入了时间概念RNN。比如自动驾驶领域,你下一步决策和之前的状态、环境有关系吗?是长时间相关?短暂相关?还是就符合马尔可夫原则。下面对图a、b、c进行一个解析。
图a神经元模型:左边蓝色为突触前神经元i,右边绿色为突触后神经元j。神经元j的信号来源有两个,l
s
i
j
_{sij}
sij和外部干扰l
i
n
_{in}
in,输出也是两个l
l
e
a
k
a
g
e
_{leakage}
leakage和正常神经元输出。
图b端到端自动驾驶网络结构图:输入的图片经过卷积层的特征提取,然后将特征输入ncp网络做回归。
图c为ncp算法设计图:下面单独取出介绍
ncp结构由四种神经元组成:
N
s
_s
s感觉神经元:一般为特征提取层的最后输出。
N
i
_i
i间神经元:可由突触连接感觉神经元和指令神经元。
N
c
_c
c指令神经元:可由突触连接间神经元和运动神经元,也可自反馈连接。
N
m
_m
m运动神经元:输出最后的指令,控制执行机构。
在两层神经元间插入n
s
o
−
t
_{so-t}
so−t(n
s
o
−
t
_{so-t}
so−t<=N
t
_t
t)个突触,且n
s
o
−
t
_{so-t}
so−t
∼
\sim
∼B(n
s
o
−
t
_{so-t}
so−t,p
1
_1
1),突触极性
∼
\sim
∼伯努利分布(p
2
_2
2)。
在两层神经元之间,对于任意没有突触连接的神经元j,插入m
s
o
−
t
_{so-t}
so−t个突触(m
s
o
−
t
_{so-t}
so−t
≤
\leq
≤
1
N
t
\frac{1}{N_t}
Nt1
∑
i
=
1
,
i
≠
j
N
t
L
t
i
\sum\limits_{i=1,i\not=j}^{N_t}L_{ti}
i=1,i=j∑NtLti),且m
s
o
−
t
_{so-t}
so−t
∼
\sim
∼B(m
s
o
−
t
_{so-t}
so−t,p
3
_3
3)。这里的
L
t
i
L_{ti}
Lti是第i个靶神经元的突触数量,突触极性
∼
\sim
∼伯努利分布(p
2
_2
2),m
s
o
−
t
_{so-t}
so−t为无突触连接的源神经元到靶神经元的突触数。
指令神经元之间可以相互连接,在任意指令神经元间插入l s o − t _{so-t} so−t个突触(l s o − t ≤ N c _{so-t}\leq N_c so−t≤Nc),l s o − t _{so-t} so−t ∼ \sim ∼B(l s o − t _{so-t} so−t,p 4 _4 4),极性 ∼ \sim ∼伯努利分布(p 2 _2 2),l s o − t _{so-t} so−t表示一个间神经元到靶神经元的突触数。
与其他网络的比较
原文中以端到端自动驾驶模型来做比较,使用过的人都很清楚这里不做介绍。总结起来就是鲁棒性强、泛化能力强、响应速度快。图中已经详细展示了,不在重复。
四层神经元学习状态
1、端到端自动驾驶模型结构
前置摄像头输入图片(这里严格来说是视频流,模型处理时也考虑了时间相关性,单张图片易于理解),卷积层提取特征,最后一层特征层为1x4x8,一共生成32个感觉神经元,之后经过12个间神经元,6个指令神经元,1个运动神经元用以控制车辆的方向(这里的车速是固定值)。
2、运动神经元的活性分析
左边图:车辆在最右侧点出发,逆时针运行,训练后运动神经元的输出是左转黄色正值,右转蓝色负值。
右边图:在转角处敏感性较强,直线处较弱。
3、指令神经元的活性分析
指令神经元一共6个,原文给出了其中2个神经元的分析。
左上图:左转为蓝色负值,直线为黄色正值,对右转不敏感没有响应。
右上图:左转处敏感性较强,直线和右转出较低。
下面的图同理。
4、间神经元活性分析
间神经元一共12个,原文给出了其中2个神经元的分析。
左上图:左转输出值大于-0.2,直线和右转小于-0.2,从颜色看对右转较为敏感为深蓝色。
右上图:对右转耦合敏感性较强,左转较低。
下面图同理。
总结:由于神经元数量少,可以将每个神经元的状态进行分析。这对系统的可观测性有很大提高,系统的安全性也可得到保证。传统的dnn网络由于数量巨大,可解释性欠缺,端到端模型很难走出实验室,ncp的实现对于工程运用有着较大推进。(个人想法,不具参考性)
其他
原文中还给出了每种神经元的创建方式,神经元之间的连接算法,公式推导等。需要详细了解的建议看原文,GitHub上的实现暂时只有tensorflow2的版本,模型搭建过程也很简单。有兴趣的同学可以自行尝试。
模型示例
下面给出一个端到端的模型实列:
1、导入相关模块,这里需要tensorflow2.0以上。
from tensorflow import keras
import kerasncp as kncp
from tensorflow.keras.layers.experimental.preprocessing import Rescaling
2、设计模型结构:
示例中模型的输入为(5,256,455,3),这里的5不是batch_size,而是指5帧连续的图像。因此在制作数据集时需要注意这点。
ncp的尺寸和论文中在感知神经元出有点区别,这里为1x2x16,最后都是32个。具体尺寸可根据个人数据集需求自己设计。
#定义ncp网络结构
wiring = kncp.wirings.NCP(
inter_neurons=12, # Number of inter neurons
command_neurons=6, # Number of command neurons
motor_neurons=1, # Number of motor neurons
sensory_fanout=4, # How many outgoing synapses has each sensory neuron
inter_fanout=4, # How many outgoing synapses has each inter neuron
recurrent_command_synapses=4, # Now many recurrent synapses are in the
# command neuron layer
motor_fanin=6, # How many incomming syanpses has each motor neuron
)
rnn_cell = kncp.LTCCell(wiring)
inputs = keras.Input(shape=(5,256,455,3))
x = Rescaling(scale=1.0/255)(inputs)
#conv1
conv1 = keras.layers.TimeDistributed(keras.layers.Conv2D(filters=24,kernel_size=(5,5),strides=(3,3),padding='same',activation="relu"))(x)
#conv2
conv2 = keras.layers.TimeDistributed(keras.layers.Conv2D(filters=36,kernel_size=(5,5),strides=(3,3),padding='same',activation="relu"))(conv1)
#conv3
conv3 = keras.layers.TimeDistributed(keras.layers.Conv2D(filters=48,kernel_size=(3,3),strides=(3,3),padding='same',activation="relu"))(conv2)
#conv4
conv4 = keras.layers.TimeDistributed(keras.layers.Conv2D(filters=64,kernel_size=(2,2),strides=(2,2),padding='same',activation="relu"))(conv3)
#conv5
conv5 = keras.layers.TimeDistributed(keras.layers.Conv2D(filters=16,kernel_size=(2,2),strides=(2,2),padding='same',activation="relu"))(conv4)
pool5 = keras.layers.TimeDistributed(keras.layers.MaxPool2D(pool_size=(2,2),strides=(2,2),padding="valid"))(conv5)
#flatten
flatten = keras.layers.TimeDistributed(keras.layers.Flatten())(pool5)
#ncp
outputs = keras.layers.RNN(rnn_cell,return_sequences=True)(flatten)
#定义模型
model = keras.Model(inputs=inputs,outputs=outputs)
#打印模型结构
model.summary()
#设置优化器
model.compile(
optimizer=keras.optimizers.Adam(0.001), loss="mean_squared_error",
metrics=[keras.metrics.SparseCategoricalAccuracy(name="acc")],
)