【TensorFlow實戰筆記】卷積神經網絡CNN實戰-cifar10數據集(tensorboard可視化)

IDE:pycharm
Python: Python3.6
OS: win10
tf : CPU版本

代碼可在github中下載,歡迎star,謝謝 CNN-CIFAR-10

一、CIFAR10數據集

數據集代碼下載

from tensorflow.models.tutorials.image.cifar10 import cifar10

cifar10.maybe_download_and_extract()

直接下載數據集的路徑爲

./tmp/cifar10_data

如果下載不了就直接 官網下載CIFAR-10數據集
下載 CIFAR-10 binary version
放到相應的path,到時候對應即可
官網和網上都有很詳細的這個數據集的講解,基本就是因爲是-10所以最後的分類有10類,一種有60000 張32x32三色圖片,每種6000張, 50000張train set,10000張test set,還有另外一個孿生數據集CIFAR-100
這裏寫圖片描述

二、卷積神經網絡

卷積神經一般結構:
卷積層+池化層(最大)+全連接層
卷積層和池化層就是最神奇的地方,相當於自動選取特徵的過程,也就是提取特徵的過程, 全連接層就是輸出相應的label,也就是分類的過程。

全連接層又稱爲多層感知機

這裏寫圖片描述
顧名思義就是全連接層的節點與前後層的節點全都有連接。

卷積層和池化層

這裏面有一個概念需要知道那就是kernel,有的書裏叫做filter
個人覺得filter的概念更容易understand一些
這裏寫圖片描述
如圖所示

  • 經過卷積層之後整塊矩陣節點會變得更深,也就是更加深入的分析,從而得到抽象程度更高的特徵
  • 經過池化層之後矩陣節點的深度沒有發生改變,而大小發生改變,可以看成將圖片的分辨率變低,主要目的也是讓最後與全連接層連接的節點數目變少,從而weights和bias大大減小,加快訓練速度

filter過濾器(kernel內核)

這裏寫圖片描述
這裏假設 矩陣大小是 1281283
現在的fliter的大小 爲55(or 33)

  • filter中的參數是共享的,這也是使整理的參數減少的策略之一
  • 人工除了指定filter的尺寸之外還有就是想得到的新的矩陣的深度
#  5*5大小的fliter 3爲前一個矩陣的深度, 16是後一個矩陣的深度
weight = tf.get_variable('weight', shape=[5, 5, 3, 16], initializer=tf.truncated_normal_initializer(stddev=0.1))
#biases的shape就是後一個矩陣的深度
biases = tf.get_variable('biases', [16], initializer=tf.constant_initializer(0.1))

如果是kernel的話就是5*5爲kernel的大小, 3爲input的深度, 16爲kernel的個數
大概的寫代碼的規律就是這樣,還有一個知識點就是stride步長和padding是否補全,這些都是基礎,詳情參照《Tensorflow實戰Google深度學習框架》寫的很詳細

三、可視化工具 tensorboard

安裝tensorflow的時候自動就安裝了tensorboard
可視化工具

  • Image: 圖像
  • Audio: 音頻
  • Histogram: 直方圖
  • Scalar: 標量
  • Graph:計算圖
    這裏面主要使用 後三個
    基本使用方法見代碼:
 tf.summary.scalar(name, var) #添加scalar量來繪製var
 tf.summary.histogram(name, var)# 添加histogram來繪製var
 #合併全部的summary
 merged = tf.summary.merge_all()
 #寫入日誌文件和計算圖(如果看總體的計算圖的話推薦多使用tf.name_scope()劃分結構)
 train_writer = tf.summary.FileWriter(LOG_DIR, sess.graph)
 summary, _, loss_value = sess.run([merged, train_op, loss], feed_dict={image_holder: image_batch, label_holder: label_batch})
  #每步進行記錄
 train_writer.add_summary(summary, step)

之後再命令臺,cd到本項目文件夾
執行

tensorboard --logdir=./LOG

默認 6006 port
這裏寫圖片描述
記住這裏一定要用Chrome瀏覽器進行瀏覽就是圖中生成的https網站,其他瀏覽器可能會不好用。

