<section id="primary" class="content-area">
<main id="main" class="site-main">
深度學習:欠擬合問題的幾種解決方案
<div class="entry-content">
<p>點擊量:29849</p><p>我最近做深度學習在連續中文語音識別方向的應用的時候,根據一些論文和網上一些公開代碼和模型結構,設計了一個神經網絡的模型。但是在訓練的時候,就首先遇到了很讓人頭疼的欠擬合問題。神經網絡欠擬合的特征是,訓練了很長時間,但是在訓練集上,loss值仍然很大甚至與初始值沒有太大區別,而且精確度也很低,幾乎接近於0,在測試集上亦如此。且先不管模型結構配置的優劣,就欠擬合問題來說,需要從如下方面來着手。</p>
就我目前所遇到的來說,神經網絡的欠擬合大致分為兩種情況,一種是神經網絡的擬合能力不足,一種是網絡配置的問題。先說說欠擬合的特征吧,即如何判斷當前是不是欠擬合,以及到底是上述我說的哪一種情況。
我們先用兩張圖來說明一下吧:
如果我們訓練神經網絡的時候,在訓練集上得到了這樣的loss:
以及這樣的Accurancy:
那么,欠擬合基本上是沒得跑了。因為,一開始就有一個較大的loss,以及幾乎為0的精度,然后不論怎么訓練,比如訓練了一整天,loss遲遲不下降,精度遲遲不上升,即神經網絡總是不能很好地擬合訓練數據,那么這就是欠擬合了。
判斷神經網絡的擬合能力是否足夠
這時候,有一個小技巧,那就是,讓神經網絡在每次訓練時,只迭代同樣的數據,甚至每一個batch里面也是完全相同一模一樣的數據,再來看看loss值和accurancy值的變化。如果發現,這時候,神經網絡的Loss開始下降,accurancy也開始上升了,並且在訓練了一段時間后神經網絡能夠正確地計算出所訓練樣本經過神經網絡的輸出值了,那么這種情況屬於神經網絡擬合能力不足。對於大量的數據樣本,神經網絡無法去擬合全部數據,只能擬合大量樣本的整體特征,或者少數樣本的具體特征。此時,需要做的很簡單,只需要增加深度,也就是增加神經網絡的層數就可以了。也可以增加神經網絡的寬度,將每一層的神經單元數量增加,但是同等情況下,效果明顯不如增加層數,而且要想達到較好的效果,需要增加的神經元數遠超過增加一層增加的神經元數。深度深比寬度寬的模型更優這一點,是大家普遍認同的。
那么如果loss和accurancy仍然如此呢?不論怎么增加神經網絡的層數,用哪怕只有一條數據去訓練擬合,神經網絡就是“巋然不動”,loss的值“屹立不倒”,那么這就與神經網絡的擬合能力無關了,就要考慮一下其他的因素了。這也是我遇到的那個問題的根源所在。
尋找最優的權重初始化方案
首先要說的就是權重的初始化方案。神經網絡在訓練之前,我們需要給其賦予一個初值,但是如何選擇這個初始值,這是個問題。神經網絡有大概如下的幾種初始化方案:
- 全零初始化 Zeros
- 全1初始化 Ones
- 初始化為固定值value Constant
- 隨機正態分布初始化 RandomNormal
- 隨機均勻分布初始化 RandomUniform
- 截尾高斯分布初始化 TruncatedNormal
- VarianceScaling
- 用隨機正交矩陣初始化Orthogonal
- 使用單位矩陣初始化 Identiy
- LeCun均勻分布初始化方法 lecun_uniform
- LeCun正態分布初始化方法 lecun_normal
- Glorot正態分布初始化方法 glorot_normal
- Glorot均勻分布初始化 glorot_uniform
- He正態分布初始化 he_normal
- LeCun均勻分布初始化 he_uniform
參考資料:
https://keras-cn.readthedocs.io/en/latest/other/initializations/
https://keras.io/initializers/
具體的初始化方案的原理本文不再贅述,這么多初始化方案,其實按照大類來分,主要就三種:均勻分布、正太分布和相同固定值。
全0的初始化,一般只會被用於邏輯斯蒂回歸之類的這種二分類問題上,最多是淺層的神經網絡上。全為1或者某個其他相同的值的方案則很少見。因為這種初始化方案,會使得網絡處於對稱狀態,導致的結果就是,每個神經元都具有相同的輸出,然后在反向傳播計算梯度時,會得到一個同一個梯度值,並且進行着同樣的參數更新,這是我們不希望看到的。
在我用的基於tensorflow的神經網絡框架keras中,神經網絡默認初始化全部被初始化為了glorot_uniform,也就是一種均值為0,以0為中心的對稱區間均勻分布的隨機數。在我的模型上,這種接近於0的均勻分布會導致什么問題呢?那就是梯度的消失,使得訓練時的loss難以收斂,就出現了上面那兩張圖的情況。這種初始化方案,訓練速度不僅僅慢,而且結果也不好。可以考慮一些其他的方案試一試,比如he_normal和xavier normal等。所以,初始化就跟黑科技一樣,用對了,超參數都不用調,沒用對,跑出來的結果跟模型有bug一樣,不忍直視。
使用適當的激活函數
不僅僅是初始化,在神經網絡的激活函數方面的選取,也不是隨意的。比如,卷積神經網絡中,卷積層的輸出,需要使用的激活函數一般為ReLu,循環神經網絡中的循環層使用的激活函數一般為tanh,或者ReLu,全連接層一般也是多用ReLu來激活,只有在神經網絡的輸出層,使用全連接層來分類的情況下,才會使用softmax這種激活函數。而在各種機器學習入門教程里面最常講到的sigmoid函數,想都不要想它,它已經不適用於深度學習了,哪怕是作為其改進版的softmax函數,也僅僅是在輸出層才使用。
選擇合適的優化器和學習速率
神經網絡訓練的優化器也是需要考慮的一大因素。神經網絡的優化器其實有很多種,每種都有其不同的特點,我們最耳熟能詳的就是梯度下降法,對應着有批量梯度下降,隨機梯度下降。這種優化方法其實不賴,尤其是在神經網絡即將最終收斂的時候,使用一個合適的學習速率使得其最終下降到盡可能低的點上。但是隨機梯度下降有着明顯的缺點,尤其是跟Momentum、Adagrad、Adadelta等其他優化器對比之后。
而且,這里我最推薦Adadelta,在一開始的效果很顯著,只有在最終收斂之前可能不如SGD,可以選擇這時候再換成SGD就行了。而且Adadelta不需要太多關注學習率,因為其訓練的原理已經不怎么跟學習率有關了。
不過,如果是SGD的話,在排除了以上情況之后,當神經網絡仍欠擬合或者loss不再下降時,可以將學習率調小一些試試。
一般來說,經過以上的組合拳式的優化調參,欠擬合問題基本上都能夠得到解決,哪怕最后仍然准確率不高,但肯定是擬合了。欠擬合問題解決之后,接下來要解決的就是過擬合問題了。
版權聲明 本博客的文章除特別說明外均為原創,本人版權所有。歡迎轉載,轉載請注明作者及來源鏈接,謝謝。 本文地址: https://blog.ailemon.me/2018/04/09/deep-learning-the-ways-to-solve-underfitting/ All articles are under Attribution-NonCommercial-ShareAlike 4.0 |
<div class="tab-nav-item item-weixin current"><span>微信</span></div><div class="tab-nav-item item-alipay"><span>支付寶</span></div>
</div>
<div class="tab-conts">
<div class="tab-cont current"><div class="pic"><img src="https://src.ailemon.me/common/Wechat_QRCODE.png" alt="微信二維碼圖片"></div><p>用<span class="hl">微信</span>掃描二維碼打賞</p></div><div class="tab-cont"><div class="pic"><img src="https://src.ailemon.me/common/Alipay_QRCODE.png" alt="支付寶二維碼圖片"></div><p>用<span class="hl">支付寶</span>掃描二維碼打賞</p></div>
</div>
</div>
<a class="wb-ppo-close"><svg class="wb-icon wbsico-close"><use xlink:href="#wbsico-close"></use></svg></a>
</div></div></div><div class="crp_related "><h3>Related Posts:</h3><ul><li><a href="https://blog.ailemon.me/2019/02/26/solution-to-loss-doesnt-drop-in-nn-train/" target="_blank"><span class="crp_title">如何解決神經網絡訓練時loss不下降的問題</span></a></li><li><a href="https://blog.ailemon.me/2017/02/17/how-to-collect-data-for-machine-learning/" target="_blank"><span class="crp_title">在數據為王的人工智能時代如何收集機器學習數據</span></a></li><li><a href="https://blog.ailemon.me/2017/02/22/overfitting-and-underfitting/" target="_blank"><span class="crp_title">機器學習:過擬合與欠擬合問題</span></a></li><li><a href="https://blog.ailemon.me/2018/08/02/map-routing-dijkstra-algorithm/" target="_blank"><span class="crp_title">地圖路由問題算法——Dijkstra算法</span></a></li><li><a href="https://blog.ailemon.me/2017/02/10/machine-learningregression-statistic-model/" target="_blank"><span class="crp_title">機器學習:統計回歸模型</span></a></li><li><a href="https://blog.ailemon.me/2017/05/08/physiognomys-new-clothes/" target="_blank"><span class="crp_title">【偽科學爭議】谷歌研究員兩萬字批駁上交大用深度學習推斷犯罪分子</span></a></li></ul><div class="crp_clear"></div></div> </div><!-- .entry-content -->
<footer class="entry-footer">
<span class="byline"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">發布者:</span><span class="author vcard"><a class="url fn n" href="https://blog.ailemon.me/author/ailemon/">AI檸檬博主</a></span></span><span class="posted-on"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><path id="a" d="M0 0h24v24H0V0z"></path></defs><clipPath id="b"><use xlink:href="#a" overflow="visible"></use></clipPath><path clip-path="url(#b)" d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2zm4.2 14.2L11 13V7h1.5v5.2l4.5 2.7-.8 1.3z"></path></svg><a href="https://blog.ailemon.me/2018/04/09/deep-learning-the-ways-to-solve-underfitting/" rel="bookmark"><time class="entry-date published updated" datetime="2018-04-09T00:01:12+08:00">2018-04-09</time></a></span><span class="cat-links"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">發布於</span><a href="https://blog.ailemon.me/category/machine-learning/" rel="category tag">機器學習</a>、<a href="https://blog.ailemon.me/category/deep-learning/" rel="category tag">深度學習</a></span> </footer><!-- .entry-footer -->
<nav class="navigation post-navigation" role="navigation">
<h2 class="screen-reader-text">文章導航</h2>
<div class="nav-links"><div class="nav-previous"><a href="https://blog.ailemon.me/2018/03/27/parallel-computing-introduction-mpich-install-and-test/" rel="prev"><span class="meta-nav" aria-hidden="true">上一篇文章</span> <span class="screen-reader-text">上一篇文章:</span> <br><span class="post-title">並行計算入門:mpich的安裝與測試</span></a></div><div class="nav-next"><a href="https://blog.ailemon.me/2018/04/30/using-c-and-python-by-mpi-to-parallel-compute-pi-value/" rel="next"><span class="meta-nav" aria-hidden="true">下一篇文章</span> <span class="screen-reader-text">下一篇文章:</span> <br><span class="post-title">使用C語言和Python基於MPI並行計算PI的值</span></a></div></div>
</nav>
</article><!-- .comment-body -->
<div class="comment-reply"><a rel="nofollow" class="comment-reply-link" href="/2018/04/09/deep-learning-the-ways-to-solve-underfitting/?replytocom=228#respond" data-commentid="228" data-postid="396" data-belowelement="div-comment-228" data-respondelement="respond" aria-label="回復給王一">回復</a></div> <ol class="children">
<li id="comment-229" class="comment byuser comment-author-ailemon bypostauthor odd alt depth-2">
<article id="div-comment-229" class="comment-body">
<footer class="comment-meta">
<div class="comment-author vcard">
<a href="https://blog.ailemon.me/" rel="external nofollow" class="url"><img alt="" src="https://secure.gravatar.com/avatar/82c426dda402e3d6bb7ef5766c98930f?s=60&d=mm&r=g" srcset="https://secure.gravatar.com/avatar/82c426dda402e3d6bb7ef5766c98930f?s=120&d=mm&r=g 2x" class="avatar avatar-60 photo" height="60" width="60"><span class="post-author-badge" aria-hidden="true"><svg class="svg-icon" width="24" height="24" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"></path><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"></path></svg></span><span class="post-author-badge" aria-hidden="true"><svg class="svg-icon" width="24" height="24" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"></path><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"></path></svg></span><b class="fn">AI檸檬博主</b><span class="screen-reader-text says">說:</span></a> </div><!-- .comment-author -->
<div class="comment-metadata">
<a href="https://blog.ailemon.me/2018/04/09/deep-learning-the-ways-to-solve-underfitting/#comment-229">
<time datetime="2019-10-15T20:42:33+08:00" title="2019-10-15 20:42">
2019-10-15 20:42 </time>
</a>
</div><!-- .comment-metadata -->
</footer><!-- .comment-meta -->
<div class="comment-content">
<p>這可能是模型的初始化方案不好,該位置的梯度幾乎為0,跟我一開始遇到的問題一樣,博客中也寫到了,就是初始化方案問題,尤其是用Keras框架而且用到卷積層的時候。keras默認的初始化方案不適用於卷積層,建議使用“he_normal”微軟亞研何凱明大神提出的初始化方案。當然激活函數也是可能的問題之一,卷積層和全連接層盡量用relu,循環層就tanh,輸出層就softmax,可以試試。</p>
</div><!-- .comment-content -->
</article><!-- .comment-body -->
<div class="comment-reply"><a rel="nofollow" class="comment-reply-link" href="/2018/04/09/deep-learning-the-ways-to-solve-underfitting/?replytocom=229#respond" data-commentid="229" data-postid="396" data-belowelement="div-comment-229" data-respondelement="respond" aria-label="回復給AI檸檬博主">回復</a></div> </li><!-- #comment-## -->
</main><!-- #main -->
</section><!-- #primary -->
</div>