国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

使用TensorFlow和TensorBoard從零開始構建卷積神經網絡

ninefive / 1473人閱讀

摘要:在本教程中,我會介紹如何只使用低級別的工具從零開始構建卷積神經網絡,以及使用可視化我們的計算圖和網絡的表現。選擇模型接下來,我必須決定使用哪個卷積神經網絡的模型。實質上,大多數卷積神經網絡都包含卷積和池化。

如果使用TensorFlow的所有較高級別的工具,例如tf.contrib.learn和Keras,你可以輕松地使用非常少量的代碼來構建卷積神經網絡。但是經常使用這些較高級別的應用,你就沒法看到它們內部的代碼,從而缺失了對這些應用背后所發生的事情的理解。

在本教程中,我會介紹如何只使用低級別的TensorFlow工具從零開始構建卷積神經網絡,以及使用TensorBoard可視化我們的計算圖和網絡的表現。如果你還不了解全連接神經網絡的一些基礎知識,我強烈建議你首先查看這篇《這不是另外一個使用TensorFlow來做MNIST數字圖像識別的教程》。在本文中我也會把卷積神經網絡的每個步驟分解到基礎的程度,以便你可以完全了解計算圖中的每個步驟。通過從零開始構建該模型,你可以輕松地將計算圖的各方面可視化,以便可以看到每層卷積并使用它們做出你自己的推斷。我會只強調主要代碼,如果想查看全部代碼,你可以在GitHub上找到相應的Jupyter Notebook文件。

獲得一個數據集

一開始我需要決定要使用哪個圖像數據集。我決定用牛津大學視覺幾何團隊的寵物數據集。我之所以選擇這個數據集,是因為它很簡單且有很好的標注,同時訓練數據也足夠多,而且還有對象邊界區域標注——如果我以后想訓練一個對象檢測模型就可以使用該信息。另一個我認為對于構造第一個模型非常好的數據集是在Kaggle上發現的辛普森數據集,其中有很多可用于訓練的簡單數據。

選擇模型

接下來,我必須決定使用哪個卷積神經網絡的模型。非常流行的一些模型包括GoogLeNet或VGG16,它們都具有多個卷積層可用于檢測具有1000多個類別的ImageNet數據集。不過我要使用一個更簡單的四層卷積網絡:

圖1 圖片由Justin Francis友情提供

我們分解一下這個模型。它從一張224x224x3的圖像開始,在三個通道上通過卷積得到32個特征圖。我們將這組32個特征圖一起卷積得到另外32個特征。 然后將其池化得到112x112x32的圖像,隨后兩次卷積得到64個特征,最后池化到56x56x64。然后將這個最終池化的層的每個單元全連接到512個神經元上,并基于類別的數量最后連接到softmax層。

處理和構建數據集

首先我們開始加載依賴項,其中包括一組我所編寫的imFunctions函數,它可以幫助來處理圖像數據。

import imFunctions as imf

import tensorflow as tf

import scipy.ndimage

from scipy.misc import imsave

import matplotlib.pyplot as plt

import numpy as np

然后,我們可以使用imFunctions下載和提取圖像。

imf.downloadImages(‘annotations.tar.gz’, 19173078)

imf.downloadImages(‘images.tar.gz’, 791918971)

imf.maybeExtract(‘annotations.tar.gz’)

imf.maybeExtract(‘images.tar.gz’)

我們可以將圖像分到不同的文件夾,包括訓練和測試文件夾。 sortImages函數中的參數數值表示測試數據跟訓練數據的百分比。

imf.sortImages(0.15)

接著使用一個相應的one hot向量將我們的數據集構建成一個numpy數組以表示我們的類別。它還也會從所有的訓練和測試圖像中減去圖像的平均值,這是在構建卷積網絡時的標準化動作。該函數會詢問你要包括哪些類別——由于我有限的GPU 內存(3GB),我選擇了一個非常小的數據集,試圖區分兩種狗:柴犬和薩摩耶犬。

train_x, train_y, test_x, test_y, classes, classLabels = imf.buildDataset()

卷積和池化是如何工作的

現在我們有了一個可用的數據集,不過讓我們先停一下,看看卷積的最底層是如何工作的。在跳到彩色卷積濾波器之前,讓我們來看一張灰度圖以確保能弄明白每個細節。讓我們編寫一個7×7的濾波器可用于四個不同的特征圖。TensorFlow的conv2d函數相當簡單,它有四個變量:輸入、濾波器、步幅、填充方式。在TensorFlow網站上是這么描述conv2d函數的:

對于給定的4維輸入和濾波器張量計算一個2維卷積。

輸入是一個維度為[batch,in_height,in_width,in_channels]的一個張量,濾波器/核張量的維度是[filter_height,filter_width,in_channels,out_channels]。

因為我們正在處理灰度圖像,所以in_channels是1,而我們應用了四個濾波器,所以out_channels將會是4。我們將圖2里所示的四個濾波器/核應用到一張圖像或每批批次一張。

圖2 圖像由Justin Francis友情提供

讓我們來看下這個過濾器是如何影響我們輸入的灰度圖像的。

gray = np.mean(image,-1)

X = tf.placeholder(tf.float32, shape=(None, 224, 224, 1))

conv = tf.nn.conv2d(X, filters, [1,1,1,1], padding=”SAME”)

test = tf.Session()

test.run(tf.global_variables_initializer())

filteredImage = test.run(conv, feed_dict={X: gray.reshape(1,224,224,1)})

tf.reset_default_graph()

這會返回一個4維(1, 224, 224, 4)的張量,我們可以用來可視化這四個濾波器:

圖3 圖像由Justin Francis友情提供

很明顯可以看到濾波器內核的卷積是非常強大的。將其分解,我們的7×7內核每次以1的步幅覆蓋49個圖像像素,將每個像素的值乘以每個內核值,然后將所有49個值加在一起以構成一個像素。如果你對圖像濾波器內核的思想仍然覺得沒有感覺,我強烈推薦這個網站——他們在內核可視化方面做得非常出色。

實質上,大多數卷積神經網絡都包含卷積和池化。最常見的是,一個用于卷積的3×3內核濾波器。特別是,以2×2的步幅和2×2內核的較大值池化是基于內核中的較大像素值來縮小圖像的一種激進方式。下圖展示的是一個內核為2X2和兩維上步幅都為2的簡單例子。

圖4 圖片由Justin Francis友情提供

對于conv2d和較大值池化,它們都有兩個填充選項:“VALID”會縮小輸入圖像;“SAME”會通過在輸入圖像邊緣周圍添加零來保持輸入圖像大小。下圖是一個內核為3×3步幅為1×1的最值大池化的示例,展示了不同的填充選項的結果:

圖5 圖像由Justin Francis友情提供

構建卷積神經網

我們已經介紹了基本知識,現在讓我們開始構建我們的卷積神經網絡模型。我們可以從占位符開始。 X是我們的輸入符,我們將把圖像輸入到X中,Y_是一組圖像的真實類別。

X = tf.placeholder(tf.float32, shape=(None, 224, 224, 3))

Y_ = tf.placeholder(tf.float32, [None, classes])

keepRate1 = tf.placeholder(tf.float32)

keepRate2 = tf.placeholder(tf.float32)

我們將在一個命名空間內創建每個過程的所有部分。命名空間對以后在TensorBoard中可視化計算圖是非常有用的,因為它們將所有東西都打包成一個可擴展的對象。我們創建了第一組內核大小為3×3的濾波器,需要三個通道分別輸出32個濾波器。這意味著32個濾波器中的每一個R、G和B通道都會有3×3的內核權重。非常重要的是我們濾波器的權重值是使用截斷正太分布來初始化的,所以會有多個隨機濾波器使TensorFlow能適用于我們的模型。

# CONVOLUTION 1 – 1

with tf.name_scope(‘conv1_1′):

filter1_1 = tf.Variable(tf.truncated_normal([3, 3, 3, 32], dtype=tf.float32, stddev=1e-1), name=’weights1_1′)

stride = [1,1,1,1]

conv = tf.nn.conv2d(X, filter1_1, stride, padding=’SAME’)

biases = tf.Variable(tf.constant(0.0, shape=[32], dtype=tf.float32), trainable=True, name=’biases1_1′)

out = tf.nn.bias_add(conv, biases)

conv1_1 = tf.nn.relu(out)

在第一層卷積的最后,conv1_1使用了relu函數,它是將每個負數賦值為零的閾。然后我們將這32個特征跟另外的32個特征做卷積。你可以看到conv2d的輸入是第一個卷積層的輸出。

# CONVOLUTION 1 – 2

with tf.name_scope(‘conv1_2′):

