深度学习——卷积神经网络在tensorflow框架下的应用案例

一、简单的卷积神经网络的小应用

tensorflow框架下构建训练一个简单的3层卷积神经网络实现分类问题

(一)数据集介绍——SIGNS Datasets

教电脑破译手语,在白色的墙壁前拍照,得到以下数据集。

现在的任务是建立一个算法,使有语音障碍的人与不懂手语的人交流。

训练集:1080张图片,每张图片大小为:64*64*3,表示数字0至5,每个数字的图片为180张。

测试集:120张图片,每张图片大小为:64*64*3,表示数字0至5,每个数字的图片为20张。

每一张图片是64*64像素,3表示RGB的3个颜色通道。



加载数据集函数、随机生成mini_batch函数以及独热编码的函数放在文件cnn_utils.py中,具体代码如下:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:ZhengzhengLiu

import math
import numpy as np
import h5py
import matplotlib.pyplot as plt
import tensorflow as tf
from tensorflow.python.framework import ops

#加载数据集
def load_dataset():
    train_dataset = h5py.File('datasets/train_signs.h5', "r")
    train_set_x_orig = np.array(train_dataset["train_set_x"][:])  # your train set features
    train_set_y_orig = np.array(train_dataset["train_set_y"][:])  # your train set labels

    test_dataset = h5py.File('datasets/test_signs.h5', "r")
    test_set_x_orig = np.array(test_dataset["test_set_x"][:])  # your test set features
    test_set_y_orig = np.array(test_dataset["test_set_y"][:])  # your test set labels

    classes = np.array(test_dataset["list_classes"][:])  # the list of classes

    train_set_y_orig = train_set_y_orig.reshape((1, train_set_y_orig.shape[0]))
    test_set_y_orig = test_set_y_orig.reshape((1, test_set_y_orig.shape[0]))

    return train_set_x_orig, train_set_y_orig, test_set_x_orig, test_set_y_orig, classes

#随机生成大小为64的mini_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

#独热编码
def convert_to_one_hot(Y, C):
    Y = np.eye(C)[Y.reshape(-1)].T
    return Y
(二) 创建占位符

首先,为输入图像 X 和 输出 Y 创建占位符,在后面执行session会话的时候传递训练集数据。

为灵活性选择训练集数量,在创建占位符时可以先用 None 来表示训练集的数目,其中,

输入图像 X 的维度大小为 [None, n_H0, n_W0, n_C0] 和 输出 Y的维度大小为[None, n_y]

#创建占位符
def create_placeholder(n_H0,n_W0,n_C0,n_y):
    """
    param :
    n_H0 -- 标量,输入图像的高度
    n_W0 -- 标量,输入图像的宽度
    n_C0 -- 标量,输入图像的通道数目
    n_y -- 标量,分类的数目

    return:
    X -- 输入图像的占位符,维度大小为:[None, n_H0, n_W0, n_C0] 类型为:"float"
    Y -- 输入分类标签的占位符,维度大小为:[None, n_y]  类型为:"float"
    """
    X = tf.placeholder(dtype=tf.float32,shape=(None,n_H0,n_W0,n_C0),name="X")
    Y = tf.placeholder(dtype=tf.float32,shape=(None,n_y),name="Y")

    return X,Y

X,Y = create_placeholder(64,64,3,6)
print("X="+str(X))
print("Y="+str(Y))

#运行结果:
X=Tensor("X:0", shape=(?, 64, 64, 3), dtype=float32)
Y=Tensor("Y:0", shape=(?, 6), dtype=float32)
(三)用tensorflow初始化参数

利用tf.contrib.layers.xavier_initializer(seed=0)初始化参数W1、W2:权重/过滤器filter。不用担心偏向,

后面tensorflow函tf.nn.bias_add()会涉及到,即只需为后面用到的conv2d函数初始化权重。另外,tensorflow会

自动地为全连接层部分初始化层数。每一组过滤器filter的维度如下,即初始化权重W的维度顺序是[1,2,3,4]:


#初始化参数
def initilize_parameters():
    """
    用tensorflow初始化权重参数构建卷积神经网络,维度为:
    W1 : [4, 4, 3, 8]    W2 : [2, 2, 8, 16]

    return:
    parameters -- 字典形式的张量,包含W1和W2
    """
    w1 = tf.get_variable(name="w1",shape=(4,4,3,8),dtype=tf.float32,initializer=tf.contrib.layers.xavier_initializer(seed=0))
    w2 = tf.get_variable(name="w2",shape=(2,2,8,16),dtype=tf.float32,initializer=tf.contrib.layers.xavier_initializer(seed=0))

    parameters = {"w1":w1,"w2":w2}

    return parameters

tf.reset_default_graph()
with tf.Session() as sess:
    parameters = initilize_parameters()
    init = tf.global_variables_initializer()
    sess.run(init)
    print("w1="+str(parameters["w1"].eval()[1,1,1]))
    print("w2="+str(parameters["w2"].eval()[1,1,1]))

#运行结果:
w1=[-0.0752826   0.08046506 -0.18115364  0.01793462 -0.11417466 -0.15131985
 -0.1336818  -0.06460937]
w2=[ 0.18771225  0.02089775  0.00491112 -0.12298661 -0.04200333  0.13979024
  0.05375856 -0.10530782 -0.15856427  0.19796973  0.04295498 -0.0471608
  0.01342118  0.21189791  0.1855194  -0.13519925]
(四)在tensorflow中应用前向传播

 卷积部分tensorflow自带的函数如下:

1、tf.nn.conv2d(X,W1, strides = [1,s,s,1], padding = 'SAME')

 给出输入 X 和一组权重参数/过滤器filter W1,参数strides = [1,f,f,1]代表输入每一个维度

  (m, n_H_prev, n_W_prev, n_C_prev)上的步长。

2、tf.nn.max_pool(A, ksize = [1,f,f,1], strides = [1,s,s,1], padding = 'SAME')

 对于输入 A,该函数使用 (f*f) 大小的过滤器和 (s*s) 大小的步长对于每一个窗口执行最大池化。

3、tf.nn.relu(Z1)

 计算Z1的ReLU函数。

4、tf.contrib.layers.flatten(P)

 对于输入的参数 P,该函数的作用是将每一个样本转换成一维的向量同时保持批大小(batch_size)。

它返回一个维度大小为 [batch_size, k] 的伸长转换后的张量。

5、tf.contrib.layers.fully_connected(F, num_outputs)

 给出伸长转换后的输入参数 F,返回一个应用全连接层的输出。该函数中全连接层会自动初始化

 图中的权重,并在训练模型时继续训练它们。因此,初始化参数时不需要初始化这些权重。

建立一个前向传播函数,包含的模型如下:

CONV2D -> RELU -> MAXPOOL -> CONV2D -> RELU -> MAXPOOL -> FLATTEN -> FULLYCONNECTED

具体的,我们将为所有步骤使用以下参数:

 - Conv2D: stride 1, padding is "SAME"(步长为 1 ,采用“SAME”卷积,8个filters,大小:4*4*3)
 - ReLU
 - Max pool: Use an 8 by 8 filter size and an 8 by 8 stride, padding is "SAME"
 (步长为 8 ,采用“SAME”卷积,filters,大小:8*8)
 - Conv2D: stride 1, padding is "SAME"(步长为 1 ,用“SAME”卷积,16个filters,大小:2*2*8)
 - ReLU

- Max pool: Use a 4 by 4 filter size and a 4 by 4 stride, padding is "SAME"
 (步长为 4 ,采用“SAME”卷积,filters,大小:4*4)
- Flatten the previous output.
 - FULLYCONNECTED (FC) layer:
