基于keras的Resnet

本文的部分內(nèi)容借鑒https://zhuanlan.zhihu.com/p/21586417

首先看看Resnet最常見的一張圖:

v2-358f29d5d8fab3ed6bea88ca7075f3a9_b.png

當(dāng)網(wǎng)絡(luò)結(jié)構(gòu)越來越深時, 想必淺層結(jié)構(gòu), 網(wǎng)絡(luò)越來越難被訓(xùn)練.
如今有很多常用的方法, 比如 BatchNormalization, Dropout等手段, 以前關(guān)于BN的文章可以看出, 不加BN時網(wǎng)絡(luò)可能直接發(fā)散了.
DL的原則是網(wǎng)絡(luò)的深度越深越好, 深度代表著一種熵, 也就是網(wǎng)絡(luò)的深度代表著網(wǎng)絡(luò)對特征的抽象化程度, 抽象程度越高的越可能包含有語義級的含義. 但是如何解決難以訓(xùn)練的問題呢?

  • 該怎么解決呢?

如果加入的神經(jīng)元是線性的, 也就是x = x, 網(wǎng)絡(luò)結(jié)構(gòu)的實(shí)際深度實(shí)際上沒有變化.
對于DL的一層來說, 正常的映射應(yīng)該是 x -> f(x) 如果這時按照上圖則應(yīng)該有x -> h(x)+x, 如果想要二者相等, h(x)+x=f(x), 也就是h(x) = f(x)-x,這就是"殘差"概念的由來. 當(dāng)h(x) = 0時, 網(wǎng)絡(luò)等價于x->x,與此同時x=f(x),一方面網(wǎng)絡(luò)基本等于線性,可以擴(kuò)展到很深,另一方面本來希望得到的非線性映射也傳播了下去.

  • 還有一種說法是低層的特征與高層的特征進(jìn)行了融合,從而獲得了更好的效果,這種說法也有一定的道理.
  • 當(dāng)然,后來還有一篇論文證明resnet的深度沒有實(shí)質(zhì)的加深,這篇論文我還沒有看過,等看完以后我還會來更新這篇博客.
  • conv_block
v2-ab8ddd6f4efd4635222211443c72de6d_b.png
程序沒有管每個節(jié)點(diǎn)的命名, 主路1,3,1結(jié)構(gòu),側(cè)路1結(jié)構(gòu)
def conv_block(input_tensor, filters):
    filter1, filter2, filter3 = filters

    x = Conv2D(filter1,(1,1),strides=1)(input_tensor)
    x = BatchNormalization(axis=-1)(x)
    x = Activation('relu')(x)

    x = Conv2D(filter2,(3,3),strides=1,padding='same')(x)
    x = BatchNormalization(axis=-1)(x)
    x = Activation('relu')(x)

    x = Conv2D(filter3,(1,1),strides=1)(x)
    x = BatchNormalization(axis=-1)(x)
    x = Activation('relu')(x)

    y = Conv2D(filter3,(1,1),strides=1)(input_tensor)
    y = BatchNormalization(axis=-1)(y)
    y = Activation('relu')(y)

    out = merge([x,y],mode='sum')
    z = Activation('relu')(out)

    return z

  • identity_block 不同的地方是側(cè)路沒有卷積
v2-7b95380d6bec5e74a3253ce5ff0fd724_b.png
def identity_block(input_tensor, filters):


    filter1, filter2, filter3 = filters

    x = Conv2D(filter1,(1,1),strides=1)(input_tensor)
    x = BatchNormalization(axis=-1)(x)
    x = Activation('relu')(x)

    x = Conv2D(filter2,(3,3),strides=1,padding='same')(x)
    x = BatchNormalization(axis=-1)(x)
    x = Activation('relu')(x)

    x = Conv2D(filter3,(1,1),strides=1)(x)
    x = BatchNormalization(axis=-1)(x)
    x = Activation('relu')(x)

    y = Conv2D(filter3,(1,1),strides=1)(input_tensor)
    y = BatchNormalization(axis=-1)(y)
    y = Activation('relu')(y)

    out = merge([x,input_tensor],mode='sum')
    z = Activation('relu')(out)
    return z

網(wǎng)絡(luò)的整體結(jié)構(gòu)為:

data  1,3,224,224

conv  filter=64, kernel_size=7, pad=3,stride=2 1,64,112,112

bn

activation('relu')

maxpool kernel_size=3,stride=2  1,64,56,56

# block 1  (64,64,256)
conv_block() in:1,64,56,56 filter=(64,64,256),out=1,256,56,56

identity_block  in=1,256,56,56, filter=(64,64,256),out=1,256,56,56

identity_block  in=1,256,56,56, filter=(64,64,256),out=1,256,56,56

# block 2  (128,128,512)

conv_block  in=1,256,56,56 filter=(128,128,512),out=1,512,28,28

identity_block  in=1,256,56,56 filter=(128,128,512),out=1,512,28,28

identity_block  in=1,256,56,56 filter=(128,128,512),out=1,512,28,28

