卷积神经网络通俗易懂篇

    欢迎关注本人的微信公众号AI_Engine

    由于工作的原因,本人有一段时间没有更新文章了,再加上前一段时间出差去了趟杭州,基本每天凌晨下班,整个人都已经不好了。在杭州的时候和同事们讨论了下卷积神经网络的构成和原理,今天小编就和大家一起粗略的neng1neng这个卷积神经网路吧。

    上回书我们说到了感知器,这个只有两层的神经网络显得有些单薄,只能解决线性可分的问题。在这之后伊瓦赫年科提出可多层人工神经网络的设想,也正是基于多层神经网路的机器学习才逐渐衍生出了现如今的深度学习。常见的多层神经网络的结构就是这个样子:输出层===>隐藏层===>输出层,当然中间还包括了激活函数,正反向传播等逆天的操作,由于本文主要讲解卷积神经网络的内容,所以后续有需要的话会将多层感知器的内容补上。

    好了,先让我们一睹为快,what is a 卷积神经网络?(Convolutional Neural Network,后续统一称为CNN),This is a CNN!是不是有点懵逼?说实话我第一眼看到的时候可能比大家还要懵逼,不过没有关系,让我们一层一层一层一层的剥开CNN的心。

    首先介绍CNN存在的意义,本人秉着存在即合理的态度告诉大家,CNN存在的理由就是:解放人类。在传统的机器学习任务中,算法的性能好坏很大程度上取决于特征工程做得好不好,而特征工程恰恰是最耗费时间和人力的,所以在图像、语言、视频处理中就显得更加困难。CNN可以做到从原始数据出发,避免前期的数据处理(特征抽取),在数据中找出规律,进而完成任务,这也就是端到端的含义(某为中经常会听到这三字)。理由已经和大家说我了,现在我们就来剥了它吧。

    卷积层。我们从结构出发,通常最左边为输入层,对数据可能需要做一些处理,比如去均值(把输入数据各个维度都中心化为0,避免数据过多偏差,影响训练效果)、归一化(把所有的数据都归一到同样的范围)、PCA/白化等等。下一层即为卷积层了,这一层的主要目的就是将数据与权重矩阵(滤波器)进行线性乘积并输出特征图。下图中红框框起来的部分便可以理解为一个滤波器,即带着一组固定权重的神经元,多个滤波器叠加便成了卷积层。

    我们举个例子, 比如下图中左边部分是原始输入数据,中间部分是滤波器filter,图中右边是输出的新的特征图:

    在CNN中,滤波器filter对局部输入数据进行卷积计算。每计算完一个数据窗口内的局部数据后,数据窗口不断平移滑动,直到计算完所有数据。这个过程中,有这么几个参数: a. 深度depth:神经元个数,决定输出的depth厚度。同时代表滤波器个数。b. 步长stride:决定滑动多少步可以到边缘。盗个图:

    可以看到:两个神经元,即depth=2,意味着有两个滤波器。数据窗口每次移动两个步长取3*3的局部数据,即stride=2。zero-padding=1。然后分别以两个滤波器filter为轴滑动数组进行卷积计算,得到两组不同的结果。 随着左边数据窗口的平移滑动,滤波器Filter w0 / Filter w1对不同的局部数据进行卷积计算。与此同时,随着数据窗口滑动,导致输入在变化,但中间滤波器Filter w0的权重(即每个神经元连接数据窗口的权重)是固定不变的,这个权重不变即所谓的CNN中的参数(权重)共享机制。综上所述,卷积层就是用来局部感知提取特征,降低输入参数的网络层。

    池化层。在卷积神经网络中,池化层对输入的特征图进行压缩,一方面使特征图变小,简化网络计算复杂度。另一方面进行特征压缩,提取主要特征。采用池化层可以忽略目标的倾斜、旋转之类的相对位置的变化,以提高精度, 同时降低了特征图的维度,并且在一定程度上可以避免过拟合。池化层通常非常简单,取平均值或最大值来创建自己的特征图。当然池化层分为多类,上面的思维导图已经贴出,读者可以自行尝试。

    全连接层。全连接层在整个卷积神经网络中起到分类器的作用。如果说卷积层、池化层等操作是将原始数据映射到隐藏层的特征空间的话,全连接层则起到将学到的“ 分布式特征表示”映射到样本标记空间的作用。全连接层通常具有非线性激活函数或softmax激活函数,预测输出类的概率。在卷积层和池化层执行特征抽取和合并之后,在网络末端使用全连接层用于创建特征的最终非线性组合,并用于预测。下图即为一个较为完成卷积神经网络结构图:

    好了,接下来我们又到了无码不欢的时刻了。这里我们将使用keras与tensorflow分别对mnist数据集进行训练并预测。作为一个小实例,和大家一同分享体验:

Kerars:

# coding=utf-8

import sys

reload(sys)

sys.setdefaultencoding('utf8')

from keras.models import Sequential

from keras.layers import Dense

from keras.layers import Dropout

from keras.layers import Flatten

from keras.layers.convolutional import Conv2D

from keras.layers.convolutional import MaxPooling2D

from keras.datasets import mnist

from keras.utils import np_utils

from keras import backend

backend.set_image_data_format('channels_first')

import numpy as np

seed=7

np.random.seed(seed)

(x_train,y_train),(x_test,y_test) = mnist.load_data()

x_train = x_train.reshape(x_train.shape[0],1,28,28).astype('float')

