Udacity P7 經(jīng)歷筆記

  • 獲得訓練圖片的路徑和標簽

load_files()
函數(shù)讀取之后輸出的是文本文檔
filenames 的輸出是文件的路徑
target 的輸出是子文件夾的名字。在這里子文件夾名字是 c0,c1,c2,c3...c9穷当。但是讀取出來的是0,1,2,3,....9辰企。不過不會影響使用宠能,后面要轉(zhuǎn)化成為獨熱編碼方灾。
*特別注意:如果讀取的文件夾下面沒有子文件夾塘秦,命令用不了讼渊,也就是沒有'target'的值。

def img_load(path):
    data = load_files(path)
    files = data['filenames']
    #targets = np_utils.to_categorical(np.array(data['target']), 10)
    targets = data['target']

    return files, targets   
  • 獲得文件名&路徑

for maindir, subdir, file_name_list in os.walk(dirname):
命令讀取文件目錄尊剔,文件上一級目錄爪幻,文件名。os.walk()輸出的是三個值(列表)。
如果要組成完整的文件目錄挨稿,需要再加工一步:
apath = os.path.join(maindir, filename)

def path_and_name(dirname):  
    result = []
    
    for maindir, subdir, file_name_list in os.walk(dirname):
        for filename in file_name_list:
            apath = os.path.join(maindir, filename)
            result.append(apath)
        name = file_name_list
    return result,name
  • 讀取圖片為array

cv2.imread().astpye(np.uint8)
讀取圖片的時候仇轻,默認格式是np.float64,在這里為了省內(nèi)存奶甘,用np.uint8
矩陣2個常用的命令
np.expand_dims(x,axis=0)
此為增加維度命令篷店。axis值代表的是在什么地方增加維度。0代表在最前面增加
x=x.transpose((2,0,1))
此為轉(zhuǎn)換維度順序臭家。原本是(0疲陕,1,2)的3維矩陣钉赁,轉(zhuǎn)換成了(2蹄殃,0,1)你踩。最常見的情況就是將顏色通道放在最前面/最后面
要查看某個矩形的形狀 x.shape

def img_read(path,img_cols=299, img_rows=299):
    img = cv2.imread(path).astype(np.uint8)
    img_newsize = cv2.resize(img,(img_cols,img_rows))
    #img_newsize.transpose((2,0,1))
    #np.expand_dims(img_newsize, axis=2)
    return img_newsize 
  • 按司機ID來劃分訓練集

由于一個司機ID的圖像是從視頻里面截取出來的诅岩,所以如果訓練的時候,訓練集合驗證集都有同一個ID的圖像带膜》郧基本可以說是判斷準確率100%了。這樣訓練的分數(shù)高膝藕,實際在其他地方很低式廷。
劃分ID是讀取了CSV的文件。使用的命令包括
pd.read_csv()
讀取CSV文件之后束莫,list.index代表了第一列
隨后使用set()簡單粗暴的去除重復懒棉。
list.classname 可以獲得分類的名字,其中'classname'是表格中的表頭內(nèi)容
list.img可以獲得圖片的名字

  • 用遷移學習提取特征
    這是一次失敗的嘗試览绿。最開始使用可VGG19來提取特征,然后分類穗慕,效果很不理想饿敲。推斷是VGG19預訓練的模型(在ImageNet預訓練)和司機的圖片契合度太差了。
def found_features(path):
    base_model = VGG19(weights = 'imagenet')
    x = img_read(path)
    x = np.expand_dims(x, axis=0)
    base_model = bese_model
    model = Model(inputs=base_model.input, 
                  outputs=base_model.get_layer('block4_pool').output)
           
    return model.predict(x)
  • 保存model文件

先創(chuàng)建一個文件夾來保存h5文件逛绵,判斷如果文件夾不存在怀各,則創(chuàng)立新的文件夾'cache'。使用命令:
if not os.path.isdir('cache'): os.mkdir('cache')
保存文件术浪,在這里使用overwrite=True

def save_model(model, index, cross=''):
    json_string = model.to_json()
    if not os.path.isdir('cache'):
        os.mkdir('cache')
    json_name = 'architecture' + str(index) + cross + '.json'
    weight_name = 'model_weights' + str(index) + cross + '.h5'
    #open(os.path.join('cache', json_name), 'w').write(json_string)
    model.save_weights(os.path.join('cache', weight_name), overwrite=True)