identity_block  in=1,256,56,56 filter=(128,128,512),out=1,512,28,28

# block 3 (256,256,1024)

conv_block  in=1,512,28,28 filter=(256,256,1024),out=1,1024,14,14

identity_block  in=1,512,28,28 filter=(256,256,1024),out=1,1024,14,14

identity_block  in=1,512,28,28 filter=(256,256,1024),out=1,1024,14,14

identity_block  in=1,512,28,28 filter=(256,256,1024),out=1,1024,14,14

identity_block  in=1,512,28,28 filter=(256,256,1024),out=1,1024,14,14

identity_block  in=1,512,28,28 filter=(256,256,1024),out=1,1024,14,14

# block 4 (512,512,2048)

conv_block  in=1,1024,14,14 filter=(512,512,2048),out=1,2048,7,7

identity_block  in=1,1024,14,14 filter=(512,512,2048),out=1,2048,7,7

identity_block  in=1,1024,14,14 filter=(512,512,2048),out=1,2048,7,7

maxpool kernel_size=7, stride=1 out=1,2048,1,1

flatten

dence(1,1000)

acivation('softmax')

probbility(1,1000)

主函數(shù)

# coding:utf-8
import keras
from resnet_model import resnet_model
from keras.datasets import cifar10
from keras.utils import plot_model
from keras.callbacks import TensorBoard, ModelCheckpoint, LearningRateScheduler
import math

if __name__ == '__main__':

    n_class = 10
    img_w = 32
    img_h = 32
    BATCH_SIZE = 128
    EPOCH = 100

    (x_train, y_train), (x_test, y_test) = cifar10.load_data()

    x_train = x_train.astype('float32')
    x_train /= 255.
    y_train = keras.utils.np_utils.to_categorical(y_train, n_class)

    x_test = x_test.astype('float32')
    x_test /= 255.
    y_test = keras.utils.np_utils.to_categorical(y_test, n_class)


    tb = TensorBoard(log_dir='log')
    cp = ModelCheckpoint(filepath='best_model.h5', monitor='val_loss',save_best_only=1, mode='auto')


    def step_decay(epoch):
        initial_lrate = 0.01
        drop = 0.5
        epochs_drop = 10.0
        lrate = initial_lrate * math.pow(drop, math.floor((1 + epoch) / epochs_drop))
        return lrate

    lr = LearningRateScheduler(step_decay)
    CB = [tb, cp, lr]
    input_shape = [x_train.shape[1], x_train.shape[2], x_train.shape[3]]

    model = resnet_model(out_class=n_class, input_shape = input_shape)

    plot_model(model, show_layer_names=1)

    model.compile(optimizer='Adam', loss='categorical_crossentropy', metrics=['accuracy'])

    model.fit(x_train, y_train, batch_size=BATCH_SIZE, epochs=EPOCH, validation_split=0.3,
              callbacks=CB, shuffle=1)

    loss, acc = model.evaluate(x_test, y_test, batch_size= BATCH_SIZE)

模型函數(shù)

# coding: utf-8
from keras.models import Model
from keras.layers import Input,Conv2D,BatchNormalization,Activation,MaxPool2D,merge,Flatten,Dense
import math
# from identity_block import identity_block
# from conv_block import conv_block
# from keras.layers import Conv2D,BatchNormalization,Activation

def conv_block(input_tensor, filters):
    filter1, filter2, filter3 = filters

    x = Conv2D(filter1,(1,1),strides=1)(input_tensor)
    x = BatchNormalization(axis=-1)(x)
    x = Activation('relu')(x)

    x = Conv2D(filter2,(3,3),strides=1,padding='same')(x)
    x = BatchNormalization(axis=-1)(x)
    x = Activation('relu')(x)

    x = Conv2D(filter3,(1,1),strides=1)(x)
    x = BatchNormalization(axis=-1)(x)
    x = Activation('relu')(x)

    y = Conv2D(filter3,(1,1),strides=1)(input_tensor)
    y = BatchNormalization(axis=-1)(y)
    y = Activation('relu')(y)

    out = merge([x,y],mode='sum')
    z = Activation('relu')(out)

    return z




def identity_block(input_tensor, filters):


    filter1, filter2, filter3 = filters

    x = Conv2D(filter1,(1,1),strides=1)(input_tensor)
    x = BatchNormalization(axis=-1)(x)
    x = Activation('relu')(x)

    x = Conv2D(filter2,(3,3),strides=1,padding='same')(x)
    x = BatchNormalization(axis=-1)(x)
    x = Activation('relu')(x)

    x = Conv2D(filter3,(1,1),strides=1)(x)
    x = BatchNormalization(axis=-1)(x)
    x = Activation('relu')(x)

    y = Conv2D(filter3,(1,1),strides=1)(input_tensor)
    y = BatchNormalization(axis=-1)(y)
    y = Activation('relu')(y)

    out = merge([x,input_tensor],mode='sum')
    z = Activation('relu')(out)
    return z



