在isic數據集上進行malignant和nevus的分類嘗試

本文爲一個使用深度學習經典模型對isic中的惡黑malignant和nevus痣進行分類任務的文章html


引言

智能醫療領域是如今一個很是火的領域,使用AI去解決醫療領域的一些痛點如今已是不少企業和組織正在作或者即將作的一件事情,雖然AI在醫療領域中的落地應用上還不能看到明確的道路,但能夠預見各個企業個組織必然會在本身的領域上有更多的成果,有更多的能夠落地的應用。網絡


皮膚病領域的痛點

皮膚病是發生在皮膚和皮膚附屬器官疾病的總稱。皮膚是人體最大的器官,皮膚病的種類不但繁多,多種內臟發生的疾病也能夠在皮膚上有表現。嚴重的皮膚病,如惡黑,極可能致人死亡,誤診的後果會很是嚴重,症狀輕的皮膚病,如痣,也許並不能稱之爲皮膚病,而是皮損,不少人不選擇去治療。更嚴肅的是不少致死皮膚病和清症狀皮膚病形態學及其類似,如上面提到的惡黑和痣,去有效的識別疾病,對挽救患者的生命起着相當重要的做用。app

解決問題的論文及思路

有幸拜讀了谷歌發出的一篇XXX論文,論文地址
先說說論文的思路。這篇論文是在一個公開數據集isic上面進行的訓練和測試,這個數據集包含1萬多張皮膚病圖片,其中包含惡黑和痣這兩種形態學很是類似,可是後果徹底不同的兩個皮膚鏡下圖片數據集,惡黑是一種可致死的疾病,而痣通常不會有重大影響,但醫學上常常會有惡黑和痣的誤診存在,給患者形成了很大的損害,所以這篇論文中使用了深度神經網絡的方法進行惡黑和痣的識別,也是打開了一個新視野,形成了很大的影響。機器學習

論文使用了經典的神經網絡inception_v3,使用在imageNet中已經訓練好的參數進行了遷移學習,論文結果對惡黑的皮膚病圖片識別也達到了92%左右的準確率,在這以後的另一篇論文XXX中則使用了一個5層的簡單網絡結構,分別在皮膚病圖片的rgb空間、hsv空間和fft空間進行了訓練,獲得了三個模型,最終對模型進行了模型融合,對惡黑的預測達到了97%的準確率。ide


嘗試重現論文的結果:

首先,須要搭建一個神經網絡,使用當下最流行的tensorflow進行了網絡結構的搭建和模型的訓練,在tensorflow的slim庫中提供了inception_v3的封裝好的網絡結構,我能夠直接使用該網絡結構進行訓練。以下圖,網絡結構函數

而後,下載isic的數據集(PS:數據集網站居然不提供現成的下載連接,可是提供了能夠下載數據的API),而後整理出其中的惡黑和痣的圖片,人爲的將他們分紅了訓練集和測試集,訓練集數據和測試集數據的比例大體爲2:1,訓練集的惡黑大約1500張,痣約爲6500張,測試集惡黑大約爲750張,痣3000張左右,這裏主要採起隨機分配的方式,並無刻意去篩選質量好的圖片做爲訓練集。學習

而後,編寫數據讀取方法(我並無將圖片轉化爲tensorflow推薦的tfrecords文件再去訓練,而是直接讀入圖片訓練),將訓練集數據目錄所有加載,打亂後,每次讀取batch_size個圖片,讀取數據時,用圖片路徑讀取圖片,將256X的圖片resize爲224224的大小,並作基本的翻轉和左右變換,測試

而後,編寫神經網絡訓練的訓練過程,對fearture maps進行softmax,定義損失函數,選擇優化器,編寫驗證方法優化

而後,使用已經訓練好的inception_v3的模型,進行遷移學習,並在訓練中對驗證集和測試集進行同步輸出結果網站

最後,學出模型

學習率0.1,batchsize爲64,參數初始化採用必定範圍內的正態分佈

可喜可賀可喜可賀可喜可賀,最終的結果很是好,對惡黑識別的準確率達到了驚人的50%左右,意不意外,驚不驚喜,以後固然就是例行的優化程序,所謂一天寫網絡,一月調參數就是這樣的。

這之間我發現再這個數據集上面進行遷移學習和重頭開始學習,區別並不大,故以後的訓練都是重頭開始訓練的.


