美文网首页
tensorflow 学习

tensorflow 学习

作者: 此间不留白 | 来源:发表于2019-10-29 21:20 被阅读0次

    前言

    在之前的中,已经通过python中的numpy库实现了神经网络。现在,可以通过一些深度学习框架更高效的实现神经网络,这些深度学习框架包括pytroch,tensorflow,caffe和keras等。本篇文章将通过利用tensorflow框架实现一个神经网络,并实现一个手势识别的项目。

    tensorflow初体验

    导入相关库

    首先,需要导入相关python库,如下代码所示:

    
    import math
    import numpy as np
    import h5py
    import matplotlib.pyplot as plt
    import tensorflow as tf
    from tensorflow.python.framework import ops
    %matplotlib inline
    np.random.seed(1)
    

    tensorflow张量定义及使用

    首先,通过tensorflow实现一个损失函数的计算,损失函数的公式,如下所示:
    loss = \mathcal{L}(\hat{y}, y) = (\hat y^{(i)} - y^{(i)})^2 \tag{1}

    
    y_hat = tf.constant(36, name='y_hat')            # 定义y_hat常量,36
    y = tf.constant(39, name='y')                    # 定义y,39
    
    loss = tf.Variable((y - y_hat)**2, name='loss')  # 创建一个损失变量
    
    init = tf.global_variables_initializer()         # 创建一个全局变量初始化
                                                     # 损失变量计算前被初始化
    with tf.Session() as session:                    # 创建一个会话并打印输出
        session.run(init)                            # 初始化变量
        print(session.run(loss))                     # 打印输出
    

    以上,可以总结运行一个tensorflow程序的四个步骤:

    • 创建未被执行的tensorflow张量(变量)
    • 操作这些张量(建立表达式)
    • 初始化这些张量
    • 创建一个Session
    • 运行Session,这个Session会计算张量的表达式

    事实上,创建张量语句并不会给这些张量赋值,当初始化之后,在session中这些张量才会被赋值并运算。

    placeholder是一个只允许稍后指定其值的对象,给placeholder赋值时,可以用feed dictionary实现,具体如下代码所示:

    x = tf.placeholder(tf.int64, name = 'x')
    print(sess.run(2 * x, feed_dict = {x: 3}))
    sess.close()
    

    如上述代码所示,定义了一个x张量,但是并未赋值,通过placeholder对象的声明,可以在其运行过程中利用feed_dict字典参数为其赋值。

    tensorflow实现线性函数

    现在可以通过tensorflow实现一个线性函数了,其函数表达式如公式(2)所示:
    Y = WX+b\tag{2}
    其中参数W的维数为(4,3)和,输入X的维数为(3,1),偏置参数b的维数是$(4,1),具体的实现代码如下所示:

    
    def linear_function():
       
        np.random.seed(1)
      
        X = tf.constant(np.random.randn(3,1),name = "X")
        W = tf.constant(np.random.randn(4,3),name="W")
        b = tf.constant(np.random.randn(4,1),name = "b")
        Y = tf.constant(np.random.randn(4,1),name="Y")
      
        sess = tf.Session()
        result = sess.run(tf.add(tf.matmul(W,X),b))
     
        sess.close()
    
        return result
    

    tensorflow实现激活函数

    使用tensorflow可以很方便的实现激活函数,实现激活函数是,需要注意的一点是需要利用到plaaceholder对象,具体实现代码如下所示:

    
    
    def sigmoid(z):
        x = tf.placeholder(tf.float32,name ='x')
        sigmoid = tf.sigmoid(x)
        with tf.Session() as sess:
             result = sess.run(sigmoid,feed_dict={x:z})
       
        return result
    

    计算损失

    交叉熵损失的计算公式如下所示:
    J = - \frac{1}{m} \sum_{i = 1}^m \large ( \small y^{(i)} \log a^{ [2] (i)} + (1-y^{(i)})\log (1-a^{ [2] (i)} )\large )\small\tag{3}
    在代码实现过程中,输入z,利用激活函数求得a,再根据公式(3)求得交叉熵损失。具体实现代码如下所示:

    
    def cost(logits, labels):
      
        z = tf.placeholder(tf.float32,name = 'z')
        y = tf.placeholder(tf.float32,name='y')
        
    
        cost = tf.nn.sigmoid_cross_entropy_with_logits(logits = z,labels = y)
       
        sess = tf.Session()
        cost = sess.run(cost,feed_dict={z:logits,y:labels})
        sess.close()
       
        return cost
    

    独热编码

    对于多元分类问题,假设要分为C类,则可以用一个(0,C-1)范围的向量表示,但是为了计算的仿表,需要将其转换为用0和1表示的矩阵,具体过程可以如下图所示:

    根据上图描述,在tensorflow中可以很轻松的实现,具体如下所示:

    
    
    def one_hot_matrix(labels, C):
      
        C =tf.constant(C,name = 'C')
        one_hot_matrix = tf.one_hot(labels,C,axis = 0)
        sess = tf.Session()
        one_hot = sess.run(one_hot_matrix)
        
        sess.close()
    
        return one_hot
    

    初始化为0和1

    初始化为0和1的矩阵在tensorflow中用tf.ones(shape)实现,shape表示的是初始化后的矩阵形状,在tensorflow中初始化一个全为1的矩阵可以用以下代码实现,具体实现如下所示:

    
    def ones(shape):
      
        ones = tf.ones(shape)
        sess = tf.Session()
        ones = sess.run(ones)
        sess.close()
        return ones
    

    用tensorflow搭建一个神经网络

    这一部分将利用tensorflow构建一个算法用来识别手势,整个数据集分为以下两部分:

    • 训练数据集:1080张64×64像素的手势图片用来表示(0,6),每个手势的图片是180张。
    • 测试数据集:120帐64×64像素的手势图片,每个手势的图片是20张。

    一些图片数据集和表示的数字之间的对应关系如下图所示:


    首先,加载训练集和测试集,具体如下代码所示:

    
    def load_dataset():
        train_dataset = h5py.File('datasets/train_signs.h5', "r")
        train_set_x_orig = np.array(train_dataset["train_set_x"][:]) # 训练集特征
        train_set_y_orig = np.array(train_dataset["train_set_y"][:]) #训练集标签
    
        test_dataset = h5py.File('datasets/test_signs.h5', "r")
        test_set_x_orig = np.array(test_dataset["test_set_x"][:]) # 测试集特征
        test_set_y_orig = np.array(test_dataset["test_set_y"][:]) # y测试集
        classes = np.array(test_dataset["list_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
    
    

    数据集标签和图像之间的示例如下所示:

    index = 0
    plt.imshow(X_train_orig[index])
    print ("y = " + str(np.squeeze(Y_train_orig[:, index])))
    

    对于图像数据集,归一化的方法是每一个输入特征都除以255,对于矩阵表示的3通道图像,需要将其转化为一个向量,实现方式是3×64×64(3表示图片是rgb的3通道,64表示图像像素),并且,对于输出标签,需将其实现独热编码,具体的实现,如下代码所示:

    
    
    # 转化训练集和测试集特征为向量
    X_train_flatten = X_train_orig.reshape(X_train_orig.shape[0], -1).T
    X_test_flatten = X_test_orig.reshape(X_test_orig.shape[0], -1).T
    # 归一化图像向量
    X_train = X_train_flatten/255.
    X_test = X_test_flatten/255.
    # 转化为独热编码矩阵
    Y_train = convert_to_one_hot(Y_train_orig, 6)
    Y_test = convert_to_one_hot(Y_test_orig, 6)
    
    

    用numpy实现的独热编码转化实现如下代码所示:

    
    def convert_to_one_hot(Y, C):
        Y = np.eye(C)[Y.reshape(-1)].T
        return Y
    

    以上代码中,reshape(-1)表示将其转化为一个一维向量,np.eye(C)生成一个单位矩阵,而Y = np.eye(C)[Y.reshape(-1)].T表示按单位矩阵的列索引取值。

    创建输入X和输出Y的placeholder

    首先,需要利用tensorflow创建输入变量和输出变量的placholder,以便后续session计算,具体实现代码如下:

    
    def create_placeholders(n_x, n_y):
        X = tf.placeholder(tf.float32,shape=(12288,None),name = 'X')
        Y = tf.placeholder(tf.float32,shape=(6,None),name = 'Y')
        return X, Y
    

    参数初始化

    利用tensorflow实现参数初始化的方式如下代码所示,在实现过程中,需要注意每个参数的维数,实现代码如下:

    
    def initialize_parameters():
        """
       用tensorflow初始化权重参数,各个参数的维数如下所示
                            W1 : [25, 12288]
                            b1 : [25, 1]
                            W2 : [12, 25]
                            b2 : [12, 1]
                            W3 : [6, 12]
                            b3 : [6, 1]
        """
    
        tf.set_random_seed(1)                   
            
      
        W1 = tf.get_variable("W1",[25,12288],initializer = tf.contrib.layers.xavier_initializer())
        b1 = tf.get_variable("b1",[25,1],initializer = tf.zeros_initializer())
        W2 = tf.get_variable("W2",[12,25],initializer = tf.contrib.layers.xavier_initializer())
        b2 = tf.get_variable("b2",[12,1],initializer = tf.zeros_initializer())
        W3 = tf.get_variable("W3",[6,12],initializer = tf.contrib.layers.xavier_initializer())
        b3 = tf.get_variable("b3",[6,1],initializer = tf.zeros_initializer())
     
        parameters = {"W1": W1,
                      "b1": b1,
                      "W2": W2,
                      "b2": b2,
                      "W3": W3,
                      "b3": b3}
        
        return parameters
    

    tensorflow实现前向传播

    根据前向传播的实现方式,tensorflow的前向传播如下所示:

    
    
    
    def forward_propagation(X, parameters):
      
        W1 = parameters['W1']
        b1 = parameters['b1']
        W2 = parameters['W2']
        b2 = parameters['b2']
        W3 = parameters['W3']
        b3 = parameters['b3']
    
        Z1 = tf.add(tf.matmul(W1, X), b1)                                        
        A1 = tf.nn.relu(Z1)                                             
        Z2 = tf.add(tf.matmul(W2, A1),b2)                                          
        A2 = tf.nn.relu(Z2)                                              
        Z3 = tf.add(tf.matmul(W3,A2),b3) 
        return Z3
    
    

    计算损失

    在tensorflow中,可以很方便的计算损失,具体代码如下所示,其中参数logits代表前向传播的输出,参数labels代表输出的标签。

    具体实现代码如下所示:

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

    构建模型

    在tensorflow中实现反向传播和参数更新可以用一行代码轻松实现,也可以直接在tensorflow中的session中实现,并且加以优化。具体的实现代码如下所示:

    
    def model(X_train, Y_train, X_test, Y_test, learning_rate = 0.0001,
              num_epochs = 1500, minibatch_size = 32, print_cost = True):
        """
        实现一个三层神经网络: LINEAR->RELU->LINEAR->RELU->LINEAR->SOFTMAX.
        
        参数:
        X_train -- 训练数据集 维数 (input size = 12288, number of training examples = 1080)
        Y_train -- 训练集输出, 维数 (output size = 6, number of training examples = 1080)
        X_test -- 测试集输入,维数 (input size = 12288, number of training examples = 120)
        Y_test -- 测试集输出,维数 (output size = 6, number of test examples = 120)
        learning_rate --学习率
        num_epochs -- 迭代次数
        minibatch_size --mini—batch大小
        print_cost --设置为True,每1000次迭代打印损失
        
        返回值:
        parameters -- 模型参数,用来预测
        """
        
        ops.reset_default_graph()                         # 能够返回不用重写的变量
        tf.set_random_seed(1)                             # 保存随机种子
        seed = 3                                          
        (n_x, m) = X_train.shape                          # 训练集维数(n_x,m),创建placeholder时,列数设置为None的原因
        n_y = Y_train.shape[0]                            # n_y : 输出标签的大小
        costs = []                                        # 保存损失
        
       
        X, Y = create_placeholders(n_x,n_y)
      
    
        #初始化参数
        parameters = initialize_parameters()
       
       #前向传播的实现
        Z3 = forward_propagation(X,parameters)
      
       #计算损失
       
        cost = compute_cost(Z3,Y)
       
       #反向传播的定义,使用Adam优化算法
       
        optimizer = tf.train.AdamOptimizer(learning_rate).minimize(cost)
       
        
        # 初始化变量
        init = tf.global_variables_initializer()
    
        # 创建Session
        with tf.Session() as sess:
            
            # 运行初始化
            sess.run(init)
            
            # 迭代训练
            for epoch in range(num_epochs):
    
                epoch_cost = 0.                       # 定义每次迭代相关的损失
                num_minibatches = int(m / minibatch_size) # 训练集mini-batch的大小
                seed = seed + 1
                minibatches = random_mini_batches(X_train, Y_train, minibatch_size, seed)
    
                for minibatch in minibatches:
    
                    # 选择一个mini-batch
                    (minibatch_X, minibatch_Y) = minibatch
                    
                    
                    _ , minibatch_cost = sess.run([optimizer, cost], feed_dict={X:minibatch_X, Y:minibatch_Y})
                    
                    
                    epoch_cost += minibatch_cost / num_minibatches
    
                # 打印出每次迭代的损失
                if print_cost == True and epoch % 100 == 0:
                    print ("Cost after epoch %i: %f" % (epoch, epoch_cost))
                if print_cost == True and epoch % 5 == 0:
                    costs.append(epoch_cost)
                    
            # 绘制损失图形
            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)
            print ("Parameters have been trained!")
    
            # 计算预测精确度
            correct_prediction = tf.equal(tf.argmax(Z3), tf.argmax(Y))
    
            # 计算测试集的精度
            accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
    
            print ("Train Accuracy:", accuracy.eval({X: X_train, Y: Y_train}))
            print ("Test Accuracy:", accuracy.eval({X: X_test, Y: Y_test}))
            
            return parameters
    

    经过多次迭代之后,结果如下所示:


    预测

    根据上述训练的参数,可以很方便的用来预测自己的图片,具体实现如下代码所示:

    
    import scipy
    from PIL import Image
    from scipy import ndimage
    
    #图片路径和名称
    my_image = "thumbs_up.jpg"
    #将图片转换为矩阵
    fname = "images/" + my_image
    image = np.array(ndimage.imread(fname, flatten=False))
    my_image = scipy.misc.imresize(image, size=(64,64)).reshape((1, 64*64*3)).T
    my_image_prediction = predict(my_image, parameters)
    
    plt.imshow(image)
    print("Your algorithm predicts: y = " + str(np.squeeze(my_image_prediction)))
    

    相关文章

      网友评论

          本文标题:tensorflow 学习

          本文链接:https://www.haomeiwen.com/subject/imtivctx.html