深入浅出解读卷积神经网络

作者:石文华

编辑:田 旭

卷积神经网络

图1 全连接神经网络结构图

图2 卷积神经网络结构图

卷积神经网络和全连接的神经网络结构上的差异还是比较大的,全连接的网络,相邻两层的节点都有边相连,而卷积神经网络,相邻节点只有部分节点相连。

全连接神经网络处理图像的最大问题在于全连接层的参数太多,参数太多的话容易发生过拟合而且会导致计算速度减慢,卷积神经网络可以减小参数个数的目的。

假设输入是一张图片大小为28*28*3,第一层隐藏层有500个节点,那么第一层的参数就有28*28*3*500+500=1176000个参数,当图片更大时,参数就更多了,而且这只是第一层。

那么为什么卷积神经网络可以达到减小参数的目的呢?

卷积神经网络最为关键的有卷积层,池化层,全连接层。

卷积层

卷积层中每个节点的输入只是上一层神经网络的一小块,通常由卷积核来实现,卷积核是一个过滤器,可以想象成一个扫描窗口,扣到每张图片上,然后根据设置好的大小步长等等扫描图片,计算规则是被扣的图像像素矩阵跟卷积核的权重对应位置相乘然后求和,每扫描一次得到一个输出。卷积层所做的工作可以理解为对图像像素的每一小块进行特征抽象。可以通过多个不同的卷积核对同一张图片进行卷积,卷积核的个数,其实就是卷积之后输出矩阵的深度。卷积神经网络的参数个数与图片大小无关,只跟过滤器的尺寸、深度以及卷积核的个数(输出矩阵的深度)有关。假设是还是28*28*3的图片,卷积核的大小设为3*3*3,输出矩阵的深度为500,那么参数个数为3*3*3*500+500=14000个参数,对比全连接层,参数减少了很多。

图3 形象的卷积层示例

池化层

池化层可以认为是将一张高分辨率的图片转化为低分辨率的图片。可以非常有效的缩小矩阵的尺寸,从而减小全连接层的参数个数,这样可以加快计算速率同时又防止过拟合,池化,可以减小模型,提高速度,同时提高所提取特征的鲁棒性。

使用2*2的过滤器步长为2,最大池化如下图所示:

图4 2*2过滤器最大池化示例图

我们可以将卷积层和池化层看成是自动特征提取就可以了。

通过上面直观的介绍,现在我们就知道为什么卷积神经网络可以达到减小参数的目的了?

和全连接神经网络相比,卷积神经网络的优势在于共享权重和稀疏连接。共享权重在于参数只与过滤器有关。卷积神经网络减少参数的另外一个原因是稀疏连接。输出节点至于输入图片矩阵的部分像素矩阵有关,也就是跟卷积核扣上去的那一小块矩阵有关。这就是稀疏连接的概念。

卷积神经网络通过权重共享和稀疏连接来减少参数的。从而防止过度拟合。

训练过程

卷积神经网络的训练过程大致可分为如下几步:

第一步:导入相关库、加载参数

(左右滑动,查看完整代码)

import math
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
import h5py
from tensorflow.python.framework import ops
from tf_utils import *
np.random.seed(1)
X_train_orig,Y_train_orig,X_test_orig,Y_test_orig,classes=load_dataset()
index=0
plt.imshow(X_train_orig[index])
print("y="+str(np.squeeze(Y_train_orig[:,index])))
plt.show()

第二步:归一化,有利于加快梯度下降

(左右滑动,查看完整代码)

X_train=X_train_orig/255.0
X_test=X_test_orig/255.0
Y_train=convert_to_one_hot(Y_train_orig,6)
Y_test=convert_to_one_hot(Y_test_orig,6)

第三步:定义参数及卷积神经网络结构

(左右滑动,查看完整代码)

def create_placeholder(num_px,channel,n_y):
    X=tf.placeholder(tf.float32,shape=(None,num_px,num_px,channel),name='X')
    Y=tf.placeholder(tf.float32,shape=(None,n_y),name='Y')
    return X,Y
X,Y=create_placeholder(64,3,6)
print("X="+str(X))
print("Y="+str(Y))

def weight_variable(shape):
    return tf.Variable(tf.truncated_normal(shape,stddev=0.1))
def bias_variable(shape):
    return tf.Variable(tf.constant(0.1,shape=shape))
def conv2d(x,W):
    return tf.nn.conv2d(x,W,strides=[1,1,1,1],padding='SAME')