模型優化:

在調參數以前,首先要知道須要調的參數是什麼.能夠參考下面連接,學習率、權重初始化方法,加減網絡層數,增長正則化都是常見的能夠調節的參數。

http://blog.csdn.net/qq_20259...  

一、 首先是學習率

這是可能在調參數過程當中第一個應該調的參數,調整學習率能夠調大或者調小。

上面網絡的初始的學習率爲0.1,這對不少數據集的分類來講已經夠了,一般來講也不該該有太小的初始化學習率,這一般會致使過擬合,但並不老是這樣,何凱明大神一次接受採訪時說過,在有些狀況下即便學習率達到0.000001,也不會太小。也不該該有過大的學習率,這會致使結果在極值點兩邊跳動。

分析訓練結果,基本能夠知道咱們的學習率過大了。逐漸的下降學習率並逐步對照,觀察訓練結果的變化,發現預測的整體精度確實在上升,在學習率達到0.005時測試集總體平均精度達到了最高,爲75%左右,再調小會出現測試集精度降低的狀況,且訓練速度變慢。

這一步的訓練結果在測試集上面出現了使人不愉快的表現,召回率很是低,大部分預測都偏向了痣,即惡黑的測試集大部分都預測爲了痣,這顯然是不對的。

二、 解決數據的問題

  首先,在出現上面的結果後,我查了一些資料,對樣本不均衡有了一些新的認識。考慮當前訓練出現了樣本不均衡,致使訓練出現一些問題.參考文章
在分類中如何處理訓練集中不平衡問題
深度 | 解決真實世界問題:如何在不平衡類上使用機器學習?

通常推薦從增長數據來源開始,但在此例中,由於數據集來源於公開數據集,而且含有惡黑和痣的分類數據的公開數據集幾乎不存在,已不存在增長數據集的可能性。

這時咱們考慮使用重採樣和降採樣

1> 首先降採樣,即把痣的訓練集減小到和惡黑同樣,調整了痣數據的訓練集和測試集的比例。繼續訓練,獲得的結果在測試集上中,對惡黑的測試精度獲得了大幅提高,但對於負樣本痣的精度確降低到合格線如下

2> 而後再採用重採樣的方式,將惡黑的圖片進行復制,將其擴展到和痣的數量相等。繼續訓練,獲得的結果正好和降採樣相反,在測試集上,惡黑精度不高,但整體的精度確實比以前高了,這樣的結果一樣也是咱們不能接受的

上面出現的兩個極端狀況,再必定程度上來講就是發生了欠擬合和過擬合。減小痣的訓練集,致使對痣的訓練出現了欠擬合,對惡黑重採樣,致使對惡黑的訓練出現了過擬合。

那麼是否能夠經過必定方式生成一些數據呢,考慮原圖是256X的尺寸,考慮採用剪裁的方式而不是經過resize的方式去獲取圖片。對圖片進行預處理,對每一幅圖片從左上角開始,水平方向每隔1個像素進行一次224高度(數據集中高度不固定,但都小於224)的裁剪,而且對高度垂直方向進行了zero padding,而後對生成的圖片進行了水平和垂直方向的隨機翻轉,生成了新的訓練數據集和測試數據集(一樣保持訓練集中正樣本和負樣本數量基本相同)。繼續訓練,狀況並無多少改善,提高也有限,而且依然是痣的精度明顯高於惡黑的精度.

這個時候我不對數據集產生了懷疑,是否是由於痣的數據集存在一些過大的噪聲干擾呢,因而我將痣的數據集換成脂溢性角化病,即老年斑的數據集進行訓練。

isic數據集中也含有1000多例的脂溢性角化病的數據,比惡黑的數據略少,採用上一次的網絡進行訓練,發現再兩個分類上的精度均可以達到98%以上,因而我再返回對痣的數據集進行了審視,發現其中有一半以上的數據中包含不知是用來幹什麼用的有色圓圈

圖片描述圖片描述圖片描述

我將訓練集中把這部分去除掉,用剩下的數據進行訓練,把帶有有色圓圈的數據先行擱置,對剩餘的數據進行訓練(惡黑和痣),發現結果有了明顯的改善, 在惡黑數據集上的召回率能夠達到85%左右,準確率達到89%左右。

