【机器学习】--神经网络(NN)

简单介绍:

     神经网络主要是默认人类脑结构进行的一种代码程序结构的表现,同时是RNN,CNN,DNN的基础。结构上大体上分为三个部分(输入,含隐,输出),各层都有个的讲究,其中,输入层主要是特征处理后的入口,含隐层用来训练相应函数,节点越多,训练出的函数就越复杂,输出层输出相应的预测结果,比较常见的就是多分类了。

算法特点:

     1、神经网络属于有监督学习的一种;
     2、计算复杂度比较高,因为增加了相应的激活函数,所以等于复合函数嵌套复合函数;
     3、含隐层的神经元越多,计算函数便越复杂,但带来的好处是,不用过度考虑特征方程,较其它机器学习入门算法而言,省却了特征适配;
     4、BP后向传播其实就是误差函数反推参数求导过程,不知道为什么网络上的很多博客都没有人点出来,可能是使用BP后向传播算法,让别人听起来更厉害一些吧;
     5、需要考虑过拟合问题;
     6、数学不好别看了,看前五条就行了。


学习神经网络的基本流程:

1、了解基础知识(简单的神经网络构造,激活函数,误差函数);
2、推导
3、完成代码
4、画图看效果

基础知识:

神经网络

上图建立具有一个输入层、一个隐藏层、一个输出层的三层神经网络。输入层的结点数由数据维度决定,这里是2维。类似地,输出层的结点数由类别数决定,也是2。(因为我们只有两类输出,实际中我们会避免只使用一个输出结点预测0和1,而是使用两个输出结点以使网络以后能很容易地扩展到更多类别)。每一个神经元都可以理解成一个函数,这个函数,也可以叫做激活函数,例如,输入神经元理解为Fin(x),含隐神经元理解为Fhn(x),输出神经元理解为Fou(x),每一层之间都是具有一个权重参数w(或者叫θ),每一层的输出乘上权重参数,都是下一层的输入,例如,Fin( input1 ) * w1 就是含隐层的输入,Fhn( Fin( input1 ) * w1 ) *w2 就是输出层的输入,Fou( Fhn( Fin(input1 ) * w1 ) * w2 )计算出最后的输出值。

常见的激活函数:
1、Sigmoid函数(也叫logistics函数)
2、Tanh函数(双曲函数)
3、sgn函数(阶跃函数)
4、ReLU函数
5、softmax函数
6、Linear函数

误差函数:
参考我写的机器学习--逻辑回归这篇文章吧,里面有提到,这里我们使用的是对数似然损失。这里特别说明一下,需要注意,交叉熵和对数似然很像,需要注意区别。

本次神经网络的三层形式:
输入层:特征,用x表示
输入层和含隐层之间的权重:使用w1表示
含隐层:tanh()
含隐层和输出层之间的权重:使用w2表示
输出层:softmax()
输出结果:Y表示(带上角标的那个我打不出来。。。)

softmax的函数如下:

其中,Yi表示第i类的输出,xi表示第i类的输入,底部的是所有输入的求和。

softmax的求导:
需要先行注意的是,底部xk的累加和是包含n个未知参数的,但在求导过程中,除了对其求到的那个未知参数外,其它参数,都视为常数项;
f(xi)对xi求导:


f(xi)对xa求导:




推导:

正向传播(也就是预测过程,即开始输入到最后输出的过程,求y):
     y = softmax ( tanh ( x * w1 ) * w2 )

后向传播(求w2,w1):
     后向传播就是倒着推,先推输出层到含隐层之间的权重w2,那么假设我们的真实值用大Y表示,我们的预测值用小y表示,那么他们之间的误差是Loss = ( Y - y) ,但由于我们softmax函数是指数形式,且本身是概率性问题,我们使用最大似然损失函数(也叫对数似然损失函数),Loss = -ln ( y ) ,(注,在书上见到的log其实就是ln,表示以e为底,表示的含义是,y是当前样本下预测模型得到的概率)
     那么损失函数Loss =- ln ( y ) ,也就是说,要在损失最小的情况下求参数w2, 求参数求参数还要损失最小,梯度下降就可以了,已知梯度下降公式: w = w - α( ∂Loss / ∂w);
     那么令 结果 a = tanh(x*w1)* w2
     求取过程如下:

     各项如下:

  所以:w2 = w2 - α  * [  ( yi - 1) * tanh( xi * w1 ) ]

     同理,对b2进行求导:

同理,进行对误差函数中的w1求导:
所以:w1 = w1 - α  * [  (  yi - 1 ) * [ 1 - (tanh( w1 * xi ))^2 ] * w2 * xi ]    
     
      同理,对b1求导:

  这样,后向传播也推导完了。

开始部署程序,程序分为以下几步:

     1、获取数据进行处理
     2、softmax公式构建
     2.5、参数初始化(主要是权重)
     3、前向传播(就是预测函数)构建
     4、后向传播构建
     5、误差函数构建
     5.5、组合函数进行训练
     6、训练结果评估
     7、画图

本程序使用以下库,并使用以下全局变量:
import numpy as np
from sklearn.datasets import make_moons
import matplotlib.pyplot as plt
#学习速率
learning_rate = 0.01

#正则化参数
reg_lambda = 0.01

#特征数据
data_x = []

#data_y对应结果,mat_data_y结果的表示矩阵形式
data_y = []
mat_data_y = []

#权重参数
weights1 = []
weights2 = []
b1      = []
b2      = []

#误差
loss = []

第一步,数据获取:
def get_data():
    global data_x,data_y
    np.random.seed(0)
    data_x, data_y = make_moons(200, noise=0.20)
    max_y = max(data_y)
    m = len(data_x)


第二步,数学公式构建(我们只需要构建最后的分类函数softmax):
#定义softmax函数
def softmax(x):
    return np.exp(x)/(np.sum( np.exp(x) ,axis=1,keepdims=True))

第二点五步,参数初始化(主要是权重):
#input_layout_num是输入层层数,hide_layout_num是含隐层层数,output_layout_num是输出层层数
def set_params(hide_layout_num = 3 ):
    global weights1, weights2 ,b1 ,b2
    input_layout_num = len(data_x[0])
    output_layout_num = len(mat_data_y[0])

    # weights1 = np.ones((input_layout_num, hide_layout_num))
    # weights2 = np.ones((hide_layout_num, output_layout_num))
    weights1 = np.random.randn(input_layout_num, hide_layout_num)/ np.sqrt(input_layout_num)
    weights2 = np.random.randn(hide_layout_num, output_layout_num)/np.sqrt(hide_layout_num)
    # print(weights1)
    # weights1 = np.ones((input_layout_num, hide_layout_num))
    b1      = np.zeros((1,hide_layout_num))
    b2      = np.zeros((1,output_layout_num))
 
第三步,前向传播(就是预测函数)构建:
#前向传播计算
def forward_propagation():
    input_hide_calc_pe = np.dot(data_x ,weights1) + b1 #input_hide_calc_pe为输入层和含隐层之间的参数方程计算值
    hide_activation_val = np.tanh(input_hide_calc_pe)#hide_activation_val是含隐层激活函数值
    hide_output_calc_pe = np.dot(hide_activation_val, weights2) + b2#hide_output_calc_pe是含隐层和输出层之间的参数方程计算值
    output_proba = softmax(hide_output_calc_pe)#out_proba是最后选择softmax函数计算出的概率,也就是预测值
    return hide_activation_val,output_proba

#预测函数
def predict(x):
    input_hide_calc_pe = np.dot(x ,weights1) + b1 #input_hide_calc_pe为输入层和含隐层之间的参数方程计算值
    hide_activation_val = np.tanh(input_hide_calc_pe)#hide_activation_val是含隐层激活函数值
    hide_output_calc_pe = np.dot(hide_activation_val, weights2) + b2#hide_output_calc_pe是含隐层和输出层之间的参数方程计算值
    output_proba = softmax(hide_output_calc_pe)#out_proba是最后选择softmax函数计算出的概率,也就是预测值

    result = np.max(output_proba,axis=1)
    kind = np.argmax(output_proba,axis=1)
    print(output_proba)
    print("预测结果为第:" + str( kind) + "类\n"
          +"预测系数为:" + str(result) )
    return kind#返回每一组中最大数值对应位置的索引