对全连接层不使用非线性激活函数,输出层有6个神经单元的softmax。在tensorflow中,softmax 和 目标函数(cost function)合并在一个函数里面,用另外一个函数计算目标函数值cost
#前向传播
def forward_propagation(X,parameters):
    """
    前向传播的模型:
    CONV2D -> RELU -> MAXPOOL -> CONV2D -> RELU -> MAXPOOL -> FLATTEN -> FULLYCONNECTED
    param :
    X -- 占位符的输入数据集,维度大小为(样本数目,输入大小)
    parameters -- python字典包含参数 "W1", "W2",维度大小为:初始化时的维度

    return:
    Z3 -- 最后线性单元部分的输出
    """

    W1 = parameters["w1"]
    W2 = parameters["w2"]

    # CONV2D: stride of 1, padding 'SAME',8个filters:4*4*3
    Z1 = tf.nn.conv2d(X,filter=W1,strides=(1,1,1,1),padding="SAME")
    # RELU
    A1 = tf.nn.relu(Z1)
    # MAXPOOL: window 8x8, sride 8, padding 'SAME'
    P1 = tf.nn.max_pool(A1,ksize=(1,8,8,1),strides=(1,1,1,1),padding="SAME")
    # CONV2D:  stride 1, padding 'SAME',16个filters:2*2*8
    Z2 = tf.nn.conv2d(P1,filter=W2,strides=(1,1,1,1),padding="SAME")
    # RELU
    A2 = tf.nn.relu(Z2)
    # MAXPOOL: window 4x4, sride 4, padding 'SAME'
    P2 = tf.nn.max_pool(A2,ksize=(1,4,4,1),strides=(1,4,4,1),padding="SAME")
    # FLATTEN
    P2 = tf.contrib.layers.flatten(inputs=P2)
    # FULLY-CONNECTED (没有使用非线性激活)
    # 输出层有 6 个神经单元.
    Z3 = tf.contrib.layers.fully_connected(P2,6,activation_fn = None)

    return Z3

tf.reset_default_graph()
with tf.Session() as sess:
    np.random.seed(1)
    X,Y = create_placeholder(64,64,3,6)
    parameters = initilize_parameters()
    Z3 = forward_propagation(X,parameters)
    init = tf.global_variables_initializer()
    sess.run(init)
    a = sess.run(Z3,feed_dict={X:np.random.randn(2,64,64,3),Y:np.random.randn(2,6)})
    print("Z3="+str(a))

#运行结果:
Z3=[[ 1.51075494  0.22193617 -1.84866357 -1.52119231 -0.01560354  0.82328957]
 [ 1.52116859  0.54076135 -1.3488152  -1.2703172   0.43205178  0.65169412]]
(五)计算目标函数
计算目标函数,应用的两个函数如下:
1、tf.nn.softmax_cross_entropy_with_logits(logits = Z3, labels = Y)
计算softmax的交叉熵。
2、tf.reduce_mean
通过张量的维数计算元素的平均值。用它来将所有样本的损失结合以得到总的cost。
#计算成本函数
def compute_cost(Z3,Y):
    """
    param :
    Z3 -- 前向传播最后一个线性单元的输出,维度大小为:(样本数目,6)
    Y -- 占位符,真实分类标签的向量,维度与Z3相同

    return:
    cost -- 目标值cost的向量
    """
    cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=Z3,labels=Y))

    return cost

tf.reset_default_graph()
with tf.Session() as sess:
    np.random.seed(1)
    X, Y = create_placeholder(64, 64, 3, 6)
    parameters = initilize_parameters()
    Z3 = forward_propagation(X, parameters)
    cost = compute_cost(Z3,Y)
    init = tf.global_variables_initializer()
    sess.run(init)
    a = sess.run(cost,feed_dict={X:np.random.randn(4,64,64,3),Y:np.random.randn(4,6)})
    print("cost="+str(a))

#运行结果:
cost=1.4205

(六)模型构建
1、创建占位符
2、初始化参数
3、前向传播
4、计算目标函数
5、创建优化器
最后,创建一个会话并对 num_epochs 运行一个 for 循环,得到 mini-batches 批量样本,然后用每个小批量样本对目标函数进行优化。
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:ZhengzhengLiu

import math
import numpy as np
import h5py
import matplotlib.pyplot as plt
import scipy
from PIL import Image
from scipy import ndimage
import tensorflow as tf
from tensorflow.python.framework import ops
from cnn_utils import *

np.random.seed(1)

#加载数据集
X_train_orig,Y_train_orig,X_test_orig,Y_test_orig,classes = load_dataset()

#标准化特征值,使得数值在0至1之间
X_train = X_train_orig/255
X_test = X_test_orig/255
Y_train = convert_to_one_hot(Y_train_orig,6).T
Y_test = convert_to_one_hot(Y_test_orig,6).T

print("Number of training examples = "+str(X_train.shape[0]))
print("Number of testing examples = "+str(X_test.shape[0]))
print("X_train shape:"+str(X_train.shape))
print("Y_train shape:"+str(Y_train.shape))
print("X_test shape:"+str(X_test.shape))
print("Y_test shape:"+str(Y_test.shape))