def max_pool_2x2(x):
    return tf.nn.max_pool(x,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')

def initialize_parameters():
    w_conv1=weight_variable([5,5,3,32])
    b_conv1=bias_variable([32])
    
    w_conv2=weight_variable([5,5,32,64])
    b_conv2=bias_variable([64])
    
    w_fc1=weight_variable([16*16*64,512])
    b_fc1=bias_variable([512])
    
    w_fc2=weight_variable([512,6])
    b_fc2=bias_variable([6])
    
    parameters={
        "w_conv1":w_conv1,
        "b_conv1":b_conv1,
        "w_conv2":w_conv2,
        "b_conv2":b_conv2,
        "w_fc1":w_fc1,
        "b_fc1":b_fc1,
        "w_fc2":w_fc2,
        "b_fc2":b_fc2
    }
    return parameters

第四步:前行传播过程

(左右滑动,查看完整代码)

def forward_propagation(X,parameters):
    w_conv1=parameters["w_conv1"]
    b_conv1=parameters["b_conv1"]
    h_conv1=tf.nn.relu(conv2d(X,w_conv1)+b_conv1)
    h_pool1=max_pool_2x2(h_conv1)
    
    w_conv2=parameters["w_conv2"]
    b_conv2=parameters["b_conv2"]
    h_conv2=tf.nn.relu(conv2d(h_pool1,w_conv2)+b_conv2)
    h_pool2=max_pool_2x2(h_conv2)
    
    w_fc1=parameters["w_fc1"]
    b_fc1=parameters["b_fc1"]
    h_pool2_flat=tf.reshape(h_pool2,[-1,16*16*64])
    h_fc1=tf.nn.relu(tf.matmul(h_pool2_flat,w_fc1)+b_fc1)
    
    #keep_prob=tf.placeholder(tf.float32)
    #h_fc1_drop=tf.nn.dropout(h_fc1,keep_prob)
    
    w_fc2=parameters["w_fc2"]
    b_fc2=parameters["b_fc2"]
    y_conv=tf.matmul(h_fc1,w_fc2)+b_fc2
    return y_conv

第五步:成本函数

(左右滑动,查看完整代码)

def compute_cost(y_conv,Y):    cost=tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=y_conv,labels=Y))
    return cost

第六步:梯度下降更新参数

(左右滑动,查看完整代码)

def random_mini_batches1(X, Y, mini_batch_size = 64, seed = 0):
    m = X.shape[0]                  # number of training examples
    mini_batches = []
    np.random.seed(seed)
    Y=Y.T         #(1080,6)
    # Step 1: Shuffle (X, Y)
    permutation = list(np.random.permutation(m))
    shuffled_X = X[permutation,:,:,:]
    shuffled_Y = Y[permutation,:].reshape((m,Y.shape[1]))

    # Step 2: Partition (shuffled_X, shuffled_Y). Minus the end case.
    num_complete_minibatches = math.floor(m/mini_batch_size) # number of mini batches of size mini_batch_size in your partitionning
    for k in range(0, num_complete_minibatches):
        mini_batch_X = shuffled_X[k * mini_batch_size : k * mini_batch_size + mini_batch_size,:,:,:]
        mini_batch_Y = shuffled_Y[k * mini_batch_size : k * mini_batch_size + mini_batch_size,:]
        mini_batch = (mini_batch_X, mini_batch_Y)
        mini_batches.append(mini_batch)
    
    # Handling the end case (last mini-batch < mini_batch_size)
    if m % mini_batch_size != 0:
        mini_batch_X = shuffled_X[num_complete_minibatches * mini_batch_size : m,:,:,:]
        mini_batch_Y = shuffled_Y[num_complete_minibatches * mini_batch_size : m,:]
        mini_batch = (mini_batch_X, mini_batch_Y)
        mini_batches.append(mini_batch)
    
    return mini_batches

第七步:训练模型

(左右滑动,查看完整代码)

