天天看點

LeNet神經網絡

1. LeNet神經網絡介紹

LeNet神經網絡由深度學習三巨頭之一的Yan LeCun提出,他同時也是卷積神經網絡 (CNN,Convolutional Neural Networks)之父。LeNet主要用來進行手寫字元的識别與分類,并在美國的銀行中投入了使用。LeNet的實作确立了CNN的結構,現在神經網絡中的許多内容在LeNet的網絡結構中都能看到,例如卷積層,Pooling層,ReLU層。雖然LeNet早在20世紀90年代就已經提出了,但由于當時缺乏大規模的訓練資料,計算機硬體的性能也較低,是以LeNet神經網絡在處理複雜問題時效果并不理想。雖然LeNet網絡結構比較簡單,但是剛好适合神經網絡的入門學習。

2. LeNet神經網絡結構

LeNet的神經網絡結構圖如下:

LeNet神經網絡

LeNet網絡的執行流程圖如下:

LeNet神經網絡

2.1 LeNet第一層(卷積運算)

接下來我們來具體的一層層的分析LeNet的網絡結構。首先要了解圖像(輸入資料)的表示。在LeNet網絡中,輸入圖像是手寫字元,圖像的表示形式為二維資料矩陣,如下圖所示:

LeNet神經網絡

LeNet網絡除去輸入輸出層總共有六層網絡。第一層是卷積層(C1層),卷積核的大小為

5\*5

,卷積核數量為

6

個,輸入圖像的大小為

32*32

,是以輸入資料在進行第一層卷積之後,輸出結果為大小為

28*28

,數量為

6

個的feature map。卷積操作如下面兩幅圖所示:

LeNet神經網絡
LeNet神經網絡

卷積操作的過程可描述為:卷積核在圖像上滑動,滑動步長為1(即每次移動一格,水準方向從左到右,到最右邊之後再從最左邊開始,向下移動一格,重複從左到右滑動),當卷積核與圖像的一個局部塊重合時進行卷積運作,卷積計算方式為圖像塊對應位置的數與卷積核對應位置的數相乘,然後将所有相乘結果相加即為feature map的值,相乘累加之後的結果位于卷積核中心點的位置,是以如果是

3\*3

的卷積核,feature map比原圖像在水準和垂直方向上分别減少兩行(上下各一行)和兩列(左右各一列),是以上面圖像原圖為

5*5

,卷積核為

3\*3

,卷積結果大小為

3*3

,即

(5-2)*(5-2)

,如果卷積核為

5*5

,則卷積結果大小為

(5-4)*(5-4)

。上圖中的卷積核為:

LeNet神經網絡

由于神經網絡層與層的結構是通過連接配接來實作的,是以輸入層與第一個卷積層的連接配接數量應為

(32-2-2)\*(32-2-2)\*(5\*5+1)\*6= 28\*28\*156 =122304

卷積的作用主要是:通過卷積運算,可以使原信号特征增強,并且降低噪音。在圖像上卷積之後主要是減少圖像噪聲,提取圖像的特征。例如sobel算子就是一種卷積運算,主要是提取圖像的邊緣特征。卷積網絡能很好地适應圖像的平移不變性:例如稍稍移動一幅貓的圖像,它仍然是一幅貓的圖像。卷積操作保留了圖像塊之間的空間資訊,進行卷積操作的圖像塊之間的相對位置關系沒有改變。圖像在不同卷積核上進行卷積之後的效果圖如下:

LeNet神經網絡

2.2 LeNet第二層(pooling運算)

圖像在LeNet網絡上進行第一層卷積之後,結果為大小為

28*28

,數量為

6

個的feature map。LeNet網絡的第二層為pooling層(S2層),也稱為下采樣。在圖像進行中,下采樣之後,圖像的大小會變為原來的

1/4

,即水準方向和垂直方向上圖像大小分别減半。Pooling有多種,這裡主要介紹兩種,max-pooling和average-pooling。max-pooling即為從四個元素中選取一個最大的來表示這四個元素,average-pooling則用四個元素的平均值來表示這四個元素。Pooling示意圖如下:

LeNet神經網絡
LeNet神經網絡

在LeNet在進行第二層Pooling運算後,輸出結果為

14*14

6

個feature map。其連接配接數為

(2*2+1) * 14 * 14 *6 = 5880

。Pooling層的主要作用就是減少資料,降低資料緯度的同時保留最重要的資訊。在資料減少後,可以減少神經網絡的緯度和計算量,可以防止參數太多過拟合。LeNet在這一層是将四個元素相加,然後乘以參數w再加上偏置b,然後計算sigmoid值。

2.3 LeNet第三層(卷積運算)

LeNet第三層(C3層)也是卷積層,卷積核大小仍為

5*5

,不過卷積核的數量變為

16

個。第三層的輸入為

14*14

6

個feature map,卷積核大小為

5*5

,是以卷積之後輸出的feature map大小為

10*10

,由于卷積核有

16

個,是以希望輸出的feature map也為

16

個,但由于輸入有

6

個feature map,是以需要進行額外的處理。輸入的

6

個feature map與輸出的

16

個feature map的關系圖如下:

LeNet神經網絡

如上圖所示,第一個卷積核處理前三幅輸入的feature map,得出一個新的feature map。

2.4 LeNet第四層(Pooling運算)

上一層卷積運算之後,結果為大小為

10*10

16

個feature map,是以在第四層(S4層)進行pooling運算之後,輸出結果為

16

個大小為

5*5

的feature map。與S2層進行同樣的操作。

2.5 LeNet第五層

LeNet第五層是卷積層(C5層),卷積核數目為120個,大小為

5*5

,由于第四層輸出的feature map大小為

