GLM

原文地址:http://www.cnblogs.com/sumai/p/5240170.html
http://www.cnblogs.com/BYRans/
https://blog.csdn.net/tudaodiaozhale/article/details/80432552

0 準備知識:多項式分佈

多項式分佈是二項分佈的推廣。二項分佈(也叫伯努利分佈)的典型例子是扔硬幣,硬幣正面朝上概率爲p, 重複扔n次硬幣,k次爲正面的概率即爲一個二項分佈概率。而多項分佈就像扔骰子,有6個面對應6個不同的點數。二項分佈時事件X只有2種取值,而多項分佈的X有多種取值,多項分佈的概率公式爲

P(X1=x1, ,Xk=xk)={n!x1!, ,xk!px1pxk,i=1kxi=n0,otherwiseP(X_1=x_1,\cdots,X_k=x_k)= \left\{\begin{array}{ll} \frac{n!}{x_1!,\cdots,x_k!}p^{x_1}\cdots p^{x_k},&\sum\limits_{i=1}^k x_i=n\\ 0,& otherwise \end{array}\right.

下面證明這個式子.
多項式定理:當n是一個正整數時,我們有

(x_1+x_2+\cdots+x_k)^n=\sum\frac{n!}{r_1!r_2!\cdots r_k!}x_1^{r_1}\cdots x_k^{r_k}

其中,r1++rk=n,ri0,1ik.r_1+\cdots+r_k=n,r_i\geq 0,1\leq i \leq k.

這個多項式定理的推導如下,將式子左邊展開

(x_1+x_2+\cdots+x_k)^n=(x_1+x_2+\cdots+x_k)\cdots(x_1+x_2+\cdots+x_k)

上面的式子是由n個因子相乘得到,而它的展開式可以看做在每個式子裏選取某一個xi,總共選取n個xi相乘,所以所有的展開式項都會有

x_1^{r_1}x_2^{r_2}\cdots x_k^{r_k}

這樣的公有項,而且r1++rk=nr_1+\cdots+r_k=n.

這樣的話,我們可以把問題看成在n個式子裏,先選取r1r_1x1x_1,然後選取r2r_2x2x_2,最後選取rkr_kxkx_k,然後求有多少種方法。類似把n 個球放到k個不同的盒子裏的方法有多少種,我們得到

C_n^{r_1,r_2,\cdots,r_k}=C_n^{r_1}C_{n-r_1}^{r_2}\cdots C_{n-r_1-\cdots-r_{k-1}}^{r_k}=\frac{n!}{r_1!r_2!\cdots r_k!}

所以x1r1x2r2xkrkx_1^{r_1}x_2^{r_2}\cdots x_k^{r_k}的係數爲Cnr1,r2, ,rkC_n^{r_1,r_2,\cdots,r_k},這樣,我們就能得到展開式的通式。舉個例子,當k=2時,我們就得到了常見的二項式公式:

(a+b)^n=\sum\limits_{i=0}^n C_n^{i} a^i b^{n-i}.

再來看之前的多項分佈的概率公式,假設X1,X2, ,XkX_1,X_2,\cdots,X_k發生的概率爲p1,p2, ,pkp_1,p_2,\cdots,p_k,由於事件之間是相互獨立的,可得p1+p2++pk=1p_1+p_2+\cdots+p_k=1.

我們將式子p1+p2++pk=1p_1+p_2+\cdots+p_k=1的左邊看做一次抽樣各種事件發生的概率和,那麼(p1+p2++pk)n=1n=1(p_1+p_2+\cdots+p_k)^n=1^n=1則是進行了n次抽樣所有事件相互組合的對應概率和。把這個多項式展開,它的每一項都對應着一個特殊事件的出現概率。我們把展開式的通項作爲X1X_1出現x1x_1次,X2X_2出現x2x_2次,\cdotsXkX_k出現xkx_k次的這種事件的出現概率,這樣就得到了多項分佈的概率公式。

1 指數分佈族

1.1 定義

我們在建模的時候,關心的目標變量Y可能服從很多種分佈。像線性迴歸,我們會假設目標變量Y服從正態分佈,而邏輯迴歸,則假設服從伯努利分佈。在廣義線性模型的理論框架中,則假設目標變量Y則是服從指數分佈族,正態分佈和伯努利分佈都屬於指數分佈族,因此線性迴歸和邏輯迴歸可以看作是廣義線性模型的特例。那什麼是指數分佈族呢?若一個分佈的概率密度或者概率分佈可以寫成這個形式,那麼它就屬於指數分佈族,

p(y,\eta)=b(y)exp(\eta^TT(y)-a(\eta))

其中,η成爲分佈的自然參數(nature parameter);T(y)是充分統計量(sufficient statistic),通常T(y)=y。expa(η)exp^{-a(\eta)}是起到歸一化作用。當參數 a、b、T 都固定的時候,就定義了一個以η爲參數的函數族。
統計中很多熟悉的概率分佈都是指數族分佈的特定形式,如伯努利分佈,高斯分佈,多項分佈(multionmal), 泊松分佈等。下面介紹其中的伯努利分佈和高斯分佈。

  • 伯努利分佈

p(y;ϕ)=ϕy(1ϕ)1yp(y;\phi)=\phi^y(1-\phi)^{1-y}

=exp[ylogϕ+(1y)log(1ϕ)]\qquad\quad=exp[ylog\phi+(1-y)log(1-\phi)]

=exp(ylogϕ1ϕ+log(1ϕ)]\qquad\quad=exp(ylog\frac{\phi}{1-\phi}+log(1-\phi)]
把伯努利分佈可以寫成指數族分佈的形式,則

T(y)=yη=logϕ1ϕa(η)=log(1ϕ)=log(1+eη),b(y)=1\begin{array}{cll} T(y)&=&y \\ \eta&=&log\frac{\phi}{1-\phi} \\ a(\eta)&=&-log(1-\phi)=log(1+e^{\eta}),b(y)=1 \end{array}.

同時我們可以看到ϕ=11+eη\phi=\frac{1}{1+e^{-\eta}},居然是logistic sigmoid的形式,後面在討論LR是廣義線性模型時,也會用到。

  • 高斯分佈

高斯分佈也可以寫爲指數族分佈的形式如下:

p(y;μ)=12πexp(12(yμ)2)p(y;\mu)=\frac{1}{\sqrt{2\pi}}exp(-\frac{1}{2}(y-\mu)^2)

=12πexp(12y2)exp(μy12μ2)\qquad\quad=\frac{1}{\sqrt{2\pi}}exp(-\frac{1}{2}y^2)exp(\mu y-\frac{1}{2}\mu ^2).

我們假設方差爲1,當然不爲1的時候也是可以推導的。上述我們就把高斯分佈寫爲了指數族分佈的形式,對應的

η=μT(y)=ya(η)=μ2/2=η2/2b(y)=12πexp(12y2)\begin{array}{cll} \eta&=&\mu \\ T(y)&=&y \\ a(\eta)&=&\mu^2/2=\eta^2/2 \\ b(y)&=&\frac{1}{\sqrt{2\pi}}exp(-\frac{1}{2}y^2) \end{array}

2 廣義線性模型(GLM)

本節將講述廣義線性模型的概念,以及LR,最小二乘爲何也屬於廣義線性模型。

考慮一個分類或迴歸問題,我們就是想預測某個隨機變量yy,yy 是某些特徵(feature)xx的函數。爲了推導廣義線性模式,我們必須做出如下三個假設:

  • 1 p(yx;θ)p(y|x;\theta)服從指數族分佈;
  • 2 給了x, 我們的目的是爲了預測T(y)的在條件x下的期望。一般情況T(y)=y, 這就意味着我們希望預測h(x)=E[y|x];
  • 3 參數η和輸入x是線性相關的:η=θTx\eta=\theta^T x.

在這三個假設(也可以理解爲一種設計)的前提下,我們可以推導出一系列學習算法,稱之爲廣義線性模型(GLM)。下面我們可以推導出一系列算法,稱之爲廣義線性模型GLM.

2.1 最小二乘法

假設p(yx;θ)N(μ,σ2)p(y|x;\theta)\sim N(\mu,\sigma^2),則,

hθ=E[yx;θ]=μ=η=θTx\begin{array}{cll} h_{\theta}&=&E[y|x;\theta]\\ &=&\mu \\ &=&\eta \\ &=&\theta^T x \end{array}

第一行因爲假設2,第二行因爲高斯分佈的特點,第三行根據上面高斯分佈爲指數族分佈的推導,第四行因爲假設3.

2.2 邏輯迴歸問題

考慮LR二分類問題,y0,1y\in 0,1,因爲是二分類問題,我們很自然的選擇p(yx;θ)Bernoulli(θ)p(y|x;\theta)\sim Bernoulli(\theta),即服從伯努利分佈。那麼

hθ(x)=E[yx;θ]=ϕ=11+eϕ=11+eθTxh_{\theta}(x)=E[y|x;\theta]=\phi=\frac{1}{1+e^{-\phi}}=\frac{1}{1+e^{-\theta^Tx}}.

第一行因爲假設2,第二行因爲伯努利分佈的性質,第三行因爲伯努利分佈爲指數族分佈時的推導,第四行因爲假設3.

所以我們終於知道邏輯迴歸LR的p(y=1x)=11+eθTxp(y=1|x)=\frac{1}{1+e^{-\theta^Tx}}從何而來了。

2.3 Softmax Regression

Softmax Regression是GLM的另外一個例子。假設預測值 y 有 k 種可能,即 y∈{1,2,…,k}。比如 k=3 時,可以看作是要將一封未知郵件分爲垃圾郵件、個人郵件還是工作郵件這三類。

  • 步驟一:

假設y服從推廣的伯努利分佈(多項式分佈中n=1的情況),總共有k個類別,用k-1個參數ϕ1, ,ϕk1,ϕk(ϕk=1i=1k1ϕi)\phi_1,\cdots,\phi_{k-1},\phi_k(\phi_k=1-\sum\limits_{i=1}^{k-1}\phi_i)代表y屬於每一類的概率。

接着,我們要把y的分佈寫成指數分佈族的形式。首先,先考慮伯努利分佈的表達式爲:p(y;ϕ)=ϕy(1ϕ)1y(y{0,1}p(y;\phi)=\phi^y(1-\phi)^{1-y}(y\in \{0,1\},這是y只有兩個分類的情況。現在,我們的y有k個情況,這是我們引入一個示性函數1{.}(1{True} = 1, 1{False} = 0)。

那麼這時候y服從分佈:p(y;ϕ)=ϕ11{y=1}ϕ11{y=2}ϕ11{y=k}p(y;\phi)=\phi_1^{1\{y=1\}}\phi_1^{1\{y=2\}}\cdots \phi_1^{1\{y=k\}},然後我們把它寫成指數分佈族的形式:

$
\begin{array}{lcl}
p(y;\phi)&=&\phi_1{1{y=1}}\phi_1{1{y=2}}\cdots \phi_1^{1{y=k}} \
&=&\phi_1{1{y=1}}\phi_1{1{y=2}}\cdots \phi_1{1-\sum\limits_{i=1}{k-1}1{y=i}}\
&=&exp[1{y=1}log(\phi_1)+\cdots +(1-\sum\limits_{i=1}^{k-1}1{y=i})log(\phi_k)]\
&=&exp[1{y=1}log(\frac{\phi_1}{\phi_k})+\cdots +1{y=k-1}log(\frac{\phi_{k-1}}{\phi_k}+log(\phi_k)] \
&=&b(y)exp(\eta^TT(y)-a(\eta))
\end{array}
$
其中,
η=[log(ϕ1/ϕk)log(ϕ2/ϕk)log(ϕk1/ϕk)]\eta=\begin{bmatrix} log(\phi_1/\phi_k) \\ log(\phi_2/\phi_k) \\ \vdots \\ log(\phi_{k-1}/\phi_k) \end{bmatrix},
T(y)=[1{y=1}1{y=2}1{y=k1}]T(y)=\begin{bmatrix} 1\{y=1\}\\1\{y=2\}\\ \vdots \\ 1\{y=k-1\} \end{bmatrix},

a(η)=log(ϕk),b(y)=1a(\eta)=-log(\phi_k),b(y)=1.

  • 步驟二:

這時候,T(y)是一組 k-1 維的向量,不再是 y,如下所示:

$
T(1)=\begin{bmatrix}1\0\0\ \vdots \ 0\end{bmatrix}
$,
$
T(2)=\begin{bmatrix}0\1\0\ \vdots \ 0\end{bmatrix}
$,
$
T(3)=\begin{bmatrix}0\0\1\ \vdots \ 0\end{bmatrix}
,\cdots,$
$
T(k-1)=\begin{bmatrix}0\0\0\ \vdots \ 1\end{bmatrix}
$,
$
T(k)=\begin{bmatrix}0\0\0\ \vdots \ 0\end{bmatrix}
$.

首先,構造hθ(x)h_{\theta}(x):

hθ(x)=E[T(y)x;θ]=E[1{y=1}1{y=2}1{y=k1}]=[ϕ1ϕ2ϕk1]h_{\theta}(x)=E[T(y)|x;\theta] =E\begin{bmatrix} 1\{y=1\}\\ 1\{y=2\} \\ \vdots \\ 1\{y=k-1\} \end{bmatrix} =\begin{bmatrix} \phi_1 \\ \phi_2 \\ \vdots \\ \phi_{k-1} \end{bmatrix}.

其次,我們可以看到:

ηi=logϕiϕk\eta_i=log\frac{\phi_i}{\phi_k}.

當i=0時上式爲零。我們的目的是爲了得到參數,於是

eηi=ϕiϕkϕkeϕi=ϕiϕki=1keηi=i=1kϕi=1e^{\eta_i}=\frac{\phi_i}{\phi_k}\Rightarrow \phi_k e^{\phi_i}= \phi_i\Rightarrow \phi_k\sum\limits_{i=1}^k e^{\eta_i}=\sum\limits_{i=1}^k \phi_i =1.

最後我們終於得到:

\phi_i=\frac{e^{\eta_i}}{\sum\limits_{j=1}^k e^{\eta_j}}.

上式將η映射到φ,此函數稱爲softmax函數.

  • 步驟三:

又根據線性假設,對於每個η有ηi=θiTX(i=1,2, ,k1)\eta_i=\theta_i^TX(i=1,2,\cdots,k-1),同時令ηk=0\eta_k=0,對求和式沒有影響,那麼有

\begin{array}{lcl}
p(y=i|x;\theta)&=&\phi_i \\
&=&\frac{e^{\eta_i}}{\sum_{j=1}^k e^{\eta_j}}\\
&=&\frac{e^{\theta_i^T x}}{\sum_{j=1}^k e^{\theta_j^T x}}
\end{array}

綜上所述,得到的預測函數h爲:

\begin{array}{lcl}
h_{\theta}(x)&=&E[T(y)|x;\theta]
=E\begin{bmatrix}
1\{y=1\}\\ 1\{y=2\} \\ \vdots \\ 1\{y=k-1\}
\end{bmatrix}
=\begin{bmatrix}
\phi_1 \\ \phi_2 \\ \vdots \\ \phi_{k-1}
\end{bmatrix} \\
&=&\begin{bmatrix}
\frac{exp(\theta_1^Tx)}{\sum\limits_{j=1}^k exp(\theta_j^T x)} \\
\frac{exp(\theta_2^Tx)}{\sum\limits_{j=1}^k exp(\theta_j^T x)} \\
\vdots \\
\frac{exp(\theta_{k-1}^Tx)}{\sum\limits_{j=1}^k exp(\theta_j^T x)} 
\end{bmatrix}
\end{array}

那麼就建立了假設函數,最後就獲得了最大似然估計:

\begin{array}{lcl}
\ell(\theta)&=&\sum\limits_{i=1}^m  logp(y^{(i)}|x^{(i)};\theta)\\
&=&\sum\limits_{i=1}^m log\prod\limits_{l=1}^k (\frac{e^{\theta_l^Tx^{(i)}}}{\sum_{j=1}^k e^{\theta_j^Tx^{(i)}}})^{1\{y^{(i)}=l\}}
\end{array}

對該式子可以使用梯度下降算法或者牛頓方法求得參數θ後,使用假設函數h對新的樣例進行預測,即可完成多類分類任務。對於互斥的多分類問題,這種模型比較合適,而對於非互斥的多分類問題,構建k個one-vs-all邏輯迴歸模型更爲合適。

2.4 Softmax迴歸 VS k個二元分類器

如果你在開發一個音樂分類的應用,需要對k種類型的音樂進行識別,那麼是選擇使用softmax分類器呢,還是使用logistic迴歸算法建立 k個獨立的二元分類器呢?

這一選擇取決於你的類別之間是否互斥,例如,如果你有四個類別的音樂,分別爲:古典音樂、鄉村音樂、搖滾樂和爵士樂,那麼你可以假設每個訓練樣本只會被打上一個標籤(即:一首歌只能屬於這四種音樂類型的其中一種),此時你應該使用類別數 k = 4 的softmax迴歸。(如果在你的數據集中,有的歌曲不屬於以上四類的其中任何一類,那麼你可以添加一個“其他類”,並將類別數 k 設爲5。)

如果你的四個類別如下:人聲音樂、舞曲、影視原聲、流行歌曲,那麼這些類別之間並不是互斥的。例如:一首歌曲可以來源於影視原聲,同時也包含人聲 。這種情況下,使用4個二分類的logistic迴歸分類器更爲合適。這樣,對於每個新的音樂作品 ,我們的算法可以分別判斷它是否屬於各個類別。

3 Softmax迴歸 Python實現

現實中常常會遇到需要多分類的問題,比如手寫體識別,你需要識別手寫的數字是幾(0~9),比如文本生成,你需要知道生成的是哪個字,都需要進行多分類。那麼我們最常用的多分類函數就是softmax了。接下來本文將會實現一個softmax來進行手寫體識別。

3.1 數據集
本次的數據集分爲訓練集:文件名爲"trainingDigits"和測試集:文件名爲"testDigits",每個文件夾裏面有txt文件若干,比如’0_83.txt’文件名前部分是標籤,後部分是編號,這個可以不用管。用記事本打開文件可以看到,裏面是一幅由32X32的0、1數字組成的矩陣。

0506g1

可以依稀看出是0的手寫體,其它類似。

 def loadData(self, dir):    #給出文件目錄,讀取數據
        digits = list() #數據集(數據)
        labels = list() #標籤
        if os.path.exists(dir): #判斷目錄是否存在
            files = os.listdir(dir) #獲取目錄下的所有文件名
            for file in files:  #遍歷所有文件
                labels.append(file.split('_')[0])   #按照文件名規則,文件名第一位是標籤
                with open(dir + '\\' + file) as f:  #通過“目錄+文件名”,獲取文件內容
                    digit = list()
                    for line in f:  #遍歷文件每一行
                        digit.extend(map(int, list(line.replace('\n', ''))))    #遍歷每行時,把數字通過extend的方法擴展
                    digits.append(digit)    #將數據擴展進去
        digits = np.array(digits)   #數據集
        labels = list(map(int, labels)) #標籤
        labels = np.array(labels).reshape((-1, 1))  #將標籤重構成(N, 1)的大小
        return digits, labels

這裏由loadData函數實現了對文件夾的讀取,並返回數據集和標籤。

3.2 算法實現

3.2.1 代價函數

之前的機器學習中,總是將類別分成兩類,比如邏輯斯諦迴歸中,將>=0.5的概率分成正類,<0.5的概率分成負類。如果是要分成多類,那可以將邏輯斯諦迴歸進行一個推廣,比如要分成10類,可以用一個數組表示,就是[0.11, 0.13, 0.06, 0.07, 0.03, 0.15, 0.3, 0.08, 0.03, 0.04]來表示每一個類別的概率,其中0.3概率最大,則有很大可能是這個類別。邏輯斯諦迴歸用的sigmoid函數,而多分類用的是softmax函數,可以表示成如下形式

p(y=i|x;\theta)=\frac{exp(\theta_i^T x)}{\sum\limits_{j=1}^k exp(\theta_j^T x)}

對應代碼,這段代碼會返回一個10X1的一個數組(因爲我們這次的手寫體識別只有10類,從0~9):

def softmax(self, X):   #softmax函數
        return np.exp(X) / np.sum(np.exp(X))

類似邏輯斯諦迴歸,其目標函數是對數似然估計:

\begin{array}{lcl}
\ell(\theta)&=&\sum\limits_{i=1}^m  logp(y^{(i)}|x^{(i)};\theta)\\
&=&\sum\limits_{i=1}^m log\prod\limits_{l=1}^k (\frac{e^{\theta_l^Tx^{(i)}}}{\sum_{j=1}^k e^{\theta_j^Tx^{(i)}}})^{1\{y^{(i)}=l\}} \\
&=&\sum\limits_{i=1}^m\sum\limits_{l=1}^k 1\{y^{(i)}=l\}log\frac{e^{\theta_l^T x^{(i)}}}{\sum\limits_{j=1}^k e^{\theta_j^T x^{(i)}}}
\end{array}

值得注意的是,上述公式是logistic迴歸代價函數的推廣。logistic迴歸代價函數可以改爲:

(θ)=i=1my(i)logπ(z(i))+(1y(i))log(1π(z(i)))=i=1ml=0k1{y(i)=l}logp(y(i)=lx(i);θ)\begin{array}{lcl}\ell(\theta)&amp;=&amp;\sum\limits_{i=1}^m y^{(i)}log\pi(z^{(i)})+(1-y^{(i)})log(1-\pi(z^{(i)}))\\ &amp;=&amp;\sum\limits_{i=1}^m\sum\limits_{l=0}^k 1\{y^{(i)}=l\}logp(y^{(i)}=l|x^{(i)};\theta) \end{array}

可以看到,Softmax代價函數與logistic 代價函數在形式上非常類似,只是在Softmax損失函數中對類標記的 \textstyle k 個可能值進行了累加。注意在Softmax迴歸中將 \textstyle x 分類爲類別 \textstyle j 的概率爲:

p(y^{(i)}=l|x^{(i)};\theta)=\frac{e^{\theta_l^T x^{(i)}}}{\sum\limits_{j=1}^k e^{\theta_j^T x^{(i)}}}

對於 \textstyle J(\theta) 的最小化問題,目前還沒有閉式解法。因此,我們使用迭代的優化算法(例如梯度下降法,或 L-BFGS)。經過求導,我們得到梯度公式如下:

\nabla_{\theta_j}J(\theta)=\sum\limits_{i=1}^m[x^{(i)}(1\{y^{(i)}=j\}-p(y^{(i)}=j|x^{(i)};\theta))]

讓我們來回顧一下符號"θj\nabla_{\theta_j}"的含義. θjJ(θ)\nabla_{\theta_j}J(\theta)本身是一個向量,它的第 \textstyle l 個元素J(θ)θjt\frac{\partial J(\theta)}{\partial \theta_{jt}}J(θ)J(\theta)θj\theta_j 的第\ell個分量的偏導數。

有了上面的偏導數公式以後,我們就可以將它代入到梯度下降法等算法中,來最小化J(θ)J(\theta). 例如,在梯度下降法的標準實現中,每一次迭代需要進行如下更新: θj:=θjαθjJ(θ)(j=1,&ThinSpace;,k).)\theta_j:=\theta_j-\alpha \nabla_{\theta_j}J(\theta)(j=1,\cdots,k).).

當實現 softmax 迴歸算法時, 我們通常會使用上述代價函數的一個改進版本。具體來說,就是和權重衰減(weight decay)一起使用。我們接下來介紹使用它的動機和細節。


3.2.2 Softmax迴歸模型參數化的特點

Softmax 迴歸有一個不尋常的特點:它有一個“冗餘”的參數集。爲了便於闡述這一特點,假設我們從參數向量θj\theta_j中減去了向量ψ\psi,這時,每一個θj\theta_j都變成了θjψ(j=1,&ThinSpace;,k))\theta_j-\psi(j=1,\cdots,k)).此時假設函數變成了以下的式子:

\begin{array}{lcl}
p(y^{(i)}=j|x^{(i)};\theta)&=&\frac{e^{(\theta_j-\psi)^T x^{(i)}}}{\sum\limits_{l=1}^k e^{(\theta_l-\psi)^Tx^{(i)}}}\\
&=&\frac{e^{\theta_j^Tx^{(i)}}e^{-\psi^Tx^{(i)}}}{\sum\limits_{l=1}^k e^{\theta_l^Tx^{(i)}}e^{-\psi^T x^{(i)}}}\\
&=&\frac{e^{\theta_j^Tx^{(i)}}}{\sum\limits_{l=1}^ke^{\theta_l^Tx^{(i)}}}
\end{array}

換句話說,從θj\theta_j中減去ψ\psi完全不影響假設函數的預測結果!這表明前面的 softmax 迴歸模型中存在冗餘的參數。更正式一點來說, Softmax 模型被過度參數化了。對於任意一個用於擬合數據的假設函數,可以求出多組參數值,這些參數得到的是完全相同的假設函數π(z)\pi(z).

進一步而言,如果參數(θ1,θ2,&ThinSpace;,θk)(\theta_1,\theta_2,\cdots,\theta_k)是代價函數(θ)(\theta)的極小值點,那麼(θ1ψ,θ2ψ,&ThinSpace;,θkψ)(\theta_1-\psi,\theta_2-\psi,\cdots,\theta_k-\psi)同樣也是它的極小值點,其中ψ\psi 可以爲任意向量。因此使J(θ)J(\theta)最小化的解不是唯一的。(有趣的是,由於J(θ)J(\theta)仍然是一個凸函數,因此梯度下降時不會遇到局部最優解的問題。但是 Hessian 矩陣是奇異的/不可逆的,這會直接導致採用牛頓法優化就遇到數值計算的問題).

注意,當ψ=θ1\psi=\theta_1時,我們總是可以將θ1\theta_1替換爲θ1ψ)=0\theta_1-\psi)=\vec{0}(即替換爲全零向量),並且這種變換不會影響假設函數。因此我們可以去掉參數向量θ1\theta_1 (或者其他 θj\theta_j 中的任意一個)而不影響假設函數的表達能力。實際上,與其優化全部的k×(n+1)k\times (n+1)個參數(θ1,θ2,&ThinSpace;,θk)(\theta_1,\theta_2,\cdots,\theta_k)(其中θjRn+1\theta_j\in R^{n+1}),,我們可以令θ1=0\theta_1=\vec{0},只優化剩餘的(k1)×(n+1)(k-1)\times(n+1) 個參數,這樣算法依然能夠正常工作。