filter1_2 = tf.Variable(tf.truncated_normal([3, 3, 32, 32], dtype=tf.float32,

stddev=1e-1), name=’weights1_2′)

conv = tf.nn.conv2d(conv1_1, filter1_2, [1,1,1,1], padding=’SAME’)

biases = tf.Variable(tf.constant(0.0, shape=[32], dtype=tf.float32),

trainable=True, name=’biases1_2′)

out = tf.nn.bias_add(conv, biases)

conv1_2 = tf.nn.relu(out)

然后進行池化將圖像縮小一半。

# POOL 1

with tf.name_scope(‘pool1′):

pool1_1 = tf.nn.max_pool(conv1_2,

ksize=[1, 2, 2, 1],

strides=[1, 2, 2, 1],

padding=’SAME’,

name=’pool1_1′)

pool1_1_drop = tf.nn.dropout(pool1_1, keepRate1)

最后一部分涉及到在池化層上使用dropout(我們將在后面更詳細地介紹)。然后緊接著是使用64個特征的兩個卷積和另一個池化。請注意第一個卷積必須將先前的32個特征通道轉換為64。

# CONVOLUTION 2 – 1

with tf.name_scope(‘conv2_1′):

filter2_1 = tf.Variable(tf.truncated_normal([3, 3, 32, 64], dtype=tf.float32,

stddev=1e-1), name=’weights2_1′)

conv = tf.nn.conv2d(pool1_1_drop, filter2_1, [1, 1, 1, 1], padding=’SAME’)

biases = tf.Variable(tf.constant(0.0, shape=[64], dtype=tf.float32),

trainable=True, name=’biases2_1′)

out = tf.nn.bias_add(conv, biases)

conv2_1 = tf.nn.relu(out)

# CONVOLUTION 2 – 2

with tf.name_scope(‘conv2_2′):

filter2_2 = tf.Variable(tf.truncated_normal([3, 3, 64, 64], dtype=tf.float32,

stddev=1e-1), name=’weights2_2′)

conv = tf.nn.conv2d(conv2_1, filter2_2, [1, 1, 1, 1], padding=’SAME’)

biases = tf.Variable(tf.constant(0.0, shape=[64], dtype=tf.float32),

trainable=True, name=’biases2_2′)

out = tf.nn.bias_add(conv, biases)

conv2_2 = tf.nn.relu(out)

# POOL 2

with tf.name_scope(‘pool2′):

pool2_1 = tf.nn.max_pool(conv2_2,

ksize=[1, 2, 2, 1],

strides=[1, 2, 2, 1],

padding=’SAME’,

name=’pool2_1′)

pool2_1_drop = tf.nn.dropout(pool2_1, keepRate1)

接下來我們創建一個含有512個神經元全連接的網絡層,它將與我們的大小為56x56x64的pool2_1層的每個像素建立一個權重連接。這會有超過1億個不同的權重值!為了計算全連接的網絡,我們必須將輸入展開到一維,然后就可以乘以權重并加上偏置項。

#FULLY CONNECTED 1

with tf.name_scope(‘fc1′) as scope:

shape = int(np.prod(pool2_1_drop.get_shape()[1:]))

fc1w = tf.Variable(tf.truncated_normal([shape, 512], dtype=tf.float32,

stddev=1e-1), name=’weights3_1′)

fc1b = tf.Variable(tf.constant(1.0, shape=[512], dtype=tf.float32),

trainable=True, name=’biases3_1’)

pool2_flat = tf.reshape(pool2_1_drop, [-1, shape])

out = tf.nn.bias_add(tf.matmul(pool2_flat, fc1w), fc1b)

fc1 = tf.nn.relu(out)

fc1_drop = tf.nn.dropout(fc1, keepRate2)

然后是softmax及其相關的權重和偏置,最后是我們的輸出Y.

#FULLY CONNECTED 3 & SOFTMAX OUTPUT

with tf.name_scope(‘softmax’) as scope:

fc2w = tf.Variable(tf.truncated_normal([512, classes], dtype=tf.float32,

stddev=1e-1), name=’weights3_2′)

fc2b = tf.Variable(tf.constant(1.0, shape=[classes], dtype=tf.float32),

trainable=True, name=’biases3_2′)

Ylogits = tf.nn.bias_add(tf.matmul(fc1_drop, fc2w), fc2b)

Y = tf.nn.softmax(Ylogits)

創建損失函數和優化器

