卷积神经网络通俗易懂篇

    欢迎关注本人的微信公众号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})))

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容