在實際應用中,爲了使算法實現更簡單清楚,往往保留所有參數(θ1,θ2,&ThinSpace;,θk)(\theta_1,\theta_2,\cdots,\theta_k),而不任意地將某一參數設置爲 0。但此時我們需要對代價函數做一個改動:加入權重衰減。權重衰減可以解決 softmax 迴歸的參數冗餘所帶來的數值問題。


3.3.3 權重衰減

我們通過添加一個權重衰減項λ2i=1kj=0nθij2\frac{\lambda}{2}\sum\limits_{i=1}^k\sum\limits_{j=0}^n \theta_{ij}^2來修改代價函數,這個衰減項會懲罰過大的參數值,現在我們的代價函數變爲:

J(\theta)=\sum\limits_{i=1}^m\sum\limits_{j=1}^k [1\{y_{(i)}=j\}log\frac{e^{\theta_j^Tx^{(i)}}}{\sum\limits_{l=1}^k e^{\theta_l^Tx^{(i)}}}]+\frac{\lambda}{2}\sum\limits_{i=1}^k\sum\limits_{j=0}^n \theta_{ij}^2

有了這個權重衰減項以後(λ&gt;0\lambda &gt; 0),代價函數就變成了嚴格的凸函數,這樣就可以保證得到唯一的解了。 此時的 Hessian矩陣變爲可逆矩陣,並且因爲J(θ)J(\theta)是凸函數,梯度下降法和 L-BFGS 等算法可以保證收斂到全局最優解。

