深度学习之路--神经网络结构的学习总结

0. 前言

神经网络是为了解决感知机的缺陷,感知机的权重和偏置需要人为设定,但神经网络可以自动从数据中学习到合适的权重和偏置值,下面给出一个2层的神经网络结构(有些书称为3层),包含输入层、中间层(也称作隐层)和输出层:

 1. 激活函数

在感知机介绍中,当输出值大于0时,输出结果为1,当输出值小于等于0时,输出结果为0,在介绍它时并没有明确说明其使用的算法,其实单层感知机使用了阶跃函数作为其激活函数,将输入信号的总和(\sum x_{i}w_{i}+b_{i})被激活函数(阶跃函数转换),阶跃函数表达式如下:

 

Python实现阶跃函数:

import numpy as np
import matplotlib.pyplot as plt

def step_fun(x):
    #方法一
    #y = x > 0
    #return y.astype(int)

    #方法二
    return np.array(x>0,dtype=int)

if __name__ == '__main__':
    x = np.arange(-10,10,0.1)
    y = step_fun(x)
    print(y)

    plt.plot(x,y)
    plt.show()

 

 在神经网络中,则使用一种平滑的曲线作为激活函数,换句话说激活函数从单位阶跃函数换成其他函数,就从感知机的世界走进了神经网络的世界。

1.1 Sigmoid激活函数

首先,给出sigmoid函数的表达式及其图像:

 Python 实现sigmoid函数:

import numpy as np
import matplotlib.pyplot as plt

def sigmoid_fun(x):
    return 1/(1+np.exp(-x))

if __name__ == '__main__':
    x = np.arange(-10,10,0.1)
    y = sigmoid_fun(x)

    plt.plot(x,y)
    plt.show()

通过对比sigmoid函数和阶跃函数,明显可以看出两者的区别,阶跃函数只能返回0和1,sigmoid函数可以返回0-1之间的数,具有一定的平滑作用,当输入信号重要时,输出就会向1靠拢,当输入信号不重要时,输出就会向0靠拢。

为什么神经网络要以非线性函数作为激活函数呢? 

这是线性函数,比如h(x) = cx,采用此函数作为激活函数,那么无论怎么加深隐层深度,总会有一个与之等效的无隐藏层的神经网络,假设有个3层的神经网络,那么可以得到输出y = h(h(h(x))), 即 y = c *c *c *x; 与y = ax(a = c^3)等效, 所以用线性函数作为激活函数无法发挥多层网络带来的优势。

 

 1.2 Relu函数

Relu函数的表达式很简单,此处只给出公式,不做过多的解释:

 

2. 神经网络的实现

与感知机原理类似,但实现神经网络之前,需要简单了解以下矩阵乘法相关的知识以及numpy中矩阵的相关操作,具体可以复习下线性代数的知识,以下是简单的矩阵A*矩阵B:

2.1 实现一个3层的神经网络

下图是一个两个输入两个输出的神经网络结构,具有2个隐层,数据在神经网络中流动满足公式,其中i代表第几层神经网络,m、n、k是矩阵的维度

 如图中所述,除输入数据外的每个神经元的输出都会通过一个激活函数,根据上图,我们利用Python来实现一个简单3层神经网络,注:此处权重、偏置均为人工设定,假设是神经网络学习得到的参数值。

import numpy as np

def sigmoid_fun(x):
    return 1/(1+np.exp(-x))

def Relu_fun(x):
    return np.maximum(0,x)

def init_network():
    network = {} #字典形式保存权重和偏置值
    #根据图中分析,第1层神经网络权重维度为2行3列,偏置1行3列
    network['W1'] = np.array([[0.1, 0.2, 0.3], [0.01, 0.7, 0.4]])
    network['B1'] = np.array([-0.3, -0.8, -0.4])

    #根据图中分析,第2层神经网络权重维度为3行2列,偏置1行2列
    network['W2'] = np.array([[0.3, 0.01], [0.5, 0.3], [0.6, 0.4]])
    network['B2'] = np.array([-0.2, -0.4])

    #根据图中分析,第一层神经网络权重维度为2行2列,偏置1行2列
    network['W3'] = np.array([[0.8, 0.4], [0.05, 0.08]])
    network['B3'] = np.array([-0.06, -0.8])

    return network

def forward_network(x, network):
    A1 = np.dot(x, network['W1']) + network['B1']
    # A1通过sigmoid激活函数
    A1_Hx = sigmoid_fun(A1)
    #print(A1_Hx)

    A2 = np.dot(A1_Hx, network['W2']) + network['B2']
    # A2通过sigmoid激活函数
    A2_Hx = sigmoid_fun(A2)
    #print(A2_Hx)

    A3 = np.dot(A2_Hx, network['W3']) + network['B3']
    #print(A3)
    # A3通过Relu激活函数
    return Relu_fun(A3)

if __name__ == '__main__':
    x = np.array([2, 50])
    network = init_network()
    result = forward_network(x, network)
    print(result)

2.2 输出层激活函数和输出层神经元个数

输出层的激活函数根据是回归问题还是分类问题进行区分,一般情况下回归问题(预测)采用恒等变换,即原来输出什么就输出什么,举个例子,根据一个人的身高年龄等等数据预测一个人的体重,输出的是一个预测值,则该值一般即为我们需要的结果。分类问题又分为二元分类和多元分类,二元分类用sigmoid函数,多元分类用softmax函数,关于sigmoid函数以上介绍比较多,下面介绍softmax函数,首先看softmax函数的表达式:

细心的朋友会发现,其实是每个元素与所有的元素的和之比,也就是概率问题,概率最大的那个元素,分类到它的可能性也就最大,但是在Python中直接使用该公式会存在一点问题,就是ai比较大时,会溢出

测试代码如下:

import numpy as np

def softmax_fun(x):
    sum_x = np.sum(np.exp(x))
    return np.exp(x)/sum_x


if __name__ == '__main__':
    x = np.array([2000, 5])
    y = softmax_fun(x)
    print (y)

为了解决溢出问题,可以利用下面的公式解决,即在计算时,每个数据同时加上或减去一个数,所求softmax函数值不变

 所以,若在计算softmax激活函数时,每个数据都同时减去数据中的最大值,所得的数会变小,则不会溢出,修改后的代码如下:

import numpy as np

def softmax_fun(x):

    sum_x = np.sum(np.exp(x-np.max(x)))
    return np.exp(x-np.max(x))/sum_x


if __name__ == '__main__':
    x = np.array([2000, 5, 1967, 205])
    y = softmax_fun(x)
    print (y)

softmax函数能够得到输出值概率最大的那一项,但是在预测时,它的位置不会发生变化,所以预测时一般不包含softmax函数,但它在神经网络在学习参数有作用。

 

输出神经元数目一般按照分类目标数目确定,比如要识别0-9 十个数字,那么输出神经元的数目一般定为十个。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值