#创建占位符
def create_placeholder(n_H0,n_W0,n_C0,n_y):
    """
    param :
    n_H0 -- 标量,输入图像的高度
    n_W0 -- 标量,输入图像的宽度
    n_C0 -- 标量,输入图像的通道数目
    n_y -- 标量,分类的数目

    return:
    X -- 输入图像的占位符,维度大小为:[None, n_H0, n_W0, n_C0] 类型为:"float"
    Y -- 输入分类标签的占位符,维度大小为:[None, n_y]  类型为:"float"
    """
    X = tf.placeholder(dtype=tf.float32,shape=(None,n_H0,n_W0,n_C0),name="X")
    Y = tf.placeholder(dtype=tf.float32,shape=(None,n_y),name="Y")

    return X,Y

X,Y = create_placeholder(64,64,3,6)
print("X="+str(X))
print("Y="+str(Y))

#初始化参数
def initilize_parameters():
    """
    用tensorflow初始化权重参数构建卷积神经网络,维度为:
    W1 : [4, 4, 3, 8]    W2 : [2, 2, 8, 16]

    return:
    parameters -- 字典形式的张量,包含W1和W2
    """
    w1 = tf.get_variable(name="w1",shape=(4,4,3,8),dtype=tf.float32,initializer=tf.contrib.layers.xavier_initializer(seed=0))
    w2 = tf.get_variable(name="w2",shape=(2,2,8,16),dtype=tf.float32,initializer=tf.contrib.layers.xavier_initializer(seed=0))

    parameters = {"w1":w1,"w2":w2}

    return parameters

tf.reset_default_graph()
with tf.Session() as sess:
    parameters = initilize_parameters()
    init = tf.global_variables_initializer()
    sess.run(init)
    print("w1="+str(parameters["w1"].eval()[1,1,1]))
    print("w2="+str(parameters["w2"].eval()[1,1,1]))

#前向传播
def forward_propagation(X,parameters):
    """
    前向传播的模型:
    CONV2D -> RELU -> MAXPOOL -> CONV2D -> RELU -> MAXPOOL -> FLATTEN -> FULLYCONNECTED
    param :
    X -- 占位符的输入数据集,维度大小为(样本数目,输入大小)
    parameters -- python字典包含参数 "W1", "W2",维度大小为:初始化时的维度

    return:
    Z3 -- 最后线性单元部分的输出
    """

    W1 = parameters["w1"]
    W2 = parameters["w2"]

    # CONV2D: stride of 1, padding 'SAME',8个filters:4*4*3
    Z1 = tf.nn.conv2d(X,filter=W1,strides=(1,1,1,1),padding="SAME")
    # RELU
    A1 = tf.nn.relu(Z1)
    # MAXPOOL: window 8x8, sride 8, padding 'SAME'
    P1 = tf.nn.max_pool(A1,ksize=(1,8,8,1),strides=(1,1,1,1),padding="SAME")
    # CONV2D:  stride 1, padding 'SAME',16个filters:2*2*8
    Z2 = tf.nn.conv2d(P1,filter=W2,strides=(1,1,1,1),padding="SAME")
    # RELU
    A2 = tf.nn.relu(Z2)
    # MAXPOOL: window 4x4, sride 4, padding 'SAME'
    P2 = tf.nn.max_pool(A2,ksize=(1,4,4,1),strides=(1,4,4,1),padding="SAME")
    # FLATTEN
    P2 = tf.contrib.layers.flatten(inputs=P2)
    # FULLY-CONNECTED (没有使用非线性激活)
    # 输出层有 6 个神经单元.
    Z3 = tf.contrib.layers.fully_connected(P2,6,activation_fn = None)

    return Z3

tf.reset_default_graph()
with tf.Session() as sess:
    np.random.seed(1)
    X,Y = create_placeholder(64,64,3,6)
    parameters = initilize_parameters()
    Z3 = forward_propagation(X,parameters)
    init = tf.global_variables_initializer()
    sess.run(init)
    a = sess.run(Z3,feed_dict={X:np.random.randn(2,64,64,3),Y:np.random.randn(2,6)})
    print("Z3="+str(a))

#计算成本函数
def compute_cost(Z3,Y):
    """
    param :
    Z3 -- 前向传播最后一个线性单元的输出,维度大小为:(样本数目,6)
    Y -- 占位符,真实分类标签的向量,维度与Z3相同

    return:
    cost -- 目标值cost的向量
    """
    cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=Z3,labels=Y))

    return cost