四、總體代碼

  1. 使用cifar10數據集
  2. 使用cnn網絡
  3. tensorboard可視化
    tool.py
"""
@Author:Che_Hongshu
@Function: tools for CNN-CIFAR-10 dataset
@Modify:2018.3.5
@IDE: pycharm
@python :3.6
@os : win10
"""

import tensorflow as tf
"""
函數說明: 得到weights變量和weights的loss
Parameters:
   shape-維度
   stddev-方差
   w1-
Returns:
    var-維度爲shape,方差爲stddev變量
CSDN:
    http://blog.csdn.net/qq_33431368
Modify:
    2018-3-5
"""
def variable_with_weight_loss(shape, stddev, w1):
    var = tf.Variable(tf.truncated_normal(shape, stddev=stddev))
    if w1 is not None:
        weight_loss = tf.multiply(tf.nn.l2_loss(var), w1, name='weight_loss')
        tf.add_to_collection('losses', weight_loss)
    return var
"""
函數說明: 得到總體的losses
Parameters:
   logits-通過神經網絡之後的前向傳播的結果
   labels-圖片的標籤
Returns:
   losses
CSDN:
    http://blog.csdn.net/qq_33431368
Modify:
    2018-3-5
"""
def loss(logits, labels):
    labels = tf.cast(labels, tf.int64)
    cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits\
        (logits=logits, labels=labels, name='total_loss')
    cross_entropy_mean = tf.reduce_mean(cross_entropy, name='cross_entorpy')
    tf.add_to_collection('losses', cross_entropy_mean)
    return tf.add_n(tf.get_collection('losses'), name='total_loss')

"""
函數說明: 對變量進行min max 和 stddev的tensorboard顯示
Parameters:
    var-變量
    name-名字
Returns:
    None
CSDN:
    http://blog.csdn.net/qq_33431368
Modify:
    2018-3-5
"""
def variables_summaries(var, name):
    with tf.name_scope('summaries'):
        mean = tf.reduce_mean(var)
        tf.summary.scalar('mean/'+name, mean)
        with tf.name_scope('stddev'):
            stddev = tf.sqrt(tf.reduce_sum(tf.square(var-mean)))
        tf.summary.scalar('stddev/' + name, stddev)
        tf.summary.scalar('max/' + name, tf.reduce_max(var))
        tf.summary.scalar('min/' + name, tf.reduce_min(var))
        tf.summary.histogram(name, var)
        tf.summary.histogram()

CNN:

"""
@Author:Che_Hongshu
@Function: CNN-CIFAR-10 dataset
@Modify:2018.3.5
@IDE: pycharm
@python :3.6
@os : win10
"""
from tensorflow.models.tutorials.image.cifar10 import cifar10
from tensorflow.models.tutorials.image.cifar10 import cifar10_input

import tensorflow as tf
import numpy as np
import time
import tools
max_steps = 3000 # 訓練輪數
batch_size = 128  #一個bacth的大小
data_dir = './cifar-10-batches-bin' #讀取數據文件夾
LOG_DIR = './LOG'

#下載CIFAR數據集 如果不好用直接
# http://www.cs.toronto.edu/~kriz/cifar.html 下載CIFAR-10 binary version 文件解壓放到相應的文件夾中
#cifar10.maybe_download_and_extract()
#得到訓練集的images和labels
#print(images_train) 可知是一個shape= [128, 24, 24, 3]的tensor
images_train, labels_train = cifar10_input.\
    distorted_inputs(data_dir=data_dir, batch_size=batch_size)
#得到測試集的images和labels
images_test, labels_test = cifar10_input.\
    inputs(eval_data=True, data_dir=data_dir, batch_size=batch_size)
#以上兩個爲什麼分別用distorted_inputs and inputs  請go to definition查詢
#創建輸入數據的placeholder
with tf.name_scope('input_holder'):
    image_holder = tf.placeholder(tf.float32, [batch_size, 24, 24, 3])
    label_holder = tf.placeholder(tf.int32, [batch_size])
