
使用這些基本 REST API 最佳實踐構建出色的 API
這個是工作環境:
# 這個Jupyter Notebook的環境
import platform
import tensorflow
import keras
print("Platform: {}".format(platform.platform()))
print("Tensorflow version: {}".format(tensorflow.__version__))
print("Keras version: {}".format(keras.__version__))
%matplotlib inline
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np
from IPython.display import Image
from keras.models import Sequential
from keras.layers import Dense
# 構建模型
model = Sequential([Dense(2, input_shape=(1,)), Dense(1)])
當然我們也可以一層一層分段添加上去
from keras.models import Sequential
from keras.layers import Dense
# 構建模型
model = Sequential()
model.add(Dense(2, input_shape=(1,)))
model.add(Dense(1))
Keras函數式(functional)API為構建網絡模型提供了更為靈活的方式。
它允許您定義多個輸入或輸出模型以及共享圖層的模型。除此之外,它允許您定義動態(ad-hoc)的非周期性(acyclic)網絡圖。
模型是通過創建層的實例(layerinstances)并將它們直接相互連接成對來定義的,然后定義一個模型(model)來指定那些層是要作為這個模型的輸入和輸出。
讓我們依次看看Keras功能(functional)API的三個獨特特性:
與Sequential模型不同,您必須創建獨立的Input層對象的instance并定義輸入數據張量的維度形狀(tensor shape)。
輸入層采用一個張量形狀參數(tensorshape),它是一個tuple,用于宣吿輸入張量的維度。
例如: 我們要把MNIST的每張圖像(28×28)打平成一個一維(784)的張量做為一個多層感知器(MLP)的Input
from keras.layers import Input
mnist_input = Input(shape=(784,))
模型中的神經層是成對連接的,就像是一個樂高積木一樣有一面是凸一面是凹, 一個神經層的輸出會接到另一個神經層的輸入。
這是通過在定義每個新神經層時指定輸入的來源來完成的。使用括號表示法,以便在創建圖層之后,指定作為輸入的神經層。
我們用一個簡短的例子來說明這一點。我們可以像上面那樣創建輸入層,然后創建一個隱藏層作為密集層,它接收來自輸入層的輸入。
from keras.layers import Input
from keras.layers import Dense
mnist_input = Input(shape=(784,))
hidden = Dense(512)(mnist_input)
正是這種逐層連接的方式賦予功能性(functional)API靈活性。您可以看到開始一些動態的神經網絡是多么容易。
在創建所有模型圖層并將它們連接在一起之后,您必須定義一個模型(Model)對象的instance。
與SequentialAPI一樣,這個模型是您可以用于總結(summarize),擬合(fit),評估(evaluate)和預測(predict)。
Keras提供了一個Model類別,您可以使用它從創建的圖層創建模型的instance。它會要求您只指定整個模型的第一個輸入層和最后一個的輸出層。例如:
from keras.layers import Input
from keras.layers import Dense
from keras.models import Model
mnist_input = Input(shape=(784,))
hidden = Dense(512)(mnist_input)
model = Model(inputs=mnist_input, outputs=hidden)
現在我們已經知道了Keras函數式API的所有關鍵部分,讓我們通過定義一系列不同的模型來開展工作。
每個范例都是可以執行的,并打印網絡結構及產生網絡圖表。我建議你為自己的模型做這個事情,以明確你所定義的是什么樣的網絡結構。
我希望這些范例能夠在將來使用函數式API定義自己的模型時為您提供模板。
在開始使用函數式API時,最好先看一些標準的神經網絡模型是如何定義的。在本節中,我們將著眼于定義一個簡單的多層感知器(MLP),卷積神經網絡(CNN)和遞歸神經網絡(RNN)。這些范例將為以后了解更復雜的網絡構建提供基礎。
用pydot和graphviz時總是出現錯誤,按照這個方法順利解決。
Error description:
OSError: pydot
failed to call GraphViz.Please install GraphViz (https://www.graphviz.org/) and ensure that its executables are in the $PATH.
Environment: Anaconda, Python 3.6.7, Keras 2.2.4
Solution:
conda install python-graphviz
conda install pydot-ng pydot
if not work
also do:
1 . Download and install graphviz-2.38.msi from
https://graphviz.gitlab.io/_pages/Download/Download_windows.html
Double-click to install graphviz-2.38.msi using default path
2 . Set the path variable
(a) Control Panel > System and Security > System > Advanced System Settings > Environment Variables > Path > Edit
(b) add ‘C:\Program Files (x86)\Graphviz2.38\bin’
3. Restart python coding environment
eferences:
https://www.experts-exchange.com/questions/29106033/Pydot-having-problems-with-GraphViz.html
https://github.com/ContinuumIO/anaconda-issues/issues/1666
讓我們來定義了一個多類別分類(multi-class classification)的多層感知器(MLP)模型。該模型有784個輸入,3個隱藏層,512,216和128個隱藏神經元,輸出層有10個輸出。在每個隱藏層中使用relu
激活函數,并且在輸出層中使用softmax
激活函數進行多類別分類。
# 多層感知器(MLP)模型
from keras.models import Model
from keras.layers import Input, Dense
from keras.utils import plot_model
mnist_input = Input(shape=(784,), name='input')
hidden1 = Dense(512, activation='relu', name='hidden1')(mnist_input)
hidden2 = Dense(216, activation='relu', name='hidden2')(hidden1)
hidden3 = Dense(128, activation='relu', name='hidden3')(hidden2)
output = Dense(10, activation='softmax', name='output')(hidden3)
model = Model(inputs=mnist_input, outputs=output)
# 打印網絡結構
model.summary()
# 產生網絡拓撲圖
plot_model(model, to_file='multilayer_perceptron_graph.png')
# 秀出網絡拓撲圖
Image('multilayer_perceptron_graph.png')
我們將定義一個用于圖像分類的卷積神經網絡(convolutional neural network)。
該模型接收灰階的28×28圖像作為輸入,然后有一個作為特征提取器的兩個卷積和池化層的序列,
然后是一個完全連接層來解釋特征,并且具有用于10類預測的softmax
激活的輸出層。
# 卷積神經網絡(CNN)
from keras.models import Model
from keras.layers import Input, Dense
from keras.layers.convolutional import Conv2D
from keras.layers.pooling import MaxPool2D
from keras.utils import plot_model
mnist_input = Input(shape=(28, 28, 1), name='input')
conv1 = Conv2D(128, kernel_size=4, activation='relu', name='conv1')(mnist_input)
pool1 = MaxPool2D(pool_size=(2, 2), name='pool1')(conv1)
conv2 = Conv2D(64, kernel_size=4, activation='relu', name='conv2')(pool1)
pool2 = MaxPool2D(pool_size=(2, 2), name='pool2')(conv2)
hidden1 = Dense(64, activation='relu', name='hidden1')(pool2)
output = Dense(10, activation='softmax', name='output')(hidden1)
model = Model(inputs=mnist_input, outputs=output)
# 打印網絡結構
model.summary()
# 產生網絡拓撲圖
plot_model(model, to_file='convolutional_neural_network.png')
# 秀出網絡拓撲圖
Image('convolutional_neural_network.png')
我們將定義一個長期短期記憶(LSTM)遞歸神經網絡用于圖像分類。該模型預期一個特征的784個時間步驟作為輸入。該模型具有單個LSTM隱藏層以從序列中提取特征, 接著是完全連接的層來解釋LSTM輸出,接著是用于進行10類別預測的輸出層。
# 遞歸神經網絡(RNN)
from keras.models import Model
from keras.layers import Input, Dense
from keras.layers.recurrent import LSTM
from keras.utils import plot_model
mnist_input = Input(shape=(784, 1), name='input') # 把每一個像素想成是一序列有前後關係的time_steps
lstm1 = LSTM(128, name='lstm1')(mnist_input)
hidden1 = Dense(128, activation='relu', name='hidden1')(lstm1)
output = Dense(10, activation='softmax', name='output')(hidden1)
model = Model(inputs=mnist_input, outputs=output)
# 打印網絡結構
model.summary()
# 產生網絡拓撲圖
plot_model(model, to_file='recurrent_neural_network.png')
# 秀出網絡拓撲圖
Image('recurrent_neural_network.png')
多個神經層可以共享一個神經層的輸出來當成輸入。
例如,一個輸入可能可以有多個不同的特征提取層,或者多個神經層用于解釋特征提取層的輸出。
我們來看這兩個例子。
我們定義具有不同大小的內核的多個卷積層來解釋圖像輸入。
該模型使用28×28像素的灰階圖像。有兩個CNN特征提取子模型共享這個輸入;第一個具有4的內核大小和第二個8的內核大小。
這些特征提取子模型的輸出被平坦化(flatten)為向量(vector),并且被串連成一個長向量, 然后被傳遞到完全連接的層以用于在最終輸出層之前進行10類別預測。
# 共享輸入層
from keras.models import Model
from keras.layers import Input, Dense, Flatten
from keras.layers.convolutional import Conv2D
from keras.layers.pooling import MaxPool2D
from keras.layers.merge import concatenate
from keras.utils import plot_model
# 輸入層
mnist_input = Input(shape=(28, 28, 1), name='input')
# 第一個特徵提取層
conv1 = Conv2D(32, kernel_size=4, activation='relu', name='conv1')(mnist_input) # <-- 看這裡
pool1 = MaxPool2D(pool_size=(2, 2), name='pool1')(conv1)
flat1 = Flatten()(pool1)
# 第二個特徵提取層
conv2 = Conv2D(16, kernel_size=8, activation='relu', name='conv2')(mnist_input) # <-- 看這裡
pool2 = MaxPool2D(pool_size=(2, 2), name='pool2')(conv2)
flat2 = Flatten()(pool2)
# 把兩個特徵提取層的結果併起來
merge = concatenate([flat1, flat2])
# 進行全連結層
hidden1 = Dense(64, activation='relu', name='hidden1')(merge)
# 輸出層
output = Dense(10, activation='softmax', name='output')(hidden1)
# 以Model來組合整個網絡
model = Model(inputs=mnist_input, outputs=output)
# 打印網絡結構
model.summary()
# plot graph
plot_model(model, to_file='shared_input_layer.png')
# 秀出網絡拓撲圖
Image('shared_input_layer.png')
我們將使用兩個并行子模型來解釋用于序列分類的LSTM特征提取器的輸出。
該模型的輸入是1個特征的784個時間步長。具有10個存儲單元的LSTM層解釋這個序列。第一種解釋模型是淺層單連通層,第二層是深層3層模型。兩個解釋模型的輸出連接成一個長向量,傳遞給用于進行10類別分類預測的輸出層。
from keras.models import Model
from keras.layers import Input, Dense
from keras.layers.recurrent import LSTM
from keras.layers.merge import concatenate
from keras.utils import plot_model
# 輸入層
mnist_input = Input(shape=(784, 1), name='input') # 把每一個像素想成是一序列有前後關係的time_steps
# 特徵提取層
extract1 = LSTM(128, name='lstm1')(mnist_input)
# 第一個解釋層
interp1 = Dense(10, activation='relu', name='interp1')(extract1) # <-- 看這裡
# 第二個解釋層
interp21 = Dense(64, activation='relu', name='interp21')(extract1) # <-- 看這裡
interp22 = Dense(32, activation='relu', name='interp22')(interp21)
interp23 = Dense(16, activation='relu', name='interp23')(interp22)
# 把兩個特徵提取層的結果併起來
merge = concatenate([interp1, interp23], name='merge')
# 輸出層
output = Dense(10, activation='softmax', name='output')(merge)
# 以Model來組合整個網絡
model = Model(inputs=mnist_input, outputs=output)
# 打印網絡結構
model.summary()
# plot graph
plot_model(model, to_file='shared_feature_extractor.png')
# 秀出網絡拓撲圖
Image('shared_feature_extractor.png')
函數式(functional)API也可用于開發具有多個輸入或多個輸出的模型的更復雜的模型。
我們將開發一個圖像分類模型,將圖像的兩個版本作為輸入,每個圖像的大小不同。特別是一個灰階的64×64版本和一個32×32的彩色版本。分離的特征提取CNN模型對每個模型進行操作,然后將兩個模型的結果連接起來進行解釋和最終預測。
請注意,在創建Model()實例(instance)時,我們將兩個輸入圖層定義為一個數組(array)。
# 多輸入模型
from keras.models import Model
from keras.layers import Input, Dense, Flatten
from keras.layers.convolutional import Conv2D
from keras.layers.pooling import MaxPool2D
from keras.layers.merge import concatenate
from keras.utils import plot_model
# 第一個輸入層
img_gray_bigsize = Input(shape=(64, 64, 1), name='img_gray_bigsize')
conv11 = Conv2D(32, kernel_size=4, activation='relu', name='conv11')(img_gray_bigsize)
pool11 = MaxPool2D(pool_size=(2, 2), name='pool11')(conv11)
conv12 = Conv2D(16, kernel_size=4, activation='relu', name='conv12')(pool11)
pool12 = MaxPool2D(pool_size=(2, 2), name='pool12')(conv12)
flat1 = Flatten()(pool12)
# 第二個輸入層
img_rgb_smallsize = Input(shape=(32, 32, 3), name='img_rgb_smallsize')
conv21 = Conv2D(32, kernel_size=4, activation='relu', name='conv21')(img_rgb_smallsize)
pool21 = MaxPool2D(pool_size=(2, 2), name='pool21')(conv21)
conv22 = Conv2D(16, kernel_size=4, activation='relu', name='conv22')(pool21)
pool22 = MaxPool2D(pool_size=(2, 2), name='pool22')(conv22)
flat2 = Flatten()(pool22)
# 把兩個特徵提取層的結果併起來
merge = concatenate([flat1, flat2])
# 用隱藏的全連結層來解釋特徵
hidden1 = Dense(128, activation='relu', name='hidden1')(merge)
hidden2 = Dense(64, activation='relu', name='hidden2')(hidden1)
# 輸出層
output = Dense(10, activation='softmax', name='output')(hidden2)
# 以Model來組合整個網絡
model = Model(inputs=[img_gray_bigsize, img_rgb_smallsize], outputs=output)
# 打印網絡結構
model.summary()
# plot graph
plot_model(model, to_file='multiple_inputs.png')
# 秀出網絡拓撲圖
Image('multiple_inputs.png')
我們將開發一個模型,進行兩種不同類型的預測。給定一個特征的784個時間步長的輸入序列,該模型將對該序列進行分類并輸出具有相同長度的新序列。
LSTM層解釋輸入序列并返回每個時間步的隱藏狀態。第一個輸出模型創建一個堆棧的LSTM,解釋這些特征,并進行多類別預測。第二個輸出模型使用相同的輸出層對每個輸入時間步進行多類別預測。
# 多輸出模型
from keras.models import Model
from keras.layers import Input, Dense
from keras.layers.recurrent import LSTM
from keras.layers.wrappers import TimeDistributed
from keras.utils import plot_model
# 輸入層
mnist_input = Input(shape=(784, 1), name='input') # 把每一個像素想成是一序列有前後關係的time_steps
# 特徵擷取層
extract = LSTM(64, return_sequences=True, name='extract')(mnist_input)
# 分類輸出
class11 = LSTM(32, name='class11')(extract)
class12 = Dense(32, activation='relu', name='class12')(class11)
output1 = Dense(10, activation='softmax', name='output1')(class12)
# 序列輸出
output2 = TimeDistributed(Dense(10, activation='softmax'), name='output2')(extract)
# 以Model來組合整個網絡
model = Model(inputs=mnist_input, outputs=[output1, output2])
# 打印網絡結構
model.summary()
# plot graph
plot_model(model, to_file='multiple_outputs.png')
# 秀出網絡拓撲圖
以上有一些小技巧可以幫助你充分利用函數式API定義自己的模型。
* 一致性的變量名稱命名
對輸入(可見)和輸出神經層(輸出)使用相同的變量名,甚至可以使用隱藏層(hidden1,hidden2)。這將有助于正確地將許多的神經層連接在一起。
* 檢查圖層摘要
始終打印模型摘要并查看圖層輸出,以確保模型如您所期望的那樣連接在一起。
* 查看網絡拓樸圖像
總是盡可能地創建網絡拓樸圖像,并審查它,以確保一切按照你的意圖連接在一起。
* 命名圖層
您可以為圖層指定名稱,這些名稱可以讓你的模型圖形摘要和網絡拓樸圖像更容易被解讀。例如:Dense(1,name =’hidden1’)。
* 獨立子模型
考慮分離出子模型的發展,并最終將子模型結合在一起。
文章轉自微信公眾號@兀知筆記