現在可以開始訓練我們的模型。首先必須決定批量大小,我不能使用批量大小超過10以防止耗盡GPU內存。然后必須確定周期的數量,它是指算法循環遍歷所有分批的訓練數據的次數,最后是我們的學習速率α。

numEpochs = 400

batchSize = 10

alpha = 1e-5

然后我們為交叉熵、精度檢查器和反向傳播優化器指定范圍。

with tf.name_scope(‘cross_entropy’):

cross_entropy = tf.nn.softmax_cross_entropy_with_logits(logits=Ylogits, labels=Y_)

loss = tf.reduce_mean(cross_entropy)

with tf.name_scope(‘accuracy’):

correct_prediction = tf.equal(tf.argmax(Y, 1), tf.argmax(Y_, 1))

accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

with tf.name_scope(‘train’):

train_step = tf.train.AdamOptimizer(learning_rate=alpha).minimize(loss)

接著就可以創建我們的會話和初始化我們所有的變量。

sess = tf.Session()

init = tf.global_variables_initializer()

sess.run(init)

創建TensorBoard用的匯總

現在我們要使用TensorBoard,以便可以看到分類器工作的表現怎么樣。我們將創建兩個圖:一個用于我們的訓練集,一個用于我們的測試集。我們可以通過使用add_graph函數來可視化我們的計算圖。我們將使用匯總標量來衡量我們的總體損失和準確性,并將我們的匯總合并到一起以便只需調用write_op來記錄標量。

writer_1 = tf.summary.FileWriter(“/tmp/cnn/train”)

writer_2 = tf.summary.FileWriter(“/tmp/cnn/test”)

writer_1.add_graph(sess.graph)

tf.summary.Scalar(‘Loss’, loss)

tf.summary.scalar(‘Accuracy’, accuracy)

tf.summary.histogram(“weights1_1”, filter1_1)

write_op = tf.summary.merge_all()

訓練模型

現在我們可以開始編寫進行評估和訓練的代碼。我們不希望每步的損失和準確性都使用匯總記錄器來記錄,因為這會大大減慢分類器的訓練速度。因此我們會每五步記錄一次。

steps = int(train_x.shape[0]/batchSize)

for i in range(numEpochs):

accHist = []

accHist2 = []

train_x, train_y = imf.shuffle(train_x, train_y)

for ii in range(steps):

#Calculate our current step

step = i * steps + ii

#Feed forward batch of train images into graph and log accuracy

acc = sess.run([accuracy], feed_dict={X: train_x[(ii*batchSize):((ii+1)*batchSize),:,:,:], Y_: train_y[(ii*batchSize):((ii+1)*batchSize)], keepRate1: 1, keepRate2: 1})

accHist.append(acc)

if step % 5 == 0:

# Get Train Summary for one batch and add summary to TensorBoard

summary = sess.run(write_op, feed_dict={X: train_x[(ii*batchSize):((ii+1)*batchSize),:,:,:], Y_: train_y[(ii*batchSize):((ii+1)*batchSize)], keepRate1: 1, keepRate2: 1})

writer_1.add_summary(summary, step)

writer_1.flush()

# Get Test Summary on random 10 test images and add summary to TensorBoard

test_x, test_y = imf.shuffle(test_x, test_y)

summary = sess.run(write_op, feed_dict={X: test_x[0:10,:,:,:], Y_: test_y[0:10], keepRate1: 1, keepRate2: 1})

writer_2.add_summary(summary, step)

writer_2.flush()

#Back propigate using adam optimizer to update weights and biases.

sess.run(train_step, feed_dict={X: train_x[(ii*batchSize):((ii+1)*batchSize),:,:,:], Y_: train_y[(ii*batchSize):((ii+1)*batchSize)], keepRate1: 0.2, keepRate2: 0.5})

print(‘Epoch number {} Training Accuracy: {}’.format(i+1, np.mean(accHist)))

#Feed forward all test images into graph and log accuracy

for iii in range(int(test_x.shape[0]/batchSize)):

acc = sess.run(accuracy, feed_dict={X: test_x[(iii*batchSize):((iii+1)*batchSize),:,:,:], Y_: test_y[(iii*batchSize):((iii+1)*batchSize)], keepRate1: 1, keepRate2: 1})

accHist2.append(acc)

print(“Test Set Accuracy: {}”.format(np.mean(accHist2)))

可視化計算圖

在訓練過程中,讓我們通過在終端中激活TensorBoard來檢查運行情況。