x_test = x_test.reshape(x_test.shape[0],1,28,28).astype('float')

x_train = x_train/255

x_test = x_test/255

#one-hot编码

y_train = np_utils.to_categorical(y_train)

y_test = np_utils.to_categorical(y_test)

#创建模型

def create_model():

    model = Sequential()

    #第一个隐藏层是Conv2D卷积层,它会输出32个特征图,拥有5x5个感受野(每个过滤器覆盖的范围),并接受input_shape参数所描述的特征

    model.add(Conv2D(filters=32,kernel_size=(5,5),input_shape=(1,28,28),activation='relu'))

    #第二层是采用最大值MaxPooling2D的池化层,并且通过pool_size的参数配置2x2,使输入张量的两个维度都缩小一半

    model.add(MaxPooling2D(pool_size=(2,2)))

    #正则化,排除20%的神经元

    model.add(Dropout(0.2))

    #将多维数组转化成1维数组,它的输出便于全连接层的处理

    model.add(Flatten())

    #128个神经元全连接

    model.add(Dense(units=128,activation='relu'))

    model.add(Dense(units=10,activation='softmax'))

    model.compile(loss='categorical_crossentropy',optimizer='adam',metrics=['accuracy'])

    return model

model = create_model()

model.fit(x_train,y_train,epochs=10,batch_size=200)

score = model.evaluate(x_test,y_test)

print(score)


Tensorflow:

# coding=utf-8

import tensorflow as tf

import numpy as np

import input_data

mnist=input_data.read_data_sets('./mnist_data',one_hot=True)

trX,trY,teX,teY=mnist.train.images,mnist.train.labels,mnist.test.images,mnist.test.labels

trX=trX.reshape(-1,28,28,1)

teX=teX.reshape(-1,28,28,1)

X=tf.placeholder(tf.float32,[None,28,28,1])

Y=tf.placeholder(tf.float32,[None,10])

#初始化权重与定义网络结构

def init_weights(shape):

    return tf.Variable(tf.random_normal(shape,stddev=0.01))

#patch大小为3×3,输入维度为1,输出维度为32。

w=init_weights([3,3,1,32])

#patch大小为3×3,输入维度为32,输出维度为64

w2=init_weights([3,3,32,64])

#patch大小为3×3,输入维度为64,输出维度为128

w3=init_weights([3,3,64,128])

#全连接层,输入维度为128 × 4 × 4,是上一层的输出数据由三维的转变成一维,输出维度为625

w4=init_weights([128*4*4,625])

#print w4.get_shape().as_list()[0]

#输出层,输入维度为625,输出维度为10,代表10类(labels)

w5=init_weights([625,10])

def create_model(X,w,w2,w3,w4,w5,p_keep_conv,p_keep_hidden):

     #步长strides:strides[0]和strides[3]的两个1是默认值,中间第二个值和第三个值为在水平方向和竖直方向移动的步长

    c1=tf.nn.relu(tf.nn.conv2d(X,w,strides=[1,1,1,1],padding='SAME'))

    #ksize是核,核函数大小为2*2

    p1=tf.nn.max_pool(c1,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')

     #神经元正则化

    o1=tf.nn.dropout(p1,p_keep_conv)

    c2=tf.nn.relu(tf.nn.conv2d(o1,w2,strides=[1,1,1,1],padding='SAME'))

    p2=tf.nn.max_pool(c2,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')

    o2=tf.nn.dropout(p2,p_keep_conv)

    c3=tf.nn.relu(tf.nn.conv2d(o2, w3, strides=[1, 1, 1, 1], padding='SAME'))

    p3=tf.nn.max_pool(c3, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')

     #通过tf.reshape()将p2的输出值从三维数据变为一维的数据p2_flat,进行数据展平.    

    p3_flat=tf.reshape(p3,[-1,w4.get_shape().as_list()[0]])

    o3=tf.nn.dropout(p3_flat,p_keep_conv)

    #全连接层

    l4=tf.nn.relu(tf.matmul(o3,w4))

    o4=tf.nn.dropout(l4,p_keep_hidden)

     #输出层

    o5=tf.matmul(o4,w5)

     return o5

p_keep_conv=tf.placeholder(tf.float32)

p_keep_hidden=tf.placeholder(tf.float32)

pred = create_model(X,w,w2,w3,w4,w5,p_keep_conv,p_keep_conv)

loss=tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=Y,logits=pred))

train_op=tf.train.RMSPropOptimizer(0.001,0.9).minimize(loss)

pred_lable = tf.arg_max(pred,1)

batch_size=128

test_batch_size=256

with tf.Session() as sess:

    sess.run(tf.global_variables_initializer())

     for i in range(100):

        training_batch = zip(range(0, len(trX), batch_size),range(batch_size, len(trX) + 1, batch_size))

        for start, end in training_batch:

            sess.run(train_op, feed_dict={X: trX[start:end], Y: trY[start:end], p_keep_conv: 0.8, p_keep_hidden: 0.5})

            test_indices = np.arange(len(teX))

            #打乱顺序

            np.random.shuffle(test_indices)

            test_indices = test_indices[0:test_batch_size]

            print(i,np.mean(np.argmax(teY[test_indices], axis=1)==sess.run(pred_lable,feed_dict={X:teX[test_indices],p_keep_conv:1.0,p_keep_hidden:1.0})))

你可能感兴趣的:(卷积神经网络通俗易懂篇)