TensorFlow学习笔记(二十六)CNN的9大模型之LeNet5的原理讲解
在機器視覺,圖像處理領域,卷積神經網絡取得了巨大的成功。本文將參考UFLDL和DEEPLEARNING.NET的教程,結合自己的理解,梳理一下卷積神經網絡的構成以及其BP算法的求解。雖然利用theano可以方便的實現LeNet5,但是不利于學習和理解卷積神經網絡,所以最后會自己動手用Python實現一個簡單的LeNet5,并嘗試利用python的PyCUDA庫進行加速。
LeNet-5共有7層(不包含輸入),每層都包含可訓練參數。
輸入圖像大小為32*32,比MNIST數據集的圖片要大一些,這么做的原因是希望潛在的明顯特征如筆畫斷點或角能夠出現在最高層特征檢測子感受野(receptive field)的中心。因此在訓練整個網絡之前,需要對28*28的圖像加上paddings(即周圍填充0)。
C1層:該層是一個卷積層。使用6個大小為5*5的卷積核對輸入層進行卷積運算,特征圖尺寸為32-5+1=28,因此產生6個大小為28*28的特征圖。這么做夠防止原圖像輸入的信息掉到卷積核邊界之外。
S2層:該層是一個池化層(pooling,也稱為下采樣層)。這里采用max_pool(最大池化),池化的size定為2*2,池化的具體過程如下圖(圖引自cs231n)
經池化后得到6個14*14的特征圖,作為下一層神經元的輸入。
C3層:該層仍為一個卷積層,我們選用大小為5*5的16種不同的卷積核。這里需要注意:C3中的每個特征圖,都是S2中的所有6個或其中幾個特征圖進行加權組合得到的。輸出為16個10*10的特征圖。
S4層:該層仍為一個池化層,size為2*2,仍采用max_pool。最后輸出16個5*5的特征圖,神經元個數也減少至16*5*5=400。
C5層:該層我們繼續用5*5的卷積核對S4層的輸出進行卷積,卷積核數量增加至120。這樣C5層的輸出圖片大小為5-5+1=1。最終輸出120個1*1的特征圖。這里實際上是與S4全連接了,但仍將其標為卷積層,原因是如果LeNet-5的輸入圖片尺寸變大,其他保持不變,那該層特征圖的維數也會大于1*1。
F6層:該層與C5層全連接,輸出84張特征圖。為什么是84?下面有論文的解釋(感謝翻譯)。
輸出層:該層與F6層全連接,輸出長度為10的張量,代表所抽取的特征屬于哪個類別。(例如[0,0,0,1,0,0,0,0,0,0]的張量,1在index=3的位置,故該張量代表的圖片屬于第三類)
此處為論文對F6層和輸出層的解釋:
輸出層由歐式徑向基函數(Euclidean Radial Basis Function)單元組成,每類一個單元,每個有84個輸入。換句話說,每個輸出RBF單元計算輸入向量和參數向量之間的歐式距離。輸入離參數向量越遠,RBF輸出的越大。一個RBF輸出可以被理解為衡量輸入模式和與RBF相關聯類的一個模型的匹配程度的懲罰項。用概率術語來說,RBF輸出可以被理解為F6層配置空間的高斯分布的負log-likelihood。給定一個輸入模式,損失函數應能使得F6的配置與RBF參數向量(即模式的期望分類)足夠接近。這些單元的參數是人工選取并保持固定的(至少初始時候如此)。這些參數向量的成分被設為-1或1。雖然這些參數可以以-1和1等概率的方式任選,或者構成一個糾錯碼,但是被設計成一個相應字符類的7*12大小(即84)的格式化圖片。這種表示對識別單獨的數字不是很有用,但是對識別可打印ASCII集中的字符串很有用。使用這種分布編碼而非更常用的“1 of N”編碼用于產生輸出的另一個原因是,當類別比較大的時候,非分布編碼的效果比較差。原因是大多數時間非分布編碼的輸出必須為0。這使得用sigmoid單元很難實現。另一個原因是分類器不僅用于識別字母,也用于拒絕非字母。使用分布編碼的RBF更適合該目標。因為與sigmoid不同,他們在輸入空間的較好限制的區域內興奮,而非典型模式更容易落到外邊。
RBF參數向量起著F6層目標向量的角色。需要指出這些向量的成分是+1或-1,這正好在F6 sigmoid的范圍內,因此可以防止sigmoid函數飽和。實際上,+1和-1是sigmoid函數的最大彎曲的點處。這使得F6單元運行在最大非線性范圍內。必須避免sigmoid函數的飽和,因為這將會導致損失函數較慢的收斂和病態問題。
tensorflow代碼實現:
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import tensorflow as tf
slim = tf.contrib.slim
def lenet(images, num_classes=10, is_training=False,
????????? dropout_keep_prob=0.5,
????????? prediction_fn=slim.softmax,
????????? scope='LeNet'):
? """Creates a variant of the LeNet model.
? Note that since the output is a set of 'logits', the values fall in the
? interval of (-infinity, infinity). Consequently, to convert the outputs to a
? probability distribution over the characters, one will need to convert them
? using the softmax function:
??????? logits = lenet.lenet(images, is_training=False)
??????? probabilities = tf.nn.softmax(logits)
??????? predictions = tf.argmax(logits, 1)
? Args:
??? images: A batch of `Tensors` of size [batch_size, height, width, channels].
??? num_classes: the number of classes in the dataset.
??? is_training: specifies whether or not we're currently training the model.
????? This variable will determine the behaviour of the dropout layer.
??? dropout_keep_prob: the percentage of activation values that are retained.
??? prediction_fn: a function to get predictions out of logits.
??? scope: Optional variable_scope.
? Returns:
??? logits: the pre-softmax activations, a tensor of size
????? [batch_size, `num_classes`]
??? end_points: a dictionary from components of the network to the corresponding
????? activation.
? """
? end_points = {}
? with tf.variable_scope(scope, 'LeNet', [images, num_classes]):
??? net = slim.conv2d(images, 32, [5, 5], scope='conv1')
??? net = slim.max_pool2d(net, [2, 2], 2, scope='pool1')
??? net = slim.conv2d(net, 64, [5, 5], scope='conv2')
??? net = slim.max_pool2d(net, [2, 2], 2, scope='pool2')
??? net = slim.flatten(net)
??? end_points['Flatten'] = net
??? net = slim.fully_connected(net, 1024, scope='fc3')
??? net = slim.dropout(net, dropout_keep_prob, is_training=is_training,
?????????????????????? scope='dropout3')
??? logits = slim.fully_connected(net, num_classes, activation_fn=None,
????????????????????????????????? scope='fc4')
? end_points['Logits'] = logits
? end_points['Predictions'] = prediction_fn(logits, scope='Predictions')
? return logits, end_points
lenet.default_image_size = 28
def lenet_arg_scope(weight_decay=0.0):
? """Defines the default lenet argument scope.
? Args:
??? weight_decay: The weight decay to use for regularizing the model.
? Returns:
??? An `arg_scope` to use for the inception v3 model.
? """
? with slim.arg_scope(
????? [slim.conv2d, slim.fully_connected],
????? weights_regularizer=slim.l2_regularizer(weight_decay),
????? weights_initializer=tf.truncated_normal_initializer(stddev=0.1),
????? activation_fn=tf.nn.relu) as sc:
??? return sc
總結
以上是生活随笔為你收集整理的TensorFlow学习笔记(二十六)CNN的9大模型之LeNet5的原理讲解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: TensorFlow学习笔记(二十五)C
- 下一篇: java中的char可以存储汉字吗?