之所以写两个是因为后面的那个画图和单点预测需要使用

第四步,后向传播构建:
#后向传播计算,output_proba输出层计算出的概率
def back_propagation( hide_activation_val, output_proba):
    global weights2,weights1,b1,b2
    feature_x_len,feature_x0_len = np.shape(data_x)
    delta_w2_1 = output_proba

    #(yi - 1 )
    for i in range(feature_x_len):
        delta_w2_1[i][data_y[i]] = delta_w2_1[i][data_y[i]] - 1

    # (yi - 1 ) * tanh(w1 * xi)
    delta_w2 = np.dot(hide_activation_val.T, delta_w2_1)

    #b2 = yi - 1
    delta_b2 = np.sum(delta_w2_1,axis=0,keepdims=True)

    #[  (  yi - 1 ) * [ 1 - (tanh( w1 * xi ))^2 ] * w2 * xi ]
    #1 - (tanh( w1 * xi ))^2
    delta_w1_2 = (1 - hide_activation_val**2)

    delta_w1_1 = np.dot(delta_w2_1 ,weights2.T)

    delta_w1_3 = delta_w1_1 * delta_w1_2
    delta_w1 = np.dot(data_x.T,delta_w1_3)
    delta_b1 = np.sum(delta_w1_3,axis=0,keepdims=True)

    delta_w2 = delta_w2 + reg_lambda * weights2

    delta_w1 = delta_w1 + reg_lambda * weights1

    weights1 = weights1 - learning_rate * delta_w1
    b1      = b1 - learning_rate * delta_b1
    weights2 = weights2 - learning_rate * delta_w2
    b2      = b2 - learning_rate * delta_b2


第五步,误差函数构建:
#误差函数
def loss_func():
    global loss
    #Loss = - ln p(y|x) = - ln yi
    loss_sum = 0.0
    hide_activation_val, output_proba = forward_propagation()
    for i in range(len(data_x)):
        loss_sum = loss_sum + -1 * np.log( output_proba[i][data_y[i]] )
    loss.append(1/len(data_x) * loss_sum)

第五点五步,训练:
def train(iter_num = 1,hide_layout_num = 3):
    set_params(hide_layout_num)
    for i in range(iter_num):
        hide_activation_val,output_proba = forward_propagation()
        back_propagation(hide_activation_val,output_proba)
        loss_func()

第六步,训练结果评估:
#评估训练结果
def train_result_evaluate():
    hide_activation_val, output_proba = forward_propagation()
    output_result = np.argmax(output_proba,axis=1) #返回每一组中最大数值对应位置的索引
    x_num = len(output_result)
    real_num = 0.0
    for i in range(x_num):
        if output_result[i] == data_y[i]:
            real_num += 1.0
    score = real_num / x_num
    print("本次样本数共:" + str(x_num) + "个\n"
          +"训练后预测正确数量:"+ str(real_num) + "个\n"
          +"正确率为:" + str(score * 100 ) + r'%' )

第七步,画图:
#画决策边界
def show_decision_pic():
    # Set min and max values and give it some padding
    x_max = max(data_x[:,0]) + 0.5
    x_min = min(data_x[:,0]) - 0.5
    y_max = max(data_x[:,1]) + 0.5
    y_min = min(data_x[:,1]) - 0.5
    range_space = 0.01

    # Generate a grid of points with distance h between them

    feature_x1 = np.arange(x_min, x_max, range_space)  #其横向特征最大最小生成的范围值
    feature_x2 = np.arange(y_min, y_max, range_space)  #其纵向特征最大最小生成的范围值

    x1, x2 = np.meshgrid(feature_x1, feature_x2)    #将特征变化成行列相等的矩阵
    # Predict the function value for the whole gid
    feature = np.c_[x1.ravel(), x2.ravel()]  #拼接成二维矩阵
    print(np.shape(feature))
    Z = predict(feature)
    print(Z)
    Z = Z.reshape(x1.shape)

    # Plot the contour and training examples
    plt.contour(feature_x1, feature_x2, Z)

    plt.scatter(data_x[:, 0], data_x[:, 1], c=data_y, cmap=plt.cm.Spectral)
    plt.show()

