1. 程式人生 > >卷積神經網路之早期架構

卷積神經網路之早期架構

文章目錄

早期架構

文件存放更新地址:https://github.com/lartpang/ML_markdown

文章書寫匆忙,有些使用了網上其他朋友的文字以及圖片,但是沒有及時複製對應的連結,在此深表歉意,以及深深的感謝。
如有朋友看到了對應的出處,或者作者發現,可以留言,小弟馬上修改,新增引用。

lenet5架構

是一個開創性的工作,因為影象的特徵是分佈在整個影象當中的,並且學習引數利用卷積在相同引數的多個位置中提取相似特性的一種有效方法。迴歸到1998年當時沒有GPU來幫助訓練,甚至CPU速度都非常慢。

因此,對比使用每個畫素作為一個單獨的輸入的多層神經網路,Lenet5能夠節省引數和計算是一個關鍵的優勢。

lenet5論文中提到,全卷積不應該被放在第一層,因為影象中有著高度的空間相關性,並利用影象各個畫素作為單獨的輸入特徵不會利用這些相關性。

因此有了CNN的三個特性了:

  1. 區域性感知
  2. 下采樣
  3. 權值共享

img

小結

  • 每個卷積層包含三個部分:卷積、池化和非線性啟用函式
  • 使用卷積提取空間特徵
  • 降取樣(Subsample)的平均池化層(Average?Pooling)
  • 雙曲正切(Tanh)或S型(Sigmoid)的啟用函式
  • MLP作為最後的分類器
  • 層與層之間的稀疏連線減少計算複雜度

LeNet是卷積神經網路的祖師爺LeCun在1998年提出,用於解決手寫數字識別的視覺任務。自那時起,CNN的最基本的架構就定下來了:卷積層、池化層、全連線層。如今各大深度學習框架中所使用的LeNet都是簡化改進過的LeNet-5(-5表示具有5個層),和原始的LeNet有些許不同,比如把啟用函式改為了現在很常用的ReLu。

跟當前常用的cnn結構已經基本一致了。目前的cnn一般是[CONV - RELU - POOL],這裡的[CONV - POOL -
RELU],不過基本沒什麼影響。文章的啟用函式是sigmoid,目前影象一般用tanh,relu,leakly
relu較多,實踐證明,一般比sigmoid好。後面一般接全連線層FC,這裡也是一致的。目前,多分類最後一層一般用softmax,文中的與此不太相同。

總的來說LeNet5架構把人們帶入深度學習領域,值得致敬。從2010年開始近幾年的神經網路架構大多數都是基於LeNet的三大特性。

程式碼

