Tensorflow的網路模型搭建

Tensorflow的網路模型搭建

1.0 引言

神經網路模型的搭建在深度學習中必不可少。從2012年至今湧現出了很多優秀的網路,例如vgg,inception系列。所以本文主要討論如何在tensorflow框架下去搭建自己的網路。(基於tensorflow1.10穩定版本)

在tensorflow框架下,有很多已經成熟的庫可以搭建網路,例如tf.keras,tf.nn,tf.layers,tensorlayer等等。如此多的庫讓人眼花繚亂,其實甭管黑貓白貓,抓住耗子的就是好貓。但是你挑的這隻貓不僅要既能過硬,還需要壽命長啊。換句話說,這些庫都能用,但是最好挑選社區強大,官方支持強大的庫,防止開發者中途跳票。綜上所述,個人推薦tensorflow的親兒子系列tf.keras,tf.nn,tf.layers-最為穩妥且穩定。

再來說說這三種庫的區別。

  • tf.nn:最底層的函數,其他各種庫可以說都是基於這個底層庫來進行擴展的。
  • tf.layers:比tf.nn更高級的庫,對tf.nn進行了多方位功能的擴展。用程序員的話來說,就是用tf.nn造的輪子。最大的特點就是庫中每個函數都有相應的類(函數名為大寫,看了下底層源碼,是從kears那遷移過來的)
  • tf.keras:如果說tf.layers是輪子,那麼keras可以說是汽車。tf.keras是基於tf.layers和tf.nn的高度封裝。

每個庫有每個庫的優勢,tf.nn和tf.layers靈活性相對較高,如果需要對底層進行很多操作,這兩個庫的優勢就會很明顯。但是如果工業上想搭建已經很成熟的網路並進行訓練,那麼keras相對來說會更加容易一些。具體需要在實際運用中去體會。 綜上所述,這幾種庫都可以運用,都很不錯,具體看運用背景。

2.0 構建網路

接下來我會討論構建網路的一般步驟。以構建CNN為例。

2.1 Convolution

對於卷積網路來說,卷積操作是基本操作之一。

  • tf.nn

在nn庫中,根據不同的卷積方式會對應不同的卷積函數 。

tf.nn.convolution 是最基本的,

tf.nn.conv2d 能夠對二維的輸入數據進行卷積(共享卷積參數),

tf.nn.depthwise_conv2d 也能夠對二維的輸入數據進行卷積(不共享卷積參數),

tf.nn.separable_conv2d 對輸入數據進行不共享參數的方式進行卷積後,再進行一次卷積,

tf.nn.conv2d_transpose 也就是轉置卷積(反卷積)。

tf.nn.conv1d 類似於二維卷積,用來計算給定三維輸入和過濾器情況下的一維卷積。

tf.nn.conv3d 與二維卷積類似,用來計算給定五維輸入和過濾器的情況下的三維卷積.

具體的測試函數如下:

# - * - coding: utf - 8 -*-
import tensorflow as tf
import os
import numpy as np

os.environ[TF_CPP_MIN_LOG_LEVEL] = 2

# tf.nn.convolution
# 計算N維卷積的和

input_data = tf.Variable(np.random.rand(10, 9, 9, 3), dtype=np.float32)
filter_data = tf.Variable(np.random.rand(2, 2, 3, 2), dtype=np.float32)
y = tf.nn.convolution(input_data, filter_data, strides=[1, 1], padding=SAME)

print(1. tf.nn.convolution : , y)
# 1. tf.nn.convolution : Tensor("convolution:0", shape=(10, 9, 9, 2), dtype=float32)

# tf.nn.conv2d
# 對一個思維的輸入數據 input 和四維的卷積核filter 進行操作,然後對輸入的數據進行二維的卷積操作,得到卷積之後的結果
input_data = tf.Variable(np.random.rand(10, 9, 9, 3), dtype=np.float32)
filter_data = tf.Variable(np.random.rand(2, 2, 3, 2), dtype=np.float32)
y = tf.nn.conv2d(input_data, filter_data, strides=[1, 1, 1, 1], padding=SAME)

print(2. tf.nn.conv2d : , y)
#2. tf.nn.conv2d : Tensor("Conv2D:0", shape=(10, 9, 9, 2), dtype=float32)

# tf.nn.depthwise_conv2d
# input 的數據維度 [batch ,in_height,in_wight,in_channels]
# 卷積核的維度是 [filter_height,filter_heught,in_channel,channel_multiplierl]
# 講不通的卷積和獨立的應用在in_channels 的每一個通道上(從通道 1 到通道channel_multiplier)
# 然後將所有結果進行匯總,輸出通道的總數是,in_channel * channel_multiplier

input_data = tf.Variable(np.random.rand(10, 9, 9, 3), dtype=np.float32)
filter_data = tf.Variable(np.random.rand(2, 2, 3, 2), dtype=np.float32)

y = tf.nn.depthwise_conv2d(input_data, filter_data, strides=[1, 1, 1, 1], padding=SAME)
print(3. tf.nn.depthwise_conv2d : , y)