爲了使用優化算法,我們需要求得這個新函數J(θ)J(\theta)的導數,如下:

\nabla_{\theta_j}J(\theta)=\sum\limits_{i=1}^m[x^{(i)}(1\{y^{(i)}=j\}-p(y^{(i)}=j|x^{(i)};\theta))]+\lambda\theta_j,

通過最小化J(θ)J(\theta),我們就能實現一個可用的softmax 迴歸模型。

3.3.4 計算softmax和數值穩定性

對於一個給定的向量,使用Python來計算softmax的簡單方法是:

def softmax(x):
    """Compute the softmax of vector x."""
    exps = np.exp(x)
    return exps / np.sum(exps)

比如:

In [146]: softmax([1, 2, 3])
Out[146]: array([ 0.09003057, 0.24472847,  0.66524096])

然而當我們使用該函數計算較大的值時(或者大的負數時),會出現一個問題:

In [148]: softmax([1000, 2000, 3000])
Out[148]: array([ nan,  nan,  nan])

Numpy使用的浮點數的數值範圍是有限的。對於float64,最大可表示數字的大小爲1030810308。

softmax函數中的求冪運算可以輕鬆超過這個數字,即使是相當適中的輸入。避免這個問題的一個好方法是通過規範輸入使其不要太大或者太小,通過觀察我們可以使用任意的常量C,如下所示:

