0 - 背景
0.0 - 為什么需要字典學習?
這里引用這個博客的一段話,我覺得可以很好的解釋這個問題。
回答這個問題實際上就是要回答“稀疏字典學習 ”中的字典是怎么來的。做一個比喻,句子是人類社會最神奇的東西,人類社會的一切知識無論是已經發現的還是沒有發現的都必然要通過句子來表示出來(從某種意義上講,公式也是句子)。這樣說來,人類懂得的知識可要算是極為浩繁的。有人統計過人類每天新產生的知識可以裝滿一個2T(2048G)大小的硬盤。但無論有多少句子需要被書寫,對於一個句子來說它最本質的特征是什么呢?毫無疑問,是一個個構成這個句子的單詞(對英語來說)或字(對漢語來說)。所以我們可以很傲嬌的這樣認為,無論人類的知識有多么浩繁,也無論人類的科技有多么發達,一本長不過20厘米,寬不過15厘米,厚不過4厘米的新華字典或牛津字典足以表達人類從古至今乃至未來的所有知識,那些知識只不過是字典中字的排列組合罷了!直到這里,我相信相當一部分讀者或許在心中已經明白了字典學習的第一個好處——它實質上是對於龐大數據集的一種降維表示。第二,正如同字是句子最質朴的特征一樣,字典學習總是嘗試學習蘊藏在樣本背后最質朴的特征(假如樣本最質朴的特征就是樣本最好的特征),這兩條原因同時也是這兩年深度學習之風日盛的情況下字典學習也開始隨之升溫的原因。題外話:現代神經科學表明,哺乳動物大腦的初級視覺皮層干就事情就是圖像的字典表示。
0.1 - 為什么需要稀疏表示?
同樣引用這個博客的一段話,我覺得可以很好的解釋這個問題。
回答這個問題毫無疑問就是要回答“稀疏字典學習”中稀疏兩字的來歷。不妨再舉一個例子。相信大部分人都有這樣一種感覺,當我們在解涉及到新的知識點的數學題時總有一種累心(累腦)的感覺。但是當我們通過艱苦卓絕的訓練將新的知識點牢牢掌握時,再解決與這個知識點相關的問題時就不覺得很累了。這是為什么呢?意大利羅馬大學的Fabio Babiloni教授曾經做過一項實驗,他們讓新飛行員駕駛一架飛機並采集了他們駕駛狀態下的腦電,同時又讓老飛行員駕駛飛機並也采集了他們駕駛狀態下的腦電。如下圖所示:

左圖是新飛行員(不熟練的飛行員)的大腦。圖中黃色的部分,是被認為活躍的腦區。右圖是老飛行員(熟練的飛行員)的大腦,黃色區域相比左邊的圖有明顯的減少。換言之,針對某一特定任務(這里是飛行),熟練者的大腦可以調動盡可能少的腦區消耗盡可能少的能量進行同樣有效的計算(所以熟悉知識點的你,大腦不會再容易覺得累了),並且由於調動的腦區很少,大腦計算速度也會變快,這就是我們稱熟練者為熟練者的原理所在。站在我們所要理解的稀疏字典學習的角度上來講就是大腦學會了知識的稀疏表示。
稀疏表示的本質:用盡可能少的資源表示盡可能多的知識,這種表示還能帶來一個附加的好處,即計算速度快。
1 - 建模
- 將學習對象用$\mathbf{Y}$表示,其維度為$M\times N$,$M$表示樣本數,$N$表示樣本屬性個數
- 字典矩陣用$\mathbf{D}$表示,其維度為$M\times K$
- 查詢矩陣(稀疏矩陣)用$\mathbf{X}$表示,其維度為$K\times N$
其中$\mathbf{Y}$是已知的,現在需要用$\mathbf{D}$和$\mathbf{X}$來近似學習對象$\mathbf{Y}$。直觀地描述即是,現存在知識$\mathbf{Y}$,要直接從存在知識中查詢開銷太大($m$和$n$可能太大),那么可以近似成給定一個查詢矩陣$\mathbf{X}$和對應的字典$\mathbf{D}$,能夠使得查詢出來的知識和存在的知識差不多就滿足要求,並且其中查詢矩陣越簡單越好(越稀疏越好)。總的來說,即是用兩個簡單的矩陣來表示一個復雜的矩陣的過程。
將上述問題抽象成優化問題並用數學語言描述如下,
$$\min_{\mathbf{D},\mathbf{X}}\left \|\mathbf{Y}-\mathbf{D}\mathbf{X}\right \|^2_F,\ s.t. \forall i,\left \|x_i\right \|_0\leq T_0, $$
或者,也可以描述為如下,
$$\min\sum_{i}\left \|x_i\right \|_0,\ s.t.\min_{\mathbf{D},\mathbf{X}}\left \|\mathbf{Y}-\mathbf{D}\mathbf{X}\right \|^2_F\leq T_1, $$
注意到,$\left \| x_i\right \| _0$為零階范數,但在求解過程中為了方便常常用一階范數代替。
2 - 求解
用拉格朗日乘子法可以將上述約束問題轉化為如下無約束問題,
$$\min_{\mathbf{D},\mathbf{X}}\left \|\mathbf{Y}-\mathbf{D}\mathbf{X}\right \|^2_F+\lambda\left \|x_i\right \|_1,$$
注意到,這里有兩個需要優化的變量$\mathbf{X}$和$\mathbf{D}$,可以交替的固定一個變量優化另一個變量。
2.0 - 更新$\mathbf{D}$
假設$\mathbf{X}$已知,記$\mathbf{d}_k$為字典矩陣$\mathbf{D}$的第$k$列向量,$\mathbf{x}^k_T$為查詢矩陣$\mathbf{X}$的第$k$行向量,那么有如下推導,
$$\left \|\mathbf{Y}-\mathbf{D}\mathbf{X}\right \|^2_F=\left \|\mathbf{Y}-\sum_{j=1}^{K}\mathbf{d}_j\mathbf{x}_T^j\right \|^2_F=\left \|\left (\mathbf{Y}-\sum_{j\neq 1}\mathbf{d}_j\mathbf{x}_T^j \right )-\mathbf{d}_k\mathbf{x}_T^k\right \|^2_F=\left \| \mathbf{E_k}-\mathbf{d}_k\mathbf{x}_T^k\right \|^2_F, $$
其中,$\mathbf{E_k}=\mathbf{Y}-\sum_{j\neq 1}\mathbf{d}_j\mathbf{x}_T^j$,因此現在的優化目標為,
$$\min_{\mathbf{d}_k,\mathbf{x}_T^k}\left \| \mathbf{E_k}-\mathbf{d}_k\mathbf{x}_T^k\right \|^2_F,$$
注意到,這里在優化求解前應該做進一步的過濾,目的是把$\mathbf{x}_T^k$中已經為$0$的對應位置都過濾掉,而后再對非$0$的位置求最優化問題(這里的目的是要保證$\mathbf{x}_T^k$的稀疏性,如果不過濾掉已經為$0$的位置,雖然也能求解出目標,但無法保證最后的$\mathbf{X}$稀疏),過濾過程可以由下圖過程直觀描述,假設現在求解的是$k=0$(其中的數值均為隨機化賦值,不代表什么意義),紅色實線框代表當前所求對應的$\mathbf{x}_T^k$,紅色虛線框代表需要刪除的列,過濾后如右側所示。
因此,將上述最優化問題過濾成如下形式,
$$\min_{\mathbf{d}_k,\mathbf{x}_T^{'k}}\left \| \mathbf{E^{'}_k}-\mathbf{d}_k\mathbf{x}_T^{'k}\right \|^2_F,$$
優化上述問題,可以將$\mathbf{E_k^{'}}$做奇異值分解(SVD),記最大的奇異值為$\sigma_{max}$,最大奇異值對應的左奇異矩陣$\mathbf{U}$的列向量為$\mathbf{u}_{max}$,對應的右奇異矩陣$\mathbf{V}$的行向量為$\mathbf{v}_{max}$,則令$\mathbf{d}_k=\mathbf{u}_{max}$,$\mathbf{x}_T^{'k}=\sigma_{max}\mathbf{v}_{max}$,再更新到原來的$\mathbf{x}_T^k$。(如果求得的奇異值矩陣的奇異值是從大到小排列,那么上述$max=1$,可以替換表示為$\mathbf{x}_T^{'k}=\Sigma\left (1,1 \right )V(\cdot,1)^T$)。(我覺得上述過程可以這樣理解,奇異值分解出來的最大奇異值對應原矩陣最有代表性的特征,刪除這個特征可以使得剩下的整體最小,因此選取的是最大奇異值給對應的$\mathbf{x}$賦值。)
2.1 - 更新$\mathbf{X}$
假設$\mathbf{D}$固定之后,可以看作是一個監督問題,因此可以用Lasso或者OMP等算法更新(但需要保證$\mathbf{X}$的稀疏性)。
3 - 算法(K-SVD)
- Step 1:初始化。可以從$\mathbf{Y}$中隨機選取$K$個列向量或者取$\mathbf{Y}$的左奇異矩陣的前$K$個列向量初始化$\mathbf{D}^{(0)}$
- Step 2:稀疏編碼。利用更上一步的字典矩陣$\mathbf{D}^{(j)}$來獲得新的$\mathbf{X}^{(j)}$
- Step 3:計算精度,若精度達到要求,轉Step 5,否則轉Step 4
- Step 4:逐列更新字典矩陣$\mathbf{D}^{(j)}$(如2.0節所講)
- Step 5:學習完成
這里選取了K分別等於20、50、100、300進行字典學習,獲得結果如下圖所示,python代碼可見於我的github。
4 - 參考資料
https://blog.csdn.net/abc13526222160/article/details/87936459
https://www.cnblogs.com/endlesscoding/p/10090866.html
https://github.com/Chet1996/Notebooks/tree/master/Dictionary%20Learning