def resnet_model(out_class, input_shape):

    inputs = Input(shape=input_shape) #1,3,224,224

    #
    x = Conv2D(64, (7, 7), strides=2, padding='same')(inputs) #conv1  1,64,112,112
    x = BatchNormalization(axis=-1)(x) #bn_conv1
    x = Activation('relu')(x) #conv1_relu

    x = MaxPool2D(pool_size=(3,3),strides=2)(x) # 1,64,56,56

    # block1  (64,64,256) 1,2 in:1,64,56,56
    x = conv_block(x, [64, 64, 256]) #out=1,256,56,56
    x = identity_block(x, [64, 64, 256]) #out=1,256,56,56
    x = identity_block(x, [64, 64, 256]) #out=1,256,56,56

    # block2  (128,128,512) 1,3 in:1,256,56,56
    x = conv_block(x, [128,128,512]) #out=1,512,28,28
    x = identity_block(x, [128,128,512]) #out=1,512,28,28
    x = identity_block(x, [128,128,512]) #out=1,512,28,28
    x = identity_block(x, [128, 128, 512])  # out=1,512,28,28

    # block 3 (256,256,1024) 1,5 in:1,512,28,28
    x = conv_block(x, [256,256,1024])  # out=1,1024,14,14
    x = identity_block(x, [256, 256, 1024])  # out=1,1024,14,14
    x = identity_block(x, [256, 256, 1024])  # out=1,1024,14,14
    x = identity_block(x, [256, 256, 1024])  # out=1,1024,14,14
    x = identity_block(x, [256, 256, 1024])  # out=1,1024,14,14
    x = identity_block(x, [256, 256, 1024])  # out=1,1024,14,14

    # block 4 (512,512,2048) 1,2 in:1,1024,14,14
    x = conv_block(x, [512,512,2048])  # out=1,2048,7,7
    x = identity_block(x, [512, 512, 2048])  # out=1,2048,7,7
    x = identity_block(x, [512, 512, 2048])  # out=1,2048,7,7

    # maxpool kernel_size=7, stride=1 out=1,2048,1,1
    x = MaxPool2D(pool_size=(7, 7), strides=1)(x)

    # flatten
    x = Flatten()(x)

    # # Dense
    # x = Dense(1000)(x) # out=1,1000

    # Dense,這里改造了一下击蹲,適應(yīng)cifar10
    x = Dense(out_class)(x)  # out=1,1000

    out = Activation('softmax')(x)

    model = Model(inputs=inputs, outputs=out)

    return model

現(xiàn)在正在跑, 1060的卡還是太局限了, 建議有經(jīng)濟(jì)能力的同學(xué)直接上1080ti,

  • epoch=300,每輪166秒,一共用時13.8小時計算完成
圖片.png
圖片.png
圖片.png
圖片.png
  • 訓(xùn)練集效果還可以,99.75%,實(shí)際上由于關(guān)于cifar10的訓(xùn)練進(jìn)行的次數(shù)不多,之前用vgg16達(dá)到過1.000, 很難說這個比率是不是真的高,損失0.0082

  • 測試集74.39%,顯而易見出現(xiàn)了過擬合的現(xiàn)象,loss的波動也非常大,

  • 考慮解決方案, 加入dropout(0.5)嘗試,加入學(xué)習(xí)率衰減,是否因?yàn)槟P瓦^于復(fù)雜,因?yàn)閞esnet在Imagenet上的表現(xiàn)最好,Imagenet的圖像容量要遠(yuǎn)大于cifar10

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末心包,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子痕惋,更是在濱河造成了極大的恐慌岭佳,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件述寡,死亡現(xiàn)場離奇詭異,居然都是意外死亡禀崖,警方通過查閱死者的電腦和手機(jī)螟炫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來掸屡,“玉大人然评,你說我怎么就攤上這事≌登螅” “怎么了亿眠?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵纳像,是天一觀的道長。 經(jīng)常有香客問我爹耗,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任山卦,我火速辦了婚禮诵次,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘铸本。我一直安慰自己遵堵,他們只是感情好怨规,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布锡足。 她就那樣靜靜地躺著,像睡著了一般掰烟。 火紅的嫁衣襯著肌膚如雪沐批。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天惧磺,我揣著相機(jī)與錄音捻撑,去河邊找鬼顾患。 笑死,一個胖子當(dāng)著我的面吹牛江解,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播鳖枕,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼桨螺,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了魏烫?” 一聲冷哼從身側(cè)響起肝箱,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤煌张,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后骏融,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體萌狂,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡粥脚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年刷允,在試婚紗的時候發(fā)現(xiàn)自己被綠了碧囊。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡天通,死狀恐怖熄驼,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情瓜贾,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站龟劲,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏仰禀。R本人自食惡果不足惜避矢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧卸勺,春花似錦、人聲如沸碍庵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽苹享。三九已至,卻和暖如春囤攀,著一層夾襖步出監(jiān)牢的瞬間宫纬,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工蝌衔, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蝌蹂,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓亩冬,卻偏偏與公主長得像硼身,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子佳遂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容