Sj=ezjk=1nezk=Cezjk=1nCezk,\qquad S_j=\frac{e^{z_j}}{\sum_{k=1}^ne^{z_k}}=\frac{Ce^{z_j}}{\sum_{k=1}^nCe^{z_k}},

然後將這個變量轉換到指數上:

Sj=ezj+log(C)k=1nezk+log(C),\qquad S_j=\frac{e^{z_j+\log(C)}}{\sum_{k=1}^ne^{z_k+\log(C)}},

因爲C是一個隨機的常量,所以我們可以寫爲:

Sj=ezj+Dk=1nezk+D,\qquad S_j=\frac{e^{z_j+D}}{\sum_{k=1}^ne^{z_k+D}},

D也是一個任意常量。對任意D,這個公式等價於前面的式子,這讓我們能夠更好的進行計算。對於D,一個比較好的選擇是所有輸入的最大值的負數:

D=max(z1,z2,&ThinSpace;,zn)D=-max(z_1,z_2,\cdots,z_n)

假定輸入本身彼此相差不大,這會使輸入轉換到接近於0的範圍。最重要的是,它將所有的輸入轉換爲負數(除最大值外,最大值變爲0)。很大的負指數結果會趨於0而不是無窮,這就讓我們很好的避免了出現NaN的結果。