def preprocess_image(image, output_height, output_width, is_training):
  """Preprocesses the given image.

  Args:
    image: A `Tensor` representing an image of arbitrary size.
    output_height: The height of the image after preprocessing.
    output_width: The width of the image after preprocessing.
    is_training: `True` if we're preprocessing the image for training and
      `False` otherwise.

  Returns:
    A preprocessed image.
  """
  image = tf.to_float(image)
  image = tf.image.resize_image_with_crop_or_pad(
      image, output_width, output_height)
  image = tf.subtract(image, 128.0)
  image = tf.div(image, 128.0)
  return image

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. If 0 or None, the logits
      layer is omitted and the input features to the logits layer are returned
      instead.
    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:
     net: a 2D Tensor with the logits (pre-softmax activations) if num_classes
      is a non-zero integer, or the inon-dropped-out nput to the logits layer
      if num_classes is 0 or None.
    end_points: a dictionary from components of the network to the corresponding
      activation.
  """
  end_points = {}

  with tf.variable_scope(scope, 'LeNet', [images]):
    net = end_points['conv1'] = slim.conv2d(images, 32, [5, 5], scope='conv1')
    net = end_points['pool1'] = slim.max_pool2d(net, [2, 2], 2, scope='pool1')
    net = end_points['conv2'] = slim.conv2d(net, 64, [5, 5], scope='conv2')
    net = end_points['pool2'] = slim.max_pool2d(net, [2, 2], 2, scope='pool2')
    net = slim.flatten(net)
    end_points['Flatten'] = net

    net = end_points['fc3'] = slim.fully_connected(net, 1024, scope='fc3')
    if not num_classes:
      return net, end_points
    net = end_points['dropout3'] = slim.dropout(
        net, dropout_keep_prob, is_training=is_training, scope='dropout3')
    logits = end_points['Logits'] = slim.fully_connected(
        net, num_classes, activation_fn=None, scope='fc4')

  end_points['Predictions'] = prediction_fn(logits, scope='Predictions')

  return logits, end_points
lenet.default_image_size = 28

Dan Ciresan Net

2010年Dan Claudiu Ciresan和Jurgen Schmidhuber發表了一個GPU神經網路。論文裡面證明了使用 NVIDIA GTX 280 GPU之後能夠處理高達9層的神經網路。

從此之後,Nvidia公司的股價開始不斷攀升,深度學習也越來越為人們所熟知。

後續幾種網路的概要

http://www.infoq.com/cn/articles/cnn-and-imagenet-champion-model-analysis

img

我們簡單回顧卷積神經網路的歷史,上圖所示大致勾勒出最近幾十年卷積神經網路的發展方向。

  • Perceptron(感知機)於1957年由Frank?Resenblatt提出,而Perceptron不僅是卷積網路,也是神經網路的始祖。

  • Neocognitron(神經認知機)是一種多層級的神經網路,由日本科學家Kunihiko Fukushima於20世紀80年代提出,具有一定程度的視覺認知的功能,並直接啟發了後來的卷積神經網路。

  • LeNet-5由CNN之父Yann?LeCun於1997年提出,首次提出了多層級聯的卷積結構,可對手寫數字進行有效識別。可以看到前面這三次關於卷積神經網路的技術突破,間隔時間非常長,需要十餘年甚至更久才出現一次理論創新。

  • 而後於2012年,Hinton的學生Alex依靠8層深的卷積神經網路一舉獲得了ILSVRC?2012比賽的冠軍,瞬間點燃了卷積神經網路研究的熱潮。AlexNet成功應用了ReLU啟用函式、Dropout、最大覆蓋池化、LRN層、GPU加速等新技術,並啟發了後續更多的技術創新,卷積神經網路的研究從此進入快車道。

    在AlexNet之後,我們可以將卷積神經網路的發展分為兩類,一類是網路結構上的改進調整(圖6-18中的左側分支),另一類是網路深度的增加(圖18中的右側分支)。

  • 網路結構上的改進調整

    • 2013年,顏水成教授的Network in Network工作首次發表,優化了卷積神經網路的結構,並推廣了1*1的卷積結構。
    • 在改進卷積網路結構的工作中,後繼者還有2014年的Google Inception Net V1,提出了Inception Module這個可以反覆堆疊的高效的卷積網路結構,並獲得了當年ILSVRC比賽的冠軍。
    • 2015年初的Inception V2提出了Batch Normalization,大大加速了訓練過程,並提升了網路效能。
    • 2015年年末的Inception V3則繼續優化了網路結構,提出了Factorization in Small Convolutions的思想,分解大尺寸卷積為多個小卷積乃至一維卷積。
  • 網路深度的增加

    • 2014年,ILSVRC比賽的亞軍VGGNet全程使用3*3的卷積,成功訓練了深達19層的網路,當年的季軍MSRA-Net也使用了非常深的網路。
    • 2015年,微軟的ResNet成功訓練了152層深的網路,一舉拿下了當年ILSVRC比賽的冠軍,top-5錯誤率降低至3.46%。

我們可以看到,自AlexNet於2012年提出後,深度學習領域的研究發展極其迅速,基本上每年甚至每幾個月都會出現新一代的技術。新的技術往往伴隨著新的網路結構,更深的網路的訓練方法等,並在影象識別等領域不斷創造新的準確率記錄。