def show_loss_pic():
    plt.figure(2)
    plt.plot(loss)
    plt.show()

运行程序:
if __name__ == "__main__":
    get_data()
    train(iter_num=20000,hide_layout_num=3)
    print("初始loss:" + str(loss[0]))
    print("最终loss:" + str(loss[-1]))
    train_result_evaluate()
    show_decision_pic()
    show_loss_pic()
    #这里进行一个单点预测
    predict(data_x[-5])


看一下结果:

决策边界如下:

误差损失逐渐收敛:

误差值:


评估结果:


最后的单点预测(因为两类分别是用0和1表示的,所以第一类是第[0]类,第二类是第[1]类):


关于关于程序中权重初始化的说明(对应在set_param函数):
     关于程序中,权重为什么是这样设置,还不是像基础的机器学习方法,设置全0或全1矩阵,原因就是因为,如果设置相同矩阵,那么所有神经元计算出来的结果是一样的,反向传播时,计算的梯度就一样了,参数就会一样,具体说明,请参考引用【4】.

     写在最后,可以看出来,神经网络的计算比之前基础机器学习稍稍复杂一些,但套路还是一样的,就是多了一点,但好处也可以从图中看出来,尤其是和之前的逻辑回归比较后更容易得出鲜明结论,神经网络省去了找寻复杂特征方程的选择,神经元的多少就会决定自己处理的特征的复杂度。
     比如使用30层含隐层,迭代2w次,看下效果
但这样的情况,就过拟合了,并不平滑,这样做出来的权重和函数,就不是预测了,无法体现我们做出来的东西的是具有通用适配性的。


图文知识及引用参考:


【2】看了这篇文章,开始尝试写神经网络: http://python.jobbole.com/82208/
【3】实际上,【2】是翻译的github上的一篇文章( 打开ipynb格式): https://github.com/dennybritz/nn-from-scratch
【4】权重初始化的选择原因: http://blog.csdn.net/bixiwen_liu/article/details/52956727
【5】python绘图的函数说明: https://www.cnblogs.com/shuhanrainbow/p/6282452.html


  • 7
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
CMSIS-NN神经网络教程是一个关于使用CMSIS-NN神经网络库的教程。该教程的第二版已于2021年9月20日发布,并且与DSP数字信号处理教程同步更新。在更新中,CMSIS-DSP和CMSIS-NN库将被独立出来,不再包含在CMSIS软件包中,以便更方便地进行独立更新和发布。同时,该教程还将介绍CMSIS-RTOS V2和CMSIS-DAP的最新更新内容。该教程旨在完善第一版教程中的内容,并分享在信号处理应用方面的经验和待解决问题。此外,教程还提到了单片机人工智能(AI)的前景,ARM正在推进单片机AI的发展,并在2020年的路线图中计划发布机器学习库和更强大的DSP库。总的来说,CMSIS-NN神经网络教程是一个重要的教程,为使用CMSIS-NN库进行神经网络开发提供了指导和示例。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [事隔五年之后,开启第2版DSP数字信号处理和CMSIS-NN神经网络教程,同步开启三代示波器,前50章发布(2021-...](https://blog.csdn.net/Simon223/article/details/105049607)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *2* [CMSIS软件包V5.8.0发布,所有组件全面更新,CMSIS-NN神经网络接口函数开始兼容TensorFlow Lite](https://blog.csdn.net/Simon223/article/details/118363349)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值