def stablesoftmax(x):
    """Compute the softmax of vector x in a numerically
    stable way."""
    shiftx = x - np.max(x)
    exps = np.exp(shiftx)
    return exps / np.sum(exps)

現在我們有:

In [150]: stablesoftmax([1000, 2000, 3000])
Out[150]: array([ 0.,  0.,  1.])

請注意,這仍然是不完美的,因爲數學上softmax永遠不會真的產生零,但這比NaN好得多,且由於輸入之間的距離非常大,所以無論如何都會得到非常接近於零的結果。

3.3.5 python實現

實現1

import numpy as np
import math
from matplotlib import pyplot as plt
from sklearn import datasets
 
#計算假設的“相對概率”分佈,注意防止指數運算數據溢出  dataset: m*(n+1)    theta: k*(n+1)  m:樣本數   n:特徵數   k:標籤類別數
def Hypothesis(theta,dataset):
    score=np.dot(theta,dataset.T)
    a=np.max(score,axis=0)
    exp_score=np.exp(score-a)
    sum_score=np.sum(exp_score,axis=0)
    relative_probability=exp_score/sum_score
    return relative_probability
 
#計算損失函數
#theta爲參數矩陣k*(n+1)
def Cost_function(theta,dataset,labels,lamda):
    m,n=dataset.shape
    new_code=One_hot_encode(labels)
    log_probability = np.log(Hypothesis(theta,dataset))
    cost = -1/m * np.sum(np.multiply(log_probability,new_code)) + lamda * np.sum(theta*theta)/2
    return cost
 
