姓名:刘强
【嵌牛导读】
神经元,是神经网络中最基本的元素,本文介绍了神经元的数学模型,并且附上了该模型的python实现
【嵌牛鼻子】
神经网络 神经元模型 Sigmoid函数
【嵌牛提问】
神经网络是怎样一回事?
【嵌牛正文】
国庆长假,眼看着身边的同学们都在忙于探索西安的名胜古迹,然而我的心中毫无波动,毕竟学习使我快乐(手动滑稽)。
近年来,人工智能技术开始流行,尤其是Google的阿尔法狗打败李世石之后,神经网络更是火的不行。作为新时代的五好青年,自然要跟上时代潮流。此篇作为《神经网络从入门到出家》系列笔记的第一篇,虽然简书不能支持LaTeX公式书写让我略感蛋疼,但是确实给了我这个卧病多年的懒癌患者一个契机,希望可以坚持完成这个系列,从而养成写博客的好习惯。
神经元模型
首先看一下生物的神经元
可以看到,生物的神经元主要包括3个部分:细胞体、树突、轴突。神经元的树突接收来自其它神经元的信息,然后将经自己处理后的信息通过树突传递给其它神经元。
类似地,建立神经元的数学模型:
上图神经元模型中,x1,x2,...,xn是神经元的输入,代表来自其它神经元的刺激,这里的输出y称为激活函数,有的书上称之为阈值函数。树突上不同的刺激有着不同的权重,这些刺激在神经元上加权叠加,当总的刺激值超过阈值theta(简书的Markdown竟然不支持LaTeX公式书写,差评) ,则输出y=1;如果未超过阈值,则输出y=0,如下图
容易想到,理想的激活函数f应该是阶跃函数,它能够把各种形式的输入映射成0或1,用“1”来表示神经元兴奋,用“0”来表示神经元抑制。但是阶跃函数有很多不好的特性,比如不连续,这样就没法对它求导(后面再解释为什么要对它求导),所以实际常用的激活函数是Sigmoid函数。
Sigmoid函数
Sigmoid函数是一个在生物学中常见的S型的函数,也称为S型生长曲线。我隐约还记得第一次看到这个函数还是在高中生物课本上,是说在一个培养皿上的细菌数目随时间的变化是一个S型生长曲线,于是特意百度了一下,百度百科里对它的解释是这样的:
当种群在有限资源里生长,其生长符合logistic微分方程,随时间变化的生长曲线就呈S形状。在数学上,它是logistic微分方程的解析解。
可以发现,神经网络的建模借鉴了大量生物学的相关概念,不知这算不算是某种朴素的唯物辩证法思想。
Sigmoid函数由下列公式定义
它的图像是这样:
容易看出,当横坐标x趋于正无穷时,Sigmoid函数值为1,当x趋于负无穷时,Sigmoid函数值为0。值得一提的是,除了能把输入映射到0~1之间,sigmoid函数还有一个很好的特性——它的导数可以用自身表示:
这样我们就能够化求导运算为四则运算,从而大大提高程序性能,毕竟计算机擅长的是加减乘除,不善于求导。
代码实现
这个神经元模型的代码实现非常简单:
# 神经元模型
import numpy as np
# sigmoid函数
def sigmoid(x):
return 1/(1+np.exp(-x))
def neural(x, w, theta):
z = np.dot(w, x)-theta
return sigmoid(z)
唯一需要注意的是我们应尽量避免使用显式for循环,例如计算加权累加的时候,诸如
def sum(x, w, n):
sum = 0
for i in range(n):
sum += x[i]*w[i]
return sum
这样的写法尽管可以完成任务,但是它的时间复杂度是O(n),因为这里用了一个显式的for循环。更好的做法是把x,w看成向量,使用numpy的内置函数dot计算向量的內积,这样计算会显著提高运算速度,这是因为numpy会调用CPU或GPU中的并行化指令,有时也叫做SIMD(single instruction multiple data,单指令流多数据流)指令,这样可以充分发挥CPU或GPU的性能。向量化在神经网络编程中是一个很重要的操作,因为神经网络通过训练不断优化自身,训练用的数据集越大,学习的效果越好,那么,程序的性能就显得尤其重要。
后话
显然,这个神经元模型描述的是一个二分分类器,它可以用于回答一些Yes or No的问题,比如,这个国庆到底要不要出去玩?
下一篇,我将介绍一个浅层的神经网络,并将其用于logistic回归,敬请期待。