但實際上咱們並無達到原論文中的對rgb空間中預測準確率93%的結果,但這個時候訓練集的精度已經達到了99%,已經到了沒法再繼續訓練的情況,繼續訓練就必須考慮提高模型的泛化能力,調整drop率從0.8到0.七、0.六、0.5,沒有明顯提升,就考慮繼續從訓練集下手。

測試集精度低於訓練集精度,這種現象就是過擬合的現象,加強泛化能力就必須減輕過擬合的影響。考慮到上一步中對原圖像每隔1像素進行裁剪獲取訓練集和測試機的方法是否是和以前的重採樣同樣,出現了很大程度的過擬合呢?雖然從一張圖片中新生成的訓練集都不相同,但他們都是從一張原圖中裁剪出來的,對生成的訓練圖像進行訓練是否是至關於對原圖進行了屢次訓練呢?

爲了驗證這個狀況,我調整了生成圖片的間隔,即把每隔1像素裁剪,變成每隔5個像素再去裁剪一次,經過在這種方式生成的訓練數據和測試數據中的實踐,在惡黑的表現召回率能夠達到88%左右,準確率達到94.5%左右。同時,考慮到咱們的測試集是滑動生成的,預測時是根據原測試集生成的數據預測,但實際要進行的預測則是,對原圖進行滑動裁剪,計算全部裁剪圖片的分類機率分佈,統計平均值得出預測結果的方法,那麼能夠想一想最終的預測效果必然會更好(沒有驗證過,但至少結果不會比當前結果差,由於準確率和召回率都超過了50%)

在以上工做的基礎上,繼續採用一些常見的優化模型的方法,如修改常規的梯度降低優化器嘗試帶有動量的梯度降低優化器學習率降低的優化器嘗試採用不一樣的激活函數嘗試使用不一樣的drop率等經常使用的優化訓練過程,再訓練和收斂速度上,最終訓練結果再測試集上的表現都有少許的提高


踩到的坑

batch norm的坑

在使用inception_v3進行訓練時,由於inception_v3網絡結構中存在batch_norm,由於以前對batch_norm的不充分了解,致使踩到了一個坑裏面。

batch norm在網絡訓練過程當中會起到關鍵性的做用,他能夠加速訓練過程,而且必定程度上提高模型的效果。原理是在訓練過程當中,計算mini-batch的平均值和標準差,對數據進行正則化,將數據約束到一個範圍內,保持他們的平均值和標準差不變,對正則化以後的數據進行訓練,
在學習卷積核和偏置項參數時,同時會學習batch norm的β和γ,但在測試時就徹底不一樣了,在測試時不須要對測試的mini-batch範圍進行約束,只須要使用訓練獲得的固化的參數進行預測就行,而我就犯了相同的錯誤。

我起初在訓練和測試的時候沒有要求is_training這個參數,這個參數指定了是要取當前mini-batch的平均值和標準差,仍是使用固化的參數,tensorflow中提供的inception_v3網絡的is_training默認爲True,因此我在訓練好模型以後作預測時,不一樣的加載數據方式,總會獲得不一樣的結果,如,順序加載全部類的數據,打亂加載全部類數據,每一個mini-batch中各種數量相同等,從新調整了batch_norm後解決(slim.batch_norm有坑,雖然不知道什麼緣由,但is_training如何設置都會有問題),編寫了一個batch_norm方法解決了這個問題

def batch_norm(x, is_training, decay=0.9, eps=1e-5):
    shape = x.get_shape().as_list()
    assert len(shape) in [2, 4]

    n_out = shape[-1]
    beta = tf.Variable(tf.zeros([n_out]))
    gamma = tf.Variable(tf.ones([n_out]))

    if len(shape) == 2:
        batch_mean, batch_var = tf.nn.moments(x, [0])
    else:
        batch_mean, batch_var = tf.nn.moments(x, [0, 1, 2])

    ema = tf.train.ExponentialMovingAverage(decay=decay)

    def mean_var_with_update():
        ema_apply_op = ema.apply([batch_mean, batch_var])
        with tf.control_dependencies([ema_apply_op]):
            return tf.identity(batch_mean), tf.identity(batch_var)

    mean, var = tf.cond(is_training, mean_var_with_update,
                        lambda: (ema.average(batch_mean), ema.average(batch_var)))

    return tf.nn.batch_normalization(x, mean, var, beta, gamma, eps)
相關文章
相關標籤/搜索