-按司機ID來創(chuàng)立列表
一級列表有26個子列表(司機ID26個)瓢对,每個二級列表里包含的是一個司機ID對應的圖片路徑。
同樣的標簽也按同樣的方法來創(chuàng)立成兩級列表胰苏,與圖片路徑一一對應硕蛹。
來獲取一個路徑末尾文件名的方法如下:
os.path.basename(X_path[ii])
獲得pandas.DataFrame 文件某個index下的值的方法:
img_list.loc['c1'].values
為了方便查看進度,只打印一排內(nèi)容,在后面加上 , 表示不換行法焰。

def X_and_y(X_path,y_,img_list,ID):
    print('按司機ID分類數(shù)據(jù)')
    X = []
    y = []
    nu = 0
    for i in ID:
        X_array = []
        y_array = []
        for ii in range(len(X_path)):  
            if os.path.basename(X_path[ii]) in img_list.loc[i].values:
                #x_ar = found_features(X_path[ii]) #將在ID下圖片的提取特征          
                x_ar = X_path[ii]
                X_array.append(x_ar)    #形式為 [[特征 ],[特征 ] ...]
                y_array.append(y_[ii])  
                print("{}/{} Data named {}.........{}files\r".
                      format(nu+1,len(ID),i,len(img_list.loc[i]))),          
        X.append(X_array)  #形式為 [ [[ID1_特征 ],[ID1_特征 ] ...] ,[[ID2_特征 ] [ID2_特征 ] ...] ,...]
        y.append(y_array)
        nu += 1     
    return X,y
  • 執(zhí)行函數(shù)秧荆,分別獲得訓練圖片路徑以及標簽的雙層列表

ID,classname,list_img_name,img_list = driver_id('driver_imgs_list.csv',index_col = 'subject')
X_path,y_ = img_load('train')
X_data,y_data = X_and_y(X_path,y_,img_list,ID)
  • 自己先做一個測試集出來檢查算法

從訓練集中拿出兩個ID下的子列表出來,做成自己的訓練集埃仪。這個時候就要把原來的訓練集和測試集##減去##兩個ID乙濒,使用的是:del X_data[:2]。 這個命令只能執(zhí)行一次卵蛉,執(zhí)行1次就會扣除兩個子列表颁股。
既然是做測試集,這里就不需要再按ID分類了傻丝,在這一步就把兩層列表變?yōu)橐粚樱?/p>

test_fe,test_la = X_data[:2],y_data[:2] 
del X_data[:2]
del y_data[:2] 
#制作自己的test先自己測試一次
test_feature = []
test_label = []
for a in test_fe:

    for i in a:
        test_feature.append(i)
for b in test_la:
    for ii in b:
        test_label.append(ii)

print(type(test_feature),len(test_label))
print(len(X_data))
print(len(y_data))
  • 模型搭建的種種過程

  1. 使用遷移學習直接訓練模型

首先使用了VGG19的預訓練模型甘有。

從keras上直接采用,預訓練多次得分在2.3上下桑滩。觀察當時的訓練過程梧疲,
image.png

loss函數(shù)~2.0,而準確率還可以接近1运准。一定是哪里出了問題幌氮。

在第一時間想到的是模型上的問題(其實不是)。

  1. 使用遷移學習提取特征

采用了VGG19/Xception 來提取特征胁澳。在這里遇到的麻煩是:
(1) VGG輸入圖片格式為(244该互,244,3),而Xception輸入圖片格式為(299韭畸,299宇智,3)。因此在前面定義的def img_read()函數(shù)中胰丁,需要更改一下圖片的reshape随橘。
(2)提取出來的特征展平做全連接層的時候出現(xiàn)了內(nèi)存錯誤。

  1. 從頭搭建網(wǎng)絡

從頭搭建VGG16網(wǎng)絡锦庸,采用的是序貫模型机蔗。搭建好網(wǎng)絡之后載入下載的VGG16權(quán)重。
然后使用model.layers.pop() 去除最后一個輸出層(1000個分類)繼續(xù)添加全連接層和softmax分類層甘萧。
訓練幾次之后發(fā)現(xiàn)效果仍然不佳萝嘁。采用了如下方法:
(1)添加dropout,估計是過擬合扬卷。添加之后訓練過程的分數(shù)與之前無大的進步牙言。
(2)仔細檢查特征和標簽。發(fā)現(xiàn)是在寫入時有誤(下一節(jié)仔細分析)
(3)對模型使用正則怪得。
model.add(Dense(64, input_dim=64,kernel_regularizer=regularizers.l2(0.001), activity_regularizer=regularizers.l1(0.001)))
(4)調(diào)整學習率 lr=le-1/ -2/ -3/ -4 /-5
(5)不載入權(quán)重咱枉,從頭訓練

  1. 從頭搭建Xception網(wǎng)絡

