這幾天在用matlab中patternnet函數進行目標分類試驗的過程中,遇到了一個很奇葩的問題。為這個問題我苦苦糾纏了差不多兩天的時間,終於在堅持不懈的調試后,找到了問題所在。下面對這個問題及解決問題的全過程進行描述,防止以后重蹈覆轍。
在模型訓練的過程中我將已有數據集按5:3:2的比例分為訓練集、驗證集和測試集,得到如下的訓練結果,可以看出訓練得到的模型的分類效果還是比較理想的。
於是將該模型保存下來,然后迫不及待地將這個模型應用於另外收集的測試數據集中,信心滿滿地等待一個賞心悅目的結果。需要注意的是我采用的兩級分類架構,第一級分類器(不是基於神經網絡的分類器)能夠正確分類一部分目標,第一級分類器無法分類的目標才送到神經網絡分類器進行進一步分類,也就是說上述保存下來的模型被用到了第二級分類器中。分類結果讓我大失所望,居然糟到了我都不忍直視的地步。於是我郁悶了,到底是哪一個地方出現了問題。模型過擬合?提取的特征無效?matlab patternnet訓練得到的模型不支持離線保存后再應用?。。。。。一個個可能的原因終於還是在我絞盡腦汁的驗證下一一否定掉了。在測試的過程中發現一個很奇怪的現象,如果我拿全部的測試數據集里面的數據進行處理,得到的效果很好,但是只對第一個分類器分類剩下的數據進行分類,結果就是不行。而第一個分類器並不會對數據進行修改。於是我就屏蔽了第一個分類器,然后隨機從數據集中選擇部分的數據進行測試以模擬第一個分類器的效果,發現這個隨機挑選的結果有時候好,有時候壞,但是壞的結果壞得實在太離譜了,它分類錯誤的數量甚至遠遠大於在全部數據集上分類錯誤的數量,如下圖所示,左邊是選擇整體數據集的一部分數據進行測試的結果,以第三類目標為例,第三類目標被錯誤分成第一類目標的數量就達到1587個,而右圖是用全部數據集進行處理的結果,它第三類目標被錯誤分成第一類目標的數量只有5個,這顯然是不可思議的,難道這個模型在分類的時候不是一個一個樣本進行分類,而是與輸入樣本整體的情況有關?我甚至懷疑這是matlab庫函數的一個bug,於是我單步調試進入庫函數內部,想弄清它到底怎么根據現有模型對新的數據進行預測的,不過單步調試幾步之后發現它最核心部分的代碼時屏蔽着的,所以沒有辦法一探究竟。此路不通,只能另找出路了,靜下心來認真分析,首先排除matlab庫函數的問題,人家畢竟身經百戰,這庫函數被無數人驗證過,有問題怎么輪得到我這個神經網絡小白去發現呢,肯定是在某一步的處理過程中,將該網絡的輸入樣本變化了。又是一頓艱辛的操作,終於定位了問題所在,問題出現在樣本歸一化函數mapminmax的應用上面。
我們知道不同特征的取值范圍可能相差很大,所以一般需要將所有樣本的所有特征都歸一化到相同的取值范圍內,比如全部歸一化到[-1,1]之間,再將歸一化后的樣本作為神經網絡的輸入樣本。matlab提供了歸一化的函數mapminmax,它的表達式是
,
分別是歸一化前后的數據的取值范圍。在神經網絡的歸一化中要求測試集歸一化時需要和訓練集歸一化保持同樣的基准,即測試集的歸一化需要用到訓練集歸一化時的上述兩個取值范圍。而自己所犯的錯誤正是沒有遵循這一原則,對全部測試數據一起進行處理時,它的歸一化范圍與訓練集的歸一化范圍比較接近,所以此時歸一化是有效的,而采用某些部分測試數據進行處理時,它的歸一化范圍和訓練集歸一化的取值范圍相去甚遠,所以此時歸一化是無效的,導致了上述不好的結果。所以我們需要將訓練集歸一化過程的某些信息保存下來,用於后續測試集的歸一化,mapminmax函數正好提供了這一功能。對訓練集的歸一化過程我們按如下形式使用該函數[y,ps]=mapminmax(x,x_min,x_max)其中x是訓練集數據,[x_min,x_max]是訓練集要求歸一化的范圍,y是訓練集歸一化后的結果,ps就保存了歸一化過程中的一些重要信息,后續測試集歸一化需要用到。對測試集進行歸一化時需要采用如下形式y=mapminmax('apply',x,ps)才能保證測試集的歸一化和訓練集具有相同的參考基准。