#下面的卷積層的 weights的l2正則化不計算, 一般只在全連接層計算正則化loss
#第一個conv層
#5*5的卷積核大小,3個channel ,64個卷積核, weight的標準差爲0.05
with tf.name_scope('conv1'):
    #加上更多的name_scope 使graph更加清晰好看,代碼也更加清晰
    with tf.name_scope('weight1'): #權重
        weight1 = tools.variable_with_weight_loss(shape=[5, 5, 3, 64], stddev=5e-2, w1=0.0)
        #運用tensorboard進行顯示
        tools.variables_summaries(weight1, 'conv1/weight1')
    kernel1 = tf.nn.conv2d(image_holder, weight1, strides=[1, 1, 1, 1], padding='SAME')
    with tf.name_scope('bias1'): #偏置
        bias1 = tf.Variable(tf.constant(0.0, shape=[64]))
        tools.variables_summaries(bias1, 'conv1/bias1')
    with tf.name_scope('forward1'): #經過這個神經網絡的前向傳播的算法結果
        conv1 = tf.nn.relu(tf.nn.bias_add(kernel1, bias1))#cnn加上bias需要調用bias_add不能直接+
#第一個最大池化層和LRN層
with tf.name_scope('pool_norm1'):
    with tf.name_scope('pool1'):
        # ksize和stride不同 , 多樣性
        pool1 = tf.nn.max_pool(conv1, ksize=[1, 2, 2, 1], strides=[1, 3, 3, 1], padding='SAME')
    with tf.name_scope('LRN1'):
        #LRN層可以使模型更加
        norm1 = tf.nn.lrn(pool1, 4, bias=1.0, alpha=0.001/9.0, beta=0.75)

#第二層conv層 input: 64   size = 5*5   64個卷積核
with tf.name_scope('conv2'):
    with tf.name_scope('weight2'):
        weight2 = tools.variable_with_weight_loss(shape=[5, 5, 64, 64], stddev=5e-2, w1=0.0)
        tools.variables_summaries(weight2, 'conv2/weight2')
    kernel2 = tf.nn.conv2d(norm1, weight2, strides=[1, 1, 1, 1], padding='SAME')
    with tf.name_scope('bias2'):
        bias2 = tf.Variable(tf.constant(0.1, shape=[64]))
        tools.variables_summaries(bias2, 'conv2/bias2')
    with tf.name_scope('forward2'):
        conv2 = tf.nn.relu(tf.nn.bias_add(kernel2, bias2))

#第二個LRN層和最大池化層
with tf.name_scope('norm_pool2'):
    with tf.name_scope('LRN2'):
        norm2 = tf.nn.lrn(conv2, 4, bias=1.0, alpha=0.001/9.0, beta=0.75)
    with tf.name_scope('pool2'):
        pool2 = tf.nn.max_pool(norm2, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding='SAME')
# 全連接網絡
with tf.name_scope('fnn1'):
    reshape = tf.reshape(pool2, [batch_size, -1])
    dim = reshape.get_shape()[1].value
    with tf.name_scope('weight3'):
        weight3 = tools.variable_with_weight_loss(shape=[dim, 384], stddev=0.04, w1=0.004)
        tools.variables_summaries(weight3, 'fnn1/weight3')
    with tf.name_scope('bias3'):
        bias3 = tf.Variable(tf.constant(0.1, shape=[384]))
        tools.variables_summaries(bias3, 'fnn1/bias3')
    local3 = tf.nn.relu(tf.matmul(reshape, weight3) + bias3)

with tf.name_scope('fnn2'):
    with tf.name_scope('weight4'):
        weight4 = tools.variable_with_weight_loss(shape=[384, 192], stddev=0.04, w1=0.004)
    with tf.name_scope('bias4'):
        bias4 = tf.Variable(tf.constant(0.1, shape=[192]))
    local4 = tf.nn.relu(tf.matmul(local3, weight4) + bias4)
