Tensorflow(三)训练一个简单卷积神经网络

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Bazingaea/article/details/83902139

这是吴恩达老师第四课第一周的编程练习,题目是分析图片中手势得到手所表示的数字。

数据集我传到github上,可以下载https://github.com/penguin219/WU_Lesson4_week1

特别要注意的是,如果你使用的是新版本的tensorflow,很有可能得到的结果和Coursera上的有所不同!

1. 先简单介绍一个CNN(直接看代码的请往下翻)

CNN全程是Convolutional Neural Networks,它更加适用于computer vision类的应用,这是因为CNN处理图像的效果要比神经网络的处理效果更好,CNN有三个基本组成部分,卷积层,池化层和全连接层

1.1 卷积层

卷积层中有个很重要的概念,什么是卷积?理解了卷积对于池化层也会很好理解。为了方便说明,举个简单的例子。假设现在有一张(6*6)的灰度图像,要对它进行卷积操作,需要用到过滤器 Filter,这里我们用(3*3)的过滤器对这张灰度图像进行卷积,因为它们都是矩阵,所以记 A(6*6),B(3*3)

首先将(3*3)叠放在(6*6)的图像上,也就是A[0][0] 与B[0][0]是对应的,A[2][2] 与 B[2][2]对应,这里手画一下会更好理解,下一步要做的事情就是把对应位置的数字相乘,将得到的9个乘积再相加得到和,这里用sum1记录下来。

接着把B向右移动固定的单位,移动的单位数目,就称之为 步幅 Stride,我们将步幅设置为1,也就是向右移动1个单位,那么现在  A[0][1]对应B[0][0],继续上面的操作,对应位置相乘再相加得到和,记为sum2。

不难看出,B只能移动三次,加上初始位置得到的结果,一共得到4个和值,这四个值就作为完成卷积操作以后得到的矩阵的第一行,那么推测一下,第二行形式也是类似的,计算第二行时,B[0][0]对应的值就是A[1][0],然后再向右移动,得到第二行的所有值。B也只能向下移动三次,加上初始位置,也就是一共有4次,那么最后的结果就是一个(4*4)的矩阵。

这样就完成了一次卷积操作。

总结一下,一次卷积操作需要用到 Filter,也就是后面文中提到的参数,设置Stride,关于Filter再多说几句,一般来说,filter的选择可以是固定的,比如说很有名的sobel filter,scharr filter,不同的过滤器可以提取不同的特征,那么我们也可以将filter设置为随机的参数,通过喂给模型数据来训练这些参数,使得参数更好的符合我们的需求。

完成卷积的操作会使得图片缩小,并且存在一个问题,就是边缘的 像素点只会进行一次卷积操作,而中间的会进行很多次,就会在一定程度上降低边界信息的参考程度。解决办法就是padding,padding的意思是填充,在原图像的周围填充像素点,设置值为0,这样多添加的点也不会对结果造成影响。padding有两种形式,第一是Valid卷积,也就是不添加,p为0,第二种是SAME卷积,意思是卷积后的结果和原始图像尺寸是一样的,p=(f-1)/ 2。

最后要说的是,原始图像大小如果为(n*n),过滤器大小为(f*f),stride的值为s,padding的值为p

那么卷积的结果为(m*m)其中 m=(n+2p-f)/s +1 ,另m = n 就能解出上面p的值了

上面举的例子是灰度图像,是二维的,而我们一般使用的都是RGB图像,是三维。原始图像是几维对应的filter也是几维的,而filter的个数决定了卷积后得到图像的维度,保持一致!

1.2 池化层

池化层可对提取到的特征信息进行降维,使特征图变小,进行特征压缩,提取主要特征,简化网络计算复杂度并在一定程度上避免过拟合的出现。

池化层和卷积层非常类似,区别只在于,卷积层进行的是卷积操作(也就是相乘再相加)而池化层进行的是其他操作。

池化层有两种,第一种也是最常用的一种就是MAX Pooling,顾名思义,它进行的操作就是获取原图像中选取部分的最大值;

还有一种是Average Pool,计算选取部分的平均值。至于选取部分的大小也是由参数(x * x)决定的,但这里不是过滤器!

类似的池化层也有stride和padding的设置。

在tensorflow中关于padding的两种形式:https://blog.csdn.net/wuzqchom/article/details/74785643

1.3全连接层

 

其实全连接层和神经网络是很类似的,将最后一层的池化层得到的结果,全部进行flatten操作,也就是都合并成一个列向量,和后面的处理单元全部连接起来,直到最后一层网络,如果是多分类问题,就是连接到softmax。

2.CNN示例图

根据课程作业所用的CNN网络画出的示意图:

3.代码

导包:

