tag 标签: 神经网络

相关帖子
相关博文
  • 热度 2
    2020-1-16 11:50
    1743 次阅读|
    1 个评论
    深度残差网络(deep residual learning, ResNet)获得了2016年CVPR会议的最佳论文奖,截至目前,在谷歌学术上的引用次数已经达到了惊人的37185次。 深度残差收缩网络(deep residual shrinkage network)是深度残差网络的一种新颖的升级版本,其实是深度残差网络、注意力机制(参照Squeeze-and-Excitation Network,SENet)和软阈值化的深度集成。 在一定程度上,深度残差收缩网络的工作原理,可以理解为:通过注意力机制注意到不重要的特征,然后通过软阈值化将它们置为零;或者说,通过注意力机制注意到重要的特征,将它们保留下来,从而加强深度神经网络从含噪声信号中提取有用特征的能力。 1.为什么要提出深度残差收缩网络呢? 首先,在对样本进行分类的时候,样本中不可避免地会有一些噪声,就像高斯噪声、粉色噪声、拉普拉斯噪声等。更广义地讲,样本中很可能包含着与当前分类任务无关的信息,这些信息也可以理解为噪声。这些噪声可能会对分类效果产生不利的影响。(软阈值化是许多信号降噪算法中的一个关键步骤) 举例来说,在马路边聊天的时候,聊天的声音里就可能会混杂车辆的鸣笛声、车轮声等等。当对这些声音信号进行语音识别的时候,识别效果不可避免地会受到鸣笛声、车轮声的影响。从深度学习的角度来讲,这些鸣笛声、车轮声所对应的特征,就应该在深度神经网络内部被删除掉,以避免对语音识别的效果造成影响。 其次,即使是同一个样本集,各个样本的噪声量也往往是不同的。(这和注意力机制有相通之处;以一个图像样本集为例,各张图片中目标物体所在的位置可能是不同的;注意力机制可以针对每一张图片,注意到目标物体所在的位置) 例如,当训练猫狗分类器的时候,对于标签为“狗”的5张图像,第1张图像可能同时包含着狗和老鼠,第2张图像可能同时包含着狗和鹅,第3张图像可能同时包含着狗和鸡,第4张图像可能同时包含着狗和驴,第5张图像可能同时包含着狗和鸭子。我们在训练猫狗分类器的时候,就不可避免地会受到老鼠、鹅、鸡、驴和鸭子等无关物体的干扰,造成分类准确率下降。如果我们能够注意到这些无关的老鼠、鹅、鸡、驴和鸭子,将它们所对应的特征删除掉,就有可能提高猫狗分类器的准确率。 2.软阈值化是很多降噪算法的核心步骤 软阈值化,是很多信号降噪算法的核心步骤,将绝对值小于某个阈值的特征删除掉,将绝对值大于这个阈值的特征朝着零的方向进行收缩。它可以通过以下公式来实现: 软阈值化的输出对于输入的导数为 由上可知,软阈值化的导数要么是1,要么是0。这个性质是和ReLU激活函数是相同的。因此,软阈值化也能够减小深度学习算法遭遇梯度弥散和梯度爆炸的风险。 在软阈值化函数中,阈值的设置必须符合两个的条件: 第一,阈值是正数;第二,阈值不能大于输入信号的最大值,否则输出会全部为零。 同时,阈值最好还能符合第三个条件: 每个样本应该根据自身的噪声含量,有着自己独立的阈值。 这是因为,很多样本的噪声含量经常是不同的。例如经常会有这种情况,在同一个样本集里面,样本A所含噪声较少,样本B所含噪声较多。那么,如果是在降噪算法里进行软阈值化的时候,样本A就应该采用较大的阈值,样本B就应该采用较小的阈值。在深度神经网络中,虽然这些特征和阈值失去了明确的物理意义,但是基本的道理还是相通的。也就是说,每个样本应该根据自身的噪声含量,有着自己独立的阈值。 3.注意力机制 注意力机制在计算机视觉领域是比较容易理解的。动物的视觉系统可以快速扫描全部区域,发现目标物体,进而将注意力集中在目标物体上,以提取更多的细节,同时抑制无关信息。具体请参照注意力机制方面的文章。 Squeeze-and-Excitation Network(SENet)是一种较新的注意力机制下的深度学习方法。 在不同的样本中,不同的特征通道,在分类任务中的贡献大小,往往是不同的。SENet采用一个小型的子网络,获得一组权重,进而将这组权重与各个通道的特征分别相乘,以调整各个通道特征的大小。这个过程,就可以认为是在施加不同大小的注意力在各个特征通道上。 在这种方式下,每一个样本,都会有自己独立的一组权重。换言之,任意的两个样本,它们的权重,都是不一样的。在SENet中,获得权重的具体路径是,“全局池化→全连接层→ReLU函数→全连接层→Sigmoid函数”。 4.深度注意力机制下的软阈值化 深度残差收缩网络借鉴了上述SENet的子网络结构,以实现注意力机制下的软阈值化。通过蓝色框内的子网络,就可以学习得到一组阈值,对各个特征通道进行软阈值化。 在这个子网络中,首先对输入特征图的所有特征,求它们的绝对值。然后经过全局均值池化和平均,获得一个特征,记为A。在另一条路径中,全局均值池化之后的特征图,被输入到一个小型的全连接网络。这个全连接网络以Sigmoid函数作为最后一层,将输出归一化到0和1之间,获得一个系数,记为α。最终的阈值可以表示为α×A。因此,阈值就是,一个0和1之间的数字×特征图的绝对值的平均。 通过这种方式,保证了阈值为正,而且不会太大。 而且,不同的样本就有了不同的阈值。因此,在一定程度上,可以理解成一种特殊的注意力机制: 注意到与当前任务无关的特征,通过软阈值化,将它们置为零;或者说,注意到与当前任务有关的特征,将它们保留下来。 5.深度残差收缩网络或许有更广泛的通用性 深度残差收缩网络事实上是一种通用的数据分类方法。 这是因为很多分类任务中,样本中或多或少都会包含一些噪声,以及不相关的信息。这些噪声和不相关的信息,有可能会对分类的效果造成影响。例如说: 在图片分类的时候 ,如果图片同时包含着很多其他的物体,那么这些物体就可以被理解成“噪声”;深度残差收缩网络或许能够借助注意力机制,注意到这些“噪声”,然后借助软阈值化,将这些“噪声”所对应的特征置为零,就有可能提高图像分类的准确率。 在语音识别的时候 ,如果在声音较为嘈杂的环境里,比如在马路边、工厂车间里聊天的时候,深度残差收缩网络也许可以提高语音识别的准确率,或者给出了一种能够提高语音识别准确率的思路。 参考网址 深度残差收缩网络:(四)注意力机制下的阈值设置 https://www.cnblogs.com/yc-9527/p/11604082.html 【深度残差收缩网络论文翻译】 Deep Residual Shrinkage Networks for Fault Diagnosis https://www.jianshu.com/p/bcdc9d75a302 秒懂深度残差收缩网络 https://www.jianshu.com/p/90f1ef1b06bc 论文网址 M. Zhao, S. Zhong, X. Fu, et al., Deep residual shrinkage networks for fault diagnosis, IEEE Transactions on Industrial Informatics, DOI: 10.1109/TII.2019.2943898 https://ieeexplore.ieee.org/document/8850096
  • 热度 2
    2020-1-15 20:52
    1918 次阅读|
    1 个评论
    【残差网络升级】深度残差收缩网络
    深度残差网络(ResNet)是一种非常成功的深度学习模型,自2015年底在arXiv公布以来,在谷歌学术上的引用量已经达到了惊人的37185次。深度残差收缩网络是ResNet的一种新型改进,这篇文章将进行详细的介绍。 首先,深度残差网络的核心贡献在于,引入了恒等映射,也就是下图中的Identity shortcut。普通的卷积神经网络是没有跨层的恒等映射的。更具体地,下图中的(a)-(c)展示了三种残差模块(residual building unit, RBU),每个残差模块都包含了一个恒等映射。在图(a)中,输入特征图和输出特征图的尺寸是相同的。在图(b)和(c)中,输出特征图的尺寸是和输入特征图不同的。深度残差网络的整体结构如图(d)所示。我们可以发现,深度残差网络的主体部分,是由很多残差模块堆叠而成的。 通常情况下,样本中含有噪声,或者与标签无关的冗余信息,会导致深度学习算法的效果有所降低。那么怎么解决这个问题呢?深度残差收缩网络提供了一种思路。 深度残差收缩网络的主要工作之一,就是在残差模块中添加了软阈值化,作为非线性的变换。如下图(a)所示,软阈值化将绝对值小于某一阈值的特征,直接赋值为零。将其他的特征,朝着零的方向,进行一定程度的“收缩”。这也是深度残差收缩网络名称的由来。 在图(b)中,作者进一步分析了软阈值化函数的梯度特性:梯度值要么为0,要么为1。与ReLU激活函数类似,这一特性减小了深度学习在训练时遭遇“梯度消失”和“梯度爆炸”的风险。 另外,阈值的取值是要满足一些条件的。第一,阈值是正数。第二,阈值不能太大。假设输入特征的取值都在-1和1之间,如果阈值为10,那么输出就会全部是0。第三,每个样本都应该根据自己的噪声含量,确定自己的阈值。也就是说,样本之间,应该有不同的阈值设置。 在深度残差收缩网络的残差模块中,嵌入了一个子模块(类似Squeeze-and-Excitation Networks),用于自动地设置软阈值化函数所用到的阈值。在图(a)中,整个特征图共用一个阈值。在图(c)中,特征图的每个通道各有一个独立的阈值。同时,图(b)和图(d)展示了两种深度残差收缩网络(DRSN-CS和DRSN-CW)的整体结构。我们可以发现,它们的整体结构其实是一致的,唯一的区别在于残差模块的不同。 我们可以看到,在这种网络结构之下,所获得的阈值,不仅为正数,而且取值不会太大(不会让所有输出全部为0)。另外,每个样本的阈值都是根据自己的特征图所确定的,因此每个样本都会有它自己独特的一组阈值。从而满足了上述关于阈值的三个条件。 作者采集了齿轮箱在健康状态和7种故障状态下的振动信号,进行分类算法的验证。在这里,为了充分验证深度残差收缩网络对含噪信号的分类能力,作者在这些振动信号中分别添加了不同程度的高斯白噪声、拉普拉斯噪声和粉红噪声,并且与一般的卷积神经网络(ConvNet)和深度残差网络(ResNet)进行了对比。 下面是添加-5dB到5dB高斯白噪声时的分类准确率对比:(a)训练集上的准确率,(b)测试集上的准确率 然后是添加-5dB到5dB拉普拉斯噪声时的分类准确率对比:(a)训练集上的准确率,(b)测试集上的准确率 最后是添加-5dB到5dB粉红噪声时的分类准确率对比:(a)训练集上的准确率,(b)测试集上的准确率 将高层特征约简到二维空间进行可视化,可以得到如下图片:(a) ConvNet,(b) ResNet,(c) 第一种深度残差收缩网络(DRSN-CS),(d)第二种深度残差收缩网络(DRSN-CW)。我们可以看到,深度残差收缩网络能够更好地将各种健康状态分离开来。 将训练过程中训练集和测试集上的损失绘制出来,可以得到如下图片:(a) ConvNet,(b) ResNet,(c) 第一种深度残差收缩网络(DRSN-CS),(d)第二种深度残差收缩网络(DRSN-CW)。可以看到深度残差收缩网络的loss被优化得更低。 M. Zhao, S. Zhong, X. Fu, B. Tang, M. Pecht, Deep Residual Shrinkage Networks for Fault Diagnosis, IEEE Transactions on Industrial Informatics, 2019, DOI: 10.1109/TII.2019.2943898 https://ieeexplore.ieee.org/document/8850096
  • 热度 2
    2020-1-15 10:05
    1434 次阅读|
    2 个评论
    深度残差收缩网络的Keras图像识别
    从本质上讲,深度残差收缩网络属于卷积神经网络,是深度残差网络(deep residual network, ResNet)的一个变种。它的核心思想在于,在深度学习进行特征学习的过程中,剔除冗余信息是非常重要的;软阈值化是一种非常灵活的、删除冗余信息的方式。 1.深度残差网络 首先,在介绍深度残差收缩网络的时候,经常需要从深度残差网络开始讲起。下图展示了深度残差网络的基本模块,包括一些非线性层(残差路径)和一个跨层的恒等连接。恒等连接是深度残差网络的核心,是其优异性能的一个保障。 2.深度残差收缩网络 深度残差收缩网络,就是对深度残差网络的残差路径进行收缩的一种网络。这里的“收缩”指的就是软阈值化。 软阈值化是许多信号降噪方法的核心步骤,它是将接近于零(或者说绝对值低于某一阈值τ)的特征置为0,也就是将 区间内的特征置为0,让其他的、距0较远的特征也朝着0进行收缩。 如果和前一个卷积层的偏置b放在一起看的话,这个置为零的区间就变成了 。因为τ和b都是可以自动学习得到的参数,这个角度看的话,软阈值化其实是可以将任意区间的特征置为零,是一种更灵活的、删除某个取值范围特征的方式,也可以理解成一种更灵活的非线性映射。 从另一个方面来看,前面的两个卷积层、两个批标准化和两个激活函数,将冗余信息的特征,变换成接近于零的值;将有用的特征,变换成远离零的值。之后,通过自动学习得到一组阈值,利用软阈值化将冗余特征剔除掉,将有用特征保留下来。 通过堆叠一定数量的基本模块,可以构成完整的深度残差收缩网络,如下图所示: 3.图像识别及Keras编程 虽然深度残差收缩网络原先是应用于基于振动信号的故障诊断,但是深度残差收缩网络事实上是一种通用的特征学习方法,相信在很多任务(计算机视觉、语音、文本)中都可能有一定的用处。 下面是基于深度残差收缩网络的MNIST手写数字识别程序(程序很简单,仅供参考): #!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Created on Sat Dec 28 23:24:05 2019 Implemented using TensorFlow 1.0.1 and Keras 2.2.1 M. Zhao, S. Zhong, X. Fu, et al., Deep Residual Shrinkage Networks for Fault Diagnosis, IEEE Transactions on Industrial Informatics, 2019, DOI: 10.1109/TII.2019.2943898 @author: me """ from __future__ import print_function import keras import numpy as np from keras.datasets import mnist from keras.layers import Dense, Conv2D, BatchNormalization, Activation from keras.layers import AveragePooling2D, Input, GlobalAveragePooling2D from keras.optimizers import Adam from keras.regularizers import l2 from keras import backend as K from keras.models import Model from keras.layers.core import Lambda K.set_learning_phase(1) # Input image dimensions img_rows, img_cols = 28, 28 # The data, split between train and test sets (x_train, y_train), (x_test, y_test) = mnist.load_data() if K.image_data_format() == 'channels_first': x_train = x_train.reshape(x_train.shape , 1, img_rows, img_cols) x_test = x_test.reshape(x_test.shape , 1, img_rows, img_cols) input_shape = (1, img_rows, img_cols) else: x_train = x_train.reshape(x_train.shape , img_rows, img_cols, 1) x_test = x_test.reshape(x_test.shape , img_rows, img_cols, 1) input_shape = (img_rows, img_cols, 1) # Noised data x_train = x_train.astype('float32') / 255. + 0.5*np.random.random( , img_rows, img_cols, 1]) x_test = x_test.astype('float32') / 255. + 0.5*np.random.random( , img_rows, img_cols, 1]) print('x_train shape:', x_train.shape) print(x_train.shape , 'train samples') print(x_test.shape , 'test samples') # convert class vectors to binary class matrices y_train = keras.utils.to_categorical(y_train, 10) y_test = keras.utils.to_categorical(y_test, 10) def abs_backend(inputs): return K.abs(inputs) def expand_dim_backend(inputs): return K.expand_dims(K.expand_dims(inputs,1),1) def sign_backend(inputs): return K.sign(inputs) def pad_backend(inputs, in_channels, out_channels): pad_dim = (out_channels - in_channels)//2 return K.spatial_3d_padding(inputs, padding = ((0,0),(0,0),(pad_dim,pad_dim))) # Residual Shrinakge Block def residual_shrinkage_block(incoming, nb_blocks, out_channels, downsample=False, downsample_strides=2): residual = incoming in_channels = incoming.get_shape().as_list() for i in range(nb_blocks): identity = residual if not downsample: downsample_strides = 1 residual = BatchNormalization()(residual) residual = Activation('relu')(residual) residual = Conv2D(out_channels, 3, strides=(downsample_strides, downsample_strides), padding='same', kernel_initializer='he_normal', kernel_regularizer=l2(1e-4))(residual) residual = BatchNormalization()(residual) residual = Activation('relu')(residual) residual = Conv2D(out_channels, 3, padding='same', kernel_initializer='he_normal', kernel_regularizer=l2(1e-4))(residual) # Calculate global means residual_abs = Lambda(abs_backend)(residual) abs_mean = GlobalAveragePooling2D()(residual_abs) # Calculate scaling coefficients scales = Dense(out_channels, activation=None, kernel_initializer='he_normal', kernel_regularizer=l2(1e-4))(abs_mean) scales = BatchNormalization()(scales) scales = Activation('relu')(scales) scales = Dense(out_channels, activation='sigmoid', kernel_regularizer=l2(1e-4))(scales) scales = Lambda(expand_dim_backend)(scales) # Calculate thresholds thres = keras.layers.multiply( ) # Soft thresholding sub = keras.layers.subtract( ) zeros = keras.layers.subtract( ) n_sub = keras.layers.maximum( ) residual = keras.layers.multiply( ) # Downsampling (it is important to use the pooL-size of (1, 1)) 1: identity = AveragePooling2D(pool_size=(1,1), strides=(2,2))(identity) # Zero_padding to match channels (it is important to use zero padding rather than 1by1 convolution) if in_channels != out_channels: identity = Lambda(pad_backend)(identity, in_channels, out_channels) residual = keras.layers.add( ) return residual # define and train a model inputs = Input(shape=input_shape) net = Conv2D(8, 3, padding='same', kernel_initializer='he_normal', kernel_regularizer=l2(1e-4))(inputs) net = residual_shrinkage_block(net, 1, 8, downsample=True) net = BatchNormalization()(net) net = Activation('relu')(net) net = GlobalAveragePooling2D()(net) outputs = Dense(10, activation='softmax', kernel_initializer='he_normal', kernel_regularizer=l2(1e-4))(net) model = Model(inputs=inputs, outputs=outputs) model.compile(loss='categorical_crossentropy', optimizer=Adam(), metrics= ) model.fit(x_train, y_train, batch_size=100, epochs=5, verbose=1, validation_data=(x_test, y_test)) # get results K.set_learning_phase(0) DRSN_train_score = model.evaluate(x_train, y_train, batch_size=100, verbose=0) print('Train loss:', DRSN_train_score ) print('Train accuracy:', DRSN_train_score ) DRSN_test_score = model.evaluate(x_test, y_test, batch_size=100, verbose=0) print('Test loss:', DRSN_test_score ) print('Test accuracy:', DRSN_test_score ) 为方便对比,深度残差网络的代码如下: #!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Created on Sat Dec 28 23:19:03 2019 Implemented using TensorFlow 1.0 and Keras 2.2.1 K. He, X. Zhang, S. Ren, J. Sun, Deep Residual Learning for Image Recognition, CVPR, 2016. @author: me """ from __future__ import print_function import numpy as np import keras from keras.datasets import mnist from keras.layers import Dense, Conv2D, BatchNormalization, Activation from keras.layers import AveragePooling2D, Input, GlobalAveragePooling2D from keras.optimizers import Adam from keras.regularizers import l2 from keras import backend as K from keras.models import Model from keras.layers.core import Lambda K.set_learning_phase(1) # input image dimensions img_rows, img_cols = 28, 28 # the data, split between train and test sets (x_train, y_train), (x_test, y_test) = mnist.load_data() if K.image_data_format() == 'channels_first': x_train = x_train.reshape(x_train.shape , 1, img_rows, img_cols) x_test = x_test.reshape(x_test.shape , 1, img_rows, img_cols) input_shape = (1, img_rows, img_cols) else: x_train = x_train.reshape(x_train.shape , img_rows, img_cols, 1) x_test = x_test.reshape(x_test.shape , img_rows, img_cols, 1) input_shape = (img_rows, img_cols, 1) # Noised data x_train = x_train.astype('float32') / 255. + 0.5*np.random.random( , img_rows, img_cols, 1]) x_test = x_test.astype('float32') / 255. + 0.5*np.random.random( , img_rows, img_cols, 1]) print('x_train shape:', x_train.shape) print(x_train.shape , 'train samples') print(x_test.shape , 'test samples') # convert class vectors to binary class matrices y_train = keras.utils.to_categorical(y_train, 10) y_test = keras.utils.to_categorical(y_test, 10) def pad_backend(inputs, in_channels, out_channels): pad_dim = (out_channels - in_channels)//2 return K.spatial_3d_padding(inputs, padding = ((0,0),(0,0),(pad_dim,pad_dim))) def residual_block(incoming, nb_blocks, out_channels, downsample=False, downsample_strides=2): residual = incoming in_channels = incoming.get_shape().as_list() for i in range(nb_blocks): identity = residual if not downsample: downsample_strides = 1 residual = BatchNormalization()(residual) residual = Activation('relu')(residual) residual = Conv2D(out_channels, 3, strides=(downsample_strides, downsample_strides), padding='same', kernel_initializer='he_normal', kernel_regularizer=l2(1e-4))(residual) residual = BatchNormalization()(residual) residual = Activation('relu')(residual) residual = Conv2D(out_channels, 3, padding='same', kernel_initializer='he_normal', kernel_regularizer=l2(1e-4))(residual) # Downsampling (it is important to use the pooL-size of (1, 1)) 1: identity = AveragePooling2D(pool_size=(1, 1), strides=(2, 2))(identity) # Zero_padding to match channels (it is important to use zero padding rather than 1by1 convolution) if in_channels != out_channels: identity = Lambda(pad_backend)(identity, in_channels, out_channels) residual = keras.layers.add( ) return residual # define and train a model inputs = Input(shape=input_shape) net = Conv2D(8, 3, padding='same', kernel_initializer='he_normal', kernel_regularizer=l2(1e-4))(inputs) net = residual_block(net, 1, 8, downsample=True) net = BatchNormalization()(net) net = Activation('relu')(net) net = GlobalAveragePooling2D()(net) outputs = Dense(10, activation='softmax', kernel_initializer='he_normal', kernel_regularizer=l2(1e-4))(net) model = Model(inputs=inputs, outputs=outputs) model.compile(loss='categorical_crossentropy', optimizer=Adam(), metrics= ) model.fit(x_train, y_train, batch_size=100, epochs=5, verbose=1, validation_data=(x_test, y_test)) # get results K.set_learning_phase(0) resnet_train_score = model.evaluate(x_train, y_train, batch_size=100, verbose=0) print('Train loss:', resnet_train_score ) print('Train accuracy:', resnet_train_score ) resnet_test_score = model.evaluate(x_test, y_test, batch_size=100, verbose=0) print('Test loss:', resnet_test_score ) print('Test accuracy:', resnet_test_score ) 备注: (1)深度残差收缩网络的结构比普通的深度残差网络复杂,也许更难训练。 (2)程序里只设置了一个基本模块,在更复杂的数据集上,可适当增加。 (3)如果遇到这个TypeError:softmax() got an unexpected keyword argument 'axis',就点开tensorflow_backend.py,将return tf.nn.softmax(x, axis=axis)中的第一个axis改成dim即可。 参考文献: M. Zhao, S. Zhong, X. Fu, et al., Deep residual shrinkage networks for fault diagnosis, IEEE Transactions on Industrial Informatics, 2019, DOI: 10.1109/TII.2019.2943898 https://ieeexplore.ieee.org/document/8850096
  • 热度 3
    2019-11-4 21:09
    824 次阅读|
    2 个评论
    【零基础】使用Tensorflow实现神经网络
    一、序言   前面已经逐步从单神经元慢慢“爬”到了神经网络并把常见的优化都逐个解析了,再往前走就是一些实际应用问题,所以在开始实际应用之前还得把“框架”翻出来,因为后面要做的工作需要我们将精力集中在业务而不是网络本身,所以使用框架可以减少非常多的工作量,有了前面自己实现神经网络的经验,现在理解框架的一些设置也比较容易了。本篇我们就使用比较常见的Tensorflow来重置一下前面的工作。   备注一下Tensorflow的安装:   1)安装python3.6,高版本不支持   2)pip install tensorflow即可 二、softmax   在开始前需要先说下这里使用的一个新的技术“softmax”,前面我们解决的问题是“从一堆图片里识别出数字是否是9”,这里使用softmax我们可以搞定更加高深一点的问题,比如:   “识别出图片中的数字是几”   这就厉害了,前面我们只能识别是不是,即”二分类“,这里借助softmax我们可以识别图片是数字几的概率,即”多分类“。   从技术上来说其实变化不大,神经网络整体结构不变,但是还记得我们之前神经网络中使用的”激活函数“不?一般最后一层使用sigmoid,意思是将输出转为0-1之间的区间值,表示为”是数字9“的概率是多少。这里使用softmax替代sigmoid,此外输出也不是一个数,而是10个数,比如:      它的含义如下:   0的概率:10%   1的概率:20%   3的概率:30%   4的概率:70%   ...   相应的输入的label自然也是十个数,比如:      它表示我们输入的图片是数字”4“,此种表示方式称为"one_hot_label"。此种输入与输出形式就是"多分类"的基础,此外我们使用的mnist数据集可以直接将label数据转为one hot形式,只需要"one_hot_label=True"。   除了输入输出形式不一样,softmax的传播函数和反向传播肯定与sigmoid不一样了,不过借助Tensorflow强大的功能这些我们都不需要操心啦。下面我们就逐步来实现一个基于Tensorflow的神经网络。 三、创建占位符placeholder   其实这里的输入x,y代表的分别是输入图片的向量大小784和label的向量大小10。tf是tensorflow的实体,这里tf.placeholder其实就是定义了两个空的数组:   (784, None)和(10, None)   placeholder得到的一维向量在后面的作用是"占位",占位的意思是在tensorflow构建神经网络时先把位置占好,真正运行时就按这个占位的样子往里面扔数据,比如X是784,输入的img也不管你啥形状了,反正就按784将输入截成一段一段的。 四、初始化参数w、b   整体上来说与前面初始化参数差不多,变化的除了使用tf来产生随机数,还将wGroup和bGroup合并为parameters(tf框架只给输入一个参数名)。 五、传播函数   这里tf.matmul()就是实现矩阵w与IN的乘积,再通过tf.add()实现加b。但这里的"传播函数"并没有真的做传播运算,它只是按神经网络的结构将各种运算”安排“好,运算到最后一层没有使用激活函数来计算结果,而是直接返回A。剩下的运算放到了”损失函数“中。 六、损失函数   这里的tf.transpose()只是一个转置操作,之所以不用A.T这种方式,其实可以想到,此处的A并不是一个矩阵,它是一长串计算的结果,只有当神经网络运行起来了A才会是一个矩阵。所以这里的A其实是一系列“运算”的合集,使用tf.transpose()就是叠加了一个转置运算。   tf.reduce_mean()在这里就是计算"损失"的,不过暂时也不是真的计算了,只是将这个运算"安排"好了,最终结果返回为costFun 七、完整实现   等等,还没有说"反向传播"呢?不要慌,这里慢慢来。   在model中,placeholder、initialize_parameters、forward、costCAL都是前面讲过的,只是"构建"神经网络计算的过程。   optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(costFun)   这一句就是构建反向传播,其中AdamOptimizer表明使用Adam优化算法,minimize指明使用的损失函数,其实总结起来就是我们的反向传播需要使用Adam优化算法来使costFun构建的损失函数趋向于最小。   _ , cost = sess.run( , feed_dict={X: train_img, Y: train_label})   这一句就是真的运行网络了,feed_dict就是按前面"占位符"的形状将train_img和train_label输入到网络中, 是指明网络的“向前传播+反向传播”和损失计算。   parameters = sess.run(parameters)   只是将优化后的参数按原样输出回来。 八、总结   本节只是简单将之前实现过的神经网络用Tensorflow再实现了一次,其次还引入了softmax将二分类扩展为多分类。Tensorflow是后面研究的基础,可能再开一章单独讲一讲。    本节完整实现代码请关注公众号“零基础爱学习”回复AI14获取。
  • 热度 2
    2019-10-29 23:16
    735 次阅读|
    1 个评论
    【零基础】神经网络优化之Adam
    一、序言   Adam是神经网络优化的另一种方法,有点类似上一篇中的“动量梯度下降”,实际上是先提出了RMSprop(类似动量梯度下降的优化算法),而后结合RMSprop和动量梯度下降整出了Adam,所以这里我们先由动量梯度下降引申出RMSprop,最后再介绍Adam。不过,由于RMSprop、Adam什么的,真的太难理解了,我就只说实现不说原理了。 二、RMSprop   先回顾一下动量梯度下降中的“指数加权平均”公式:   vDW1 = beta*vDW0 + (1-beta)*dw1   vDb1 = beta*vDb0 + (1-beta)*db1   动量梯度下降:   W = W -learning_rate*vDW   b = b -learning_rate*vDb   简而言之就是在更新W和b时不使用dw和db,而是使用其“指数加权平均”的值。   RMSprop只是做了一点微小的改变,为了便于区分将v改成s:   sDW1= beta*sDW0 + (1-beta)*dw1^2   sDb1 =beta*sDb0 + (1-beta)*db1^2   RMSprop梯度下降,其中sqrt是开平方根的意思:   W = W -learning_rate*(dw/sqrt(sDW))   b = b-learning_rate*(db/sqrt(sDb))   需要注意的是,无论是dw^2还是sqrt(sDW)都是矩阵内部元素的平方或开根。 三、Adam   Adam是结合动量梯度下降和RMSprop的混合体,先按动量梯度下降算出vDW、vDb   vDW1 = betaV*vDW0 + (1-beta)*dw1   vDb1 = betaV*vDb0 + (1-beta)*db1   然后按RMSprop算出sDW、sDb:   sDW1= betaS*sDW0 + (1-beta)*dw1^2   sDb1 =betaS*sDb0 + (1-beta)*db1^2   最后Adam的梯度下降是结合了v和s:   W = W -learning_rate*( vDW/sqrt(sDW) )   b = b -learning_rate*( vDb/sqrt(sDb) )   我们来看下最终实现后的效果:   是的,你没有看错。。。只需要100次训练,就比以前2000次训练的效果还要好!看到这个结果其实我也很震惊,反复查了几遍。   不过使用Adam优化后的神经网络一定要注意learning_rate的设置,我这里改成了0.01(之前一直是0.1,多次试错后才发现是这个问题)否则会发生梯度消失(表现为dw等于0)。 四、回顾   本篇是在mini_batch的基础上,结合动量梯度下降、RMSprop做的Adam梯度下降,其目的与mini_batch、动量梯度下降一样,都是使神经网络可以更快找到最优解,不得不说Adam实在太给力了。 完整的实现代码请关注公众号“零基础爱学习”回复“AI13”获取。
相关资源
广告