# tf.nn.separable_conv2d
# 利用幾個分離的卷積核去做卷積,在該函數中,將應用一個二維的卷積核,在每個通道上,以深度channel_multiplier進行卷積
input_data = tf.Variable(np.random.rand(10, 9, 9, 3), dtype=np.float32)
depthwise_filter = tf.Variable(np.random.rand(2, 2, 3, 5), dtype=np.float32)
poinwise_filter = tf.Variable(np.random.rand(1, 1, 15, 20), dtype=np.float32)
# out_channels >= channel_multiplier * in_channels
y = tf.nn.separable_conv2d(input_data, depthwise_filter=depthwise_filter, pointwise_filter=poinwise_filter,
strides=[1, 1, 1, 1], padding=SAME)
print(4. tf.nn.separable_conv2d : , y)

# 計算Atrous卷積,又稱孔卷積或者擴張卷積
input_data = tf.Variable(np.random.rand(1, 5, 5, 1), dtype=np.float32)
filters = tf.Variable(np.random.rand(3, 3, 1, 1), dtype=np.float32)
y = tf.nn.atrous_conv2d(input_data, filters, 2, padding=SAME)
print(5. tf.nn.atrous_conv2d : , y)

# 在解卷積網路(deconvolutional network) 中有時被稱為反卷積,但實際上是conv2d的轉置,而不是實際的反卷積
x = tf.random_normal(shape=[1, 3, 3, 1])
kernal = tf.random_normal(shape=[2, 2, 3, 1])
y = tf.nn.conv2d_transpose(x, kernal, output_shape=[1, 5, 5, 3], strides=[1, 2, 2, 1], padding=SAME)
print(6. tf.nn.conv2d_transpose : , y)

# 與二維卷積類似,用來計算給定三維輸入和過濾器的情況下的一維卷積.
# 不同的是,它的輸入維度為 3,[batch,in_width,in_channels].
# 卷積核的維度也是三維,[filter_height,in_channel,channel_multiplierl]
# stride 是一個正整數,代表一定每一步的步長
input_data = tf.Variable(np.random.rand(1, 5, 1), dtype=np.float32)
filters = tf.Variable(np.random.rand(3, 1, 3), dtype=np.float32)
y = tf.nn.conv1d(input_data, filters, stride=2, padding=SAME)
print(7. tf.nn.conv1d : , y)

# 與二維卷積類似,用來計算給定五維輸入和過濾器的情況下的三維卷積.
# 不同的是,它的輸入維度為 5,[batch,in_depth,in_height,in_width,in_channels].
# 卷積核的維度也是三維,[filter_depth,filter_height,in_channel,channel_multiplierl]
# stride 相較二維卷積多了一維,變為[strides_batch,strides_depth,strides_height,strides_width,strides_channel],必須保證strides[0] = strides[4] =1
input_data = tf.Variable(np.random.rand(1, 2, 5, 5, 1), dtype=np.float32)
filters = tf.Variable(np.random.rand(2, 3, 3, 1, 3), dtype=np.float32)
y = tf.nn.conv3d(input_data, filters, strides=[1, 2, 2, 1, 1], padding=SAME)
print(8. tf.nn.conv3d : , y)

# 與conv2d_transpose 二維反卷積類似
# 在解卷積網路(deconvolutional network) 中有時被稱為反卷積,但實際上是conv3d的轉置,而不是實際的反卷積
x = tf.random_normal(shape=[2, 1, 3, 3, 1])
kernal = tf.random_normal(shape=[2, 2, 2, 3, 1])
y = tf.nn.conv3d_transpose(x, kernal, output_shape=[2, 1, 5, 5, 3], strides=[1, 2, 2, 2, 1], padding=SAME)
print(9. tf.nn.conv3d_transpose : , y)

最後的輸出結果如下:

1. tf.nn.convolution : Tensor("convolution:0", shape=(10, 9, 9, 2), dtype=float32)
2. tf.nn.conv2d : Tensor("Conv2D:0", shape=(10, 9, 9, 2), dtype=float32)
3. tf.nn.depthwise_conv2d : Tensor("depthwise:0", shape=(10, 9, 9, 6), dtype=float32)
4. tf.nn.separable_conv2d : Tensor("separable_conv2d:0", shape=(10, 9, 9, 20), dtype=float32)
5. tf.nn.atrous_conv2d : Tensor("convolution_1/BatchToSpaceND:0", shape=(1, 5, 5, 1), dtype=float32)
6. tf.nn.conv2d_transpose : Tensor("conv2d_transpose:0", shape=(1, 5, 5, 3), dtype=float32)
7. tf.nn.conv1d : Tensor("conv1d/Squeeze:0", shape=(1, 3, 3), dtype=float32)
8. tf.nn.conv3d : Tensor("Conv3D:0", shape=(1, 1, 3, 5, 3), dtype=float32)
9. tf.nn.conv3d_transpose : Tensor("conv3d_transpose:0", shape=(2, 1, 5, 5, 3), dtype=float32)

  • tf.layers

在layers庫中,就只有最為常見的卷積方式。

tf.layers.conv2d: 二維卷積層,layers庫中的卷積函數有更多的參數選擇,例如激活函數的選擇,參數初始化方式等。

