久久久久在线观看_又色又爽又黄的免费视频播放_一区中文字幕_日韩电影在线播放

今日頭條 焦點資訊 營銷之道 企業報道 淘寶運營 網站建設 軟件開發 400電話
  當前位置: 首頁 » 資訊 » 網站建設 » 正文

用PaddlePaddle和Tensorflow實現經典CNN網絡GoogLeNet

放大字體  縮小字體 發布日期:2018-04-13  來源:企業800網  作者:新格網  瀏覽次數:155  【去百度看看】
核心提示:前面講了LeNet、AlexNet和Vgg,這周來講講GoogLeNet。GoogLeNet是由google的Christian Szegedy等人在 2014 年的論文《Going Deeper with Convolutions》提出,其最大的亮點是提出一種叫Inception的結構,以此為基礎構建GoogLeNet,并在當年的ImageNet分類和檢測任務中獲得第一,ps:GoogLeNet的取名是為了向YannLeCun的LeNet系列致敬。(本系列所有代碼均在github:https://git

前面講了LeNet、AlexNet和Vgg,這周來講講GoogLeNet。GoogLeNet是由google的Christian Szegedy等人在 2014 年的論文《Going Deeper with Convolutions》提出,其最大的亮點是提出一種叫Inception的結構,以此為基礎構建GoogLeNet,并在當年的ImageNet分類和檢測任務中獲得第一,ps:GoogLeNet的取名是為了向YannLeCun的LeNet系列致敬。

(本系列所有代碼均在github:https://github.com/huxiaoman7/PaddlePaddle_code)

關于深度網絡的一些思考

  在本系列最開始的幾篇文章我們講到了卷積神經網絡,設計的網絡結構也非常簡單,屬于淺層神經網絡,如三層的卷積神經網絡等,但是在層數比較少的時候,有時候效果往往并沒有那么好,在實驗過程中發現,當我們嘗試增加網絡的層數,或者增加每一層網絡的神經元個數的時候,對準確率有一定的提升,簡單的說就是增加網絡的深度與寬度,但這樣做有兩個明顯的缺點:

  •  更深更寬的網絡意味著更多的參數,提高了模型的復雜度,從而大大增加過擬合的風險,尤其在訓練數據不是那么多或者某個label訓練數據不足的情況下更容易發生;

  • 增加計算資源的消耗,實際情況下,不管是因為數據稀疏還是擴充的網絡結構利用不充分(比如很多權重接近0),都會導致大量計算的浪費。

  解決以上兩個問題的基本方法是將全連接或卷積連接改為稀疏連接。不管從生物的角度還是機器學習的角度,稀疏性都有良好的表現,回想一下在講AlexNet這一節提出的Dropout網絡以及ReLU激活函數,其本質就是利用稀疏性提高模型泛化性(但需要計算的參數沒變少)。 

簡單解釋下稀疏性,當整個特征空間是非線性甚至不連續時:

  •  學好局部空間的特征集更能提升性能,類似于Maxout網絡中使用多個局部線性函數的組合來擬合非線性函數的思想;

  • 假設整個特征空間由N個不連續局部特征空間集合組成,任意一個樣本會被映射到這N個空間中并激活/不激活相應特征維度,如果用C1 表示某類樣本被激活的特征維度集合,用C2 表示另一類樣本的特征維度集合,當數據量不夠大時,要想增加特征區分度并很好的區分兩類樣本,就要降低C1 和C2 的重合度(比如可用Jaccard距離衡量),即縮小C1 和C2 的大小,意味著相應的特征維度集會變稀疏。

  不過尷尬的是,現在的計算機體系結構更善于稠密數據的計算,而在非均勻分布的稀疏數據上的計算效率極差,比如稀疏性會導致的緩存miss率極高,于是需要一種方法既能發揮稀疏網絡的優勢又能保證計算效率。好在前人做了大量實驗(如《On Two-Dimensional Sparse Matrix Partitioning: Models, Methods, and a Recipe》),發現對稀疏矩陣做聚類得到相對稠密的子矩陣可以大幅提高稀疏矩陣乘法性能,借鑒這個思想,作者提出Inception的結構。

 圖1 Inception結構

  • 把不同大小卷積核抽象得到的特征空間看做子特征空間,每個子特征空間都是稀疏的,把這些不同尺度特征做融合,相當于得到一個相對稠密的空間;

  • 采用1×1、3×3、5× 5 卷積核(不是必須的,也可以是其他大小),stride取1,利用padding可以方便的做輸出特征維度對齊;

  • 大量事實表明pooling層能有效提高卷積網絡的效果,所以加了一條max pooling路徑;

  • 這個結構符合直觀理解,視覺信息通過不同尺度的變換被聚合起來作為下一階段的特征,比如:人的高矮、胖瘦、青老信息被聚合后做下一步判斷。

這個網絡的最大問題是5× 5 卷積帶來了巨大計算負擔,例如,假設上層輸入為:28×28×192:

  • 直接經過 96 個5× 5 卷積層(stride=1,padding=2)后,輸出為:28×28×96,卷積層參數量為:192×5×5×96=460800;

  • 借鑒NIN網絡(Network in Network,后續會講),在5× 5 卷積前使用 32 個1× 1 卷積核做維度縮減,變成28×28×32,之后經過 96 個5× 5 卷積層(stride=1,padding=2)后,輸出為:28×28×96,但所有卷積層的參數量為:192×1×1×32+32×5×5×96=82944,可見整個參數量是原來的1/5.5,且效果上沒有多少損失。 

    新網絡結構為

 圖2 新Inception結構

 GoogLeNet網絡結構

  利用上述Inception模塊構建GoogLeNet,實驗表明Inception模塊出現在高層特征抽象時會更加有效(我理解由于其結構特點,更適合提取高階特征,讓它提取低階特征會導致特征信息丟失),所以在低層依然使用傳統卷積層。整個網路結構如下:

 圖3 GoogLeNet網絡結構

 圖4 GoogLeNet詳細網絡結構示意圖

網絡說明:

  • 所有卷積層均使用ReLU激活函數,包括做了1× 1 卷積降維后的激活;

  • 移除全連接層,像NIN一樣使用Global Average Pooling,使得Top1 準確率提高0.6%,但由于GAP與類別數目有關系,為了方便大家做模型fine-tuning,最后加了一個全連接層;

  • 與前面的ResNet類似,實驗觀察到,相對淺層的神經網絡層對模型效果有較大的貢獻,訓練階段通過對Inception(4a、4d)增加兩個額外的分類器來增強反向傳播時的梯度信號,但最重要的還是正則化作用,這一點在GoogLeNet v3 中得到實驗證實,并間接證實了GoogLeNet V2 中BN的正則化作用,這兩個分類器的loss會以0. 3 的權重加在整體loss上,在模型inference階段,這兩個分類器會被去掉;

  • 用于降維的1× 1 卷積核個數為 128 個;

  • 全連接層使用 1024 個神經元;

  • 使用丟棄概率為0. 7 的Dropout層;

網絡結構詳細說明: 

  輸入數據為224×224× 3 的RGB圖像,圖中"S"代表做same-padding,"V"代表不做。

  • C1 卷積層: 64 個7× 7 卷積核(stride=2,padding=3),輸出為:112×112×64;

  • P1 抽樣層: 64 個3× 3 卷積核(stride=2),輸出為56×56×64,其中:56=(112-3+1)/2+1

  • C2 卷積層: 192 個3× 3 卷積核(stride=1,padding=1),輸出為:56×56×192;

  • P2 抽樣層: 192 個3× 3 卷積核(stride=2),輸出為28×28×192,其中:28=(56-3+1)/2+1,接著數據被分出 4 個分支,進入Inception (3a)

  • Inception (3a):由 4 部分組成 

    • 64 個1× 1 的卷積核,輸出為28×28×64;

    • 96 個1× 1 的卷積核做降維,輸出為28×28×96,之后 128 個3× 3 卷積核(stride=1,padding=1),輸出為:28×28×128

    • 16 個1× 1 的卷積核做降維,輸出為28×28×16,之后 32 個5× 5 卷積核(stride=1,padding=2),輸出為:28×28×32

    • 192 個3× 3 卷積核(stride=1,padding=1),輸出為28×28×192,進行 32 個1× 1 卷積核,輸出為:28×28×32 

      最后對 4 個分支的輸出做“深度”方向組合,得到輸出28×28×256,接著數據被分出 4 個分支,進入Inception (3b);

  • Inception (3b):由 4 部分組成 

    • 128 個1× 1 的卷積核,輸出為28×28×128;

    • 128 個1× 1 的卷積核做降維,輸出為28×28×128,進行 192 個3× 3 卷積核(stride=1,padding=1),輸出為:28×28×192

    • 32 個1× 1 的卷積核做降維,輸出為28×28×32,進行 96 個5× 5 卷積核(stride=1,padding=2),輸出為:28×28×96

    • 256 個3× 3 卷積核(stride=1,padding=1),輸出為28×28×256,進行 64 個1× 1 卷積核,輸出為:28×28×64 

      最后對 4 個分支的輸出做“深度”方向組合,得到輸出28×28×480; 

      后面結構以此類推。

用PaddlePaddle實現GoogLeNet

  1.網絡結構 googlenet.py

  在PaddlePaddle的models下面,有關于GoogLeNet的實現代碼,大家可以直接學習拿來跑一下:

 1 import paddle.v2 as paddle

 2

 3 __all__ = ['googlenet']

 4

 5

 6 def inception(name, input, channels, filter1, filter3R, filter3, filter5R,

 7               filter5, proj):

 8     cov1 = paddle.layer.img_conv(

 9         name=name + '_1',

10         input=input,

11         filter_size=1,

12         num_channels=channels,

13         num_filters=filter1,

14         stride=1,

15         padding=0)

16

17     cov3r = paddle.layer.img_conv(

18         name=name + '_3r',

19         input=input,

20         filter_size=1,

21         num_channels=channels,

22         num_filters=filter3R,

23         stride=1,

24         padding=0)

25     cov3 = paddle.layer.img_conv(

26         name=name + '_3',

27         input=cov3r,

28         filter_size=3,

29         num_filters=filter3,

30         stride=1,

31         padding=1)

32

33     cov5r = paddle.layer.img_conv(

34         name=name + '_5r',

35         input=input,

36         filter_size=1,

37         num_channels=channels,

38         num_filters=filter5R,

39         stride=1,

40         padding=0)

41     cov5 = paddle.layer.img_conv(

42         name=name + '_5',

43         input=cov5r,

44         filter_size=5,

45         num_filters=filter5,

46         stride=1,

47         padding=2)

48

49     pool1 = paddle.layer.img_pool(

50         name=name + '_max',

51         input=input,

52         pool_size=3,

53         num_channels=channels,

54         stride=1,

55         padding=1)

56     covprj = paddle.layer.img_conv(

57         name=name + '_proj',

58         input=pool1,

59         filter_size=1,

60         num_filters=proj,

61         stride=1,

62         padding=0)

63

64     cat = paddle.layer.concat(name=name, input=[cov1, cov3, cov5, covprj])

65     return cat

66

67

68 def googlenet(input, class_dim):

69     # stage 1

70     conv1 = paddle.layer.img_conv(

71         name="conv1",

72         input=input,

73         filter_size=7,

74         num_channels=3,

75         num_filters=64,

76         stride=2,

77         padding=3)

78     pool1 = paddle.layer.img_pool(

79         name="pool1", input=conv1, pool_size=3, num_channels=64, stride=2)

80

81     # stage 2

82     conv2_1 = paddle.layer.img_conv(

83         name="conv2_1",

84         input=pool1,

85         filter_size=1,

86         num_filters=64,

87         stride=1,

88         padding=0)

89     conv2_2 = paddle.layer.img_conv(

90         name="conv2_2",

91         input=conv2_1,

92         filter_size=3,

93         num_filters=192,

94         stride=1,

95         padding=1)

96     pool2 = paddle.layer.img_pool(

97         name="pool2", input=conv2_2, pool_size=3, num_channels=192, stride=2)

98

99     # stage 3

100     ince3a = inception("ince3a", pool2, 192, 64, 96, 128, 16, 32, 32)

101     ince3b = inception("ince3b", ince3a, 256, 128, 128, 192, 32, 96, 64)

102     pool3 = paddle.layer.img_pool(

103         name="pool3", input=ince3b, num_channels=480, pool_size=3, stride=2)

104

105     # stage 4

106     ince4a = inception("ince4a", pool3, 480, 192, 96, 208, 16, 48, 64)

107     ince4b = inception("ince4b", ince4a, 512, 160, 112, 224, 24, 64, 64)

108     ince4c = inception("ince4c", ince4b, 512, 128, 128, 256, 24, 64, 64)

109     ince4d = inception("ince4d", ince4c, 512, 112, 144, 288, 32, 64, 64)

110     ince4e = inception("ince4e", ince4d, 528, 256, 160, 320, 32, 128, 128)

111     pool4 = paddle.layer.img_pool(

112         name="pool4", input=ince4e, num_channels=832, pool_size=3, stride=2)

113

114     # stage 5

115     ince5a = inception("ince5a", pool4, 832, 256, 160, 320, 32, 128, 128)

116     ince5b = inception("ince5b", ince5a, 832, 384, 192, 384, 48, 128, 128)

117     pool5 = paddle.layer.img_pool(

118         name="pool5",

119         input=ince5b,

120         num_channels=1024,

121         pool_size=7,

122         stride=7,

123         pool_type=paddle.pooling.Avg())

124     dropout = paddle.layer.addto(

125         input=pool5,

126         layer_attr=paddle.attr.Extra(drop_rate=0.4),

127         act=paddle.activation.Linear())

128

129     out = paddle.layer.fc(

130         input=dropout, size=class_dim, act=paddle.activation.Softmax())

131

132     # fc for output 1

133     pool_o1 = paddle.layer.img_pool(

134         name="pool_o1",

135         input=ince4a,

136         num_channels=512,

137         pool_size=5,

138         stride=3,

139         pool_type=paddle.pooling.Avg())

140     conv_o1 = paddle.layer.img_conv(

141         name="conv_o1",

142         input=pool_o1,

143         filter_size=1,

144         num_filters=128,

145         stride=1,

146         padding=0)

147     fc_o1 = paddle.layer.fc(

148         name="fc_o1",

149         input=conv_o1,

150         size=1024,

151         layer_attr=paddle.attr.Extra(drop_rate=0.7),

152         act=paddle.activation.Relu())

153     out1 = paddle.layer.fc(

154         input=fc_o1, size=class_dim, act=paddle.activation.Softmax())

155

156     # fc for output 2

157     pool_o2 = paddle.layer.img_pool(

158         name="pool_o2",

159         input=ince4d,

160         num_channels=528,

161         pool_size=5,

162         stride=3,

163         pool_type=paddle.pooling.Avg())

164     conv_o2 = paddle.layer.img_conv(

165         name="conv_o2",

166         input=pool_o2,

167         filter_size=1,

168         num_filters=128,

169         stride=1,

170         padding=0)

171     fc_o2 = paddle.layer.fc(

172         name="fc_o2",

173         input=conv_o2,

174         size=1024,

175         layer_attr=paddle.attr.Extra(drop_rate=0.7),

176         act=paddle.activation.Relu())

177     out2 = paddle.layer.fc(

178         input=fc_o2, size=class_dim, act=paddle.activation.Softmax())

179

180     return out, out1, out2

  2.訓練模型

 1 import gzip

 2 import paddle.v2.dataset.flowers as flowers

 3 import paddle.v2 as paddle

 4 import reader

 5 import vgg

 6 import resnet

 7 import alexnet

 8 import googlenet

 9 import argparse

10

11 DATA_DIM = 3 * 224 * 224

12 CLASS_DIM = 102

13 BATCH_SIZE = 128

14

15

16 def main():

17     # parse the argument

18     parser = argparse.ArgumentParser()

19     parser.add_argument(

20         'model',

21         help='The model for image classification',

22         choices=['alexnet', 'vgg13', 'vgg16', 'vgg19', 'resnet', 'googlenet'])

23     args = parser.parse_args()

24

25     # PaddlePaddle init

26     paddle.init(use_gpu=True, trainer_count=7)

27

28     image = paddle.layer.data(

29         name="image", type=paddle.data_type.dense_vector(DATA_DIM))

30     lbl = paddle.layer.data(

31         name="label", type=paddle.data_type.integer_value(CLASS_DIM))

32

33     extra_layers = None

34     learning_rate = 0.01

35     if args.model == 'alexnet':

36         out = alexnet.alexnet(image, class_dim=CLASS_DIM)

37     elif args.model == 'vgg13':

38         out = vgg.vgg13(image, class_dim=CLASS_DIM)

39     elif args.model == 'vgg16':

40         out = vgg.vgg16(image, class_dim=CLASS_DIM)

41     elif args.model == 'vgg19':

42         out = vgg.vgg19(image, class_dim=CLASS_DIM)

43     elif args.model == 'resnet':

44         out = resnet.resnet_imagenet(image, class_dim=CLASS_DIM)

45         learning_rate = 0.1

46     elif args.model == 'googlenet':

47         out, out1, out2 = googlenet.googlenet(image, class_dim=CLASS_DIM)

48         loss1 = paddle.layer.cross_entropy_cost(

49             input=out1, label=lbl, coeff=0.3)

50         paddle.evaluator.classification_error(input=out1, label=lbl)

51         loss2 = paddle.layer.cross_entropy_cost(

52             input=out2, label=lbl, coeff=0.3)

53         paddle.evaluator.classification_error(input=out2, label=lbl)

54         extra_layers = [loss1, loss2]

55

56     cost = paddle.layer.classification_cost(input=out, label=lbl)

57

58     # Create parameters

59     parameters = paddle.parameters.create(cost)

60

61     # Create optimizer

62     optimizer = paddle.optimizer.Momentum(

63         momentum=0.9,

64         regularization=paddle.optimizer.L2Regularization(rate=0.0005 *

65                                                          BATCH_SIZE),

66         learning_rate=learning_rate / BATCH_SIZE,

67         learning_rate_decay_a=0.1,

68         learning_rate_decay_b=128000 * 35,

69         learning_rate_schedule="discexp", )

70

71     train_reader = paddle.batch(

72         paddle.reader.shuffle(

73             flowers.train(),

74             # To use other data, replace the above line with:

75             # reader.train_reader('train.list'),

76             buf_size=1000),

77         batch_size=BATCH_SIZE)

78     test_reader = paddle.batch(

79         flowers.valid(),

80         # To use other data, replace the above line with:

81         # reader.test_reader('val.list'),

82         batch_size=BATCH_SIZE)

83

84     # Create trainer

85     trainer = paddle.trainer.SGD(

86         cost=cost,

87         parameters=parameters,

88         update_equation=optimizer,

89         extra_layers=extra_layers)

90

91     # End batch and end pass event handler

92     def event_handler(event):

93         if isinstance(event, paddle.event.EndIteration):

94             if event.batch_id % 1 == 0:

95                 print "\nPass %d, Batch %d, Cost %f, %s" % (

96                     event.pass_id, event.batch_id, event.cost, event.metrics)

97         if isinstance(event, paddle.event.EndPass):

98             with gzip.open('params_pass_%d.tar.gz' % event.pass_id, 'w') as f:

99                 trainer.save_parameter_to_tar(f)

100

101             result = trainer.test(reader=test_reader)

102             print "\nTest with Pass %d, %s" % (event.pass_id, result.metrics)

103

104     trainer.train(

105         reader=train_reader, num_passes=200, event_handler=event_handler)

106

107

108 if __name__ == '__main__':

109     main()

  3.運行方式

1 python train.py googlenet

  其中最后的googlenet是可選的網絡模型,輸入其他的網絡模型,如alexnet、vgg3、vgg6 等就可以用不同的網絡結構來訓練了。

 用Tensorflow實現GoogLeNet

  tensorflow的實現在models里有非常詳細的代碼,這里就不全部貼出來了,大家可以在models/research/slim/nets/ 里詳細看看,關于InceptionV1~InceptionV4 的實現都有。

ps:這里的slim不是tensorflow的contrib下的slim,是models下的slim,別弄混了,slim可以理解為Tensorflow的一個高階api,在構建這些復雜的網絡結構時,可以直接調用slim封裝好的網絡結構就可以了,而不需要從頭開始寫整個網絡結構。關于slim的詳細大家可以在網上搜索,非常方便。

 總結

  其實GoogLeNet的最關鍵的一點就是提出了Inception結構,這有個什么好處呢,原來你想要提高準確率,需要堆疊更深的層,增加神經元個數等,堆疊到一定層可能結果的準確率就提不上去了,因為參數更多了啊,模型更復雜,更容易過擬合了,但是在實驗中轉向了更稀疏但是更精密的結構同樣可以達到很好的效果,說明我們可以照著這個思路走,繼續做,所以后面會有InceptionV2 ,V3,V4 等,它表現的結果也非常好。給我們傳統的通過堆疊層提高準確率的想法提供了一個新的思路。

作者:Charlotte77 

免責聲明:本文為廠商推廣稿件,企業發布本文的目的在于推廣其產品或服務,站長之家發布此文僅為傳遞信息,不代表站長之家贊同其觀點,不對對內容真實性負責,僅供用戶參考之用,不構成任何投資、使用等行為的建議。請讀者使用之前核實真實性,以及可能存在的風險,任何后果均由讀者自行承擔。

 
關鍵詞: GoogLeNet CNN網絡
 
[ 資訊搜索 ]  [ 加入收藏 ]  [ 告訴好友 ]  [ 打印本文 ]  [ 違規舉報 ]  [ 關閉窗口 ]

 
0條 [查看全部]  相關評論

 
網站首頁 | 關于我們 | 聯系方式 | 使用協議 | 版權隱私 | 網站地圖 | 排名推廣 | 廣告服務 | 積分換禮 | 網站留言 | RSS訂閱 | 吉ICP備11001726號-6
企業800網 · 提供技術支持