tf.reset_default_graph()
with tf.Session() as sess:
    np.random.seed(1)
    X, Y = create_placeholder(64, 64, 3, 6)
    parameters = initilize_parameters()
    Z3 = forward_propagation(X, parameters)
    cost = compute_cost(Z3,Y)
    init = tf.global_variables_initializer()
    sess.run(init)
    b = sess.run(cost, {X: np.random.randn(4, 64, 64, 3), Y: np.random.randn(4, 6)})
    print("cost="+str(b))

#模型构建
def model(X_train,Y_train,X_test,Y_test,learning_rate = 0.009,
          num_epochs = 100,minibatch_size = 64,print_cost = True):
    """
    用tensorflow创建一个3层的卷积神经网络
    param :
    X_train -- 训练集图像,维度大小为 (None,64,64,3)
    Y_train -- 训练集分类标签,维度大小为 (None,n_y=6)
    X_test --  测试集图像,维度大小为 (None,64,64,3)
    Y_test --  测试集分类标签,维度大小为 (None,n_y=6)
    learning_rate -- 优化器中的学习率
    num_epochs -- epochs的数目(epoch:全部样本迭代完一次为一个epoch)
    minibatch_size -- minibatch的大小,每次选取批量样本的数目
    print_cost -- 是否打印目标函数cost的值

    return:
    train_accuracy -- 训练集上的准确率
    test_accuracy -- 测试集的准确率
    parameters -- 模型中学习的参数,可用于后面的预测
    """
    ops.reset_default_graph()   #在没有tf变量重写的情况下重新运行模型
    tf.set_random_seed(1)
    seed = 3
    (m,n_H0,n_W0,n_C0) = X_train.shape
    n_y = Y_train.shape[1]
    costs = []  #列表存放目标函数值

    #创建占位符
    X,Y = create_placeholder(n_H0,n_W0,n_C0,n_y)

    #初始化参数
    parameters = initilize_parameters()

    #前向传播
    Z3 = forward_propagation(X,parameters)

    #计算目标函数
    cost = compute_cost(Z3,Y)

    #创建优化器
    optm = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)

    #初始化所有参数
    init = tf.global_variables_initializer()

    #创建会话并执行计算图
    with tf.Session() as sess:
        sess.run(init)      #运行初始化
        #循环进行模型训练
        for epoch in range(num_epochs):
            minibatch_cost = 0.
            num_minibatch = int(m/minibatch_size)
            seed = seed + 1
            minibatchs = random_mini_batches(X_train,Y_train,minibatch_size,seed)

            for minibatch in minibatchs:
                #选择一个minibatch
                (minibatch_X,minibatch_Y) = minibatch
                #运行会话执行优化器和目标函数,喂minibatch的数据给(X,Y)
                _,temp_cost = sess.run([optm,cost],feed_dict={X:minibatch_X,Y:minibatch_Y})
                minibatch_cost += temp_cost/num_minibatch
            #每 5 次epoch打印目标函数值cost
            if print_cost == True and epoch % 5 == 0:
                print("Cost after epoch %i:%f"%(epoch,minibatch_cost))
            if print_cost == True and epoch % 1 == 0:
                costs.append(minibatch_cost)

        #绘制关于目标函数值cost的图
        plt.plot(np.squeeze(costs))
        plt.ylabel("cost")
        plt.xlabel("iteration(per tens)")
        plt.title("Learning rate = "+str(learning_rate))
        plt.savefig("3层卷积神经网络cost值.png")
        plt.show()

        #计算准确的预测
        correct_predict = tf.equal(tf.argmax(Z3,1),tf.argmax(Y,1))

        #在测试集上计算准确率
        accuracy = tf.reduce_mean(tf.cast(correct_predict,tf.float32))
        print(accuracy)
        train_accuracy = accuracy.eval({X:X_train,Y:Y_train})
        test_accuracy = accuracy.eval({X:X_test,Y:Y_test})
        print("Train Acurracy :" +str(train_accuracy))
        print("Test Acurracy :" +str(test_accuracy))

        return train_accuracy,test_accuracy,parameters

_,_,parameters = model(X_train,Y_train,X_test,Y_test)












  • 0
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值