5*5

,是以第五層也可以看成全連接配接層,輸出為120個大小為

1*1

的feature map。

2.6 LeNet第六層

LeNet第六層是全連接配接層(F6層),有84個神經元(84與輸出層的設計有關),與C5層全連接配接。

2.7 LeNet各層的參數變化

  • C1

    輸入大小:32*32

    核大小:5*5

    核數目:6

    輸出大小:28*28*6

    訓練參數數目:(5*5+1)*6=156

    連接配接數:(5*5+1)*6*(32-2-2)*(32-2-2)=122304

  • S2

    輸入大小:28*28*6

    核大小:2*2

    核數目:1

    輸出大小:14*14*6

    訓練參數數目:2*6=12,2=(w,b)

    連接配接數:(2*2+1)*1*14*14*6 = 5880

  • C3

    輸入大小:14*14*6

    核大小:5*5

    核數目:16

    輸出大小:10*10*16

    訓練參數數目:6*(3*5*5+1) + 6*(4*5*5+1) + 3*(4*5*5+1) + 1*(6*5*5+1)=1516

    連接配接數:(6*(3*5*5+1) + 6*(4*5*5+1) + 3*(4*5*5+1) + 1*(6*5*5+1))*10*10=151600

  • S4

    輸入大小:10*10*16

    核大小:2*2

    核數目:1

    輸出大小:5*5*16

    訓練參數數目:2*16=32

    連接配接數:(2*2+1)*1*5*5*16=2000

  • C5

    輸入大小:5*5*16

    核大小:5*5

    核數目:120

    輸出大小:120*1*1

    訓練參數數目:(5*5*16+1)*120*1*1=48120(因為是全連接配接)

    連接配接數:(5*5*16+1)*120*1*1=48120

  • F6

    輸入大小:120

    輸出大小:84

    訓練參數數目:(120+1)*84=10164

    連接配接數:(120+1)*84=10164

3. LeNet在Caffe中的配置

LeNet神經網絡結構在Caffe中的配置檔案如下:

name: "LeNet" //神經網絡名字
//本層隻有top,沒有bottom,說明是資料輸入層
layer {
  name: "mnist" //layer名字
  type: "Data" //層的資料類型,如果是Data,說明是leveldb或lmdb
  top: "data" //top表示輸入資料,類型為data
  top: "label" //top表示輸入資料,類型為label,(data,label)配對是分類模型所必需的
  //一般訓練的時候和測試的時候,模型的層是不一樣的。該層(layer)是屬于訓練階段的層,還是屬于測試階段的層,需要用include來指定。如果沒有include參數,則表示該層既在訓練模型中,又在測試模型中。
  include {
    phase: TRAIN
  }
  //資料的預處理,可以将資料變換到定義的範圍内。如設定scale為0.00390625,實際上就是1/255, 即将輸入資料由0-255歸一化到0-1之間
  transform_param {
    scale: 0.00390625
  }
  data_param {
    source: "examples/mnist/mnist_train_lmdb"
    batch_size: 64
    backend: LMDB
  }
}
layer {
  name: "mnist"
  type: "Data"
  top: "data"
  top: "label"
  include {
    phase: TEST
  }
  transform_param {
    scale: 0.00390625
  }
  data_param {
    source: "examples/mnist/mnist_test_lmdb"
    batch_size: 100
    backend: LMDB
  }
}
layer {
  name: "conv1"
  type: "Convolution"
  bottom: "data"
  top: "conv1"
  param {
    lr_mult: 1
  }
  param {
    lr_mult: 2
  }
  convolution_param {
    num_output: 20
    kernel_size: 5
    stride: 1
    weight_filler {
      type: "xavier"
    }
    bias_filler {
      type: "constant"
    }
  }
}
layer {
  name: "pool1"
  type: "Pooling"
  bottom: "conv1"
  top: "pool1"
  pooling_param {
    pool: MAX
    kernel_size: 2
    stride: 2
  }
}
layer {
  name: "conv2"
  type: "Convolution"
  bottom: "pool1"
  top: "conv2"
  param {
    lr_mult: 1
  }
  param {
    lr_mult: 2
  }
  convolution_param {
    num_output: 50
    kernel_size: 5
    stride: 1
    weight_filler {
      type: "xavier"
    }
    bias_filler {
      type: "constant"
    }
  }
}
layer {
  name: "pool2"
  type: "Pooling"
  bottom: "conv2"
  top: "pool2"
  pooling_param {
    pool: MAX
    kernel_size: 2
    stride: 2
  }
}
layer {
  name: "ip1"
  type: "InnerProduct"
  bottom: "pool2"
  top: "ip1"
  param {
    lr_mult: 1
  }
  param {
    lr_mult: 2
  }
  inner_product_param {
    num_output: 500
    weight_filler {
      type: "xavier"
    }
    bias_filler {
      type: "constant"
    }
  }
}
layer {
  name: "relu1"
  type: "ReLU"
  bottom: "ip1"
  top: "ip1"
}
layer {
  name: "ip2"
  type: "InnerProduct"
  bottom: "ip1"
  top: "ip2"
  param {
    lr_mult: 1
  }
  param {
    lr_mult: 2
  }
  inner_product_param {
    num_output: 10
    weight_filler {
      type: "xavier"
    }
    bias_filler {
      type: "constant"
    }
  }
}
layer {
  name: "accuracy"
  type: "Accuracy"
  bottom: "ip2"
  bottom: "label"
  top: "accuracy"
  include {
    phase: TEST
  }
}
layer {
  name: "loss"
  type: "SoftmaxWithLoss"
  bottom: "ip2"
  bottom: "label"
  top: "loss"
}           

複制