目錄python
參考書git
《TensorFlow:實戰Google深度學習框架》(第2版)github
劃重點編程
==從今天開始(20190505-1521),個人博客都用Markdown語法來編寫啦,也不知道之後的本身會不會被人所知,會不會有大佬來看過去的我,給我挖墳呢。想一想就有點期待呢!但願本身還能更加努力!更加優秀吧!==api
目前比較主流的TensorFlow高層封裝有4個,分別是TensorFlow-Slim、TFLearn、Keras和Estimator。數組
首先,這裏介紹先用TensorFlow-Slim在MNIST數據集上實現LeNet-5模型。瀏覽器
#!/usr/bin/env python # -*- coding: UTF-8 -*- # coding=utf-8 """ @author: Li Tian @contact: 694317828@qq.com @software: pycharm @file: slim_learn.py @time: 2019/4/22 10:53 @desc: 使用TensorFlow-Slim在MNIST數據集上實現LeNet-5模型。 """ import tensorflow as tf import tensorflow.contrib.slim as slim import numpy as np from tensorflow.examples.tutorials.mnist import input_data # 經過TensorFlow-Slim來定義LeNet-5的網絡結構 def lenet5(inputs): # 將輸入數據轉化爲一個4維數組。其中第一維表示batch大小,另三維表示一張圖片。 inputs = tf.reshape(inputs, [-1, 28, 28, 1]) # 定義第一層卷積層。從下面的代碼能夠看到經過TensorFlow-Slim定義的網絡結構 # 並不須要用戶去關心如何聲明和初始化變量,而只須要定義網絡結構便可。下一行代碼中 # 定義了一個卷積層,該卷積層的深度爲32,過濾器的大小爲5x5,使用全0補充。 net = slim.conv2d(inputs, 32, [5, 5], padding='SAME', scope='layer1-conv') # 定義一個最大池化層,其過濾器大小爲2x2,步長爲2. net = slim.max_pool2d(net, 2, stride=2, scope='layer2-max-pool') # 相似的定義其餘網絡層結構 net = slim.conv2d(net, 64, [5, 5], padding='SAME', scope='layer3-conv') net = slim.max_pool2d(net, 2, stride=2, scope='layer4-max-pool') # 直接使用TensorFlow-Slim封裝好的flatten函數將4維矩陣轉爲2維,這樣能夠 # 方便後面的全鏈接層的計算。經過封裝好的函數,用戶再也不須要本身計算經過卷積層以後矩陣的大小。 net = slim.flatten(net, scope='flatten') # 經過TensorFlow-Slim定義全鏈接層,該全鏈接層有500個隱藏節點。 net = slim.fully_connected(net, 500, scope="layer5") net = slim.fully_connected(net, 10, scope="output") return net # 經過TensorFlow-Slim定義網絡結構,並使用以前章節中給出的方式訓練定義好的模型。 def train(mnist): # 定義輸入 x = tf.placeholder(tf.float32, [None, 784], name='x-input') y_ = tf.placeholder(tf.float32, [None, 10], name='y-input') # 使用TensorFLow-Slim定義網絡結構 y = lenet5(x) # 定義損失函數和訓練方法 cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y, labels=tf.argmax(y_, 1)) # 1 means axis=1 loss = tf.reduce_mean(cross_entropy) train_op = tf.train.GradientDescentOptimizer(0.01).minimize(loss) # 訓練過程 with tf.Session() as sess: tf.global_variables_initializer().run() for i in range(10000): xs, ys = mnist.train.next_batch(100) _, loss_value = sess.run([train_op, loss], feed_dict={x: xs, y_: ys}) if i % 1000 == 0: print("After %d training step(s), loss on training batch is %g." % (i, loss_value)) def main(argv=None): mnist = input_data.read_data_sets('D:/Python3Space/BookStudy/book2/MNIST_data', one_hot=True) train(mnist) if __name__ == '__main__': main()
OK!運行吧皮卡丘!網絡
第一個例子都報錯。。。(ValueError: Rank mismatch: Rank of labels (received 1) should equal rank of logits minus 1 (received 4).)框架
我哭了!找了我半天錯誤,才發現少寫了一句。分佈式
net = slim.flatten(net, scope='flatten')
可把我愁壞了,整了半天才弄好。。。
網上都是什麼神仙回答,解釋的有板有眼的,都說這本書是垃圾,害得我差點馬上在我對這本書評價的博客上再加上幾句芬芳。
好歹是學到了知識了。對logits和labels加深了印象了。
cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y, labels=tf.argmax(y_, 1))
logits:是計算獲得的結果
labels:是原來的數據標籤。
千萬不要記混了!
labels=tf.argmax(y_, 1)
labels輸入的是[0, 0, 0, 1, 0, 0, 0, 0, 0, 0](以MNIST爲例),
而在tf.nn.sparse_softmax_cross_entropy_with_logits函數中
labels的輸入格式須要是[3],也就是說,是類別的編號。
誒!問題來了!
logits=y
logits的格式與labels同樣嗎?
不同!
logits的格式與labels轉換前的同樣,也就是
[0.2, 0.3, 0.1, 0.9, 0.1, 0.1, 0.2, 0.2, 0.4, 0.6]
若是不轉換labels的話,能夠用tf.nn.softmax_cross_entropy_with_logits達到一樣的效果。
誒?那爲何非要轉換一下labels呢?
我也沒看懂,非要騷一下吧。。。
好了正確的運行結果出來了:
若是咱們把剛纔說的那句代碼改成:
cross_entropy = tf.nn.softmax_cross_entropy_with_logits(logits=y, labels=y_)
試試看?
哇哦~正常運行了有沒有!!!
因此呢?因此爲何這裏要非要用有sparse的這個函數呢?
反正我是沒看懂(攤手┓( ´∀` )┏)。。。
與TensorFlow-Slim相比,TFLearn是一個更加簡潔的高層封裝。
由於TFLearn並無集成在TensorFlow中,因此首先是用pip安裝。
安裝完後,下面是用TFLearn在MNIST數據集上實現LeNet-5模型。
#!/usr/bin/env python # -*- coding: UTF-8 -*- # coding=utf-8 """ @author: Li Tian @contact: 694317828@qq.com @software: pycharm @file: tflearn_learn.py @time: 2019/5/5 16:53 @desc: 使用TFLearn在MNIST數據集上實現LeNet-5模型。 """ import tflearn from tflearn.layers.core import input_data, fully_connected from tflearn.layers.conv import conv_2d, max_pool_2d from tflearn.layers.estimator import regression import tflearn.datasets.mnist as mnist # 讀取mnist數據 trainX, trainY, testX, testY = mnist.load_data(data_dir="D:/Python3Space/BookStudy/book2/MNIST_data", one_hot=True) # 將圖像數據reshape成卷積神經網絡輸入的格式 trainX = trainX.reshape([-1, 28, 28, 1]) testX = testX.reshape([-1, 28, 28, 1]) # 構建神經網絡,這個過程和TensorFlow-Slim比較相似。input_data定義了一個placeholder來接入輸入數據。 net = input_data(shape=[None, 28, 28, 1], name='input') # 經過TFLearn封裝好的API定義一個深度爲5,過濾器爲5x5,激活函數爲ReLU的卷積層 net = conv_2d(net, 32, 5, activation='relu') # 定義一個過濾器爲2x2的最大池化層 net = max_pool_2d(net, 2) # 相似地定義其餘的網絡結構。 net = conv_2d(net, 64, 5, activation='relu') net = max_pool_2d(net, 2) net = fully_connected(net, 500, activation='relu') net = fully_connected(net, 10, activation='softmax') # 使用TFLearn封裝好的函數定義學習任務。指定優化器爲sgd,學習率爲0.01,損失函數爲交叉熵。 net = regression(net, optimizer='sgd', learning_rate=0.01, loss='categorical_crossentropy') # 經過定義的網絡結構訓練模型,並在指定的驗證數據上驗證模型的效果。 # TFLearn將模型的訓練過程封裝到了一個類中,這樣能夠減小很是多的冗餘代碼。 model = tflearn.DNN(net, tensorboard_verbose=0) model.fit(trainX, trainY, n_epoch=20, validation_set=([testX, testY]), show_metric=True)
我的感相較於Slim,TFLearn好用太多了吧。。。特別是model.fit真的是給我眼前一亮的感受,這也太帥了吧,瞧這交叉熵小黃字,瞧這epoch,瞧這step。。。封裝萬歲!!!(對我這種菜雞而言,不要跟我談底層,我!不!夠!格!)
運行結果:
下面是用原生態的Keras在MNIST數據集上實現LeNet-5模型。
#!/usr/bin/env python # -*- coding: UTF-8 -*- # coding=utf-8 """ @author: Li Tian @contact: 694317828@qq.com @software: pycharm @file: keras_learn.py @time: 2019/5/5 17:42 @desc: 使用Keras在MNIST數據集上實現LeNet-5模型。 """ import keras from keras.datasets import mnist from keras.models import Sequential from keras.layers import Dense, Flatten, Conv2D, MaxPooling2D from keras import backend as K num_calsses = 10 img_rows, img_cols = 28, 28 # 經過Keras封裝好的API加載MNIST數據。其中trainX就是一個60000x28x28的數組, # trainY是每一張圖片對應的數字。 (trainX, trainY), (testX, testY) = mnist.load_data() # 由於不一樣的底層(TensorFlow或者MXNet)對輸入的要求不同,因此這裏須要根據對圖像 # 編碼的格式要求來設置輸入層的格式。 if K.image_data_format() == 'channels_first': trainX = trainX.reshape(trainX.shape[0], 1, img_rows, img_cols) testX = testX.reshape(trainX.shape[0], 1, img_rows, img_cols) # 由於MNIST中的圖片是黑白的,因此第一維的取值爲1 input_shape = (1, img_rows, img_cols) else: trainX = trainX.reshape(trainX.shape[0], img_rows, img_cols, 1) testX = testX.reshape(testX.shape[0], img_rows, img_cols, 1) input_shape = (img_rows, img_cols, 1) # 將圖像像素轉化爲0到1之間的實數。 trainX = trainX.astype('float32') testX = testX.astype('float32') trainX /= 255.0 testX /= 255.0 # 將標準答案轉化爲須要的格式(One-hot編碼)。 trainY = keras.utils.to_categorical(trainY, num_calsses) testY = keras.utils.to_categorical(testY, num_calsses) # 使用Keras API定義模型 model = Sequential() # 一層深度爲32,過濾器大小爲5x5的卷積層 model.add(Conv2D(32, kernel_size=(5, 5), activation='relu', input_shape=input_shape)) # 一層過濾器大小爲2x2的最大池化層。 model.add(MaxPooling2D(pool_size=(2, 2))) # 一層深度爲64, 過濾器大小爲5x5的卷積層。 model.add(Conv2D(64, (5, 5), activation='relu')) # 一層過濾器大小爲2x2的最大池化層。 model.add(MaxPooling2D(pool_size=(2, 2))) # 將卷積層的輸出拉直後做爲下面全鏈接的輸入。 model.add(Flatten()) # 全鏈接層,有500個節點。 model.add(Dense(500, activation='relu')) # 全鏈接層,獲得最後的輸出。 model.add(Dense(num_calsses, activation='softmax')) # 定義損失函數、優化函數和測評的方法。 model.compile(loss=keras.losses.categorical_crossentropy, optimizer=keras.optimizers.SGD(), metrics=['accuracy']) # 相似TFLearn中的訓練過程,給出訓練數據,batch大小、訓練輪數和驗證數據,Keras能夠自動完成模型的訓練過程。 model.fit(trainX, trainY, batch_size=128, epochs=20, validation_data=(testX, testY)) # 在測評數據上計算準確率 score = model.evaluate(testX, testY) print('Test loss: ', score[0]) print('Test accuracy: ', score[1])
運行以後(跑了我一晚上呀我滴媽。。。):
下面是用原生態的Keras實現循環神經網絡。
#!/usr/bin/env python # -*- coding: UTF-8 -*- # coding=utf-8 """ @author: Li Tian @contact: 694317828@qq.com @software: pycharm @file: keras_rnn.py @time: 2019/5/6 12:30 @desc: 用原生態的Keras實現循環神經網絡 """ from keras.preprocessing import sequence from keras.models import Sequential from keras.layers import Dense, Embedding, LSTM from keras.datasets import imdb # 最多使用的單詞數 max_features = 20000 # 循環神經網絡的截斷長度。 maxlen = 80 batch_size = 32 # 加載數據並將單詞轉化爲ID,max_features給出了最多使用的單詞數。和天然語言模型相似, # 會將出現頻率較低的單詞替換爲統一的的ID。經過Keras封裝的API會生成25000條訓練數據和 # 25000條測試數據,每一條數據能夠被當作一段話,而且每段話都有一個好評或者差評的標籤。 (trainX, trianY), (testX, testY) = imdb.load_data(num_words=max_features) print(len(trainX), 'train sequences') print(len(testX), 'test sequences') # 在天然語言中,每一段話的長度是不同的,但循環神經網絡的循環長度是固定的,因此這裏須要先將 # 全部段落統一成固定長度。對於長度不夠的段落,要使用默認值0來填充,對於超過長度的段落 # 則直接忽略掉超過的部分。 trainX = sequence.pad_sequences(trainX, maxlen=maxlen) testX = sequence.pad_sequences(testX, maxlen=maxlen) print('trainX shape', trainX.shape) print('testX shape: ', testX.shape) # 在完成數據預處理以後構建模型 model = Sequential() # 構建embedding層。128表明了embedding層的向量維度。 model.add(Embedding(max_features, 128)) # 構建LSTM層 model.add(LSTM(128, dropout=0.2, recurrent_dropout=0.2)) # 構建最後的全鏈接層。注意在上面構建LSTM層時只會獲得最後一個節點的輸出, # 若是須要輸出每一個時間點的結果,呢麼能夠將return_sequence參數設爲True。 model.add(Dense(1, activation='sigmoid')) # 與MNIST樣例相似的指定損失函數、優化函數和測評指標。 model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy']) # 在測試數據上評測模型。 score = model.evaluate(testX, testY, batch_size=batch_size) print('Test loss: ', score[0]) print('Test accuracy: ', score[1])
睡了個午覺就跑完啦:
面對上面的例子,都是順序搭建的神經網絡模型,相似於Inception這樣的模型結構,就須要更加靈活的模型定義方法了。
在這裏我真的是忍不住要吐槽一下書上的內容,簡直徹底沒有講清楚在說什麼鬼。。。沒說清楚到底是用的那一部分的數據,是MNIST仍是rnn的數據。。。搗鼓了半天才知道是MNIST。而後這裏的意思應該是用全鏈接的方式,即輸入數據爲(60000, -1),也就是說樣本是60000個,而後把圖片的維度拉伸爲1維。(這裏我也是摸索了很久才知道的),因此在代碼中須要對數據進行reshape處理。否則會報錯:
ValueError: Error when checking input: expected input_1 to have 2 dimensions, but got array with shape (60000, 28, 28)
參考連接:https://blog.csdn.net/u012193416/article/details/79399679
是真的坑爹,只能說。。。什麼也沒有說清楚,就特麼瞎指揮。。。(然鵝,我是真的菜。。。攤手。。。)
#!/usr/bin/env python # -*- coding: UTF-8 -*- # coding=utf-8 """ @author: Li Tian @contact: 694317828@qq.com @software: pycharm @file: keras_inception.py @time: 2019/5/6 14:29 @desc: 用更加靈活的模型定義方法在MNIST數據集上實現全鏈接層模型。 """ import keras from keras.layers import Input, Dense from keras.models import Model from keras.datasets import mnist # 使用前面介紹的相似方法生成trainX、trainY、testX、testY,惟一的不一樣是這裏只用了 # 全鏈接層,因此不須要將輸入整理成三維矩陣。 num_calsses = 10 img_rows, img_cols = 28, 28 # 經過Keras封裝好的API加載MNIST數據。其中trainX就是一個60000x28x28的數組, # trainY是每一張圖片對應的數字。 (trainX, trainY), (testX, testY) = mnist.load_data() trainX = trainX.reshape(len(trainX), -1) testX = testX.reshape(len(testX), -1) # 將圖像像素轉化爲0到1之間的實數。 trainX = trainX.astype('float32') testX = testX.astype('float32') trainX /= 255.0 testX /= 255.0 # 將標準答案轉化爲須要的格式(One-hot編碼)。 trainY = keras.utils.to_categorical(trainY, num_calsses) testY = keras.utils.to_categorical(testY, num_calsses) # 定義輸入,這裏指定的維度不用考慮batch大小。 inputs = Input(shape=(784, )) # 定義一層全鏈接層,該層有500隱藏節點,使用ReLU激活函數。這一層的輸入爲inputs x = Dense(500, activation='relu')(inputs) # 定義輸出層。注意由於keras封裝的categorical_crossentropy並無將神經網絡的輸出 # 再通過一層softmax,因此這裏須要指定softmax做爲激活函數。 predictions = Dense(10, activation='softmax')(x) # 經過Model類建立模型,和Sequential類不一樣的是Model類在初始化的時候須要指定模型的輸入和輸出 model = Model(inputs=inputs, outputs=predictions) # 使用與前面相似的方法定義損失函數、優化函數和評測方法。 model.compile(loss=keras.losses.categorical_crossentropy, optimizer=keras.optimizers.SGD(), metrics=['accuracy']) # 使用與前面相似的方法訓練模型。 model.fit(trainX, trainY, batch_size=128, epochs=10, validation_data=(testX, testY))
修改以後運行能夠獲得:
經過這樣的方式,Keras就能夠實現相似Inception這樣的模型結構了。
如今又要說坑爹的部分了,這本書在這裏直接照抄的Keras的手冊中的例子,來解釋用Keras實現Inception-v3的模型結構,因此給出的代碼是這樣的
from keras.layers import Conv2D, MaxPooling2D, Input # 定義輸入圖像尺寸 input_img = Input(shape=(256, 256, 3)) # 定義第一個分支。 tower_1 = Conv2D(64, (1, 1), padding='same', activation='relu')(input_img) tower_1 = Conv2D(64, (3, 3), padding='same', activation='relu')(tower_1) # 定義第二個分支。與順序模型不一樣,第二個分支的輸入使用的是input_img,而不是第一個分支的輸出。 tower_2 = Conv2D(64, (1, 1), padding='same', activation='relu')(input_img) tower_2 = Conv2D(64, (5, 5), padding='same', activation='relu')(tower_2) # 定義第三個分支。相似地,第三個分支的輸入也是input_img。 tower_3 = MaxPooling2D((3, 3), strides=(1, 1), padding='same')(input_img) tower_3 = Conv2D(64, (1, 1), padding='same', activation='relu')(tower_3) # 將三個分支經過concatenate的方式拼湊在一塊兒。 output = keras.layers.concatenate([tower_1, tower_2, tower_3], axis=1)
你可能要問「這就完啦?」,我想告訴你的是,對的。關於Inception-v3的部分就這麼點。而後我給你看一眼網上官方的代碼:
參考連接:https://keras.io/zh/getting-started/functional-api-guide/
是否是有種似曾相識的感受。。。
踏馬的根本就沒有想着去實現好嗎?
我也是醉了的,我就問一句,不是一直在用MNIST數據集做爲例子嗎!那這個
input_img = Input(shape=(256, 256, 3))
圖像尺寸怎麼忽然就編程(256, 256, 3)了呢?而不是(28, 28, 1)呢?
==這本書一點都不走心好嗎!==
我也是佛了,那麼我只能靠本身理解,並本身寫例子了。這裏面的艱辛我就不說了,不賣慘了,是真的恨,我只但願每個例子都可以善始善終,都可以有輸出有結果,能運行!
下面貼一下我本身想的改的代碼吧:
#!/usr/bin/env python # -*- coding: UTF-8 -*- # coding=utf-8 """ @author: Li Tian @contact: 694317828@qq.com @software: pycharm @file: keras_inception2.py @time: 2019/5/6 15:43 @desc: 用原生態的Keras實現Inception """ from keras.layers import Conv2D, MaxPooling2D, Input, Dense, Flatten import keras from keras.models import Model from keras.datasets import mnist from keras import backend as K # 使用前面介紹的相似方法生成trainX、trainY、testX、testY,惟一的不一樣是這裏只用了 # 全鏈接層,因此不須要將輸入整理成三維矩陣。 num_calsses = 10 img_rows, img_cols = 28, 28 # 經過Keras封裝好的API加載MNIST數據。其中trainX就是一個60000x28x28的數組, # trainY是每一張圖片對應的數字。 (trainX, trainY), (testX, testY) = mnist.load_data() if K.image_data_format() == 'channels_first': trainX = trainX.reshape(trainX.shape[0], 1, img_rows, img_cols) testX = testX.reshape(trainX.shape[0], 1, img_rows, img_cols) # 由於MNIST中的圖片是黑白的,因此第一維的取值爲1 input_shape = (1, img_rows, img_cols) else: trainX = trainX.reshape(trainX.shape[0], img_rows, img_cols, 1) testX = testX.reshape(testX.shape[0], img_rows, img_cols, 1) input_shape = (img_rows, img_cols, 1) # 將圖像像素轉化爲0到1之間的實數。 trainX = trainX.astype('float32') testX = testX.astype('float32') trainX /= 255.0 testX /= 255.0 # 將標準答案轉化爲須要的格式(One-hot編碼)。 trainY = keras.utils.to_categorical(trainY, num_calsses) testY = keras.utils.to_categorical(testY, num_calsses) # 定義輸入圖像尺寸 input_img = Input(shape=(28, 28, 1)) # 定義第一個分支。 tower_1 = Conv2D(64, (1, 1), padding='same', activation='relu')(input_img) tower_1 = Conv2D(64, (3, 3), padding='same', activation='relu')(tower_1) # 定義第二個分支。與順序模型不一樣,第二個分支的輸入使用的是input_img,而不是第一個分支的輸出。 tower_2 = Conv2D(64, (1, 1), padding='same', activation='relu')(input_img) tower_2 = Conv2D(64, (5, 5), padding='same', activation='relu')(tower_2) # 定義第三個分支。相似地,第三個分支的輸入也是input_img。 tower_3 = MaxPooling2D((3, 3), strides=(1, 1), padding='same')(input_img) tower_3 = Conv2D(64, (1, 1), padding='same', activation='relu')(tower_3) # 將三個分支經過concatenate的方式拼湊在一塊兒。 output = keras.layers.concatenate([tower_1, tower_2, tower_3], axis=1) # 將卷積層的輸出拉直後做爲下面全鏈接的輸入。 tower_4 = Flatten()(output) # 全鏈接層,有500個節點。 tower_5 = Dense(500, activation='relu')(tower_4) # 全鏈接層,獲得最後的輸出。 predictions = Dense(num_calsses, activation='softmax')(tower_5) # 經過Model類建立模型,和Sequential類不一樣的是Model類在初始化的時候須要指定模型的輸入和輸出 model = Model(inputs=input_img, outputs=predictions) # 使用與前面相似的方法定義損失函數、優化函數和評測方法。 model.compile(loss=keras.losses.categorical_crossentropy, optimizer=keras.optimizers.SGD(), metrics=['accuracy']) # 使用與前面相似的方法訓練模型。 model.fit(trainX, trainY, batch_size=128, epochs=20, validation_data=(testX, testY)) # 在測試數據上評測模型。 score = model.evaluate(testX, testY, batch_size=128) print('Test loss: ', score[0]) print('Test accuracy: ', score[1])
運行結果:
說明,我改了以後是能跑的。。。
對了,若是有槓精問我,人家只是拋磚引玉,讓讀者觸類旁通。。。那我沒什麼好說的。。。
又花了一夜跑完。。。
用原生態的Keras實現非順序模型,多輸入和多輸出模型。
#!/usr/bin/env python # -*- coding: UTF-8 -*- # coding=utf-8 """ @author: Li Tian @contact: 694317828@qq.com @software: pycharm @file: keras_inception3.py @time: 2019/5/7 14:54 @desc: 用原生態的Keras實現非順序模型,多輸入和多輸出模型 """ import keras from tflearn.layers.core import fully_connected from keras.datasets import mnist from keras.layers import Input, Dense from keras.models import Model from keras import backend as K # 相似前面的方式生成trainX、trainY、testX、testY num_calsses = 10 img_rows, img_cols = 28, 28 # 經過Keras封裝好的API加載MNIST數據。其中trainX就是一個60000x28x28的數組, # trainY是每一張圖片對應的數字。 (trainX, trainY), (testX, testY) = mnist.load_data() trainX = trainX.reshape(len(trainX), -1) testX = testX.reshape(len(testX), -1) # 將圖像像素轉化爲0到1之間的實數。 trainX = trainX.astype('float32') testX = testX.astype('float32') trainX /= 255.0 testX /= 255.0 # 將標準答案轉化爲須要的格式(One-hot編碼)。 trainY = keras.utils.to_categorical(trainY, num_calsses) testY = keras.utils.to_categorical(testY, num_calsses) # 定義兩個輸入,一個輸入爲原始的圖片信息,另外一個輸入爲正確答案。 input1 = Input(shape=(784, ), name='input1') input2 = Input(shape=(10, ), name='input2') # 定義一個只有一個隱藏節點的全鏈接網絡。 x = Dense(1, activation='relu')(input1) # 定義只使用了一個隱藏節點的網絡結構的輸出層。 output1 = Dense(10, activation='softmax', name='output1')(x) # 將一個隱藏節點的輸出和正確答案拼接在一塊兒,這個將做爲第二個輸出層的輸入。 y = keras.layers.concatenate([x, input2]) # 定義第二個輸出層。 output2 = Dense(10, activation='softmax', name='output2')(y) # 定義一個有多個輸入和多個輸出的模型,這裏只須要將全部的輸入和輸出給出便可。 model = Model(inputs=[input1, input2], outputs=[output1, output2]) # 定義損失函數、優化函數和評測方法。若多個輸出的損失函數相同,能夠只指定一個損失函數。 # 若是多個輸出的損失函數不一樣,則能夠經過一個列表或一個字典來指定每個輸出的損失函數。 # 好比可使用:loss = {'output1': 'binary_crossentropy', 'output2': 'binary_crossentropy'} # 來爲不一樣的輸出指定不一樣的損失函數。相似的,Keras也支持爲不一樣輸出產生的損失指定權重, # 這能夠經過經過loss_weights參數來完成。在下面的定義中,輸出output1的權重爲1,output2 # 的權重爲0.1。因此這個模型會更加偏向於優化第一個輸出。 model.compile(loss=keras.losses.categorical_crossentropy, optimizer=keras.optimizers.SGD(), loss_weights=[1, 0.1], metrics=['accuracy']) # 模型訓練過程。由於有兩個輸入和輸出,因此這裏提供的數據也須要有兩個輸入和兩個期待的正確 # 答案輸出。經過列表的方式提供數據時,Keras會假設數據給出的順序和定義Model類時輸入輸出 # 給出的順序是對應的。爲了不順序不一致致使的問題,這裏更推薦使用字典的形式給出。 model.fit( [trainX, trainY], [trainY, trainY], batch_size=128, epochs=20, validation_data=([testX, testY], [testY, testY]) )
運行結果:
咱們能夠看出,因爲輸出層1只使用了一個一維的隱藏節點,因此正確率很低,輸出層2雖然使用了正確答案最爲輸入,可是損失函數中的權重較低,因此收斂速度較慢,準確率只有0.804。如今咱們把權重設置相同,運行獲得:
這樣輸出二通過了足夠的訓練,精度就提升了不少。
雖然經過返回值的方式已經能夠實現大部分的神經網絡模型,然而Keras API還存在兩大問題。一是對訓練數據的處理流程支持的不太好;二十沒法支持分佈式訓練。爲了解決這兩個問題,Keras提供了一種與原生態TensorFlow結合得更加緊密的方式。下面的代碼是:實現Keras與TensorFlow聯合起來解決MNIST問題。
#!/usr/bin/env python # -*- coding: UTF-8 -*- # coding=utf-8 """ @author: Li Tian @contact: 694317828@qq.com @software: pycharm @file: keras_test4.py @time: 2019/5/7 15:45 @desc: 實現Keras與TensorFlow聯合起來解決MNIST問題。 """ import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_data mnist_data = input_data.read_data_sets('D:/Python3Space/BookStudy/book2/MNIST_data', one_hot=True) # 經過TensorFlow中的placeholder定義輸入。相似的,Keras封裝的網絡層結構也能夠支持使用 # 前面章節中介紹的輸入隊列。這樣能夠有效避免一次性加載全部數據的問題。 x = tf.placeholder(tf.float32, shape=(None, 784)) y_ = tf.placeholder(tf.float32, shape=(None, 10)) # 直接使用TensorFlow中提供的Keras API定義網絡結構。 net = tf.keras.layers.Dense(500, activation='relu')(x) y = tf.keras.layers.Dense(10, activation='softmax')(net) # 定義損失函數和優化方法。注意這裏能夠混用Keras的API和原生態TensorFlow的API loss = tf.reduce_mean(tf.keras.losses.categorical_crossentropy(y_, y)) train_step = tf.train.GradientDescentOptimizer(0.5).minimize(loss) # 定義預測的正確率做爲指標。 acc_value = tf.reduce_mean(tf.keras.metrics.categorical_accuracy(y_, y)) # 使用原生態TensorFlow的方式訓練模型。這樣能夠有效地實現分佈式。 with tf.Session() as sess: tf.global_variables_initializer().run() for i in range(10000): xs, ys = mnist_data.train.next_batch(100) _, loss_value = sess.run([train_step, loss], feed_dict={x: xs, y_: ys}) if i % 1000 == 0: print("After %d training step(s), loss on training batch is %g." % (i, loss_value)) print(acc_value.eval(feed_dict={x: mnist_data.test.images, y_: mnist_data.test.labels}))
運行結果:
經過和原生態TensorFlow更緊密地結合,可使建模的靈活性進一步提升,可是同時也會損失一部分封裝帶來的易用性。因此在實際問題中,須要根據需求合理的選擇封裝的程度。
基於MNIST數據集,經過Estimator實現全鏈接神經網絡。
#!/usr/bin/env python # -*- coding: UTF-8 -*- # coding=utf-8 """ @author: Li Tian @contact: 694317828@qq.com @software: pycharm @file: estimator_test1.py @time: 2019/5/7 16:22 @desc: 基於MNIST數據集,經過Estimator實現全鏈接神經網絡。 """ import numpy as np import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_data # 將TensorFlow日誌信息輸出到屏幕 tf.logging.set_verbosity(tf.logging.INFO) mnist = input_data.read_data_sets('D:/Python3Space/BookStudy/book2/MNIST_data', one_hot=True) # 指定神經網絡的輸入層,全部這裏指定的輸入都會拼接在一塊兒做爲整個神經網絡的輸入。 feature_columns = [tf.feature_column.numeric_column("image", shape=[784])] # 經過TensorFlow提供的封裝好的Estimator定義神經網絡模型。feature_columns參數 # 給出了神經網絡輸入層須要用到的數據,hidden_units列表中給出了每一層 # 隱藏層的節點數。n_classes給出了總共類目的數量,optimizer給出了使用的優化函數。 # Estimator會將模型訓練過程當中的loss變化以及一些其餘指標保存到model_dir目錄下, # 經過TensorFlow能夠可視化這些指標的變化過程。並經過TensorBoard可視化監控指標結果。 estimator = tf.estimator.DNNClassifier( feature_columns=feature_columns, hidden_units=[500], n_classes=10, optimizer=tf.train.AdamOptimizer(), model_dir="./log" ) # 定義數據輸入。這裏x中須要給出全部的輸入數據。由於上面feature_columns只定義了一組 # 輸入,因此這裏只須要制定一個就好。若是feature_columns中指定了多個,那麼這裏也須要 # 對每個指定的輸入提供數據。y中須要提供每個x對應的正確答案,這裏要求分類的結果 # 是一個正整數。num_epochs指定了數據循環使用的輪數。好比在測試時能夠將這個參數指定爲1. # batch_size指定了一個batch的大小。shuffle指定了是否須要對數據進行隨機打亂。 train_input_fn = tf.estimator.inputs.numpy_input_fn( x={"image": mnist.train.images}, y=mnist.train.labels.astype(np.int32), num_epochs=None, batch_size=128, shuffle=True ) # 訓練模型。注意這裏沒有指定損失函數,經過DNNClassifier定義的模型會使用交叉熵做爲損失函數。 estimator.train(input_fn=train_input_fn, steps=10000) # 定義測試時的數據輸入。指定的形式和訓練時的數據輸入基本一致。 test_input_fn = tf.estimator.inputs.numpy_input_fn( x={"image": mnist.test.images}, y=mnist.test.labels.astype(np.int32), num_epochs=1, batch_size=128, shuffle=False ) # 經過evaluate評測訓練好的模型的效果。 accuracy_score = estimator.evaluate(input_fn=test_input_fn)["accuracy"] print("\nTest accuracy: %g %%" % (accuracy_score*100))
運行可得:
使用下面的命令開啓tensorboard之旅:(我又要噴了,書里根本沒說怎麼開啓tensorboard,我徹底靠自行百度摸索的。。。)
tensorboard --logdir=""
引號裏面填本身的log所在的地址。而後運行:
複製最下面的那個地址,在瀏覽器(我是谷歌瀏覽器)粘貼並轉到。
記住!是粘貼並轉到,不是ctrl+v,是右鍵,粘貼並轉到。
別問!問就是吃了好多虧。。。
反正個人電腦是粘貼並轉到以後,卡了一下子,就出現了這個界面:
雖然跟書上的圖的佈局不同,下面摺疊的指標,展開也有圖就是了。。。
固然GRAPHS也是有的嘿嘿。。。
經過自定義的方式使用卷積神經網絡解決MNIST問題:
#!/usr/bin/env python # -*- coding: UTF-8 -*- # coding=utf-8 """ @author: Li Tian @contact: 694317828@qq.com @software: pycharm @file: estimator_test2.py @time: 2019/5/9 12:31 @desc: 經過自定義的方式使用卷積神經網絡解決MNIST問題 """ import numpy as np import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_data tf.logging.set_verbosity(tf.logging.INFO) # 經過tf.layers來定義模型結構。這裏可使用原生態TensorFlow API或者任何 # TensorFlow的高層封裝。X給出了輸入層張量,is_training指明瞭是否爲訓練。 # 該函數返回前向傳播的結果。 def lenet(x, is_training): # 將輸入轉化爲卷積層須要的形狀 x = tf.reshape(x, shape=[-1, 28, 28, 1]) net = tf.layers.conv2d(x, 32, 5, activation=tf.nn.relu) net = tf.layers.max_pooling2d(net, 2, 2) net = tf.layers.conv2d(net, 64, 3, activation=tf.nn.relu) net = tf.layers.max_pooling2d(net, 2, 2) net = tf.contrib.layers.flatten(net) net = tf.layers.dense(net, 1024) net = tf.layers.dropout(net, rate=0.4, training=is_training) return tf.layers.dense(net, 10) # 自定義Estimator中使用的模型,定義的函數有4個輸入,features給出了在輸入函數中 # 會提供的輸入層張量。注意這是一個字典,字典裏的內容是經過tf.estimator.inputs.numpy_input_fn # 中x參數的內容指定的。labels是正確答案,這個字段的內容是經過numpy_input_fn中y參數給出的。 # mode的取值有3中可能,分別對應Estimator類的train、evaluate和predict這3個函數。經過 # 這個參數能夠判斷當前會否是訓練過程。最後params是一個字典,這個字典中能夠給出模型相關的任何超參數 # (hyper-parameter)。好比這裏將學習率放在params中。 def model_fn(features, labels, mode, params): # 定義神經網絡的結構並經過輸入獲得前向傳播的結果。 predict = lenet(features["image"], mode == tf.estimator.ModeKeys.TRAIN) # 若是在預測模式,那麼只須要將結果返回便可。 if mode == tf.estimator.ModeKeys.PREDICT: # 使用EstimatorSpec傳遞返回值,並經過predictions參數指定返回的結果。 return tf.estimator.EstimatorSpec( mode=mode, predictions={"result": tf.argmax(predict, 1)} ) # 定義損失函數 loss = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=predict, labels=labels)) # 定義優化函數。 optimizer = tf.train.GradientDescentOptimizer(learning_rate=params["learning_rate"]) # 定義訓練過程。 train_op = optimizer.minimize(loss=loss, global_step=tf.train.get_global_step()) # 定義評測標準,在運行evaluate時會計算這裏定義的全部評測標準。 eval_metric_ops = { "my_metric": tf.metrics.accuracy(tf.argmax(predict, 1), labels) } # 返回模型訓練過程須要使用的損失函數、訓練過程和評測方法。 return tf.estimator.EstimatorSpec( mode=mode, loss=loss, train_op=train_op, eval_metric_ops=eval_metric_ops ) mnist = input_data.read_data_sets("D:/Python3Space/BookStudy/book2/MNIST_data", one_hot=False) # 經過自定義的方式生成Estimator類。這裏須要提供模型定義的函數並經過params參數指定模型定義時使用的超參數。 model_params = {"learning_rate": 0.01} estimator = tf.estimator.Estimator(model_fn=model_fn, params=model_params) # 和前面的相似,訓練和評測模型。 train_input_fn = tf.estimator.inputs.numpy_input_fn( x={"image": mnist.train.images}, y=mnist.train.labels.astype(np.int32), num_epochs=None, batch_size=128, shuffle=True ) estimator.train(input_fn=train_input_fn, steps=30000) test_input_fn = tf.estimator.inputs.numpy_input_fn( x={"image": mnist.test.images}, y=mnist.test.labels.astype(np.int32), num_epochs=1, batch_size=128, shuffle=False ) test_results = estimator.evaluate(input_fn=test_input_fn) # 這裏使用的my_metric中的內容就是model_fn中eval_metric_ops定義的評測指標。 accuracy_score = test_results["my_metric"] print("\nTest accuracy: %g %%" % (accuracy_score*100)) # 使用訓練好的模型在新數據上預測結果。 predict_input_fn = tf.estimator.inputs.numpy_input_fn( x={"image": mnist.test.images[:10]}, num_epochs=1, shuffle=False ) predictions = estimator.predict(input_fn=predict_input_fn) for i, p in enumerate(predictions): # 這裏result就是tf.estimator.EstimatorSpec的參數predicitons中指定的內容。 # 由於這個內容是一個字典,因此Estimator能夠很容易支持多輸出。 print("Prediction %s : %s" % (i + 1, p["result"]))
運行以後獲得:
預測結果:
#!/usr/bin/env python # -*- coding: UTF-8 -*- # coding=utf-8 """ @author: Li Tian @contact: 694317828@qq.com @software: pycharm @file: estimator_test3.py @time: 2019/5/9 14:13 @desc: 經過Estimator和數據集相結合的方式完成整個數據讀取和模型訓練的過程。 """ import tensorflow as tf tf.logging.set_verbosity(tf.logging.INFO) # Estimator的自定義輸入函數須要每一次被調用時能夠獲得一個batch的數據(包括全部的 # 輸入層數據和期待的正確答案標註),經過數據集能夠很天然地實現這個過程。雖然Estimator # 要求的自定義輸入函數不能有參數,可是經過python提供的lambda表達式能夠快速將下面的 # 函數轉化爲不帶參數的函數。 def my_input_fn(file_path, perform_shuffle=False, repeat_count=1): # 定義解析csv文件中一行的方法。 def decode_csv(line): # 將一行中的數據解析出來。注意iris數據中最後一列爲正確答案,前面4列爲特徵。 parsed_line = tf.decode_csv(line, [[0.], [0.], [0.], [0.], [0]]) # Estimator的輸入函數要求特徵是一個字典,因此這裏返回的也須要是一個字典。 # 字典中key的定義須要和DNNclassifier中feature_columns的定義匹配。 return {"x": parsed_line[:-1]}, parsed_line[-1:] # 使用數據集處理輸入數據。數據集的具體使用方法能夠參考前面。 dataset = (tf.data.TextLineDataset(file_path).skip(1).map(decode_csv)) if perform_shuffle: dataset = dataset.shuffle(buffer_size=256) dataset = dataset.repeat(repeat_count) dataset = dataset.batch(12) iterator = dataset.make_one_shot_iterator() # 經過定義的數據集獲得一個batch的輸入數據。這就是整個自定義的輸入過程的返回結果。 batch_features, batch_labels = iterator.get_next() # 若是是爲預測過程提供輸入數據,那麼batch_labels能夠直接使用None。 return batch_features, batch_labels # 與前面中相似地定義Estimator feature_columns = [tf.feature_column.numeric_column("x", shape=[4])] classifier = tf.estimator.DNNClassifier( feature_columns=feature_columns, hidden_units=[10, 10], n_classes=3 ) # 使用lambda表達式將訓練相關的信息傳入自定義輸入數據處理函數並生成Estimator須要的輸入函數 classifier.train(input_fn=lambda: my_input_fn("./iris_data/iris_training (1).csv", True, 10)) # 使用lambda表達式將測試相關的信息傳入自定義輸入數據處理函數並生成Estimator須要的輸入函數。 # 經過lambda表達式的方式能夠大大減小冗餘代碼。 test_results = classifier.evaluate(input_fn=lambda: my_input_fn("./iris_data/iris_test (1).csv", False, 1)) print("\nTest accuracy: %g %%" % (test_results["accuracy"]*100))
運行以後,玄學報錯。。。
我佛了,查了一萬種方法,也解決不了玄學報錯。。。
而後,我換了個機器,macbook。。。就正常運行了。。。
頭就很疼。。。
要什麼總結,不就是幾種常見的TensorFlow高層封裝嘛!包括TensorFlow-Slim、TFLearn、Keras和Estimator。反正就是結合起來,反正就是頭疼。
個人CSDN:https://blog.csdn.net/qq_21579045
個人博客園:https://www.cnblogs.com/lyjun/
個人Github:https://github.com/TinyHandsome
紙上得來終覺淺,絕知此事要躬行~
歡迎你們過來OB~
by 李英俊小朋友