#對標籤進行獨熱編碼
#new_code爲 k*m  k爲標籤數 m爲樣本數
def One_hot_encode(labels):
    m=len(labels)
    k=len(np.unique(labels))
    new_code=np.zeros((k,m))
    for i in range(m):
        new_code[labels[i],i]=1
    return new_code
#使用Batch Gradient Descent優化損失函數
#迭代終止條件:  1:達到最大迭代次數   2:前後兩次梯度變化小於一個極小值   3:迭代前後損失函數值變化極小
#dataset爲原始數據集:m*n     labels:標籤   lamda:正則項係數   learning_rate:學習率   max_iter:最大迭代次數
#eps1:損失函數變化量的閾值  eps2:梯度變化量閾值
def SoftmaxRegression(dataset,labels,lamda,learning_rate,max_iter,eps1,eps2,EPS):
    loss_record=[]
    m,n = dataset.shape
    k = len(np.unique(labels))
    new_code = One_hot_encode(labels)
    iter = 0
    new_cost = 0
    cost = 0
    dataset=np.column_stack((dataset,np.ones(m)))
    theta = np.random.random((k,n+1))
    gradient = np.zeros(n)
    while iter < max_iter:
        new_theta = theta.copy()
        temp = new_code - Hypothesis(new_theta,dataset)
        for j in range(k):
            sum = np.zeros(n+1)
            for i in range(m):
                a=dataset[i,:]
                sum += a * temp[j,i]
            j_gradient=-1/m * sum + lamda * new_theta[j,:] #計算屬於第j類相對概率的梯度向量
            new_theta[j,:] = new_theta[j,:] - learning_rate * j_gradient
        iter += 1
        #print("第"+str(iter)+"輪迭代的參數:")
        new_cost = Cost_function(new_theta,dataset,labels,lamda)
        loss_record.append(new_cost)
        print("損失函數變化量:" + str(abs(new_cost-cost)))
        if abs(new_cost-cost) < eps1:
            break
        theta = new_theta
        cost=new_cost
    return theta,loss_record
