深度学习_全连接神经网络
1.什么是神经网络
神经网络中信息只向一个方向移动,即从输入节点向前移动,通过隐藏节点,再向输出节点移
动,网络中没有循环或者环。其中的基本构件是:
输入层:即输入x的那一层
输出层:即输出y的那一层
隐藏层:输入层和输出层之间都是隐藏层
特点是:
同一层的神经元之间没有连接。
第N层的每个神经元和第N-1层的所有神经元相连(这就是full connected的含义),第N-1层神
经元的输出就是第N层神经元的输入。
每个连接都有一个权值。
2.神经元是如何工作的
人工神经元接收到一个或多个输入,对他们进行加权并相加,总和通过一个非线性函数产生输
出。
3.激活函数
在神经元中引入了激活函数,它的本质是向神经网络中引入非线性因素的,通过激活函数,神经
网络就可以拟合各种曲线。
如果不用激活函数,每一层输出都是上层输入的线性函数,无论神经网络有多少层,输出都是输入的线性组合,引入非线性函数作为激活函数,那输出不再是输入的线性组合,可以逼近任意函数。
常用的激活函数有:
3.1 Sigmoid/logistics函数
sigmoid 在定义域内处处可导,且两侧导数逐渐趋近于0。如果X的值很大或者很小的时候,那么
函数的梯度(函数的斜率)会非常小,在反向传播的过程中,导致了向低层传递的梯度也变得非
常小。此时,网络参数很难得到有效训练。这种现象被称为梯度消失。
一般来说, sigmoid 网络在 5 层之内就会产生梯度消失现象。而且,该激活函数并不是以0为中心的,所以在实践中这种激活函数使用的很少。sigmoid函数一般只用于二分类的输出层。
3.2 tanh(双曲正切曲线)
tanh也是一种非常常见的激活函数。与sigmoid相比,它是以0为中心的,使得其收敛速度要比
sigmoid快,减少迭代次数。然而,从图中可以看出,tanh两侧的导数也为0,同样会造成梯度消
失。
若使用时可在隐藏层使用tanh函数,在输出层使用sigmoid函数。
3.3 ReLu
ReLU是目前最常用的激活函数。 从图中可以看到,当x<0时,ReLU导数为0,而当x>0时,则不存在饱和问题。所以,ReLU 能够在x>0时保持梯度不衰减,从而缓解梯度消失问题。
然而,随着训练的推进,部分输入会落入小于0区域,导致对应权重无法更新。这种现象被称为“神经元死亡”。
与sigmoid相比,RELU的优势是:
- 采用sigmoid函数,计算量大(指数运算),反向传播求误差梯度时,求导涉及除法,计算
量相对大,而采用Relu激活函数,整个过程的计算量节省很多。 - sigmoid函数反向传播时,很容易就会出现梯度消失的情况,从而无法完成深层网络的训
练。 - Relu会使一部分神经元的输出为0,这样就造成了网络的稀疏性,并且减少了参数的相互依
存关系,缓解了过拟合问题的发生。
3.3 LeakReLu
3.5 SoftMax
softmax用于多分类过程中,它是二分类函数sigmoid在多分类上的推广,目的是将多分类的结果以概率的形式展现出来。
softmax直白来说就是将网络输出的logits通过softmax函数,就映射成为(0,1)的值,而这些值的累和为1(满足概率的性质),那么我们将它理解成概率,选取概率最大(也就是值对应最大的)接点,作为我们的预测目标类别。
3.6 其他激活函数
3.7 如何选择激活函数
隐藏层
- 优先选择RELU激活函数
- 如果ReLu效果不好,那么尝试其他激活,如Leaky ReLu等
- 如果你使用了Relu, 需要注意一下Dead Relu问题, 避免出现大的梯度从而导致过多的神经元死亡
- 不要使用sigmoid激活函数,可以尝试使用tanh激活函数
输出层
- 二分类问题选择sigmoid激活函数
- 多分类问题选择softmax激活函数
- 回归问题选择identity激活函数
4. 神经网络的优缺点
1.优点
- 精度高,性能优于其他的机器学习方法,甚至在某些领域超过了人类
- 可以近似任意的非线性函数
- 随之计算机硬件的发展,近年来在学界和业界受到了热捧,有大量的框架和库可供调用
2.缺点 - 黑箱,很难解释模型是怎么工作的
- 训练时间长,需要大量的计算力
- 网络结构复杂,需要调整超参数
- 小数据集上表现不佳,容易发生过拟合
5.神经网络案例
手写数字的识别
# 导入相应的工具包
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['figure.figsize'] = (7,7) # Make the figures a bit bigger
import tensorflow as tf
# 数据集
from tensorflow.keras.datasets import mnist
# 构建序列模型
from tensorflow.keras.models import Sequential
# 导入需要的层
from tensorflow.keras.layers import Dense, Dropout,
Activation,BatchNormalization
# 导入辅助工具包
from tensorflow.keras import utils
# 正则化
from tensorflow.keras import regularizers# 类别总数
nb_classes = 10
# 加载数据集
(X_train, y_train), (X_test, y_test) = mnist.load_data()
# 打印输出数据集的维度
print("训练样本初始维度", X_train.shape)
print("训练样本目标值初始维度", y_train.shape)# 数据展示:将数据集的前九个数据集进行展示
for i in range(9):
plt.subplot(3,3,i+1)
# 以灰度图显示,不进行插值
plt.imshow(X_train[i], cmap='gray', interpolation='none')
# 设置图片的标题:对应的类别
plt.title("数字{}".format(y_train[i]))# 数据处理
# 神经网络中的每个训练样本是一个向量,因此需要对输入进行重塑,使每个28x28的图像成为一个的784维向量。另外,将输入数据进行归一化处理,从0-255调整到0-1# 调整数据维度:每一个数字转换成一个向量
X_train = X_train.reshape(60000, 784)
X_test = X_test.reshape(10000, 784)
# 格式转换
X_train = X_train.astype('float32')
X_test = X_test.astype('float32')
# 归一化
X_train /= 255
X_test /= 255
# 维度调整后的结果
print("训练集:", X_train.shape)
print("测试集:", X_test.shape)# 将目标值转换为热编码的形式
Y_train = utils.to_categorical(y_train, nb_classes)
Y_test = utils.to_categorical(y_test, nb_classes)# 利用序列模型来构建模型
model = Sequential()
# 全连接层,共512个神经元,输入维度大小为784
model.add(Dense(512, input_shape=(784,)))
# 激活函数使用relu
model.add(Activation('relu'))
# 使用正则化方法drouout
model.add(Dropout(0.2))
# 全连接层,共512个神经元,并加入L2正则化
model.add(Dense(512,kernel_regularizer=regularizers.l2(0.001)))
# BN层
model.add(BatchNormalization())
# 激活函数
model.add(Activation('relu'))
model.add(Dropout(0.2))
# 全连接层,输出层共10个神经元
model.add(Dense(10))
# softmax将神经网络输出的score转换为概率值
model.add(Activation('softmax'))# 模型编译,指明损失函数和优化器,评估指标
model.compile(loss='categorical_crossentropy', optimizer='adam',metrics=
['accuracy'])# batch_size是每次送入模型中样本个数,epochs是所有样本的迭代次数,并指明验证数据集
history = model.fit(X_train, Y_train,
batch_size=128, epochs=4,verbose=1,
validation_data=(X_test, Y_test))
Q1: 为什么要对数据进行归一化
Q2:为什么要对数据进行热编码