with tf.name_scope('inference'):
    with tf.name_scope('weight5'):
        weight5 = tools.variable_with_weight_loss(shape=[192, 10], stddev=1/192.0, w1=0.0)
    with tf.name_scope('bias5'):
        bias5 = tf.Variable(tf.constant(0.0, shape=[10]))
    logits = tf.add(tf.matmul(local4, weight5), bias5)


with tf.name_scope('loss_func'):
    #求出全部的loss
    loss = tools.loss(logits, label_holder)
    tf.summary.scalar('loss', loss)

with tf.name_scope('train_step'):
	step = tf.train.get_or_create_global_step()
    #調用優化方法Adam,這裏學習率是直接設定的自行可以decay嘗試一下
    train_op = tf.train.AdamOptimizer(1e-3).minimize(loss, global_step=step)
    top_k_op = tf.nn.in_top_k(logits, label_holder, 1)

#創建會話
sess = tf.InteractiveSession()
#變量初始化
tf.global_variables_initializer().run()
#合併全部的summary
merged = tf.summary.merge_all()
#將日誌文件寫入LOG_DIR中
train_writer = tf.summary.FileWriter(LOG_DIR, sess.graph)
#因爲數據集讀取需要打開線程,這裏打開線程
tf.train.start_queue_runners()
#開始迭代訓練
for step in range(max_steps):
    start_time = time.time()
    image_batch, label_batch = sess.run([images_train, labels_train])
    summary, _, loss_value = sess.run([merged, train_op, loss], feed_dict={image_holder: image_batch, label_holder: label_batch})
    #每步進行記錄
    train_writer.add_summary(summary, step)
    duration = time.time() - start_time
    if step % 10 == 0:
        examples_per_sec = batch_size / duration
        #訓練一個batch的time
        sec_per_batch = float(duration)
        format_str = ('step %d, loss=%.2f (%.1f examples/sec; %.3f sec/batch)')
        print(format_str % (step, loss_value, examples_per_sec, sec_per_batch))

num_examples = 10000
import math
num_iter = int(math.ceil(num_examples/batch_size))
true_count = 0
total_sample_count = num_iter * batch_size
step = 0
while step < num_iter:
    image_batch, label_batch = sess.run([images_test, labels_test])
    predictions = sess.run([top_k_op], feed_dict={image_holder: image_batch, label_holder: label_batch})
    true_count += np.sum(predictions)
    step += 1
precision = true_count/total_sample_count

print('precision = %.3f' % precision)

五、結果分析

大概經過20分鐘左右吧,關鍵還得看你的電腦和你的tf的版本我的是CPU版本比較慢,建議用linux的GPU版本。

1.程序結果

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-nQ7S5fcB-1571489621323)(https://img-blog.csdn.net/20180305234129693?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzM0MzEzNjg=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)]
測試集之後的acc比較低,因爲我們沒有其他的trick,比如learning decay之類的。

2. tensorboard的可視化

這裏寫圖片描述
輸入之後打開Chrome瀏覽器進入tensorboard
這裏寫圖片描述
上面爲各個指標的顯示形式的選擇,右下方爲conv1的參數變化

CONV2:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-FYA9oTZR-1571489621324)(https://img-blog.csdn.net/201803052348062?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzM0MzEzNjg=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)]

FNN1:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-TNip5chG-1571489621324)(https://img-blog.csdn.net/20180305235021181?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzM0MzEzNjg=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)]

loss:(一般分析主要看loss loss減小的越小越好)

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-gl7r7vax-1571489621325)(https://img-blog.csdn.net/20180305235122324?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzM0MzEzNjg=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)]

IMAGES:

這裏寫圖片描述

HISTOGRAMS

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-xoe1olLL-1571489621325)(https://img-blog.csdn.net/20180305235339122?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzM0MzEzNjg=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)]
其他的自行觀看即可這裏不再過多介紹

計算圖的框圖:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-kjvDKY6H-1571489621325)(https://img-blog.csdn.net/20180305235458265?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzM0MzEzNjg=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)]
講道理不知道爲啥這麼醜。。。
之後每個帶+號的都可以展開
比如

conv2:

這裏寫圖片描述

over。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章