用TensorFlow搭建一個萬能的神經網絡框架(持續更新),tensorflow常用函數_台中搬家

※台中搬家公司費用怎麼算?

擁有20年純熟搬遷經驗,提供免費估價且流程透明更是5星評價的搬家公司

博客作者:凌逆戰

博客地址:https://www.cnblogs.com/LXP-Never/p/12774058.html

文章代碼:https://github.com/LXP-Never/blog_data/tree/master/tensorflow_model

  我一直覺得TensorFlow的深度神經網絡代碼非常困難且繁瑣,對TensorFlow搭建模型也十分困惑,所以我近期閱讀了大量的神經網絡代碼,終於找到了搭建神經網絡的規律,各位要是覺得我的文章對你有幫助不妨點個贊,點個關注吧。

  我個人把深度學習分為以下步驟:數據處理 –> 模型搭建 –> 構建損失 –> 模型訓練 –> 模型評估

我先把代碼放出來,然後一點一點來講

# Author:凌逆戰
# -*- encoding:utf-8 -*-
# 修改時間:2020年5月31日
import time
from tensorflow.examples.tutorials.mnist import input_data
from nets.my_alex import alexNet
from ops import *

tf.flags.DEFINE_integer('batch_size', 50, 'batch size, default: 1')
tf.flags.DEFINE_integer('class_num', 10, 'batch size, default: 1')
tf.flags.DEFINE_integer('epochs', 10, 'batch size, default: 1')
tf.flags.DEFINE_float('learning_rate', 1e-4, '初始學習率, 默認: 0.0002')
tf.flags.DEFINE_string('checkpoints_dir', "checkpoints", '保存檢查點的地址')
FLAGS = tf.flags.FLAGS

# 從MNIST_data/中讀取MNIST數據。當數據不存在時,會自動執行下載
mnist = input_data.read_data_sets('./data', one_hot=True, reshape=False)
# reshape=False  (None, 28,28,1)    # 用於第一層是卷積層
# reshape=False  (None, 784)        # 用於第一層是全連接層

# 我們看一下數據的shape
print(mnist.train.images.shape)  # 訓練數據圖片(55000, 28, 28, 1)
print(mnist.train.labels.shape)  # 訓練數據標籤(55000, 10)
print(mnist.test.images.shape)  # 測試數據圖片(10000, 28, 28, 1)
print(mnist.test.labels.shape)  # 測試數據圖片(10000, 10)
print(mnist.validation.images.shape)  # 驗證數據圖片(5000, 28, 28, 1)
print(mnist.validation.labels.shape)  # 驗證數據圖片(5000, 784)


def train():
    batch_size = FLAGS.batch_size  # 一個batch訓練多少個樣本
    batch_nums = mnist.train.images.shape[0] // batch_size  # 一個epoch中應該包含多少batch數據
    class_num = FLAGS.class_num  # 分類類別數
    epochs = FLAGS.epochs  # 訓練周期數
    learning_rate = FLAGS.learning_rate  # 初始學習率

    ############    保存檢查點的地址   ############
    checkpoints_dir = FLAGS.checkpoints_dir  # checkpoints
    # 如果檢查點不存在,則創建
    if not os.path.exists(checkpoints_dir):
        os.makedirs(FLAGS.checkpoints_dir)

    ######################################################
    #                    創建圖                          #
    ######################################################
    graph = tf.Graph()  # 自定義圖
    # 在自己的圖中定義數據和操作
    with graph.as_default():
        inputs = tf.placeholder(dtype="float", shape=[None, 28, 28, 1], name='inputs')
        labels = tf.placeholder(dtype="float", shape=[None, class_num], name='labels')
        # 看個人喜歡,有的人在初始化定義中就定義了learning_rate,有的人喜歡通過feed傳learning_rate
        learning_rate = tf.placeholder("float", None, name='learning_rate')
        # 如果網絡結構有dropout層,需要定義keep_probn,如果沒有則不需要
        # 訓練的時候需要,測試的時候需要設置成1
        keep_prob = tf.placeholder(dtype="float", name='keep_prob')
        ############    搭建模型   ############
        logits = alexNet(inputs, class_num, keep_prob=keep_prob)  # 使用placeholder搭建模型
        ############    損失函數   ############
        loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=labels, logits=logits))
        tf.add_to_collection('losses', loss)
        total_loss = tf.add_n(tf.get_collection("losses"))  # total_loss=模型損失+權重正則化損失
        ############    模型精度   ############
        predict = tf.argmax(logits, 1)  # 模型預測結果
        accuracy = tf.reduce_mean(tf.cast(tf.equal(predict, tf.argmax(labels, 1)), tf.float32))
        ############    優化器   ############
        variable_to_train = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES)  # 可訓練變量列表
        # 創建優化器,更新網絡參數,最小化loss,
        global_step = tf.Variable(0, trainable=False)
        learning_rate = tf.train.exponential_decay(learning_rate=learning_rate,  # 初始學習率
                                                   global_step=global_step,
                                                   decay_steps=batch_nums,  # 多少步衰減一次
                                                   decay_rate=0.1,  # 衰減率
                                                   staircase=True)  # 以階梯的形式衰減
        # 移動平均值更新參數
        # train_op = moving_average(loss, learning_rate, global_step)
        # adam優化器,adam算法好像會自動衰減學習率,
        train_op = tf.train.AdamOptimizer(learning_rate).minimize(loss=total_loss,
                                                                  global_step=global_step,
                                                                  var_list=variable_to_train)
        ############    TensorBoard可視化 summary  ############
        summary_writer = tf.summary.FileWriter(logdir="./logs", graph=graph)  # 創建事件文件
        tf.summary.scalar(name="losses", tensor=total_loss)  # 收集損失值變量
        tf.summary.scalar(name="acc", tensor=accuracy)  # 收集精度值變量
        tf.summary.scalar(name='learning_rate', tensor=learning_rate)
        merged_summary_op = tf.summary.merge_all()  # 將所有的summary合併為一個op
        ############    模型保存和恢復 Saver   ############
        saver = tf.train.Saver(max_to_keep=5)

    ######################################################
    #                   創建會話                          #
    ######################################################
    max_acc = 0.
    config = tf.ConfigProto(allow_soft_placement=True, log_device_placement=True)
    with tf.Session(config=config, graph=graph) as sess:
        # 加載模型,如果模型存在返回 是否加載成功和訓練步數
        could_load, checkpoint_step = load_model(sess, saver, FLAGS.checkpoints_dir)
        if could_load:
            print(" [*] 模型加載成功")
        else:
            print(" [!] 模型加載失敗")
            try:
                tf.global_variables_initializer().run()
            except:
                tf.initialize_all_variables().run()

        for epoch in range(epochs):
            for i in range(batch_nums):
                start_time = time.time()
                # batch_images = data_X[i * batch_size:(i + 1) * batch_size]
                # batch_labels = data_y[i * batch_size:(i + 1) * batch_size]
                train_batch_x, train_batch_y = mnist.train.next_batch(batch_size)

                # 使用真實數據填充placeholder,運行訓練模型和合併變量操作
                _, summary, loss, step = sess.run([train_op, merged_summary_op, total_loss, global_step],
                                                  feed_dict={inputs: train_batch_x,
                                                             labels: train_batch_y,
                                                             keep_prob: 0.5})
                if step % 100 == 0:
                    summary_writer.add_summary(summary, step)  # 將每次迭代后的變量寫入事件文件
                    summary_writer.flush()  # 強制summary_writer將緩存中的數據寫入到日誌文件中(可選)

                    ############    可視化打印   ############
                    print("Epoch:[%2d] [%4d/%4d] time:%4.4f,loss:%.8f" % (
                        epoch, i, batch_nums, time.time() - start_time, loss))

                # 打印一些可視化的數據,損失...
                if step % 100 == 0:
                    acc = sess.run(accuracy, feed_dict={inputs: mnist.validation.images,
                                                        labels: mnist.validation.labels,
                                                        keep_prob: 1.0})
                    print("Epoch:[%2d] [%4d/%4d] accuracy:%.8f" % (epoch, i, batch_nums, acc))
                    ############    保存模型   ############
                    if acc > max_acc:
                        max_acc = acc
                        save_path = saver.save(sess,
                                               save_path=os.path.join(checkpoints_dir, "model.ckpt"),
                                               global_step=step)
                        tf.logging.info("模型保存在: %s" % save_path)
        print("優化完成!")


def main(argv=None):
    train()


if __name__ == '__main__':
    # logging.basicConfig(level=logging.INFO)
    tf.logging.set_verbosity(tf.logging.INFO)
    tf.app.run()

main(global_step)

# Author:凌逆戰
# -*- encoding:utf-8 -*-
# 修改時間:2020年5月31日
import time
from tensorflow.examples.tutorials.mnist import input_data
from nets.my_vgg import VGG16Net
from ops import *

tf.flags.DEFINE_integer('batch_size', 100, 'batch size, default: 1')
tf.flags.DEFINE_integer('class_num', 10, 'batch size, default: 1')
tf.flags.DEFINE_integer('epochs', 10, 'batch size, default: 1')
tf.flags.DEFINE_float('learning_rate', 2e-4, '初始學習率, 默認: 0.0001')
tf.flags.DEFINE_string('checkpoints_dir', "checkpoint", '保存檢查點的地址')
FLAGS = tf.flags.FLAGS

# 從MNIST_data/中讀取MNIST數據。當數據不存在時,會自動執行下載
mnist = input_data.read_data_sets('./MNIST_data', one_hot=True, reshape=False)
# reshape=False  (None, 28,28,1)    # 用於第一層是卷積層
# reshape=False  (None, 784)        # 用於第一層是全連接層

# 我們看一下數據的shape
print(mnist.train.images.shape)  # 訓練數據圖片(55000, 28, 28, 1)
print(mnist.train.labels.shape)  # 訓練數據標籤(55000, 10)
print(mnist.test.images.shape)  # 測試數據圖片(10000, 28, 28, 1)
print(mnist.test.labels.shape)  # 測試數據圖片(10000, 10)
print(mnist.validation.images.shape)  # 驗證數據圖片(5000, 28, 28, 1)
print(mnist.validation.labels.shape)  # 驗證數據圖片(5000, 784)