import math
import numpy as np
import h5py
import matplotlib.pyplot as plt
import tensorflow as tf

获取数据:

#加载数据
def load_dataset():
    train_dataset = h5py.File('d:/jupyProject/datasets/train_signs.h5','r')
    
    #可以看看读取到的文件中包含的key值 ['list_classes', 'train_set_x', 'train_set_y']
    #print(list(train_dataset.keys()))
    
    train_x = np.array(train_dataset['train_set_x'][:]) #(1080, 64, 64, 3)
    train_y = np.array(train_dataset['train_set_y'][:])
    
    test_dataset = h5py.File('d:\jupyProject/datasets/test_signs.h5','r')
    test_x = np.array(test_dataset['test_set_x'][:]) 
    test_y = np.array(test_dataset['test_set_y'][:])
    
    classes = np.array(test_dataset['list_classes'][:]) 
    
    train_y = train_y.reshape(train_y.shape[0],1) #(1080,1)
    test_y = test_y.reshape(test_y.shape[0],1)
    
    #将上面的y集改为one-hot形式
    label_num = len(classes)
    train_y = np.eye(label_num)[train_y.reshape(-1)] #(1080, 6)
    test_y = np.eye(label_num)[test_y.reshape(-1)]
    
    train_x = train_x/255.
    test_x = test_x/255.
    
    
    return train_x,train_y,test_x,test_y,classes 
    

占位符:

#新建占位符
def create_placeholders(n_H0,n_W0,n_C0,n_y):
    X = tf.placeholder(shape=[None,n_H0,n_W0,n_C0],dtype = tf.float32)
    Y = tf.placeholder(shape=[None,n_y],dtype = tf.float32)
    return X,Y

初始化参数,也就是filter:

#初始化过滤器 这里用w[f,f,channels,numbers]来表示
def initialize_parameters():
    tf.set_random_seed(1)
    W1 = tf.get_variable('W1',[4,4,3,8],initializer = tf.contrib.layers.xavier_initializer(seed = 0))
    W2 = tf.get_variable('W2',[2,2,8,16],initializer = tf.contrib.layers.xavier_initializer(seed = 0))
    
    parameters = {
        'W1':W1,
        'W2':W2
    }
    
    return parameters
    

向前传播:

def forward_propagation(X,parameters):
    
    W1 = parameters['W1']
    W2 = parameters['W2']
    
    #strides 表示对X的每个维度的步幅
    Z1 = tf.nn.conv2d(X,W1,strides=[1,1,1,1],padding='SAME')
    A1 = tf.nn.relu(Z1)
    #ksize [1,f,f,1]表示用f*f大小的pool
    P1 = tf.nn.max_pool(A1,ksize=[1,8,8,1],strides=[1,8,8,1],padding='SAME')
    
    Z2 = tf.nn.conv2d(P1,W2,strides=[1,1,1,1],padding='SAME')
    A2 = tf.nn.relu(Z2)
    P2 = tf.nn.max_pool(A2,ksize=[1,4,4,1],strides=[1,4,4,1],padding='SAME')
    
    
    P2 = tf.contrib.layers.flatten(P2)

    
    #全连接会自动初始化参数并训练,所以不需要提前初始化参数
    #注意不要在这里调用softmax函数 ,tf的sofmax函数和cost计算连接在一起
    Z3 = tf.contrib.layers.fully_connected(P2,num_outputs=6,activation_fn=None)
    
    return Z3

计算代价:

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

在每次迭代时获取不一样的batch数据,保证了每次迭代的数据组合顺序是不同的,更有利于算法的进步

def random_mini_batches(X, Y, mini_batch_size = 64, seed = 0):
    """
    Creates a list of random minibatches from (X, Y)
    
    Arguments:
    X -- input data, of shape (input size, number of examples) (m, Hi, Wi, Ci)
    Y -- true "label" vector (containing 0 if cat, 1 if non-cat), of shape (1, number of examples) (m, n_y)
    mini_batch_size - size of the mini-batches, integer
    seed -- this is only for the purpose of grading, so that you're "random minibatches are the same as ours.
    
    Returns:
    mini_batches -- list of synchronous (mini_batch_X, mini_batch_Y)
    """
    
    m = X.shape[0]                  # number of training examples
    mini_batches = []
    np.random.seed(seed)
    
    # Step 1: Shuffle (X, Y)
    permutation = list(np.random.permutation(m))
    shuffled_X = X[permutation,:,:,:]
    shuffled_Y = Y[permutation,:]

    # 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

整合模型:

from tensorflow.python.framework import ops
def model(train_x,train_y,test_x,test_y,learning_rate = 0.0009,iteration=300,batch_size=64,print_cost=True):
   
    # 返回模型无需重写参数
    ops.reset_default_graph() 
    tf.set_random_seed(1)
    
    costs = []
    seed = 3
    
    m,n_H0,n_W0,n_C0 = train_x.shape
    n_y = train_y.shape[1]
    
    
    X,Y = create_placeholders(n_H0,n_W0,n_C0,n_y)
    
    parameters = initialize_parameters()
    
    Z3 = forward_propagation(X,parameters)
    
    cost = compute_cost(Z3,Y)
    
    optimizer = tf.train.AdamOptimizer(learning_rate).minimize(cost)
    
    
    with tf.Session() as sess:
        
        sess.run(tf.global_variables_initializer())
        
        for epoch in range(iteration):
            batch_cost = 0.
            batch_n = int(m/batch_size)
            seed = seed+1
            batches = random_mini_batches(train_x,train_y,batch_size,seed)
            
            for batch in batches:
                (mini_x,mini_y)=batch
                _,temp_cost = sess.run([optimizer,cost],feed_dict={X:mini_x,Y:mini_y})
                batch_cost += temp_cost / batch_n
            
            if print_cost ==  True and epoch % 5 == 0:
                print('Cost after epoch %i : %f' %(epoch,batch_cost))
            
            if print_cost == True and epoch % 1 == 0:
                costs.append(batch_cost)
        
        #代价图像
        plt.plot(np.squeeze(costs))
        plt.ylabel('cost')
        plt.xlabel('iterations per tens')
        plt.show()

        #做出预测
        predict_op = tf.argmax(Z3,1)
        correct_prediction = tf.equal(predict_op,tf.argmax(Y,1))

        accuracy = tf.reduce_mean(tf.cast(correct_prediction,'float'))
        train_accuracy = accuracy.eval({X:train_x,Y:train_y})
        test_accuracy = accuracy.eval({X:test_x,Y:test_y})

        print('train accuracy is :',train_accuracy)
        print('test accuracy is :',test_accuracy)
    
model(train_x,train_y,test_x,test_y)

#结果
Cost after epoch 0 : 1.976589
Cost after epoch 5 : 1.895094
Cost after epoch 10 : 1.884952
Cost after epoch 15 : 1.862152
Cost after epoch 20 : 1.792553
Cost after epoch 25 : 1.659748
Cost after epoch 30 : 1.439652
Cost after epoch 35 : 1.210028
Cost after epoch 40 : 1.059912
Cost after epoch 45 : 0.950599
Cost after epoch 50 : 0.864589
Cost after epoch 55 : 0.779795
Cost after epoch 60 : 0.721491
Cost after epoch 65 : 0.659299
Cost after epoch 70 : 0.622481
Cost after epoch 75 : 0.587786
Cost after epoch 80 : 0.553721
Cost after epoch 85 : 0.515339
Cost after epoch 90 : 0.481323
Cost after epoch 95 : 0.464154
Cost after epoch 100 : 0.450780
Cost after epoch 105 : 0.419089
Cost after epoch 110 : 0.393920
Cost after epoch 115 : 0.381122
Cost after epoch 120 : 0.375946
Cost after epoch 125 : 0.361885
Cost after epoch 130 : 0.344810
Cost after epoch 135 : 0.328714
Cost after epoch 140 : 0.321064
Cost after epoch 145 : 0.299867
Cost after epoch 150 : 0.298625
Cost after epoch 155 : 0.284655
Cost after epoch 160 : 0.269399
Cost after epoch 165 : 0.264294
Cost after epoch 170 : 0.269712
Cost after epoch 175 : 0.267915
Cost after epoch 180 : 0.242613
Cost after epoch 185 : 0.228068
Cost after epoch 190 : 0.218832
Cost after epoch 195 : 0.213510
Cost after epoch 200 : 0.205735
Cost after epoch 205 : 0.200092
Cost after epoch 210 : 0.196989
Cost after epoch 215 : 0.187289
Cost after epoch 220 : 0.181605
Cost after epoch 225 : 0.186336
Cost after epoch 230 : 0.177865
Cost after epoch 235 : 0.174295
Cost after epoch 240 : 0.165915
Cost after epoch 245 : 0.168665
Cost after epoch 250 : 0.151124
Cost after epoch 255 : 0.157855
Cost after epoch 260 : 0.157312
Cost after epoch 265 : 0.150373
Cost after epoch 270 : 0.148940
Cost after epoch 275 : 0.139157
Cost after epoch 280 : 0.136293
Cost after epoch 285 : 0.127223
Cost after epoch 290 : 0.132367
Cost after epoch 295 : 0.118375

train accuracy is : 0.9759259
test accuracy is : 0.89166665

猜你喜欢

转载自blog.csdn.net/Bazingaea/article/details/83902139