• 神经元的计算


     


    一个神经网络分为输入层、隐藏层、输出层。

    • 输入层:输入数据
    • 隐藏层:负责计算
    • 输出层:计算和输出结果


     


    输入层

    1、数据输入
    • 语音/图像/传感器数据都会转成数字形式(如矩阵),再把他们转化为一个特征向量(向量),将其输入到神经网络中。

    比如图像数据,世界上的所有颜色都可以通过,红绿蓝三种颜色调配出来。

    计算机保存一张图片,要保存三个独立矩阵,分别对应红、绿、蓝三个颜色通道。

    假设图片是 64x64 像素的,就有 3 个 64x64 的矩阵,分别对应红绿蓝三个像素的亮度。

    为了方便计算,我们会把 3 个矩阵转化为 1 个列向量(特征向量)。


    这个向量的总维数就是 64*64*3,结果是 12288 个特征。

     


    隐藏层

    正向传播:输入端向输出端传递信息

    2、得到输出值:直线方程进行预测

    将待预测数据,这些特征 x 1 ⋅ ⋅ ⋅ x 1288 x_{1}···x_{1288} x1⋅⋅⋅x1288 输入到神经网络中:

    单层神经元的计算,就是一个直线方程:

    • y i ^ = σ ( W T x i + b ) \hat{y_{i}}=\sigma(W^{T}x_{i}+b) yi^=σ(WTxi+b)

    前置知识:为什么是一个直线方程,请猛击《神经元的计算》。

    现在我们来看多层神经元:


    如果第 i i i 层神经元有 m m m 个,那第 i + 1 i+1 i+1 层的每个神经元都得存储 m m m 个权重。

    如果第 i + 1 i+1 i+1 层神经元有 n n n 个,则第 i + 1 i+1 i+1 层神经元共有 m*n 个权重。

    我们会用一个 m*n 矩阵来存储:


    当前层的神经网络计算:

    编程实现:

    u = np.dot(x, w) + b    # dot() 实现矩阵乘法 
    
    • 1

    再计算激活函数,如 s i g m o d sigmod sigmod 函数:

    def sigmod(x):
    	return 1 / (1 + e.exp(-x))
    	
    y = sigmod(u)
    
    • 1
    • 2
    • 3
    • 4

    得到当前层输出 y y y,再把 y y y 当成下一层的输入。

    我们以一个三层神经网络举例:

    • 输入层神经元个数:2
    • 中间层神经元个数:2
    • 输出层神经元个数:1
    # 权重
    w_im = np.array( [ [4.0, 4.0], [4.0, 4.0] ] )      # 输入层 * 中间层,即 2 * 2
    w_mo = np.array( [ [1.0], [1.0] ] )                # 中间层 * 输出层,即 2 * 1
    
    # 偏置
    b_im = np.array( [3.0, -3.0] )                     # 中间层有 2 个神经元,就 2 个偏置
    b_mo = np.array( [0.1] )                           # 输出层有 1 个神经元,就 1 个偏置
    
    def middle_layer( x , w, b ):      # 中间层/隐藏层,输入 x、权重 w、偏置 b
        u = np.dot( x, w ) + b         # 直线方程
        return 1/(1+np.exp(-u))        # 激活处理
    
    def output_layer( x , w, b ):      # 输出层,输入 x、权重 w、偏置 b
        u = np.dot( x, w ) + b         # 直线方程
        return u                       # 恒等函数,不做激活处理
        
    # 正向传播过程
    imp = np.array([...])              # 输入层,直接输入数据即可,不用计算
    mid = middle_layer(imp, w_im, b_im)            # 中间层
    out = output_layer(mid, w_mo, b_mo)            # 输出层
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    这是处理回归问题的正向传播过程,还有一类问题是分类。

    比如处理二分类任务,输出层需要俩个神经元:

    除了输出层的激活函数使用 s o f t m a x softmax softmax 函数外,其他地方都不变。

    def output_layer( x , w, b ):      # 输出层,输入 x、权重 w、偏置 b
        u = np.dot( x, w ) + b         # 直线方程
    	return np.exp( u ) / np.sum( np.exp( u ) )    # softmax 函数
    
    • 1
    • 2
    • 3

    输出层输出的是一个概率值,我们比较俩个神经元的概率值,取最大值。

     


    反向传播:输出端向输入端传递信息

    反向传播过程:

    • 前向传播过程:直线方程计算权重参数把输入值相加,再加入偏移值得到一个处理结果,加上激活函数形成一个输出值。

    • 反向传播过程:损失函数计算误差,通过计算图先计算第 N 层的偏导数(变化比例),再计算第 N-1 层的,输出层反向往前推,直到输入层;再通过梯度下降法学习,最小化误差。

    这样来回不停的进行前向传播、反向传播,来训练(更新)参数使损失函数越来越小(预测越来越准确)。

    原理:每次新的训练数据进来,就根据正确答案对参数进行一次微调,使得神经网络输出数值更接近正确答案。

    计算过程图示:

    首先把数据,分为:输入数据、正确答案。

    正向传播输出与正确答案对比:

     


    3、得到误差:损失函数计算误差

    对输出和正确答案的误差,进行定义的就是损失函数。


    理论上我们可以用平方,但是在工程中,我们一般会用这个损失函数:

    • L ( y i ^ , y i ) = − ( y i   l o g ( y i ^ ) + ( 1 − y i )   l o g ( 1 − y i ^ ) ) L(\hat{y_{i}}, y_{i})=-(y_{i}~log(\hat{y_{i}}) + (1-y_{i})~ log(1-\hat{y_{i}})) L(yi^,yi)=(yi log(yi^)+(1yi) log(1yi^))

    这是对单个训练样本(一张图)的损失函数,但我们输入都神经网络的通常是一个训练集(大量的图片)。

    我们需要累加单个训练样本的结果,再求平均值:

    • 1 m ∑ i = 1 m L ( y i ^ , y i ) \frac{1}{m}\sum_{i=1}^{m}L(\hat{y_{i}}, y_{i}) m1i=1mL(yi^,yi)

    为什么使用这个损失函数呢?

    这个损失函数(逻辑回归)的函数图像是一个向下凸的图形。


    因为学习,就是找到一组 w w w b b b,使这个损失函数最小。

    也就是在这个函数图像的底部找到一组 w w w b b b

    这个损失函数叫逻辑回归,具体内容记录在同名博客:《逻辑回归》。

    这个损失函数没有局部最优解,只存在唯一的全局最优解。

    我们要做的,是求出损失函数的梯度,而后运用梯度下降法求出损失最小的一组 w 和 b。
     


    4、得到偏导数:计算图高效计算偏导数

    我们用函数 J ( a ,   b ,   c ) = 3 ( a + b c ) J(a,~b,~c) = 3(a+bc) J(a, b, c)=3(a+bc) 来演示传播过程。

    为了让神经网络计算,函数 J J J 以计算图的形式计算:


    一开始,我们随机初始化 a 、 b 、 c a、b、c abc 分别为 5 、 3 、 2 5、3、2 532,前向传播过程如下图:


    前向传播得到输出值。

    反向传播用于计算函数 C C C 关于各个参数的偏导数(变化比例),而后对参数进行梯度下降。

    我们先计算 C C C 关于 B B B 的偏导数,记为 d C d B \frac{dC}{dB} dBdC

    偏导数、斜率就是变化比例,即 B B B 变化一点后 C C C 会相应的变化多少。

    所以,为了计算 B B B 的偏导数,我们假设让 B B B 变化一点点,比如 B B B 加上 0.001 0.001 0.001(11.001),而后看 C C C 改变了多少, C C C 33 33 33 变成了 33.003 33.003 33.003

    C C C 的变化量除以 B B B 的变化量(0.003 / 0.001 = 3),即偏导数(变化比例)为 3 3 3

    • 同理, B B B 关于 A A A 的偏导数为 d B d A = 1 \frac{dB}{dA} = 1 dAdB=1

    • 同理, A A A 关于 b b b 的偏导数为 d A d b = 2 \frac{dA}{db} = 2 dbdA=2

    那么, C C C 关于 A A A 的偏导数是多少呢?

    • 我们让 A A A 改变一点点,从 6 6 6 变成 6.001 6.001 6.001,这会导致 B B B 11 11 11 变成 11.001 11.001 11.001,而 B B B 的改变会导致 C C C 33 33 33 变成 33.003 33.003 33.003 C C C 的改变量除以 A A A 的改变量等于 3 3 3(0.003/0.001=3),即偏导数 d C d A \frac{dC}{dA} dAdC 3 3 3

    其实间接传导的计算,我们用链式法则求导:

    • C C C 关于 A A A 的偏导数 = C C C 关于 B B B 的偏导数 * B B B 关于 A A A 的偏导数,即 d C d A = d C d B ∗ d B d A = 3 ∗ 1 = 3 \frac{dC}{dA} = \frac{dC}{dB}*\frac{dB}{dA}=3*1=3 dAdC=dBdCdAdB=31=3

    同理, C C C 关于参数 b b b 的偏导数 d C d b = d C d B ∗ d B d A ∗ d A d b = 3 ∗ 1 ∗ 2 = 6 \frac{dC}{db}=\frac{dC}{dB}*\frac{dB}{dA}*\frac{dA}{db}=3*1*2=6 dbdC=dBdCdAdBdbdA=312=6

    d C d b \frac{dC}{db} dbdC 这个偏导数才是我们最终需要的,我们需要的是函数 C C C 关于参数 a 、 b 、 c a、b、c abc 的偏导数。

    为了得到这三个偏导数,我们需要先计算出关于 B B B 的偏导数,而后再计算出关于 A A A 的偏导数,最后计算出关于参数 a 、 b 、 c a、b、c abc 的偏导数。

    • d a = d C d a = d C d B ∗ d B d a = 3 ∗ 1 = 3 da=\frac{dC}{da}=\frac{dC}{dB}*\frac{dB}{da}=3*1=3 da=dadC=dBdCdadB=31=3
    • d b = d C d b = d C d B ∗ d B d A ∗ d A d b = 3 ∗ 1 ∗ 2 = 6 db=\frac{dC}{db}=\frac{dC}{dB}*\frac{dB}{dA}*\frac{dA}{db}=3*1*2=6 db=dbdC=dBdCdAdBdbdA=312=6
    • d c = d C d c = d C d B ∗ d B d A ∗ d A d c = 3 ∗ 1 ∗ 3 = 9 dc=\frac{dC}{dc}=\frac{dC}{dB}*\frac{dB}{dA}*\frac{dA}{dc}=3*1*3=9 dc=dcdC=dBdCdAdBdcdA=313=9

    反向传播后更新 d a 、 d b 、 d c da、db、dc dadbdc 的值是通过:

    • a ′ = a − r ∗ d a a'=a -r*da a=arda
    • b ′ = b − r ∗ d b b'=b -r*db b=brdb
    • c ′ = c − r ∗ d c c'=c -r*dc c=crdc

    计算得到新的 a 、 b 、 c a、b、c abc 的值,然后再进行前向传播的到新的 J J J 函数,再进行反向传播,直到寻到最小误差。

    • 人工神经网络就是一个多层的复合函数。
    • 这种复合函数求偏导时是不能直接对 a 、 b 、 c a、b、c abc 求偏导,只能对中间函数求依次求偏导从而得出 a 、 b 、 c a、b、c abc 的偏导数,即链式法则。
       

    5、更新权重偏置:梯度下降法学习,最小化误差

    所谓学习,就是最小化误差的处理。

    以最小的神经网络举例,给定一个样本(1, 0) 训练。

    • 单样本的误差平方函数: J = 1 2 ( a − y ) 2 J=\frac{1}{2}(a-y)^{2} J=21(ay)2
    • 损失函数为: J ( w ) = 1 2 ( w x − y ) 2 = 1 2 ( w 1 − 0 ) 2 = 1 2 w 2 J(w)=\frac{1}{2}(wx-y)^{2}=\frac{1}{2}(w1-0)^{2}=\frac{1}{2}w^{2} J(w)=21(wxy)2=21(w10)2=21w2

    损失函数图像:

    一开始有一个初始值(左边的红点),我们需要找到最合适的w(谷底的w),使J最小。

    那如何自动找到这个谷底呢?


    当寻找点在左边时,梯度是负数,在右边时,梯度是正数。

    梯度下降公式: w = w − a d J d w w=w-a\frac{dJ}{dw} w=wadwdJ

    • d J d w \frac{dJ}{dw} dwdJ:变化比例,w变化时,J相应变化多少

    w − d J d w w-\frac{dJ}{dw} wdwdJ 中间是负号:

    • 点在左边时,梯度是负的,负负得正,w会增加,体现在图中是在 x 轴向右方向走
    • 点在右边时,梯度是正的,w会减少,体现在图中是在 x 轴上向左方向走
    • 最终都会向谷底靠拢

    除此之外,还有一个参数 a,代表学习率:

    一般 a = 0.01,太高会造成震荡,在俩边跳来跳去;太小下降很慢。

     
    梯度下降法的寻找思路是:粗调 + 精调。

    • 首先粗调:迭代步长要大,很快确定大致范围
    • 其次精调:迭代步长要小,速度很慢,确定精度

    就好像用显微镜一样,粗体可以看到大致图像,精调可以看清楚图像。

    具体步骤就是,先随机在曲线上找一个点,然后求出该点的斜率,也称为梯度。

    顺着这个梯度的方向往下走一步,到达一个新的点之后,重复以上步骤,直到到达最低点(或达到我们满足的某个条件)。

    如,对 w w w 进行梯度下降,则就是重复一下步骤(重复一次称为一个迭代):

    • w = w − r ( d J d w ) w = w - r(\frac{dJ}{dw}) w=wr(dwdJ)
    • b = b − r ( d J d b ) b = b - r(\frac{dJ}{db}) b=br(dbdJ)

    其中 = = = 代表 “用后面的值更新”, r r r 代表学习率(learning rate), d J d w \frac{dJ}{dw} dwdJ 就是 J J J w w w 求偏导。

    梯度下降法完整内容:《梯度下降法》。
     


    输出层

    项目驱动:《识别猫的项目》。

  • 相关阅读:
    新生儿长牙期:原因、科普和注意事项
    K8S Pod控制器:ReplicationController ReplicaSet Deployment三者的联系与区别
    OpenResty使用漏桶算法实现限流
    论文分享 | 智能放牧无人机&多旋翼无人机发展趋势
    8/9 基础思维+二分图染色+最大完美匹配KM算法
    【Docker 基础教程】容器数据持久化(一)------ 数据持久化概述
    数据结构七:七大排序(插入排序,希尔排序,选择排序,堆排序冒泡排序,快速排序,归并排序)
    【leetcode】【周赛】第 301 场
    PokéLLMon 源码解析(一)
    Dubbo高手之路6,Dubbo 服务治理详解
  • 原文地址:https://blog.csdn.net/qq_41739364/article/details/126565125