神经元的结构
- 神经元
- 内部参数的设置
- 偏移值 b 的作用
- 神经网络的分层
- 常用的激活函数
神经元 人类大脑神经元细胞的树突接收来自外部的多个强度不同的刺激,并在神经元细胞体内进行处理,将其转化为一个输出结果,功能抽象图示:
文章图片
神经元模型可分为:
- 输入 X, X = [ x 1 ,x 2 ,x 3 ] X = [x_{1},~x_{2},~x_{3}] X=[x1?, x2?, x3?]
- 内部参数权重 W,对每个输入值都给一个权重, w = [ w 1 ? x 1 ,w 2 ? x 2 ,w 3 ? x 3 ] w = [w_{1}*x_{1}, ~w_{2}*x_{2},~w_{3}*x_{3}] w=[w1??x1?, w2??x2?, w3??x3?]
- 内部参数偏移值 b,这个是一个常数,具体作用我一句话说不清
- 输出 y, 输出 y = 权重 w i ? 输入值 x i + 偏移值 b 输出 y = 权重 w_{i}* 输入值x_{i} + 偏移值 b 输出y=权重wi??输入值xi?+偏移值b
- 激活函数 f:激活函数种类很多,可确保输出值 y 在 0 和 1 之间,方便决策
- 输入: X = [ 房屋面积 100 ,房屋价格 100 万 ,社区评分 5.0 ] X = [房屋面积 100,~房屋价格 100万,~社区评分 5.0] X=[房屋面积100, 房屋价格100万, 社区评分5.0]
- 权重: W = [ 0.4 , 0.5 , 0.6 ] W = [0.4, 0.5, 0.6] W=[0.4,0.5,0.6]
- 偏置: b = 100 b = 100 b=100
- 输出: y = 0.4 ? 100 + 0.5 ? 100 w + 0.6 ? 5.0 + 100 y = 0.4*100 + 0.5*100w + 0.6*5.0 + 100 y=0.4?100+0.5?100w+0.6?5.0+100
- 激活函数: f ( y ) f(y) f(y)
如果激活后的输出值f ( y ) f(y) f(y) 大于阈值 0.5 就买这个房,否则不买。
内部参数的设置
神经元的内部参数,包括权重 W 和偏移值 b,都是可调的(开始时我们会随机初始化)。
用数据训练神经网络的过程,就是调整更新各个神经元的内部参数的过程。神经网络的结构在训练中不变,是其中神经元的参数决定了神经网络的功能。
反复学习是刺激神经元,相当于加大权重的确定程度(不是加大权重的大小)。
一开始神经元给这个输入数据的权重是0.9,但这是一个随机的分配,有很大的不确定性。
随着训练的加深,神经网络越来越相信这个权重应该是0.11,参数稳定在这里。
数值,增大或者减小了不重要,关建是确定性大大增加了。
对比到人,这就好比篮球,训练的目的不是让投篮的用力越来越大,而是越来越准确。
相当于大脑神经元之间的连接越来越稳固,经常在一起激发的两个神经元会“长”在一起,TA们之间的电信号会更强,电信号强对应参数更确定。
偏移值 b 的作用
这得从一个问题说起,如何让计算机具有分辨物体的能力?
文章图片
在一个二维的平面上,红色的 x 代表苹果,蓝色的 o 代表橘子。
我们有一些苹果、橘子的数据特征,现在出现了一个绿色的未知样本(苹果 or 橘子),如何通过建立一个模型来预测分类。
为了让计算机识别二维平面上的数据,我们可以在这个平面上画一条直线,如 ? 图,就用这条直线作分类线。
现在的思路是用已知的数据特征,来训练这条直线。
- 直线方程: y = w x + b y = wx+b y=wx+b
最朴素的思路,随机初始化( w , b ) (w, b) (w,b),暴力枚举这对参数,如下图所示:
文章图片
一开始的思路是猜,不过我们不能完全凭运气,我们可以寻找一些算法策略(如迭代)来优化这个猜,不断逼近正确答案,加速学习过程,避免无效的重复。
迭代策略,需要俩个评价标准:
- 终止条件:如何判断直线是否把俩类样本分开
- 迭代方向:如何用错分样本,来更新直线的参数
给定A 、 B 、 C A、B、C A、B、C 就能确定一条直线,满足这个方程的( x ,y ) (x, ~y) (x, y) 构成一条直线。
那在平面上其他点( x 1 ,y 1 ) (x_{1}, ~y_{1}) (x1?, y1?),代入这个式子,要么大于 0,要么小于 0。
直线把样本分开,其实就是让某一类的数据点满足到直线的距离大于 0,同时让另一类的点到直线的距离小于 0。
由于我们不用关心点到直线距离的具体数值,因此采用一个符号函数 sign 将:
- 距离大于零的点,标记成 1
- 距离小于零的点,标记成 -1
关键的问题是计算机是如何知道自己做的好不好呢?
我们必须再定义一个指示标记,让计算机自己了解它是否正确,这个指标被称为损失函数,损失函数用来评价直线的预测值和真实值不一样的程度,损失函数越好,通常模型的性能越好。
我们人类学习同理,如果一个人一直不停的学,但是不验证自己的学习成果,那么有可能学的方向或者学习方法是错误的,不停的学但结果都白学了。要验证学习成果,就要判断预测结果是否准确,损失函数就是做这个的。
直线的损失函数很简单,既然我们希望直线的输出结果s i g n ( a x + b y + c ) sign(ax+by+c) sign(ax+by+c) 尽量满足 O(+1) X(-1)。
我们把数据自带的标签记作 y,则直线的损失函数就变成:
- L o s s ( s i g n ( a x + b y + c ) , y ) = m a x ( ? y ? s i g n ( a x + b y + c ) ,0 ) Loss(sign(ax+by+c), y) = max(-y*sign(ax+by+c), ~0) Loss(sign(ax+by+c),y)=max(?y?sign(ax+by+c), 0)
只有那些错分样本,会出现? y ? s i g n ( a x + b y + c ) > 0 -y*sign(ax+by+c) >0 ?y?sign(ax+by+c)>0,他们会让感知机猜测的当前直线产生损失,损失越大,这条直线就越不舒服,它必须进行变化。
现在我们应该已经清楚,对于能够用直线分开的数据样本而言,这条之间一定能够找到, 而且满足条件的直线产生的代价是 0。
下图是更新过程:
将s i g n ( a x + b y + c ) sign(ax+by+c) sign(ax+by+c) 简记为h ( x ) h(x) h(x)。
根据直线 W 与点 P 的关系, 参数 W 的更新过程如下:
文章图片
整理成一个式子:
文章图片
最后,就会找到那条将苹果和橘子分类的直线。
偏移值 b 的作用,这根本就是一个直线方程,一条直线如果参数 b = 0,直线就只能在原点上,就做不到二维空间中任何位置的直线,也就不能进行分类了。
神经网络的分层
单个神经元的计算效果不好,但是神经网络依靠网络效应就会非常智能,比如下图的猫跟狗识别正确率会大大提高。
神经网络,从左到右分为三层,每一个圆点代表一个神经元。
- 第零层是 “输入层”,代表输入的数据。
- 第一层叫 “隐藏层”,所谓深度学习就是中间不只有一个隐藏层。
- 第二层是 “输出层”,得到一个输出值。
对于多神经元网络,拆分看就是一个个单独的神经元,神经元网络的计算就是重复单神经元的计算。
和神经元相同,神经网络预测的准确与否,由权重w w w 和偏移值b b b 决定,所以神经网络学习的目的就是找到合适的w w w 和b b b。
文章图片
可是为什么神经网络长这样?
- 用分层解决复杂性,这也是工程师的普遍思维
- 如中国有十几亿人口,我们的国家是分层管理的,从乡到县,从县到厅,从厅到省,从省到国家,都是一级一级管理的 — 如果没有这样一个清晰的机构,一千个人管理起来就很费劲,一会儿这儿出问题,会像一个救火队长一样冲过去了。
- 如十几亿晶体管集成的CPU,亿万个开关组成各种各样的逻辑门,逻辑门再组成运算器,这种结构的好处是,在每一层上搞设计,您都只需考虑紧挨着的下一层,最后程序员小哥哥只需要对一块 CPU,而不是十几亿个晶体管编程。
- 如卷积神经网络做人脸识别,每一个卷积层识别一种特定规模的图形模式,后面一层只要在前面一层的基础上进行识别。
文章图片
第一层,是先从像素点中识别一些小尺度的线条结构,像垂直条纹、水平条纹、斑点、颜色从亮到暗等等各种小结构。
第二层,是根据第一层识别出来的小尺度结构识别像眼睛、耳朵、嘴之类的局部器官。
第三层,才是根据这些局部器官识别人脸。
其中每一层的神经网络从前面一层获得输入,经过深度学习之后再输出到后面一层,从小结构上看出更大、更复杂也更多的结构来,点 -> 线 -> 面。
常用的激活函数
神经网络其实就是线性函数y = w x + b y=wx+b y=wx+b,函数就是一条直线,能处理的问题也只是线性函数可以处理的问题。
在二维平面可以描述x ? y x-y x?y 的直线关系,但曲线关系就不能描述了,线性函数只能画出直线来。
激活函数是非线性函数,不同的激活函数的样子不同,但都可以表示曲线。
而且神经网络层次越多,非线性函数叠加也会越多,产生的曲线就会越来越复杂。
线性函数加上激活函数就可以让神经网络处理各种问题了。
文章图片
最初你看,只有一条波浪线,后来在波浪线上继续叠加波浪,随着波浪不断变多,红色的线条越来越接近黑色横杠的样子 — 以曲代直。
常用的激活函数有:
文章图片
- s i g n sign sign:符号函数,输入值 > 0, s i g n ( x ) = 1 sign(x)=1 sign(x)=1;输出值 < 0, s i g n ( x ) = ? 1 sign(x)=-1 sign(x)=?1
应用问题不太关心具体数值,只需要一个分类。
- s i g m o i d = 1 1 + e ? x sigmoid=\frac{1}{1+e^{-x}} sigmoid=1+e?x1?:输出值在[ 0 ,1 ] [0,~1] [0, 1],平均值是 0.5
现在只适用于二元分类的输出层(神经网络只能判断是或否),其他方面不如t a n h tanh tanh。
- t a n hx = s i n hx c o s hx = e x ? e ? x e x + e ? x tanh~x=\frac{sinh~x}{cosh~x}=\frac{e^{x}-e^{-x}}{e^{x}+e^{-x}} tanh x=cosh xsinh x?=ex+e?xex?e?x?:输出值在[ ? 1 ,1 ] [-1,~1] [?1, 1],平均值是 0
因为平均值从 0.5 变成 0,将靠近 0 的输出值传给下层神经网络,效果更好。
不过俩者在数据规模较大时,神经网络学习速度会很慢。
学习速度和偏导数大小相关,偏导数就是斜率(变化比例),斜率(变化比例)越大偏导数越大,学习速度越快。
通过观察俩者的图像发现,当输入值越来越大时,曲线的斜率(变化比例)是越来越小的。
为了解决这个问题,后来创造了r e l u relu relu。
- r e l u relu relu:输入为正,斜率(变化比例)很大;输入为负时,就会输出 0,神经元就不会被激活 — 说明同一时间里,只有部分神经元会被激活,从而使得网络很稀疏,进而计算更高效,但没有斜率(变化比例)。
应用首选,用的最多,但只在隐藏层使用。
为了解决没有斜率(变化比例)的问题,又创造了一种激活函数:leaky relu。
- leaky relu:relu 改进,leaky relu 的优点将 0 的梯度去掉,换成一个非0的梯度,比如0.1等,这样把 0 梯度变成一个很小不为 0 的梯度。
sigmoid - leaky relu 都只能处理二元分类问题(是和否),有时候需要多分类,从二元判断到多元判断
- 【#|神经元的结构】softmax:N 元分类的输出层,输出层神经元要有 N 个。
推荐阅读
- 计算机视觉|模板匹配与像素统计
- 字符串|7行代码让B站崩溃3小时,竟因“一个诡计多端的0”
- spring|spring,springboot,springmvc底层原理解析
- #|SpringBoot2学习笔记一--Spring与SpringBoot2
- #|Servlet 架构思路(MVC)
- Python|Python 矩阵基本运算【numpy】
- 机器学习|NTU20220813-数据结构化和深度学习-WSL音频转发
- 深度学习基础|基于pytorch的BP神经网络实现
- 机器学习|李宏毅机器学习笔记p5-p8(误差和梯度下降)