def train():
    batch_size = FLAGS.batch_size
    batch_nums = mnist.train.images.shape[0] // batch_size  # 一個epoch中應該包含多少batch數據
    class_num = FLAGS.class_num
    epochs = FLAGS.epochs
    learning_rate = FLAGS.learning_rate

    ############    保存檢查點的地址   ############
    checkpoints_dir = FLAGS.checkpoints_dir  # checkpoints
    # 如果檢查點不存在,則創建
    if not os.path.exists(checkpoints_dir):
        os.makedirs(FLAGS.checkpoints_dir)

    ######################################################
    #                    創建圖                          #
    ######################################################
    graph = tf.Graph()  # 自定義圖
    # 在自己的圖中定義數據和操作
    with graph.as_default():
        inputs = tf.placeholder(dtype="float", shape=[None, 28, 28, 1], name='inputs')
        labels = tf.placeholder(dtype="float", shape=[None, class_num], name='labels')
        ############    搭建模型   ############
        logits = VGG16Net(inputs, class_num)  # 使用placeholder搭建模型
        ############    損失函數   ############
        # 計算預測值和真實值之間的誤差
        loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=labels, logits=logits))
        tf.add_to_collection('losses', loss)
        total_loss = tf.add_n(tf.get_collection("losses"))  # total_loss=模型損失+權重正則化損失
        ############    模型精度   ############
        predict = tf.argmax(logits, axis=1)
        accuracy = tf.reduce_mean(tf.cast(tf.equal(predict, tf.argmax(labels, axis=1)), tf.float32))
        ############    優化器   ############
        variable_to_train = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES)  # 可訓練變量列表
        # 創建優化器,更新網絡參數,最小化loss,
        train_op = tf.train.AdamOptimizer(learning_rate).minimize(loss=total_loss,
                                                                  var_list=variable_to_train)
        ############    TensorBoard可視化 summary  ############
        summary_writer = tf.summary.FileWriter("./logs", graph=graph)  # 創建事件文件
        tf.summary.scalar(name="loss", tensor=total_loss)  # 收集損失值變量
        tf.summary.scalar(name='accuracy', tensor=accuracy)  # 收集精度值變量
        tf.summary.scalar(name='learning_rate', tensor=learning_rate)
        merged_summary_op = tf.summary.merge_all()  # 將所有的summary合併為一個op
        ############    模型保存和恢復 Saver   ############
        saver = tf.train.Saver(max_to_keep=5)

    ######################################################
    #                   創建會話                          #
    ######################################################
    max_acc = 0.
    config = tf.ConfigProto(allow_soft_placement=True, log_device_placement=True)
    with tf.Session(config=config, graph=graph) as sess:
        # 加載模型,如果模型存在返回 是否加載成功和訓練步數
        could_load, checkpoint_step = load_model(sess, saver, FLAGS.checkpoints_dir)
        if could_load:
            step = checkpoint_step
            print(" [*] 模型加載成功")
        else:
            print(" [!] 模型加載失敗")
            try:
                tf.global_variables_initializer().run()
            except:
                tf.initialize_all_variables().run()
            step = 0

        for epoch in range(epochs):
            for i in range(batch_nums):
                start_time = time.time()    # 記錄一下開始訓練的時間
                # batch_images = data_X[i * batch_size:(i + 1) * batch_size]
                # batch_labels = data_y[i * batch_size:(i + 1) * batch_size]
                train_batch_x, train_batch_y = mnist.train.next_batch(batch_size)

                # 使用真實數據填充placeholder,運行訓練模型和合併變量操作
                _, summary, loss = sess.run([train_op, merged_summary_op, total_loss],
                                            feed_dict={inputs: train_batch_x,
                                                       labels: train_batch_y})
                if step % 100 == 0:
                    summary_writer.add_summary(summary, step)  # 將每次迭代后的變量寫入事件文件
                    summary_writer.flush()  # 強制summary_writer將緩存中的數據寫入到日誌文件中(可選)

                ############    可視化打印   ############
                print("Epoch:[%2d] [%4d/%4d] time:%4.4f,loss:%.8f" % (
                    epoch, i, batch_nums, time.time() - start_time, loss))

                # 打印一些可視化的數據,損失...
                # if np.mod(step, 100) == 1
                if step % 100 == 0:
                    acc = sess.run(accuracy, {inputs: mnist.validation.images,
                                              labels: mnist.validation.labels})
                    print("Epoch:[%2d] [%4d/%4d],acc:%.8f" % (epoch, i, batch_nums, acc))
                    ############    保存模型   ############
                    if acc > max_acc:
                        max_acc = acc
                        save_path = saver.save(sess,
                                               save_path=os.path.join(checkpoints_dir, "model.ckpt"),
                                               global_step=step)
                        # logging.info("模型保存在: %s" % save_path)
                        tf.logging.info("模型保存在: %s" % save_path)
                step += 1
            print("優化完成!")


def main(argv=None):
    train()


if __name__ == '__main__':
    # logging.basicConfig(level=logging.INFO)
    tf.logging.set_verbosity(tf.logging.INFO)
    tf.app.run()

main(step)

數據處理

  數據處理因為每個專業領域的原因各不相同,而這不同點也是各位論文創新點的新方向。不同的我沒法講,但我總結了幾點相同的地方——batch數據生成。因為深度學習模型需要一個batch一個batch的喂數據進行訓練,所以我們的數據必須是batch的形式,這裏衍生了三點問題

  1. 通過代碼批量讀取數據,
  2. 如何生成batch數據:由於篇幅過長,實在有很多地方要介紹和詳述,我把這一塊內容移到了這篇文章《TensorFlow讀取數據的三種方法》中
  3. 數據的shape:我舉兩個例子讓大家理解:圖片數據為4維 (batch_size, height,width, channels),序列數據為3維 (batch_size, time_steps, input_size),
    • 不同的shape處理方法不同,選擇神經網絡模型單元也不同。我會在後面細講

模型搭建

  閱讀這一節我默認大家已經學會了數據的batch讀取了。

  模型搭建這一步很像我們小時候玩的搭積木,我這裏以經典神經網絡模型VGG、Alex、ResNet、Google Inception Net為例講解,大家看代碼看多了也會很簡單的就找到,當然我是有一點私心的,我想把這些經典的網絡在這篇文章做一個tensorflow實現匯總,我細講第一個,大家可能看一個例子就懂了,看懂了就直接往下看,看不懂就多看幾個。

LeNet5模型

論文:1998_LeNet_Gradient-Based Learning Applied to Document Recognition

  下面我們定義一個LeNet5模型,我們先定義需要用到的神經網絡單元,相同的代碼盡量封裝成函數的形式以節省代碼量和簡潔代碼

def conv(input, kernel_size, output_size, stride, init_bias=0.0, padding="SAME", name=None, wd=None):
    input_size = input.shape[-1]
    conv_weights = tf.get_variable(name='weights',
                                   shape=[kernel_size, kernel_size, input_size, output_size],
                                   initializer=tf.truncated_normal_initializer(stddev=0.1),
                                   dtype=tf.float32)
    conv_biases = tf.get_variable(name='biases',
                                  shape=[output_size],
                                  initializer=tf.constant_initializer(init_bias),
                                  dtype=tf.float32)

    if wd is not None:
        # wd 0.004
        # tf.nn.l2_loss(var)=sum(t**2)/2
        weight_decay = tf.multiply(tf.nn.l2_loss(conv_weights), wd, name='weight_loss')
        tf.add_to_collection('losses', weight_decay)

    conv_layer = tf.nn.conv2d(input, conv_weights, [1, stride, stride, 1], padding=padding, name=name)  # 卷積操作
    conv_layer = tf.nn.bias_add(conv_layer, conv_biases)  # 加上偏置項
    conv_layer = tf.nn.relu(conv_layer)  # relu激活函數

    return conv_layer


def fc(input, output_size, init_bias=0.0, activeation_func=True, wd=None):
    input_shape = input.get_shape().as_list()
    # 創建 全連接權重 變量
    fc_weights = tf.get_variable(name="weights",
                                 shape=[input_shape[-1], output_size],
                                 initializer=tf.truncated_normal_initializer(stddev=0.1),
                                 dtype=tf.float32)
    if wd is not None:
        # wd 0.004
        # tf.nn.l2_loss(var)=sum(t**2)/2
        weight_decay = tf.multiply(tf.nn.l2_loss(fc_weights), wd, name='weight_loss')
        tf.add_to_collection('losses', weight_decay)
    # 創建 全連接偏置 變量
    fc_biases = tf.get_variable(name="biases",
                                shape=[output_size],
                                initializer=tf.constant_initializer(init_bias),
                                dtype=tf.float32)

    fc_layer = tf.matmul(input, fc_weights)  # 全連接計算
    fc_layer = tf.nn.bias_add(fc_layer, fc_biases)  # 加上偏置項
    if activeation_func:
        fc_layer = tf.nn.relu(fc_layer)  # rele激活函數
    return fc_layer

View Code

  然後利用我們搭建的神經網絡單元,搭建LeNet5神經網絡模型