tf.layers.separable_conv2d : 和nn類似,深度卷積

tf.layers.conv2d_transpose: 二維反卷積層

tf.layers.conv1d: 一維卷積層

tf.layers.conv3d: 三維卷積層

還有一些函數可以參見官方文檔。

  • tf.keras.layers

tf.keras.layers.Conv2D:大部分參數和 tf.layers 類似,但是比較關鍵的地方就是keras取消了trainable這個參數,意味著keras無法控制層的參數更新與否,默認是更新參數的,這樣的話不太好進行freeze操作。

其他大部分函數也都和其他庫函數類似,再次不贅述了。

2.2 Pooling

  • tf.nn

tf.nn.pool:池化操作的基本函數,後面的函數都可以根據這個函數演變。具體參考

tf.nn.max_pooltf.nn.max_pool3d: 最大值池化操作,具體參數可見官方文檔。

tf.nn.avg_pooltf.nn.avg_pool3d:平均值池化操作,具體參數可見官方文檔。

  • tf.layers

tf.layers.max_pooling1dtf.layers.max_pooling2dtf.layers.max_pooling3d:最大池化操作。

tf.layers.average_pooling1dtf.layers.average_pooling2dtf.layers.average_pooling3d:平均池化操作。

  • tf.keras

tf.keras.layers.MaxPool1Dtf.keras.layers.MaxPool2Dtf.keras.layers.MaxPool3D: 最大池化操作。

tf.keras.layers.AveragePool1Dtf.keras.layers.AveragePool2Dtf.keras.layers.AveragePool3D: 平均池化操作。

tf.keras.layers.MaxPool1Dtf.keras.layers.MaxPool2Dtf.keras.layers.MaxPool3D: 最大池化操作。

tf.keras.layers.GlobalMaxPool1Dtf.keras.layers.GlobalMaxPool2Dtf.keras.layers.GlobalMaxPool3D: 時域信號的全局最大池化操作。

2.3 Full connect

  • tf.nn

tf.nn.xw_plus_b:利用公式計算全連接層的輸出。需要自己定義weight和bias。底層函數。

tf.nn.relu_layer: 激活函數為relu的全連接層,nn庫中全連接的函數不多

tf.nn.softmax: softmax分類層。

tf.nn.softmax_cross_entropy_with_logitstf.nn.softmax_cross_entropy_with_logits_v2:分類層,並利用交叉熵計算label與預測值的loss。

還有一些其他函數,詳見官方文檔。

  • tf.layers

tf.layers.dense:全連接層,參數包含有激活函數等,具體參見官方文檔。在初始化dense函數時,常常利用nn庫中的激活函數。

tf.layers.flatten:將多維tensor轉變為一維的,以便全連接層進行操作。

  • tf.keras

·tf.keras.layers.Dense:全連接層。

tf.keras.layers.Flatten:將多維tensor轉變為一維的,以便全連接層進行操作。

tf.keras.layers.LeakyReLUtf.keras.layers.PReLU:這些都是常見激活函數。

2.4 activation

  • tf.nn

tf.nn.relu:最基本的激活函數

tf.nn.relu6:加入上限的激活函數。參見

Convolutional Deep Belief Networks on CIFAR-10?

www.cs.utoronto.ca

tf.nn.crelu:具體理論參見

Understanding and Improving Convolutional Neural Networks via Concatenated Rectified Linear Units?

proceedings.mlr.press

tf.nn.elu:參見

FAST AND ACCURATE DEEP NETWORK LEARNING BY EXPONENTIAL LINEAR UNITS (ELUS)?

arxiv.org

tf.nn.selu:推導過程長達102頁paper,作用和BN類似,具體效果還沒有實踐,所以還不能妄下結論。參見 Self-Normalizing Neural

tf.nn.leaky\_relu:參見

Rectifier Nonlinearities Improve Neural Network Acoustic Models?

pdfs.semanticscholar.org

  • tf.layers

在layer中,沒有單獨的函數,需要利用tf.nn中的函數配合使用。

  • tf.keras

keras的激活函數在tf.keras.activations中,種類與tf.nn中類似。詳見官方文檔。

2.5 initialization

  • tf.initializers :參數初始化在單獨的初始化庫中

  • tf.keras.initializers :keras庫中的初始化函數與上述類似,只不過集成到了keras庫中。

  • tf.layers:在layers庫中也有兩種初始化函數。

tf.contrib.layers.xavier_initializer,tf.contrib.layers.xavier_initializer_conv2d :使用sigmoid和tanh,最好使用xavir。

tf.contrib.layers.variance_scaling_initializer:如果使用relu,則最好使用這個。

2.6 regularization

  • tf.nn

tf.nn.dropout:丟棄層中某些參數,防止過擬合。

  • tf.layers

tf.layers.dropout:同上。

  • tf.keras

tf.keras.layers.AlphaDropout:同上。

2.7 總結

有了上述一些函數,就能構造出常見的網路模型了。在這裡只起到拋磚引玉的作用。以後遇到了其他相關函數還會更新的。

推薦閱讀:

TAG:深度學習(DeepLearning) | TensorFlow | 神經網路 |