tensorboard –logdir=”/tmp/cnn/”

可以將Web瀏覽器指向默認的TensorBoard地址http://0.0.0.0/6006。讓我們先來看看我們的計算圖模型。

正如你所看到的,通過使用命名空間屬性我們可以直觀地看到計算圖模型的一個相當簡潔的版本。

圖6 圖片由Justin Francis友情提供

性能表現評估

讓我們看看準確性和損失標量隨時間變化的情況。

圖7 圖片由Justin Francis友情提供

你可能會看到這里出了一個很大的問題。對于訓練數據,分類器達到了100%的準確度和0%的誤差損失,但是測試數據的準確度最多只能達到80%而且還有很大的損失。這就是一個明顯的過擬合——一些典型的原因包括沒有足夠的訓練數據或神經元數量太多。

我們可以通過調整圖片大小、對它們進行縮放和旋轉來創建更多的訓練數據,但更簡單的方法是將dropout添加到池化層和全連接層的輸出中。這會在每次訓練中隨機切割或丟棄一個圖層中的部分神經元。這將迫使我們的分類器一次只訓練一部分神經元,而不是所有神經元。這允許神經元專注于特定的任務,而不是所有神經元一起關注。丟棄80%的卷積層和50%全連接層的神經元會產生驚人的效果。

圖8 圖片由Justin Francis友情提供

僅僅通過丟棄神經元,測試數據的準確度就幾乎能達到90%——性能幾乎提高了10%!但代價是分類器花了大約6倍的時間才完成訓練。

可視化不斷進化的濾波器

為了增加樂趣,我讓一個過濾器每訓練50個步就產生一張圖片,并制作了一個隨濾波器權重進化的gif圖像。這帶來了非常酷的效果,并能很好地幫助理解卷積網絡的是如何工作的。以下是來自conv1_2的兩個濾波器:

圖9 圖片由Justin Francis友情提供

你可以看到最初的權重初始化顯示了圖像的大部分,但隨著時間推移權重不斷更新,它們變得更加專注于檢測某些邊緣。令我驚訝的是,我發現第一個卷積核心filter1_1幾乎沒有改變。似乎初始權重本身已經足夠好了。繼續深入到網絡層conv2_2,你可以看到它開始檢測更抽象的廣義特征。

圖10 圖片由Justin Francis友情提供

總而言之,使用了不到400個訓練圖像訓練了一個幾乎可以達到90%準確率的模型,這給我留下了深刻的印象。我相信如果有更多的訓練數據和進行更多的超參數調整,我可以取得更好的結果。

行文到此,我們介紹了如何使用TensorFlow從零開始創建卷積神經網絡、如何從TensorBoard中得出推論以及如何可視化濾波器。重要的是記住使用少量數據來訓練分類器時,更容易的方法是選取一個已經使用多個GPU在大型數據集上訓練好的模型和權重(如GoogLeNet或VGG16),并截斷最后一層用自己的類別替換它們。然后所有分類器要做的就是學習最后一層的權重,并使用已存在的訓練好的濾波器權重。所以,我希望你從這篇文章中獲得一些東西,然后繼續探索,從中得到樂趣,不斷實驗學習,再秀一些酷的東西!

Justin Francis

Justin居住在加拿大西海岸的一個小農場。這個農場專注于樸門道德和設計的農藝。在此之前,他是一個非營利性社區合作社自行車商店的創始人和教育者。在過去的兩年中,他住在一艘帆船上,全職探索和體驗加拿大的喬治亞海峽。但現在他的主要精力都放在了學習機器學習上。

歡迎加入本站公開興趣群

商業智能與數據分析群

興趣范圍包括各種讓數據產生價值的辦法,實際應用案例分享與討論,分析工具,ETL工具,數據倉庫,數據挖掘工具,報表系統等全方位知識

QQ群:81035754

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/4682.html

相關文章

  • 深度學習

    摘要:深度學習在過去的幾年里取得了許多驚人的成果,均與息息相關。機器學習進階筆記之一安裝與入門是基于進行研發的第二代人工智能學習系統,被廣泛用于語音識別或圖像識別等多項機器深度學習領域。零基礎入門深度學習長短時記憶網絡。 多圖|入門必看:萬字長文帶你輕松了解LSTM全貌 作者 | Edwin Chen編譯 | AI100第一次接觸長短期記憶神經網絡(LSTM)時,我驚呆了。原來,LSTM是神...

    Vultr 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<