def model(X_train,Y_train,X_test,Y_test,learning_rate=0.001,num_epochs=20,minibatch_size=32,print_cost=True):
    ops.reset_default_graph()  #(1080, 64, 64, 3)
    tf.set_random_seed(1)      #Y_train(6, 1080)
    seed=3
    (m,num_px1,num_px2,c)=X_train.shape
    n_y=Y_train.shape[0]
    costs=[]
    X,Y=create_placeholder(64,3,6)
    parameters=initialize_parameters()
    
    Z3=forward_propagation(X,parameters)
    cost=compute_cost(Z3,Y)
    optm=tf.train.AdamOptimizer(learning_rate).minimize(cost)
    
    correct_prediction=tf.equal(tf.argmax(Z3,1),tf.argmax(Y,1))#居然忘记1了,所以一直出现损失越来越小了,但是准确率却一直是0
    accuracy=tf.reduce_mean(tf.cast(correct_prediction,tf.float32))
    with tf.Session() as sess:
        tf.global_variables_initializer().run()
        for epoch in range(num_epochs):
            epoch_cost=0
            num_minibatches=int(m/minibatch_size)
            seed+=1
            #下面输入要求(6,,1080)格式,所以要加个转置
            minibatches=random_mini_batches1(X_train,Y_train,minibatch_size,seed)
            
            for minibatch in minibatches:
                (minibatch_X,minibatch_Y)=minibatch
                _,minibatch_cost=sess.run([optm,cost],feed_dict={X:minibatch_X,Y:minibatch_Y})
                epoch_cost+=minibatch_cost/num_minibatches
            if(print_cost==True and epoch % 2==0):
                #print("Epoch",'%04d' % (epoch+1),"cost={:.9f}".format(epoch_cost))
                print("Cost after epoch %i:%f" % (epoch,epoch_cost))
            if(print_cost==True and epoch %1==0):
                costs.append(epoch_cost)
                
        print("Train Accuracy:",accuracy.eval({X:X_train,Y:Y_train.T}))
        print("Test Accuracy:",accuracy.eval({X:X_test,Y:Y_test.T}))
        plt.plot(np.squeeze(costs))
        plt.ylabel('cost')
        plt.xlabel('iterations(per tens)')
        plt.title("learning rate="+str(learning_rate))
        plt.show()
        
        parameters=sess.run(parameters)
        return parameters
parameters=model(X_train,Y_train,X_test,Y_test)

原文发布于微信公众号 - 机器学习算法全栈工程师(Jeemy110)

原文发表时间:2017-11-23

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏SnailTyan

Single Shot MultiBox Detector论文翻译——中文版

SSD: Single Shot MultiBox Detector 摘要 我们提出了一种使用单个深度神经网络来检测图像中的目标的方法。我们的方法命名为SSD,...

2870
来自专栏AI研习社

用Kaggle经典案例教你用CNN做图像分类!

前言 在上一篇专栏《利用卷积自编码器对图片进行降噪》中,我们利用卷积自编码器对 MNIST 数据进行了实验,这周我们来看一个 Kaggle 上比较经典的一...

4006
来自专栏marsggbo

DeepLearning.ai学习笔记(四)卷积神经网络 -- week1 卷积神经网络基础知识介绍

一、计算机视觉 ? 如图示,之前课程中介绍的都是64* 64 3的图像,而一旦图像质量增加,例如变成1000 1000 * 3的时候那么此时的神经网络的计...

22110
来自专栏闪电gogogo的专栏

《统计学习方法》笔记七(1) 支持向量机——线性可分支持向量机

应用拉格朗日对偶性,通过求解对偶问题得到原始问题的最优解,一是因为对偶问题往往更容易求解,二是自然引入核函数,进而推广到非线性分类的问题。

682
来自专栏深度学习那些事儿

深度学习中IU、IoU(Intersection over Union)的概念理解以及python程序实现

Intersection over Union是一种测量在特定数据集中检测相应物体准确度的一个标准。我们可以在很多物体检测挑战中,例如PASCAL VOC ch...

6363
来自专栏大学生计算机视觉学习DeepLearning

深度学习(一)神经网络中的池化与反池化原理

原文链接:https://www.cnblogs.com/DOMLX/p/9579108.html

1352
来自专栏null的专栏

简单易学的机器学习算法——EM算法

一、机器学习中的参数估计问题 image.png 二、EM算法简介     在上述存在隐变量的问题中,不能直接通过极大似然估计求出模型中的参数,EM算法是一种解...

1.4K5
来自专栏小鹏的专栏

机器学习模型训练时候tricks

1. 当训练集的效果(准确率)上不去,和贝叶斯估计(人的表现)存在一定差距的时候:(1)增加模型的复杂度。 或者直接多加几层。(2)现在目前效果非常好的一些模型...

2077
来自专栏SnailTyan

Single Shot MultiBox Detector论文翻译——中英文对照

SSD: Single Shot MultiBox Detector Abstract We present a method for detecting ob...

2560
来自专栏算法channel

深度学习|卷积神经网络(CNN)介绍(后篇)

01 — 回顾 昨天介绍了CNN的卷积操作,能减少权重参数的个数,卷积操作涉及到三个超参数: 深度(Depth) 步长(Stride) 零填充(Zero-pad...

4885

扫码关注云+社区