# 訓練時:keep_prob=0.5
# 測試時:keep_prob=1.0
def leNet(inputs, class_num, keep_prob=0.5):
    # 第一層 卷積層 conv1
    with tf.variable_scope('layer1-conv1'):
        conv1 = conv(input=inputs, kernel_size=5, output_size=32, stride=1, init_bias=0.0, name="layer1-conv1",
                     padding="SAME")
    # 第二層 池化層
    with tf.name_scope('layer2-pool1'):
        pool1 = tf.nn.max_pool(conv1, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
    # 第三層 卷積層 conv2
    with tf.variable_scope('layer3-conv2'):
        conv2 = conv(input=pool1, kernel_size=5, output_size=64, stride=1, init_bias=0.0, name="layer3-conv2",
                     padding="SAME")
    # 第四層 池化層
    with tf.name_scope('layer4-pool2'):
        pool2 = tf.nn.max_pool(conv2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')

    # 後面要做全連接,因此要把數據變成2維
    # pool_shape = pool2.get_shape().as_list()
    pool_shape = pool2.shape
    flatten = tf.reshape(pool2, [-1, pool_shape[1] * pool_shape[2] * pool_shape[3]])
    with tf.variable_scope('layer5-fcl'):
        fc1 = fc(input=flatten, output_size=512, init_bias=0.1, activeation_func=tf.nn.relu, wd=None)
        fc1 = tf.nn.dropout(fc1, keep_prob=keep_prob, name="dropout1")
    with tf.variable_scope('layer6-fc2'):
        logit = fc(input=fc1, output_size=class_num, init_bias=0.1, activeation_func=False, wd=None)
    return logit

Alex模型

論文:2012_Alex_ImageNet Classification with Deep Convolutional Neural Networks

  下面我們定義一個Alex模型,我們先定義需要用到的神經網絡單元,相同的代碼盡量封裝成函數的形式以節省代碼量和簡潔代碼

def conv(input, kernel_size, output_size, stride, init_bias=0.0, padding="SAME", name=None, wd=None):
    input_size = input.shape[-1]
    conv_weights = tf.get_variable(name='weights',
                                   shape=[kernel_size, kernel_size, input_size, output_size],
                                   initializer=tf.random_normal_initializer(mean=0, stddev=0.01),
                                   dtype=tf.float32)
    if wd is not None:
        # wd 0.004
        # tf.nn.l2_loss(var)=sum(t**2)/2
        weight_decay = tf.multiply(tf.nn.l2_loss(conv_weights), wd, name='weight_loss')
        tf.add_to_collection('losses', weight_decay)

    conv_biases = tf.get_variable(name='biases',
                                  shape=[output_size],
                                  initializer=tf.constant_initializer(init_bias),
                                  dtype=tf.float32)
    conv_layer = tf.nn.conv2d(input, conv_weights, [1, stride, stride, 1], padding=padding, name=name)  # 卷積操作
    conv_layer = tf.nn.bias_add(conv_layer, conv_biases)  # 加上偏置項
    conv_layer = tf.nn.relu(conv_layer)  # relu激活函數

    return conv_layer

conv函數

def fc(input, output_size, init_bias=0.0, activeation_func=True, wd=None):
    input_shape = input.get_shape().as_list()
    # 創建 全連接權重 變量
    fc_weights = tf.get_variable(name="weights",
                                 shape=[input_shape[-1], output_size],
                                 initializer=tf.random_normal_initializer(mean=0.0, stddev=0.01),
                                 dtype=tf.float32)
    if wd is not None:
        # wd 0.004
        # tf.nn.l2_loss(var)=sum(t**2)/2
        weight_decay = tf.multiply(tf.nn.l2_loss(fc_weights), wd, name='weight_loss')
        tf.add_to_collection('losses', weight_decay)

    # 創建 全連接偏置 變量
    fc_biases = tf.get_variable(name="biases",
                                shape=[output_size],
                                initializer=tf.constant_initializer(init_bias),
                                dtype=tf.float32)

    fc_layer = tf.matmul(input, fc_weights)  # 全連接計算
    fc_layer = tf.nn.bias_add(fc_layer, fc_biases)  # 加上偏置項
    if activeation_func:
        fc_layer = tf.nn.relu(fc_layer)  # rele激活函數
    return fc_layer

fc函數

def LRN(input, depth_radius=2, alpha=0.0001, beta=0.75, bias=1.0):
    """Local Response Normalization 局部響應歸一化"""
    return tf.nn.local_response_normalization(input, depth_radius=depth_radius, alpha=alpha,
                                              beta=beta, bias=bias)

LRN函數

  然後利用我們搭建的神經網絡單元,搭建Alex神經網絡模型

def alexNet(inputs, class_num, keep_prob=0.5):
    # 第一層卷積層 conv1
    with tf.variable_scope("conv1"):
        conv1 = conv(input=inputs, kernel_size=7, output_size=96, stride=3, init_bias=0.0, name="conv1", padding="SAME")
        conv1 = LRN(conv1)
        conv1 = tf.nn.max_pool(conv1, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding='VALID', name="pool1")
    # 第二層卷積層 conv2
    with tf.variable_scope("conv2"):
        conv2 = conv(input=conv1, kernel_size=7, output_size=96, stride=3, init_bias=1.0, name="conv2", padding="SAME")
        conv2 = LRN(conv2)
        conv2 = tf.nn.max_pool(conv2, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding='VALID', name="pool2")
    # 第三層卷積層 conv3
    with tf.variable_scope("conv3"):
        conv3 = conv(input=conv2, kernel_size=7, output_size=96, stride=3, init_bias=0.0, name="conv3", padding="SAME")
    # 第四層卷積層 conv4
    with tf.variable_scope("conv4"):
        conv4 = conv(input=conv3, kernel_size=7, output_size=96, stride=3, init_bias=1.0, name="conv4", padding="SAME")
    # 第五層卷積層 conv5
    with tf.variable_scope("conv5"):
        conv5 = conv(input=conv4, kernel_size=3, output_size=256, stride=1, init_bias=1.0, name="conv5")
        conv5 = tf.nn.max_pool(conv5, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding='VALID', name="pool5")
    conv5_shape = conv5.shape  # 後面做全連接,所以要把shape改成2維
    # shape=[batch, dim]
    flatten = tf.reshape(conv5, [-1, conv5_shape[1] * conv5_shape[2] * conv5_shape[3]])
    # 第一層全連接層 fc1
    with tf.variable_scope("fc1"):
        fc1 = fc(input=flatten, output_size=4096, init_bias=1.0, activeation_func=tf.nn.relu, wd=None)
        fc1 = tf.nn.dropout(fc1, keep_prob=keep_prob, name="dropout1")
    # 第一層全連接層 fc2
    with tf.variable_scope("fc2"):
        fc2 = fc(input=fc1, output_size=4096, init_bias=1.0, activeation_func=tf.nn.relu, wd=None)
        fc2 = tf.nn.dropout(fc2, keep_prob=keep_prob, name="dropout1")
    # 第一層全連接層 fc3
    with tf.variable_scope("fc3"):
        logit = fc(input=fc2, output_size=class_num, init_bias=1.0, activeation_func=False, wd=None)

    return logit  # 模型輸出

VGG模型

論文:2014_VGG_Very Deep Convolutional Networks for Large-Scale Image Recognition

VGG有兩個比較有名的網絡:VGG16、VGG19,我在這裏搭建VGG16,有興趣的朋友可以按照上面的模型結構自己用TensorFlow搭建VGG19模型

  下面我們定義一個VGG16模型,和前面一樣,我們先定義需要用到的神經網絡單元,相同的代碼盡量封裝成函數的形式以節省代碼量和簡潔代碼

  因為模型中同一個變量域中包含多個卷積操作,因此在卷積函數中套一層變量域

def conv(inputs, scope_name, kernel_size, output_size, stride, init_bias=0.0, padding="SAME", wd=None):
    input_size = int(inputs.get_shape()[-1])
    with tf.variable_scope(scope_name):
        conv_weights = tf.get_variable(name='weights',
                                       shape=[kernel_size, kernel_size, input_size, output_size],
                                       dtype=tf.float32,
                                       initializer=tf.truncated_normal_initializer(mean=0.0, stddev=1e-1))
        if wd is not None:
            # tf.nn.l2_loss(var)=sum(t**2)/2
            weight_decay = tf.multiply(tf.nn.l2_loss(conv_weights), wd, name='weight_loss')
            tf.add_to_collection('losses', weight_decay)

        conv_biases = tf.get_variable(name='biases',
                                      shape=[output_size],
                                      dtype=tf.float32,
                                      initializer=tf.constant_initializer(init_bias))
        conv_layer = tf.nn.conv2d(inputs, conv_weights, [1, stride, stride, 1], padding=padding, name=scope_name)
        conv_layer = tf.nn.bias_add(conv_layer, conv_biases)
        conv_layer = tf.nn.relu(conv_layer)
    return conv_layer

conv函數

def fc(inputs, scope_name, output_size, init_bias=0.0, activeation_func=True, wd=None):
    input_shape = inputs.get_shape().as_list()
    with tf.variable_scope(scope_name):
        # 創建 全連接權重 變量
        fc_weights = tf.get_variable(name="weights",
                                     shape=[input_shape[-1], output_size],
                                     dtype=tf.float32,
                                     initializer=tf.truncated_normal_initializer(mean=0.0, stddev=1e-1))
        if wd is not None:
            # wd 0.004
            # tf.nn.l2_loss(var)=sum(t**2)/2
            weight_decay = tf.multiply(tf.nn.l2_loss(fc_weights), wd, name='weight_loss')
            tf.add_to_collection('losses', weight_decay)
        
        # 創建 全連接偏置 變量
        fc_biases = tf.get_variable(name="biases",
                                    shape=[output_size],
                                    dtype=tf.float32,
                                    initializer=tf.constant_initializer(init_bias),
                                    trainable=True)

        fc_layer = tf.matmul(inputs, fc_weights)  # 全連接計算
        fc_layer = tf.nn.bias_add(fc_layer, fc_biases)  # 加上偏置項
        if activeation_func:
            fc_layer = tf.nn.relu(fc_layer)  # rele激活函數
    return fc_layer

fc函數

  然後利用我們搭建的神經網絡單元,搭建VGG16神經網絡模型

def VGG16Net(inputs, class_num):
    with tf.variable_scope("conv1"):
        # conv1_1 [conv3_64]
        conv1_1 = conv(inputs=inputs, scope_name="conv1_1", kernel_size=3, output_size=64, stride=1,
                       init_bias=0.0, padding="SAME")
        # conv1_2 [conv3_64]
        conv1_2 = conv(inputs=conv1_1, scope_name="conv1_2", kernel_size=3, output_size=64, stride=1,
                       init_bias=0.0, padding="SAME")
    pool1 = tf.nn.max_pool(conv1_2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME', name='pool1')
    with tf.variable_scope("conv2"):
        # conv2_1
        conv2_1 = conv(inputs=pool1, scope_name="conv2_1", kernel_size=3, output_size=128, stride=1,
                       init_bias=0.0, padding="SAME")
        # conv2_2
        conv2_2 = conv(inputs=conv2_1, scope_name="conv2_2", kernel_size=3, output_size=128, stride=1,
                       init_bias=0.0, padding="SAME")
    pool2 = tf.nn.max_pool(conv2_2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME', name='pool2')
    with tf.variable_scope("conv3"):
        # conv3_1
        conv3_1 = conv(inputs=pool2, scope_name="conv3_1", kernel_size=3, output_size=256, stride=1,
                       init_bias=0.0, padding="SAME")
        # conv3_2
        conv3_2 = conv(inputs=conv3_1, scope_name="conv3_2", kernel_size=3, output_size=256, stride=1,
                       init_bias=0.0, padding="SAME")
        # conv3_3
        conv3_3 = conv(inputs=conv3_2, scope_name="conv3_3", kernel_size=3, output_size=256, stride=1,
                       init_bias=0.0, padding="SAME")
    pool3 = tf.nn.max_pool(conv3_3, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME', name='pool3')
    with tf.variable_scope("conv4"):
        # conv4_1
        conv4_1 = conv(inputs=pool3, scope_name="conv4_1", kernel_size=3, output_size=512, stride=1,
                       init_bias=0.0, padding="SAME")
        # conv4_2
        conv4_2 = conv(inputs=conv4_1, scope_name="conv4_2", kernel_size=3, output_size=512, stride=1,
                       init_bias=0.0, padding="SAME")
        # conv4_3
        conv4_3 = conv(inputs=conv4_2, scope_name="conv4_3", kernel_size=3, output_size=512, stride=1,
                       init_bias=0.0, padding="SAME")
    pool4 = tf.nn.max_pool(conv4_3, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME', name='pool4')
    with tf.variable_scope("conv5"):
        # conv5_1
        conv5_1 = conv(inputs=pool4, scope_name="conv4_1", kernel_size=3, output_size=512, stride=1,
                       init_bias=0.0, padding="SAME")
        # conv5_2
        conv5_2 = conv(inputs=conv5_1, scope_name="conv4_2", kernel_size=3, output_size=512, stride=1,
                       init_bias=0.0, padding="SAME")
        # conv5_3
        conv5_3 = conv(inputs=conv5_2, scope_name="conv4_3", kernel_size=3, output_size=512, stride=1,
                       init_bias=0.0, padding="SAME")
    pool5 = tf.nn.max_pool(conv5_3, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME', name='pool4')
    input_shape = pool5.get_shape().as_list()  # 後面做全連接,所以要把shape改成2維
    # shape=[batch, dim]
    flatten = tf.reshape(pool5, [-1, input_shape[1] * input_shape[2] * input_shape[3]])
    fc1 = fc(inputs=flatten, scope_name="fc1", output_size=4096, init_bias=1.0, activeation_func=True)
    fc2 = fc(inputs=fc1, scope_name="fc2", output_size=4096, init_bias=1.0, activeation_func=True)
    fc3 = fc(inputs=fc2, scope_name="fc3", output_size=class_num, init_bias=1.0, activeation_func=True)

    return fc3

上圖中有一個softmax層,我們也可以定義出來

class_num = 1000
# placeholder 定義
inputs = tf.placeholder(dtype="float", shape=[None, 28, 28, 3], name='inputs')
labels = tf.placeholder(dtype="float", shape=[None, class_num], name='labels')
learning_rate = tf.placeholder("float", None, name='learning_rate')

logits = VGG16Net(inputs)
probs = tf.nn.softmax(logits)

ResNet模型

論文:

  • 2016_ResNet_Deep Residual Learning for Image Recognition
  • 2016_ResNet_Identity Mappings in Deep Residual Networks

  ResNet的網絡結構如下圖所示

我們先定義需要用到的神經網絡單元

def batch_normalization(inputs, output_size):
    mean, variance = tf.nn.moments(inputs, axes=[0, 1, 2])  # 計算均值和方差
    beta = tf.get_variable('beta', output_size, tf.float32, initializer=tf.zeros_initializer)
    gamma = tf.get_variable('gamma', output_size, tf.float32, initializer=tf.ones_initializer)
    bn_layer = tf.nn.batch_normalization(inputs, mean, variance, beta, gamma, 0.001)

    return bn_layer

batch_normalization函數

def conv(input, kernel_size, output_size, stride, padding="SAME", wd=None):
    input_size = input.shape[-1]
    conv_weights = tf.get_variable(name='weights',
                                   shape=[kernel_size, kernel_size, input_size, output_size],
                                   dtype=tf.float32,
                                   initializer=tf.truncated_normal_initializer(mean=0.0, stddev=0.1),
                                   regularizer=tf.contrib.layers.l2_regularizer(0.00004)) # 正則損失衰減率0.000004

    conv_layer = tf.nn.conv2d(input, conv_weights, [1, stride, stride, 1], padding=padding)  # 卷積操作
    batch_norm = batch_normalization(conv_layer, output_size)
    conv_output = tf.nn.relu(batch_norm)  # relu激活函數
    return conv_output

conv函數

def fc(input, output_size, activeation_func=True):
    input_shape = input.shape[-1]
    # 創建 全連接權重 變量
    fc_weights = tf.get_variable(name="weights",
                                 shape=[input_shape, output_size],
                                 initializer=tf.truncated_normal_initializer(stddev=0.01),
                                 dtype=tf.float32,
                                 regularizer=tf.contrib.layers.l2_regularizer(0.01))
    # 創建 全連接偏置 變量
    fc_biases = tf.get_variable(name="biases",
                                shape=[output_size],
                                initializer=tf.zeros_initializer,
                                dtype=tf.float32)

    fc_layer = tf.matmul(input, fc_weights)  # 全連接計算
    fc_layer = tf.nn.bias_add(fc_layer, fc_biases)  # 加上偏置項
    if activeation_func:
        fc_layer = tf.nn.relu(fc_layer)  # rele激活函數
    return fc_layer

fc函數

def block(input, n, output_size, change_first_stride, bottleneck):
    if n == 0 and change_first_stride:
        stride = 2
    else:
        stride = 1
    if bottleneck:
        with tf.variable_scope('a'):
            conv_a = conv(input=input, kernel_size=1, output_size=output_size, stride=stride, padding="SAME")
            conv_a = batch_normalization(conv_a, output_size)
            conv_a = tf.nn.relu(conv_a)
        with tf.variable_scope('b'):
            conv_b = conv(input=conv_a, kernel_size=3, output_size=output_size, stride=1, padding="SAME")
            conv_b = batch_normalization(conv_b, output_size)
            conv_b = tf.nn.relu(conv_b)

        with tf.variable_scope('c'):
            conv_c = conv(input=conv_b, kernel_size=1, output_size=output_size * 4, stride=1, padding="SAME")
            output = batch_normalization(conv_c, output_size * 4)
    else:
        with tf.variable_scope('A'):
            conv_A = conv(input=input, kernel_size=3, output_size=output_size, stride=stride, padding="SAME")
            conv_A = batch_normalization(conv_A, output_size)
            conv_A = tf.nn.relu(conv_A)

        with tf.variable_scope('B'):
            conv_B = conv(input=conv_A, kernel_size=3, output_size=output_size, stride=1, padding="SAME")
            output = batch_normalization(conv_B, output_size)

    if input.shape == output.shape:
        with tf.variable_scope('shortcut'):
            shortcut = input  # shortcut
    else:
        with tf.variable_scope('shortcut'):
            shortcut = conv(input=input, kernel_size=1, output_size=output_size * 4, stride=1, padding="SAME")
            shortcut = batch_normalization(shortcut, output_size * 4)

    return tf.nn.relu(output + shortcut)

block函數

  然後我們定義神經網絡框架

def inference(inputs, class_num, num_blocks=[3, 4, 6, 3], bottleneck=True):
    # data[1, 224, 224, 3]

    # 我們嘗試搭建50層ResNet
    with tf.variable_scope('conv1'):
        conv1 = conv(input=inputs, kernel_size=7, output_size=64, stride=2, padding="SAME")
        conv1 = batch_normalization(inputs=conv1, output_size=64)
        conv1 = tf.nn.relu(conv1)

    with tf.variable_scope('conv2_x'):
        conv_output = tf.nn.max_pool(conv1, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding='SAME')
        for n in range(num_blocks[0]):
            with tf.variable_scope('block%d' % (n + 1)):
                conv_output = block(conv_output, n, output_size=64, change_first_stride=False, bottleneck=bottleneck)

    with tf.variable_scope('conv3_x'):
        for n in range(num_blocks[1]):
            with tf.variable_scope('block%d' % (n + 1)):
                conv_output = block(conv_output, n, output_size=128, change_first_stride=True, bottleneck=bottleneck)

    with tf.variable_scope('conv4_x'):
        for n in range(num_blocks[2]):
            with tf.variable_scope('block%d' % (n + 1)):
                conv_output = block(conv_output, n, output_size=256, change_first_stride=True, bottleneck=bottleneck)

    with tf.variable_scope('conv5_x'):
        for n in range(num_blocks[3]):
            with tf.variable_scope('block%d' % (n + 1)):
                conv_output = block(conv_output, n, output_size=512, change_first_stride=True, bottleneck=bottleneck)

    output = tf.reduce_mean(conv_output, reduction_indices=[1, 2], name="avg_pool")
    with tf.variable_scope('fc'):
        output = fc(output, class_num, activeation_func=False)

    return output

Google Inception Net模型

  Inception Net模型 以後再更新吧,如果這篇文章對大家有用,歡迎大家催促我。

RNN模型

  Tensorflow中的CNN變數很少,而RNN卻豐富多彩,不僅在RNN Cell上有很多種、在實現上也有很多種,在用法上更是花樣百出。

五個基本的RNN Cell:RNNCell、BasicRNNCell、LSTMCell、BasicLSTMCell、GRUCell

RNN Cell的封裝和變形:MultiRNNCell(多層RNN)、DropoutWrapper、ResidualWrapper、DeviceWrapper

四種架構 (static+dynamic)*(單向+雙向)=4:static_rnn(靜態RNN)、dynamic_rnn(動態RNN)、static_bidirectional_rnn(靜態雙向RNN)、bidirectional_dynamic_rnn(動態雙向RNN)

五種手法 (one+many)*(one+many) +1=5:

  1. one to one(1 vs 1):輸入一個,輸出一個。其實和全連接神經網絡並沒有什麼區別,這一類別算不得是 RNN。
  2. one to many(1 vs N):輸入一個,輸出多個。圖像標註,輸入一個圖片,得到對圖片的語言描述
  3. many to one(N vs 1):輸入多個,輸出一個。序列分類,把序列壓縮成一個向量
  4. many to many(N vs N):輸入多個,輸出多個。兩者長度可以不一樣。翻譯任務
  5. many to many(N vs N):輸入多個,輸出多個。兩者長度一樣。char RNN

我們先定義需要用到的神經網絡單元

全連接層

def fc(input, output_size, activeation_func=tf.nn.relu):
    input_shape = input.shape[-1]
    # 創建 全連接權重 變量
    fc_weights = tf.get_variable(name="weights",
                                 shape=[input_shape, output_size],
                                 initializer=tf.truncated_normal_initializer(stddev=0.01),
                                 dtype=tf.float32,
                                 regularizer=tf.contrib.layers.l2_regularizer(0.01))
    # 創建 全連接偏置 變量
    fc_biases = tf.get_variable(name="biases",
                                shape=[output_size],
                                initializer=tf.zeros_initializer,
                                dtype=tf.float32)

    fc_layer = tf.matmul(input, fc_weights)  # 全連接計算
    fc_layer = tf.nn.bias_add(fc_layer, fc_biases)  # 加上偏置項
    if activeation_func:
        fc_layer = activeation_func(fc_layer)  # rele激活函數
    return fc_layer

View Code

單層 靜態/動態 LSTM/GRU

#######################################
#       單層 靜態/動態 LSTM/GRU        #
#######################################
# 單層靜態LSTM
def single_layer_static_lstm(input_x, time_steps, hidden_size):
    """
    :param input_x: 輸入張量 形狀為[batch_size, n_steps, input_size]
    :param n_steps: 時序總數
    :param n_hidden: LSTM單元輸出的節點個數 即隱藏層節點數
    """
    # 把輸入input_x按列拆分,並返回一個有n_steps個張量組成的list
    # 如batch_sizex28x28的輸入拆成[(batch_size,28),((batch_size,28))....]
    # 如果是調用的是靜態rnn函數,需要這一步處理   即相當於把序列作為第一維度
    input_x1 = tf.unstack(input_x, num=time_steps, axis=1)
    lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(num_units=hidden_size)  # 創建LSTM_cell
    # 靜態rnn函數傳入的是一個張量list  每一個元素都是一個(batch_size,input_size)大小的張量
    output, states = tf.nn.static_rnn(cell=lstm_cell, inputs=input_x1, dtype=tf.float32)  # 通過cell類構建RNN

    return output, states


# 單層靜態gru
def single_layer_static_gru(input, time_steps, hidden_size):
    """
    :param input: 輸入張量 形狀為[batch_size, n_steps, input_size]
    :param n_steps: 時序總數
    :param n_hidden: gru單元輸出的節點個數 即隱藏層節點數
    :return: 返回靜態單層GRU單元的輸出,以及cell狀態
    """
    # 把輸入input_x按列拆分,並返回一個有n_steps個張量組成的list
    # 如batch_sizex28x28的輸入拆成[(batch_size,28),((batch_size,28))....]
    # 如果是調用的是靜態rnn函數,需要這一步處理   即相當於把序列作為第一維度
    input_x = tf.unstack(input, num=time_steps, axis=1)
    gru_cell = tf.nn.rnn_cell.GRUCell(num_units=hidden_size)  # 創建GRU_cell
    # 靜態rnn函數傳入的是一個張量list  每一個元素都是一個(batch_size,input_size)大小的張量
    output, states = tf.nn.static_rnn(cell=gru_cell, inputs=input_x, dtype=tf.float32)  # 通過cell類構建RNN

    return output, states


# 單層動態LSTM
def single_layer_dynamic_lstm(input, time_steps, hidden_size):
    """
    :param input_x: 輸入張量 形狀為[batch_size, time_steps, input_size]
    :param time_steps: 時序總數
    :param hidden_size: LSTM單元輸出的節點個數 即隱藏層節點數
    :return: 返回動態單層LSTM單元的輸出,以及cell狀態
    """
    lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(num_units=hidden_size)  # 創建LSTM_cell
    # 動態rnn函數傳入的是一個三維張量,[batch_size,time_steps, input_size]  輸出也是這種形狀
    output, states = tf.nn.dynamic_rnn(cell=lstm_cell, inputs=input, dtype=tf.float32)  # 通過cell類構建RNN
    output = tf.transpose(output, [1, 0, 2])  # 注意這裏輸出需要轉置  轉換為時序優先的
    return output, states


# 單層動態gru
def single_layer_dynamic_gru(input, time_steps, hidden_size):
    """
    :param input: 輸入張量 形狀為[batch_size, time_steps, input_size]
    :param time_steps: 時序總數
    :param hidden_size: GRU單元輸出的節點個數 即隱藏層節點數
    :return: 返回動態單層GRU單元的輸出,以及cell狀態
    """
    gru_cell = tf.nn.rnn_cell.GRUCell(num_units=hidden_size)  # 創建GRU_cell
    # 動態rnn函數傳入的是一個三維張量,[batch_size,n_steps,input_size]  輸出也是這種形狀
    output, states = tf.nn.dynamic_rnn(cell=gru_cell, inputs=input, dtype=tf.float32)  # 通過cell類構建RNN
    output = tf.transpose(output, [1, 0, 2])  # 注意這裏輸出需要轉置  轉換為時序優先的
    return output, states

View Code

多層 靜態/動態 LSTM/GRU

#######################################
#       多層 靜態/動態 LSTM/GRU        #
#######################################
# 多層靜態LSTM網絡
def multi_layer_static_lstm(input, time_steps, hidden_size):
    """
    :param input: 輸入張量 形狀為[batch_size,time_steps,input_size]
    :param time_steps: 時序總數
    :param n_hidden: LSTM單元輸出的節點個數 即隱藏層節點數
    :return: 返回靜態多層LSTM單元的輸出,以及cell狀態
    """
    # 把輸入input_x按列拆分,並返回一個有n_steps個張量組成的list
    # 如batch_sizex28x28的輸入拆成[(batch_size,28),((batch_size,28))....]
    # 如果是調用的是靜態rnn函數,需要這一步處理   即相當於把序列作為第一維度
    input_x1 = tf.unstack(input, num=time_steps, axis=1)

    # 多層RNN的實現 例如cells=[cell1,cell2,cell3],則表示一共有三層
    mcell = tf.nn.rnn_cell.MultiRNNCell(
        [tf.nn.rnn_cell.LSTMCell(num_units=hidden_size) for _ in range(3)])

    # 靜態rnn函數傳入的是一個張量list  每一個元素都是一個(batch_size,input_size)大小的張量
    output, states = tf.nn.static_rnn(cell=mcell, inputs=input_x1, dtype=tf.float32)

    return output, states


# 多層靜態GRU
def multi_layer_static_gru(input, time_steps, hidden_size):
    """
    :param input_x: 輸入張量 形狀為[batch_size,n_steps,input_size]
    :param time_steps: 時序總數
    :param hidden_size: gru單元輸出的節點個數 即隱藏層節點數
    :return: 返回靜態多層GRU單元的輸出,以及cell狀態
    """
    # 把輸入input_x按列拆分,並返回一個有n_steps個張量組成的list
    # 如batch_sizex28x28的輸入拆成[(batch_size,28),((batch_size,28))....]
    # 如果是調用的是靜態rnn函數,需要這一步處理   即相當於把序列作為第一維度
    input_x = tf.unstack(input, num=time_steps, axis=1)

    # 多層RNN的實現 例如cells=[cell1,cell2,cell3],則表示一共有三層
    mcell = tf.nn.rnn_cell.MultiRNNCell(
        [tf.nn.rnn_cell.GRUCell(num_units=hidden_size) for _ in range(3)])

    # 靜態rnn函數傳入的是一個張量list  每一個元素都是一個(batch_size,input_size)大小的張量
    output, states = tf.nn.static_rnn(cell=mcell, inputs=input_x, dtype=tf.float32)

    return output, states


# 多層靜態GRU和LSTM 混合
def multi_layer_static_mix(input, time_steps, hidden_size):
    """
    :param input: 輸入張量 形狀為[batch_size,n_steps,input_size]
    :param time_steps: 時序總數
    :param hidden_size: gru單元輸出的節點個數 即隱藏層節點數
    :return: 返回靜態多層GRU和LSTM混合單元的輸出,以及cell狀態
    """
    # 把輸入input_x按列拆分,並返回一個有n_steps個張量組成的list
    # 如batch_sizex28x28的輸入拆成[(batch_size,28),((batch_size,28))....]
    # 如果是調用的是靜態rnn函數,需要這一步處理   即相當於把序列作為第一維度
    input_x = tf.unstack(input, num=time_steps, axis=1)

    # 可以看做2個隱藏層
    lstm_cell = tf.nn.rnn_cell.LSTMCell(num_units=hidden_size)
    gru_cell = tf.nn.rnn_cell.GRUCell(num_units=hidden_size * 2)

    # 多層RNN的實現 例如cells=[cell1,cell2],則表示一共有兩層,數據經過cell1后還要經過cells
    mcell = tf.nn.rnn_cell.MultiRNNCell(cells=[lstm_cell, gru_cell])

    # 靜態rnn函數傳入的是一個張量list  每一個元素都是一個(batch_size,input_size)大小的張量
    output, states = tf.nn.static_rnn(cell=mcell, inputs=input_x, dtype=tf.float32)

    return output, states


# 多層動態LSTM
def multi_layer_dynamic_lstm(input, time_steps, hidden_size):
    """
    :param input: 輸入張量  形狀為[batch_size,n_steps,input_size]
    :param time_steps: 時序總數
    :param hidden_size: LSTM單元輸出的節點個數 即隱藏層節點數
    :return: 返回動態多層LSTM單元的輸出,以及cell狀態
    """
    # 多層RNN的實現 例如cells=[cell1,cell2],則表示一共有兩層,數據經過cell1后還要經過cells
    mcell = tf.nn.rnn_cell.MultiRNNCell(
        [tf.nn.rnn_cell.LSTMCell(num_units=hidden_size) for _ in range(3)])

    # 動態rnn函數傳入的是一個三維張量,[batch_size,n_steps,input_size]  輸出也是這種形狀
    output, states = tf.nn.dynamic_rnn(cell=mcell, inputs=input, dtype=tf.float32)

    # 注意這裏輸出需要轉置  轉換為時序優先的
    output = tf.transpose(output, [1, 0, 2])
    return output, states


# 多層動態GRU
def multi_layer_dynamic_gru(input, time_steps, hidden_size):
    """
    :param input: 輸入張量 形狀為[batch_size,n_steps,input_size]
    :param time_steps: 時序總數
    :param hidden_size: gru單元輸出的節點個數 即隱藏層節點數
    :return: 返回動態多層GRU單元的輸出,以及cell狀態
    """
    # 多層RNN的實現 例如cells=[cell1,cell2],則表示一共有兩層,數據經過cell1后還要經過cells
    mcell = tf.nn.rnn_cell.MultiRNNCell(
        [tf.nn.rnn_cell.GRUCell(num_units=hidden_size) for _ in range(3)])

    # 動態rnn函數傳入的是一個三維張量,[batch_size,n_steps,input_size]  輸出也是這種形狀
    output, states = tf.nn.dynamic_rnn(cell=mcell, inputs=input, dtype=tf.float32)

    # 注意這裏輸出需要轉置  轉換為時序優先的
    output = tf.transpose(output, [1, 0, 2])
    return output, states


# 多層動態GRU和LSTM 混合
def multi_layer_dynamic_mix(input, time_steps, hidden_size):
    """
    :param input: 輸入張量 形狀為[batch_size,n_steps,input_size]
    :param time_steps: 時序總數
    :param hidden_size: gru單元輸出的節點個數 即隱藏層節點數
    :return: 返回動態多層GRU和LSTM混合單元的輸出,以及cell狀態
    """
    # 可以看做2個隱藏層
    gru_cell = tf.nn.rnn_cell.GRUCell(num_units=hidden_size * 2)
    lstm_cell = tf.nn.rnn_cell.LSTMCell(num_units=hidden_size)

    # 多層RNN的實現 例如cells=[cell1,cell2],則表示一共有兩層,數據經過cell1后還要經過cells
    mcell = tf.nn.rnn_cell.MultiRNNCell(cells=[lstm_cell, gru_cell])

    # 動態rnn函數傳入的是一個三維張量,[batch_size,n_steps,input_size]  輸出也是這種形狀
    output, states = tf.nn.dynamic_rnn(cell=mcell, inputs=input, dtype=tf.float32)

    # 注意這裏輸出需要轉置  轉換為時序優先的
    output = tf.transpose(output, [1, 0, 2])
    return output, states

View Code

單層/多層 雙向 靜態/動態 LSTM/GRU

#######################################
#   單層/多層 雙向 靜態/動態 LSTM/GRU   #
#######################################
# 單層靜態雙向LSTM
def single_layer_static_bi_lstm(input, time_steps, hidden_size):
    """
    :param input: 輸入張量 形狀為[batch_size,time_steps,input_size]
    :param time_steps: 時序總數
    :param hidden_size: LSTM單元輸出的節點個數 即隱藏層節點數
    :return: 返回單層靜態雙向LSTM單元的輸出,以及cell狀態
    """
    # 把輸入input_x按列拆分,並返回一個有n_steps個張量組成的list
    # 如batch_sizex28x28的輸入拆成[(batch_size,28),((batch_size,28))....]
    # 如果是調用的是靜態rnn函數,需要這一步處理   即相當於把序列作為第一維度
    input_x = tf.unstack(input, num=time_steps, axis=1)
    lstm_fw_cell = tf.nn.rnn_cell.BasicLSTMCell(num_units=hidden_size)  # 正向
    lstm_bw_cell = tf.nn.rnn_cell.BasicLSTMCell(num_units=hidden_size)  # 反向

    # 靜態rnn函數傳入的是一個張量list  每一個元素都是一個(batch_size,input_size)大小的張量
    # 這裏的輸出output是一個list 每一個元素都是前向輸出,後向輸出的合併
    output, fw_state, bw_state = tf.nn.static_bidirectional_rnn(cell_fw=lstm_fw_cell,
                                                                cell_bw=lstm_bw_cell,
                                                                inputs=input_x,
                                                                dtype=tf.float32)
    print(type(output))  # <class 'list'>
    print(len(output))  # 28
    print(output[0].shape)  # (?, 256)

    return output, fw_state, bw_state


# 單層動態雙向LSTM
def single_layer_dynamic_bi_lstm(input, time_steps, hidden_size):
    """
    :param input: 輸入張量 形狀為[batch_size,time_steps,input_size]
    :param time_steps: 時序總數
    :param hidden_size: gru單元輸出的節點個數 即隱藏層節點數
    :return: 返回單層動態雙向LSTM單元的輸出,以及cell狀態
    """
    lstm_fw_cell = tf.nn.rnn_cell.BasicLSTMCell(num_units=hidden_size)  # 正向
    lstm_bw_cell = tf.nn.rnn_cell.BasicLSTMCell(num_units=hidden_size)  # 反向

    # 動態rnn函數傳入的是一個三維張量,[batch_size,time_steps,input_size]  輸出是一個元組 每一個元素也是這種形狀
    output, state = tf.nn.bidirectional_dynamic_rnn(cell_fw=lstm_fw_cell,
                                                    cell_bw=lstm_bw_cell,
                                                    inputs=input,
                                                    dtype=tf.float32)
    print(type(output))  # <class 'tuple'>
    print(len(output))  # 2
    print(output[0].shape)  # (?, 28, 128)
    print(output[1].shape)  # (?, 28, 128)

    output = tf.concat(output, axis=2)  # 按axis=2合併 (?,28,128) (?,28,128)按最後一維合併(?,28,256)
    output = tf.transpose(output, [1, 0, 2])  # 注意這裏輸出需要轉置  轉換為時序優先的

    return output, state


# 多層靜態雙向LSTM
def multi_layer_static_bi_lstm(input, time_steps, hidden_size):
    """
    :param input: 輸入張量 形狀為[batch_size,time_steps,input_size]
    :param time_steps: 時序總數
    :param hidden_size: LSTM單元輸出的節點個數 即隱藏層節點數
    :return: 返回多層靜態雙向LSTM單元的輸出,以及cell狀態
    """
    # 把輸入input_x按列拆分,並返回一個有n_steps個張量組成的list
    # 如batch_sizex28x28的輸入拆成[(batch_size,28),((batch_size,28))....]
    # 如果是調用的是靜態rnn函數,需要這一步處理   即相當於把序列作為第一維度
    input_x = tf.unstack(input, num=time_steps, axis=1)

    stacked_fw_rnn = []
    stacked_bw_rnn = []
    for i in range(3):
        stacked_fw_rnn.append(tf.nn.rnn_cell.BasicLSTMCell(num_units=hidden_size))  # 正向
        stacked_bw_rnn.append(tf.nn.rnn_cell.BasicLSTMCell(num_units=hidden_size))  # 反向

    # 靜態rnn函數傳入的是一個張量list  每一個元素都是一個(batch_size,input_size)大小的張量
    # 這裏的輸出output是一個list 每一個元素都是前向輸出,後向輸出的合併
    output, fw_state, bw_state = tf.contrib.rnn.stack_bidirectional_rnn(stacked_fw_rnn,
                                                                        stacked_bw_rnn,
                                                                        inputs=input_x,
                                                                        dtype=tf.float32)
    print(type(output))  # <class 'list'>
    print(len(output))  # 28
    print(output[0].shape)  # (?, 256)

    return output, fw_state, bw_state


# 多層動態雙向LSTM
def multi_layer_dynamic_bi_lstm(input, time_steps, hidden_size):
    """
    :param input: 輸入張量 形狀為[batch_size,n_steps,input_size]
    :param time_steps: 時序總數
    :param hidden_size: gru單元輸出的節點個數 即隱藏層節點數
    :return: 返回多層動態雙向LSTM單元的輸出,以及cell狀態
    """
    stacked_fw_rnn = []
    stacked_bw_rnn = []
    for i in range(3):
        stacked_fw_rnn.append(tf.nn.rnn_cell.BasicLSTMCell(num_units=hidden_size))  # 正向
        stacked_bw_rnn.append(tf.nn.rnn_cell.BasicLSTMCell(num_units=hidden_size))  # 反向

    # 動態rnn函數傳入的是一個三維張量,[batch_size,n_steps,input_size]  輸出也是這種形狀,
    # input_size變成了正向和反向合併之後的 即input_size*2
    output, fw_state, bw_state = tf.contrib.rnn.stack_bidirectional_dynamic_rnn(stacked_fw_rnn,
                                                                                stacked_bw_rnn,
                                                                                inputs=input,
                                                                                dtype=tf.float32)
    print(type(output))  # <class 'tensorflow.python.framework.ops.Tensor'>
    print(output.shape)  # (?, 28, 256)

    output = tf.transpose(output, [1, 0, 2])  # 注意這裏輸出需要轉置  轉換為時序優先的

    return output, fw_state, bw_state

View Code

然後我們定義神經網絡框架

※台中搬家遵守搬運三大原則,讓您的家具不再被破壞!

台中搬家公司推薦超過30年經驗,首選台中大展搬家

def RNN_inference(inputs, class_num, time_steps, hidden_size):
    """
    :param inputs: [batch_size, n_steps, input_size]
    :param class_num: 類別數
    :param time_steps: 時序總數
    :param n_hidden: LSTM單元輸出的節點個數 即隱藏層節點數
    """
    #######################################
    #       單層 靜態/動態 LSTM/GRU        #
    #######################################
    # outputs, states = single_layer_static_lstm(inputs, time_steps, hidden_size)  # 單層靜態LSTM
    # outputs, states = single_layer_static_gru(inputs, time_steps, hidden_size)   # 單層靜態gru
    # outputs, states = single_layer_dynamic_lstm(inputs, time_steps, hidden_size)  # 單層動態LSTM
    # outputs, states = single_layer_dynamic_gru(inputs, time_steps, hidden_size)  # 單層動態gru
    #######################################
    #       多層 靜態/動態 LSTM/GRU        #
    #######################################
    # outputs, states = multi_layer_static_lstm(inputs, time_steps, hidden_size)  # 多層靜態LSTM網絡
    # outputs, states = multi_layer_static_gru(inputs, time_steps, hidden_size)  # 多層靜態GRU
    # outputs, states = multi_layer_static_mix(inputs, time_steps, hidden_size)  # 多層靜態GRU和LSTM 混合
    # outputs, states = multi_layer_dynamic_lstm(inputs, time_steps, hidden_size)  # 多層動態LSTM
    # outputs, states = multi_layer_dynamic_gru(inputs, time_steps, hidden_size)  # 多層動態GRU
    # outputs, states = multi_layer_dynamic_mix(inputs, time_steps, hidden_size)  # 多層動態GRU和LSTM 混合
    #######################################
    #   單層/多層 雙向 靜態/動態 LSTM/GRU  #
    #######################################
    # outputs, fw_state, bw_state = single_layer_static_bi_lstm(inputs, time_steps, hidden_size)  # 單層靜態雙向LSTM
    # outputs, state = single_layer_dynamic_bi_lstm(inputs, time_steps, hidden_size)  # 單層動態雙向LSTM
    # outputs, fw_state, bw_state = multi_layer_static_bi_lstm(inputs, time_steps, hidden_size)  # 多層靜態雙向LSTM
    outputs, fw_state, bw_state = multi_layer_dynamic_bi_lstm(inputs, time_steps, hidden_size)  # 多層動態雙向LSTM

    # output靜態是 time_step=28個(batch=128, output=128)組成的列表
    # output動態是 (time_step=28, batch=128, output=128)
    print('hidden:', outputs[-1].shape)  # 最後一個時序的shape(128,128)

    # 取LSTM最後一個時序的輸出,然後經過全連接網絡得到輸出值
    fc_output = fc(input=outputs[-1], output_size=class_num, activeation_func=tf.nn.relu)

    return fc_output

設置全局變量和超參數

  在模型訓練之前我們首先會定義一些超參數:batch_size、batch_nums、class_num、epochs、learning_rate

batch_size = FLAGS.batch_size
batch_nums = mnist.train.images.shape[0] // batch_size  # 一個epoch中應該包含多少batch數據
class_num = FLAGS.class_num
epochs = FLAGS.epochs
learning_rate = FLAGS.learning_rate

保存檢查點的地址

############    保存檢查點的地址   ############
checkpoints_dir = FLAGS.checkpoints_dir  # checkpoints
# 如果檢查點不存在,則創建
if not os.path.exists(checkpoints_dir):
    os.makedirs(FLAGS.checkpoints_dir)

創建圖

  這一步可以不設置,因為tensorflow有一個默認圖,我們定義的操作都是在默認圖上的,當然我們也可以定義自己的,方便管理。

######################################################
#                    創建圖                          #
######################################################
graph = tf.Graph()  # 自定義圖
# 在自己的圖中定義數據和操作
with graph.as_default():

佔位符

  一般我們會把input和label做成placeholder,方便我們使用把不同的batch數據傳入網絡,一些其他的超參數也可以做成placeholder,比如learning_rate、dorpout_keep_prob。一般在搭建模型的時候把placeholder的變量傳入模型,在訓練模型sess.run(train_op, feed_dict)的時候通過參數feed_dict={input:真實數據,label:真實標籤} 把真實的數據傳入神經網絡。

inputs = tf.placeholder(dtype="float", shape=[None, 28, 28, 1], name='inputs')
labels = tf.placeholder(dtype="float", shape=[None, class_num], name='labels')
# 看個人喜歡,有的人在初始化定義中就定義了learning_rate,有的人喜歡通過feed傳learning_rate
learning_rate = tf.placeholder("float", None, name='learning_rate')
# 如果網絡結構有dropout層,需要定義keep_probn,如果沒有則不需要
# 訓練的時候需要,測試的時候需要設置成1
keep_prob = tf.placeholder(dtype="float", name='keep_prob')  

搭建模型

  傳進入的都是placeholder數據,不是我們之前整理好的batch數據。

############    搭建模型   ############
logits = alexNet(inputs, class_num, keep_prob=keep_prob)  # 使用placeholder搭建模型

構建損失

  分類任務一般輸出的是每個類別的概率向量,因此模型輸出最後都要經過softmax轉換成概率。一般經過softmax的輸出損失函數都是交叉熵損失函數,tensorflow有將以上兩步合在一起的現成函數 tf.nn.softmax_cross_entropy_with_logits

############    損失函數   ############
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=labels, logits=logits))
tf.add_to_collection('losses', loss)
total_loss = tf.add_n(tf.get_collection("loss"))  # total_loss=模型損失+權重正則化損失

自定義損失

  以後更新,歡迎大家催我。

模型精度

  在測試數據集上的精度

############    模型精度   ############
predict = tf.argmax(logits, 1)      # 模型預測結果
accuracy = tf.reduce_mean(tf.cast(tf.equal(predict, tf.argmax(labels, 1)), tf.float32))

自定義度量

  以後更新,歡迎大家催我。

優化器

  創建優化器,更新網絡參數,最小化loss

  優化器的種類有很多種,但是用法都差不多,常用的優化器有:

  • tf.train.AdamOptimizer
  • tf.train.GradientDescentOptimizer

  • tf.train.RMSPropOptimizer

下面以Adam優化器為例

############    優化器   ############
variable_to_train = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES)  # 可訓練變量列表
global_step = tf.Variable(0, trainable=False)    # 訓練step
# 設置學習率衰減
learning_rate = tf.train.exponential_decay(learning_rate=learning_rate,  # 初始學習率
                                           global_step=global_step,
                                           decay_steps=batch_nums,  # 多少步衰減一次
                                           decay_rate=0.1,  # 衰減率
                                           staircase=True)  # 以階梯的形式衰減
# 創建Adam優化器,更新模型參數,最小化損失函數
train_op = tf.train.AdamOptimizer(learning_rate).minimize(loss=total_loss,  # 損失函數
                                                          global_step=global_step,
                                                          var_list=variable_to_train)  # 通過訓練需要更新的參數列表

講解:

  • variable_to_train:上面的代碼定義了可訓練變量,我只是把列出了模型默認的可訓練變量,這一個步是tensorflow默認的,如果不設置也沒有關係。我寫出來的原因是,有的大牛會這麼寫,對不同的可訓練變量分別進行不同的優化,希望大家看到我的代碼,下次看到別人的不會覺得陌生。
  • global_step:大多數人會用step=0,然後在訓練的時候step+=1的方式更新step,但是本文介紹的是另一種方式,以tf.Variable的方式定義step,在模型訓練的時候傳入sess.run,global_step會自動+1更新
  • learning_rate:本文還設置了學習率衰減,大家也可以不設置,以固定的學習率訓練模型,但是對於大型項目,還是推薦設置。

移動平均值更新參數

採用移動平均值的方式更新損失值和模型參數

def train(total_loss, global_step):
    lr = tf.train.exponential_decay(0.01, global_step, decay_steps=350, decay_rate=0.1, staircase=True)
    # 採用滑動平均的方法更新損失值
    loss_averages = tf.train.ExponentialMovingAverage(decay=0.9, name='avg')
    losses = tf.get_collection('losses')  # losses的列表
    loss_averages_op = loss_averages.apply(losses + [total_loss])  # 計算損失值的影子變量op

    # 計算梯度
    with tf.control_dependencies([loss_averages_op]):  # 控制計算指定,只有執行了括號中的語句才能執行下面的語句
        opt = tf.train.GradientDescentOptimizer(lr)  # 創建優化器
        grads = opt.compute_gradients(total_loss)  # 計算梯度

    # 應用梯度
    apply_gradient_op = opt.apply_gradients(grads, global_step=global_step)

    # 採用滑動平均的方法更新參數
    variable_averages = tf.train.ExponentialMovingAverage(0.999, num_updates=global_step)
    variables_averages_op = variable_averages.apply(tf.trainable_variables())

    with tf.control_dependencies([apply_gradient_op, variables_averages_op]):
        # tf.no_op()表示執行完apply_gradient_op, variable_averages_op操作之後什麼都不做
        train_op = tf.no_op(name='train')

    return train_op

View Code

TensorBoard可視化 summary

############    TensorBoard可視化 summary  ############
summary_writer = tf.summary.FileWriter(logdir="./logs", graph=graph)  # 創建事件文件
tf.summary.scalar(name="losses", tensor=total_loss)  # 收集損失值變量
tf.summary.scalar(name="acc", tensor=accuracy)  # 收集精度值變量
tf.summary.scalar(name='learning_rate', tensor=learning_rate)
merged_summary_op = tf.summary.merge_all()  # 將所有的summary合併為一個op

模型保存和恢復 Saver

saver = tf.train.Saver(max_to_keep=5)  # 保存最新的5個檢查點

創建會話

配置會話

  在創建會話之前我們一般都要配置會話,比如使用GPU還是CPU,用多少GPU等等。

我們一般使用 tf.ConfigProto()配置Session運行參數&&GPU設備指定

config = tf.ConfigProto(allow_soft_placement=True, log_device_placement=True)
config.gpu_options.per_process_gpu_memory_fraction = 0.4  # 佔用40%顯存 sess = tf.Session(config=config)
# 或者
config = tf.ConfigProto()
config.allow_soft_placement = True
config.log_device_placement = True

with tf.Session(config=config) as sess:
# 或者
sess = tf.Session(config=config)

tf.ConfigProto(log_device_placement=True):記錄設備指派情況

  設置tf.ConfigProto()中參數log_device_placement = True,獲取 operations 和 Tensor 被指派到哪個設備(幾號CPU或幾號GPU)上運行,會在終端打印出各項操作是在哪個設備上運行的。

tf.ConfigProto(allow_soft_placement=True):自動選擇運行設備

  在TensorFlow中,通過命令 “with tf.device(‘/cpu:0’):“,允許手動設置操作運行的設備。如果手動設置的設備不存在或者不可用,就會導致tf程序等待或異常,為了防止這種情況,可以設置tf.ConfigProto()中參數allow_soft_placement=True,自動選擇一個存在並且可用的設備來運行操作。

config.gpu_options.allow_growth = True

當使用GPU時候,Tensorflow運行自動慢慢達到最大GPU的內存

tf.test.is_built_with_cuda():返回是否能夠使用GPU進行運算

  為了加快運行效率,TensorFlow在初始化時會嘗試分配所有可用的GPU顯存資源給自己,這在多人使用的服務器上工作就會導致GPU佔用,別人無法使用GPU工作的情況。這時我們需要限制GPU資源使用,詳細實現方法請參考我的另一篇博客 tensorflow常用函數 Ctrl+F搜索“限制GPU資源使用”

創建會話Session

  Session有兩種創建方式:

sess = tf.Session(config=config, graph=graph)
# 或通過with的方式創建Session
with tf.Session(config=config, graph=graph) as sess:

  如果我們之前自定義了graph,則在會話中也要配置graph,如果之前沒有自定義graph,使用的是tensorflow默認graph,則在會話不用自己去定義,tensorflow會自動找到默認圖。

  在訓練模型之前我們首先要設置一個高級一點的東西,那就是檢查是否有之前保存好的模型,如果有着接着前面的繼續訓練,如果沒有則從頭開始訓練模型。

恢復/重新訓練

  定義一個檢查模型是否存在的函數,為了美觀,可以把這個函數放在最上面,或者其他腳本中,通過import導入。

def load_model(sess, saver, checkpoint_dir):
    """加載模型,看看還能不能加一個功能,必須現在的檢查檢點是1000,但是我的train是100,要報錯
        還有就是讀取之前的模型繼續訓練的問題
        checkpoint_dir = checkpoint"""

    # 通過checkpoint找到模型文件名
    ckpt = tf.train.get_checkpoint_state(checkpoint_dir=checkpoint_dir)
    if ckpt and ckpt.model_checkpoint_path:
        ckpt_name = os.path.basename(ckpt.model_checkpoint_path)  # 返回最新的chechpoint文件名 model.ckpt-1000
        print("新的chechpoint文件名", ckpt_name)  # model.ckpt-2
        saver.restore(sess, os.path.join(checkpoint_dir, ckpt_name))
        # 現在不知道checkpoint文件名時怎樣的,因此不知道裏面如何運行
        counter = int(next(re.finditer("(\d+)(?!.*\d)", ckpt_name)).group(0))  # 2
        print(" [*] 成功模型 {}".format(ckpt_name))
        return True, counter
    else:
        print(" [*] 找不到checkpoint")
        return False, 0

View Code

  如果大家之前用的是global_step = tf.Variable(0, trainable=False),則使用下面diamante

# 加載模型,如果模型存在返回 是否加載成功和訓練步數
could_load, checkpoint_step = load_model(sess, saver, "./log")
if could_load:
    print(" [*] 加載成功")
else:
    print(" [!] 加載失敗")
    try:
        tf.global_variables_initializer().run()
    except:
        tf.initialize_all_variables().run()

  如果大家想使用step=0,step+=1,則可以使用下面代碼

# 加載模型,如果模型存在返回 是否加載成功和訓練步數
could_load, checkpoint_step = load_model(sess, saver, FLAGS.checkpoints_dir)
if could_load:
    step = checkpoint_step
    print(" [*] 模型加載成功")
else:
    print(" [!] 模型加載失敗")
    try:
        tf.global_variables_initializer().run()
    except:
        tf.initialize_all_variables().run()
    step = 0

開始訓練

for epoch in range(epochs):
    for i in range(batch_nums):
        start_time = time.time()
        # batch_images = data_X[i * batch_size:(i + 1) * batch_size]
        # batch_labels = data_y[i * batch_size:(i + 1) * batch_size]
        train_batch_x, train_batch_y = mnist.train.next_batch(batch_size)

        # 使用真實數據填充placeholder,運行訓練模型和合併變量操作
        _, summary, loss, step = sess.run([train_op, merged_summary_op, total_loss, global_step],
                                          feed_dict={inputs: train_batch_x,
                                                     labels: train_batch_y,
                                                     keep_prob: 0.5})
        if step % 100 == 0:
            summary_writer.add_summary(summary, step)  # 將每次迭代后的變量寫入事件文件
            summary_writer.flush()  # 強制summary_writer將緩存中的數據寫入到日誌文件中(可選)

            ############    可視化打印   ############
            print("Epoch:[%2d] [%4d/%4d] time:%4.4f,loss:%.8f" % (
                epoch, i, batch_nums, time.time() - start_time, loss))

        # 打印一些可視化的數據,損失...
        if step % 100 == 0:
            acc = sess.run(accuracy, feed_dict={inputs: mnist.validation.images,
                                                labels: mnist.validation.labels,
                                                keep_prob: 1.0})
            print("Epoch:[%2d] [%4d/%4d] accuracy:%.8f" % (epoch, i, batch_nums, acc))
            ############    保存模型   ############
            if acc > max_acc:
                max_acc = acc
                save_path = saver.save(sess,
                                       save_path=os.path.join(checkpoints_dir, "model.ckpt"),
                                       global_step=step)
                tf.logging.info("模型保存在: %s" % save_path)
print("優化完成!")

模型評估

eval.py

模型評估的代碼和模型訓練的代碼很像,只不過不需要對模型進行訓練而已。

from ops import *
import tensorflow as tf
from nets.my_alex import alexNet
from tensorflow.examples.tutorials.mnist import input_data

tf.flags.DEFINE_integer('batch_size', 50, 'batch size, default: 1')
tf.flags.DEFINE_integer('class_num', 10, 'batch size, default: 1')
tf.flags.DEFINE_integer('epochs', 10, 'batch size, default: 1')
tf.flags.DEFINE_string('checkpoints_dir', "checkpoints", '保存檢查點的地址')
FLAGS = tf.flags.FLAGS

# 從MNIST_data/中讀取MNIST數據。當數據不存在時,會自動執行下載
mnist = input_data.read_data_sets('./data', one_hot=True, reshape=False)

# 將數組張換成圖片形式
print(mnist.train.images.shape)  # 訓練數據圖片(55000, 28, 28, 1)
print(mnist.train.labels.shape)  # 訓練數據標籤(55000, 10)
print(mnist.test.images.shape)  # 測試數據圖片(10000, 28, 28, 1)
print(mnist.test.labels.shape)  # 測試數據圖片(10000, 10)
print(mnist.validation.images.shape)  # 驗證數據圖片(5000, 28, 28, 1)
print(mnist.validation.labels.shape)  # 驗證數據圖片(5000, 10)


def evaluate():
    batch_size = FLAGS.batch_size
    batch_nums = mnist.train.images.shape[0] // batch_size  # 一個epoch中應該包含多少batch數據
    class_num = FLAGS.class_num
    test_batch_size = 5000
    test_batch_num = mnist.test.images.shape[0] // test_batch_size

    ############    保存檢查點的地址   ############
    checkpoints_dir = FLAGS.checkpoints_dir  # checkpoints
    # 如果檢查點不存在,則創建
    if not os.path.exists(checkpoints_dir):
        print("模型文件不存在,無法進行評估")

    ######################################################
    #                    創建圖                          #
    ######################################################
    graph = tf.Graph()  # 自定義圖
    # 在自己的圖中定義數據和操作
    with graph.as_default():
        inputs = tf.placeholder(dtype="float", shape=[None, 28, 28, 1], name='inputs')
        labels = tf.placeholder(dtype="float", shape=[None, class_num], name='labels')
        ############    搭建模型   ############
        logits = alexNet(inputs, FLAGS.class_num, keep_prob=1)  # 使用placeholder搭建模型
        ############    模型精度   ############
        predict = tf.argmax(logits, 1)
        accuracy = tf.reduce_mean(tf.cast(tf.equal(predict, tf.argmax(labels, 1)), tf.float32))
        ############    模型保存和恢復 Saver   ############
        saver = tf.train.Saver(max_to_keep=5)

    ######################################################
    #                   創建會話                          #
    ######################################################
    config = tf.ConfigProto(allow_soft_placement=True, log_device_placement=True)
    with tf.Session(config=config, graph=graph) as sess:
        # 加載模型,如果模型存在返回 是否加載成功和訓練步數
        could_load, checkpoint_step = load_model(sess, saver, FLAGS.checkpoints_dir)
        if could_load:
            print(" [*] 加載成功")
        else:
            print(" [!] 加載失敗")
            raise ValueError("模型文件不存在,無法進行評估")

        for i in range(test_batch_num):
            test_batch_x, test_batch_y = mnist.test.next_batch(test_batch_num)
            acc = sess.run(accuracy, feed_dict={inputs: test_batch_x,
                                                labels: test_batch_y})
            print("模型精度為:", acc)
        one_image = mnist.test.images[1].reshape(1, 28, 28, 1)
        predict_label = sess.run(predict, feed_dict={inputs: one_image})
        # print("123", tf.argmax(pre_yyy, 1).eval())  # [7]
        # print("123", tf.argmax(yyy, 1).eval())  # 7


def main(argv=None):
    evaluate()


if __name__ == '__main__':
    tf.app.run()

 

參考文獻

CSDN_AlexNet神經網絡結構

CSDN_【深度學習理論3】ALexNet模型的詳解

github搜索tensorflow AlexNet

github_finetune_alexnet_with_tensorflow

github_AlexNet_with_tensorflow

github tensorflow vgg

ResNet詳解與分析

tensorflow中使用tf.ConfigProto()配置Session運行參數&&GPU設備指定

比較完整且容易入門的MNIST案例

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

※台中搬家遵守搬運三大原則,讓您的家具不再被破壞!

台中搬家公司推薦超過30年經驗,首選台中大展搬家