从人脑神经元到人工神经元 --------------------------------------------------- 本部分将介绍学者们是如何从人脑神经元中得到灵感,并设计出一种与人脑神经元类似但又有简洁数学表示的计算单元人工神经元。 生物神经元中的计算灵感 ++++++++++++++++++++++++++++++++++++++++++++++++ 早在1771年,意大利的路易吉·伽伐尼就发现如果用电火花刺激死青蛙的肌肉就能使其颤动(可怜的青蛙,不知道我们中学做的往被切除大脑的青蛙身上涂硫酸的实验是否也与这这位科学家有关)。1848年,德国人Emil du Bois-Reymond发现了神经元受到激发而产生的动作电位。1906年意大利的卡米洛·高尔基和西班牙的圣地亚哥·拉蒙·卡哈尔由于神经系统的发现而共同获得诺贝尔奖。 我们可以这样简单地描述一个神经元的工作机制。 一个神经元就是一个可以接收、发射脉冲信号的细胞。在细胞的核心之外有树突与轴突,树突接收其它神经元的脉冲信号, 而轴突将神经元的输出脉冲传递给其它神经元, 一个神经元传递给不同神经元的输出是相同的。 一个神经元的状态有两种——非激活和激活。非激活的神经元不输出脉冲,激活的神经元会输出脉冲。 神经元激活与否由其接收的脉冲决定。 模拟人脑神经元的历史几乎跟现代计算机的历史一样久远。 1943年,生理学家McCulloch和数学家Pitts提出了第一个神经网络的数学模型, 其中神经元的模型, 仍然适用于近几年开始流行的深度学习。 冯·诺意曼在1955-1956间写过一个演讲稿,后来被商务出版社以《计算机与人脑》为题出版,编入汉译世界学术名著丛书,与《理想国》、《新工具》等书并列。 在那个数字计算机和模拟计算机并存的年代, 作者在诸多方面对计算机和人脑进行了比较。 根据McCulloch和Pitts的模型, 可以将一个神经元看作一个计算单元,对输入进行线性组合, 然后进过一个非线性的激活函数作为输出。 用 :math:`x_1,x_2,\cdots x_n` 表示 :math:`n` 个输入, 用 :math:`y` 表示输出, 用 :math:`f` 表示非线性的激活函数, 则有 .. math:: y=f(u)=f(x_1w_1+ \cdots x_nw_n+b) 其中 :math:`b` 是一个与输入无关的量。 将以上模型表示为图形的结构即为下图: .. graphviz:: digraph grph{ rankdir=LR; node [shape = none]; x1; x2; xx[label="..."]; y; b; node [shape = circle]; neuron [label= "f"] ; {rank=same; b neuron}; x1 -> neuron [label= "w1"] ; x2 -> neuron [label= "w2"]; xx -> neuron; b -> neuron; neuron -> y ; } 在这里, :math:`\mathbf{x}` 与 :math:`y` 分别是输入与输出, 他们可以是任意的实数。 :math:`\mathbf{w}` 和 :math:`b` 是模型的参数, 不同的参数会构成实现不同功能的模型。 事实上,在真正的人脑神经元中,输出与输入有更复杂的关系。 激活函数 ++++++++++++++++++++++++++++++++++++++++++++++++ 不同的激活函数适合不同的具体问题和神经网络参数学习算法。 如果期望得到离散的输出, 可以使用阶跃激活函数 .. math:: s(u)=\begin{cases}1 & u > 0 \\ 0 & u \leq 0 \end{cases} 如果期望得到连续的输出, 可以使用一类被称为sigmoid的S形函数。 一种在应用中使用得比较多的是 logistic函数: .. math:: g(u)=\frac{1}{1+e^{-u}} .. note:: 如果希望值域是 :math:`(-1,1)` 而不是 :math:`(0,1)` , 激活函数还可以定义为双曲正切函数,它跟Logicatic函数非常类似: .. math:: \tanh(u)=\frac{1-e^{-2u}}{1+e^{-2u}}=2s(u)-1 阶跃函数与logistic函数的对比可见下图: .. plot:: import matplotlib.pyplot as plt import numpy as np x=np.linspace(-5,5) plt.figure(figsize=(4,3)) plt.step([-5,0,0,5],[0,0,1,1],label=r"$s(u)$") plt.plot(x,(np.tanh(x)+1)/2,"--",label=r"$g(u)$") plt.ylim([-0.5,1.5]) plt.xlim([-5,5]) plt.xlabel('$u$') plt.ylabel('$y$') plt.legend(loc="lower right") plt.grid() plt.show() 激活函数通常都是单调有界的。 此外,Logistic 函数处处连续可导, 并且导数均大于0,这为之后的参数学习提供了方便。