Xception搭建需要使用函數(shù)式模型卑硫。函數(shù)式模型可以有多個輸入以及多個輸出。
載入Xception 沒有top的權(quán)重庞钢,然后繼續(xù)分類拔恰。在這里我犯了一個觀念上的錯誤,在添加后面的層的時候還使用序貫模型的做法基括,報錯颜懊。
為了使模型可視化,有兩中辦法:
(1)采用 model.summary() 輸出簡單的模型內(nèi)容风皿『拥可以看到Output Shape,Param, Connected to 這三個內(nèi)容桐款。
(2)將模型打印成PNG圖片保存:

from keras.utils import plot_model
plot_model(model, to_file='model.png')

可以接收兩個參數(shù):
show_shapes:指定是否顯示輸出數(shù)據(jù)的形狀咸这,默認為False
show_layer_names:指定是否顯示層名稱,默認為True

  1. 采用遷移學習,融合多個模型

融合了Xception以及InceptionV3模型魔眨,將兩個模型的倒數(shù)第二層作為輸出媳维。沒有在各自遷移學習模型里用池化層。
使用函數(shù)模型將兩個結(jié)合在一起遏暴,結(jié)合之前由于輸入的形狀不一致侄刽,((None,10,10,2048)(None,8,8,2048)),因此采用GAP將輸出轉(zhuǎn)為一維朋凉,然后再進行聯(lián)合州丹。
在這里有幾個注意的地方:
(1)在這里使用的是tensor
(2)在輸入數(shù)據(jù)前需要使用Input()函數(shù)
第一次完全在訓練之后發(fā)現(xiàn)分數(shù)只達到了0.4,第二次采用方法為InceptionV3不載入預訓練權(quán)重杂彭。
兩次訓練的分數(shù)為0.4和0.6

  1. 準備訓練數(shù)據(jù)
    在訓練的時候才讀入圖片為(299,299,3)的格式墓毒。在這里有幾個注意點:
    (1)根據(jù)訓練集的大小先創(chuàng)建好空的矩陣,再逐個寫入亲怠。 train_feature_A = np.zeros(shape=[number_of_train_A,input_l,input_w, input_c])
    (2)標簽要轉(zhuǎn)換成為獨熱編碼:np_utils.to_categorical(np.array(y_data_A[i][N]),10))
    (3)在訓練時候前幾次使用了keras自帶的數(shù)據(jù)預處理命令 preprocess_input(train_feature_A) 所计。經(jīng)過測驗,這樣的預處理出來預測值非常極端团秽。后來直接采用的是不預處理的 np.uint8 格式數(shù)據(jù)醉箕。
    (4)訓練過程中最常常遇到的問題是內(nèi)存不足的問題。最終的解決辦法是每一折訓練都保存權(quán)重文件徙垫。如果內(nèi)存不足,重新載入權(quán)重繼續(xù)訓練放棒。在這里的訓練時長就比較長了:

    image.png

  2. 使用模型融合
    使用整合訓練姻报,普通堆疊。堆疊方法由上一篇翻譯文得出:kaggle 模型融合指導

  • 預測測試集间螟,制作提交文件

預測的時候的幾個細節(jié):

  1. 仍然是內(nèi)存問題吴旋。由于預測文件高達有79726個损肛,在準備測試集的時候。采用創(chuàng)建空矩陣再逐個寫入的辦法荣瑟,發(fā)現(xiàn)內(nèi)存又不夠了治拿。所以每次預測都先退出清空內(nèi)存之后,只運行載入模型和訓練好權(quán)重再預測笆焰,沒有辦法接上一歩訓練模型后繼續(xù)預測劫谅。
  2. 由于測試集沒有子目錄,所以不能使用第一步的方法取得文件路徑嚷掠。這里使用的命令是:for maindir, subdir, file_name in os.walk('test'): 必須要取得文件名的原因是在提交文件CSV里面index為img名稱捏检。
  3. 在準備提交文件的時候,由于后面采用了兩個模型整合預測不皆,占用內(nèi)存增大贯城,無論如何都無法創(chuàng)建測試集數(shù)目大小的空矩陣。
    于是采用了逐行寫入CSV的辦法霹娄,每一個圖片單獨預測能犯,得到10個分類的概率之后寫入文件:
def write_csv(path):
    path = all_path(path)
    header = ['img', 'c0', 'c1', 'c2', 'c3', 'c4', 'c5', 'c6', 'c7','c8', 'c9']
    number_all = len(path)
    with open('subm/kjkj.csv', 'wb')as f:
        f_csv = csv.DictWriter(f,header)
        f_csv.writeheader()
        path = path
        n =1
        for i in path:
            img_name = os.path.basename(i)
            img_arr = img_read(i)
            img_arr = np.expand_dims(img_arr, axis=0)
           
            p = model.predict(img_arr)
            row = [{'img':img_name, 
                    'c0':p[0][0], 
                    'c1':p[0][1],
                    'c2':p[0][2],
                    'c3':p[0][3],
                    'c4':p[0][4],
                    'c5':p[0][5],
                    'c6':p[0][6],
                    'c7':p[0][7],
                    'c8':p[0][8],
                    'c9':p[0][9] }]
            f_csv.writerows(row)
            print('pre {} complete!.........{}/{}\r'.format(n,n,number_all)),
            n+=1
  • 使用CMA查看模型關注的地方
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市犬耻,隨后出現(xiàn)的幾起案子踩晶,更是在濱河造成了極大的恐慌,老刑警劉巖香追,帶你破解...
    沈念sama閱讀 218,451評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件合瓢,死亡現(xiàn)場離奇詭異,居然都是意外死亡透典,警方通過查閱死者的電腦和手機晴楔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來峭咒,“玉大人税弃,你說我怎么就攤上這事〈斩樱” “怎么了则果?”我有些...
    開封第一講書人閱讀 164,782評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長漩氨。 經(jīng)常有香客問我西壮,道長,這世上最難降的妖魔是什么叫惊? 我笑而不...
    開封第一講書人閱讀 58,709評論 1 294
  • 正文 為了忘掉前任款青,我火速辦了婚禮,結(jié)果婚禮上霍狰,老公的妹妹穿的比我還像新娘抡草。我一直安慰自己饰及,他們只是感情好,可當我...
    茶點故事閱讀 67,733評論 6 392
  • 文/花漫 我一把揭開白布康震。 她就那樣靜靜地躺著燎含,像睡著了一般。 火紅的嫁衣襯著肌膚如雪腿短。 梳的紋絲不亂的頭發(fā)上屏箍,一...
    開封第一講書人閱讀 51,578評論 1 305
  • 那天,我揣著相機與錄音答姥,去河邊找鬼铣除。 笑死,一個胖子當著我的面吹牛鹦付,可吹牛的內(nèi)容都是我干的尚粘。 我是一名探鬼主播,決...
    沈念sama閱讀 40,320評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼敲长,長吁一口氣:“原來是場噩夢啊……” “哼郎嫁!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起祈噪,我...
    開封第一講書人閱讀 39,241評論 0 276
  • 序言:老撾萬榮一對情侶失蹤泽铛,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后辑鲤,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體盔腔,經(jīng)...
    沈念sama閱讀 45,686評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,878評論 3 336
  • 正文 我和宋清朗相戀三年月褥,在試婚紗的時候發(fā)現(xiàn)自己被綠了弛随。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,992評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡宁赤,死狀恐怖舀透,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情决左,我是刑警寧澤愕够,帶...
    沈念sama閱讀 35,715評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站佛猛,受9級特大地震影響惑芭,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜继找,卻給世界環(huán)境...
    茶點故事閱讀 41,336評論 3 330
  • 文/蒙蒙 一强衡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦漩勤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至硼瓣,卻和暖如春究飞,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背堂鲤。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評論 1 270
  • 我被黑心中介騙來泰國打工亿傅, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人瘟栖。 一個月前我還...
    沈念sama閱讀 48,173評論 3 370
  • 正文 我出身青樓葵擎,卻偏偏與公主長得像,于是被迫代替她去往敵國和親半哟。 傳聞我的和親對象是個殘疾皇子酬滤,可洞房花燭夜當晚...
    茶點故事閱讀 44,947評論 2 355

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