def Classification(theta,dataset):
    X=dataset.copy()
    X=np.column_stack((X,np.ones(X.shape[0])))
    relative_probability=Hypothesis(theta,X)
    return np.argmax(relative_probability,axis=0)

測試:

iris= datasets.load_iris()
X=iris.data
y = iris.target
target_names = iris.target_names
 
theta,loss_record=SoftmaxRegression(dataset=X,labels=y,lamda=0.1,learning_rate=1e-2,max_iter=500000,eps1=1e-6,eps2=1e-4,EPS=1e-6)
predict=Classification(theta,X)
(predict==y).astype(np.int).mean()  #訓練集上精度

結果爲96%,損失函數迭代曲線如下:

0508s2

實現2

簡單實現代碼如下:

import numpy as np
import os

class Softmax:
    def loadData(self, dir):    #給出文件目錄,讀取數據
        digits = list() #數據集(數據)
        labels = list() #標籤
        if os.path.exists(dir): #判斷目錄是否存在
            files = os.listdir(dir) #獲取目錄下的所有文件名
            for file in files:  #遍歷所有文件
                labels.append(file.split('_')[0])   #按照文件名規則,文件名第一位是標籤
                with open(dir + '\\' + file) as f:  #通過“目錄+文件名”,獲取文件內容
                    digit = list()
                    for line in f:  #遍歷文件每一行
                        digit.extend(map(int, list(line.replace('\n', ''))))    #遍歷每行時,把數字通過extend的方法擴展
                    digits.append(digit)    #將數據擴展進去
        digits = np.array(digits)   #數據集
        labels = list(map(int, labels)) #標籤
        labels = np.array(labels).reshape((-1, 1))  #將標籤重構成(N, 1)的大小
        return digits, labels

    def softmax(self, X):   #softmax函數
        return np.exp(X) / np.sum(np.exp(X))

    def train(self, digits, labels, maxIter = 1000, alpha = 0.1):
        self.weights = np.random.uniform(0, 1, (3,4))
        for iter in range(maxIter):
            for i in range(len(digits)):
                x = digits[i].reshape(-1, 1)
                y = np.zeros((3, 1))
                y[labels[i]] = 1
                y_ = self.softmax(np.dot(self.weights, x))
                self.weights -= alpha * (np.dot((y_ - y), x.T))
        return self.weights

    def predict(self, digit):   #預測函數
        return np.argmax(np.dot(self.weights, digit))   #返回softmax中概率最大的值

if __name__ == '__main__':
    softmax = Softmax()
    #trainDigits, trainLabels = softmax.loadData('files/softmax/trainingDigits')
    #testDigits, testLabels = softmax.loadData('files/softmax/testDigits')
    #softmax.train(trainDigits, trainLabels, maxIter=100) #訓練
    
    iris= datasets.load_iris()
    X=iris.data
    y = iris.target
    softmax.train(X, y, maxIter=6000) #訓練
    accuracy = 0
    N = len(X) #總共多少測試樣本
    for i in range(N):
        digit = X[i]   #每個測試樣本
        label = y[i]    #每個測試標籤
        predict = softmax.predict(digit)  #測試結果
        if (predict == label):
            accuracy += 1
        #print("predict:%d, actual:%d"% (predict, label))
    print("accuracy:%.1f%%" %(accuracy / N * 100))

結果爲:96%.


備註:Softmax迴歸與Logistic 迴歸的關係

當類別數 \textstyle k = 2 時,softmax 迴歸退化爲 logistic 迴歸。這表明 softmax 迴歸是 logistic 迴歸的一般形式。具體地說,當 \textstyle k = 2 時,softmax 迴歸的假設函數爲:

\pi(z)=\frac{1}{e^{\theta_1^Tx}+e^{\theta_2^Tx^{(i)}}}
\begin{bmatrix}
e^{\theta_1^Tx}\\e^{\theta_2^Tx}
\end{bmatrix}

利用softmax迴歸參數冗餘的特點,我們令ψ=θ1\psi=\theta_1,並且從兩個參數向量中都減去向量θ1\theta_1,得到:

\begin{array}{lcl}
\pi(z)&=&\frac{1}{e^{\vec{0}^T x}+e^{(\theta_2-\theta_1)^Tx^{(i)}}}
\begin{bmatrix}
e^{\vec{0}^T x}\\ e^{(\theta_2-\theta_1)^T x}
\end{bmatrix}\\
&=&\begin{bmatrix}
\frac{1}{1+e^{(\theta_2-\theta_1)^Tx^{(i)}}} \\
\frac{e^{(\theta_2-\theta_1)^T x}}{1+e^{(\theta_2-\theta_1)^Tx^{(i)}}}
\end{bmatrix}\\
&=&\begin{bmatrix}
\frac{1}{1+e^{(\theta_2-\theta_1)^Tx^{(i)}}}\\
1-\frac{1}{1+e^{(\theta_2-\theta_1)^Tx^{(i)}}}
\end{bmatrix}
\end{array}

因此,用θ\theta&#x27;來表示θ2θ1\theta_2-\theta_1,我們就會發現 softmax 迴歸器預測其中一個類別的概率爲11+e(θ2θ1)Tx(i)\frac{1}{1+e^{(\theta_2-\theta_1)^Tx^{(i)}}},另一個類別概率的爲 111+e(θ2θ1)Tx(i)1-\frac{1}{1+e^{(\theta_2-\theta_1)^Tx^{(i)}}},這與 logistic迴歸是一致的。

:有點書上記π(z):=hθ(x)\pi(z):=h_{\theta}(x),其中z=θTx=θ1Tx1+θ2Tx2++θkTxkz=\theta^T x=\theta_1^T x_1+\theta_2^T x_2+\cdots+\theta_k^T x_k,還有的將z記爲z=w0+w1x1+w2+x2++wk1xk1.z=w_0+w_1x_1+w_2+x_2+\cdots+w_{k-1}x_{k-1}.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章