原文地址: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有多種取值,多項分佈的概率公式爲
下面證明這個式子.
多項式定理:當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}
其中,
這個多項式定理的推導如下,將式子左邊展開
(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}
這樣的公有項,而且.
這樣的話,我們可以把問題看成在n個式子裏,先選取個,然後選取個,最後選取個,然後求有多少種方法。類似把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!}
所以的係數爲,這樣,我們就能得到展開式的通式。舉個例子,當k=2時,我們就得到了常見的二項式公式:
(a+b)^n=\sum\limits_{i=0}^n C_n^{i} a^i b^{n-i}.
再來看之前的多項分佈的概率公式,假設發生的概率爲,由於事件之間是相互獨立的,可得.
我們將式子的左邊看做一次抽樣各種事件發生的概率和,那麼則是進行了n次抽樣所有事件相互組合的對應概率和。把這個多項式展開,它的每一項都對應着一個特殊事件的出現概率。我們把展開式的通項作爲出現次,出現次,,出現次的這種事件的出現概率,這樣就得到了多項分佈的概率公式。
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。是起到歸一化作用。當參數 a、b、T 都固定的時候,就定義了一個以η爲參數的函數族。
統計中很多熟悉的概率分佈都是指數族分佈的特定形式,如伯努利分佈,高斯分佈,多項分佈(multionmal), 泊松分佈等。下面介紹其中的伯努利分佈和高斯分佈。
- 伯努利分佈
把伯努利分佈可以寫成指數族分佈的形式,則
.
同時我們可以看到,居然是logistic sigmoid的形式,後面在討論LR是廣義線性模型時,也會用到。
- 高斯分佈
高斯分佈也可以寫爲指數族分佈的形式如下:
.
我們假設方差爲1,當然不爲1的時候也是可以推導的。上述我們就把高斯分佈寫爲了指數族分佈的形式,對應的
2 廣義線性模型(GLM)
本節將講述廣義線性模型的概念,以及LR,最小二乘爲何也屬於廣義線性模型。
考慮一個分類或迴歸問題,我們就是想預測某個隨機變量yy,yy 是某些特徵(feature)xx的函數。爲了推導廣義線性模式,我們必須做出如下三個假設:
- 1 服從指數族分佈;
- 2 給了x, 我們的目的是爲了預測T(y)的在條件x下的期望。一般情況T(y)=y, 這就意味着我們希望預測h(x)=E[y|x];
- 3 參數η和輸入x是線性相關的:.
在這三個假設(也可以理解爲一種設計)的前提下,我們可以推導出一系列學習算法,稱之爲廣義線性模型(GLM)。下面我們可以推導出一系列算法,稱之爲廣義線性模型GLM.
2.1 最小二乘法
假設,則,
第一行因爲假設2,第二行因爲高斯分佈的特點,第三行根據上面高斯分佈爲指數族分佈的推導,第四行因爲假設3.
2.2 邏輯迴歸問題
考慮LR二分類問題,,因爲是二分類問題,我們很自然的選擇,即服從伯努利分佈。那麼
.
第一行因爲假設2,第二行因爲伯努利分佈的性質,第三行因爲伯努利分佈爲指數族分佈時的推導,第四行因爲假設3.
所以我們終於知道邏輯迴歸LR的從何而來了。
2.3 Softmax Regression
Softmax Regression是GLM的另外一個例子。假設預測值 y 有 k 種可能,即 y∈{1,2,…,k}。比如 k=3 時,可以看作是要將一封未知郵件分爲垃圾郵件、個人郵件還是工作郵件這三類。
- 步驟一:
假設y服從推廣的伯努利分佈(多項式分佈中n=1的情況),總共有k個類別,用k-1個參數代表y屬於每一類的概率。
接着,我們要把y的分佈寫成指數分佈族的形式。首先,先考慮伯努利分佈的表達式爲:,這是y只有兩個分類的情況。現在,我們的y有k個情況,這是我們引入一個示性函數1{.}(1{True} = 1, 1{False} = 0)。
那麼這時候y服從分佈:,然後我們把它寫成指數分佈族的形式:
$
\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}
$
其中,
,
,
.
- 步驟二:
這時候,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}
$.
首先,構造:
.
其次,我們可以看到:
.
當i=0時上式爲零。我們的目的是爲了得到參數,於是
.
最後我們終於得到:
\phi_i=\frac{e^{\eta_i}}{\sum\limits_{j=1}^k e^{\eta_j}}.
上式將η映射到φ,此函數稱爲softmax函數.
- 步驟三:
又根據線性假設,對於每個η有,同時令,對求和式沒有影響,那麼有
\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數字組成的矩陣。
可以依稀看出是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迴歸代價函數可以改爲:
可以看到,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))]
讓我們來回顧一下符號""的含義. 本身是一個向量,它的第 \textstyle l 個元素是對 的第個分量的偏導數。
有了上面的偏導數公式以後,我們就可以將它代入到梯度下降法等算法中,來最小化. 例如,在梯度下降法的標準實現中,每一次迭代需要進行如下更新: .
當實現 softmax 迴歸算法時, 我們通常會使用上述代價函數的一個改進版本。具體來說,就是和權重衰減(weight decay)一起使用。我們接下來介紹使用它的動機和細節。
3.2.2 Softmax迴歸模型參數化的特點
Softmax 迴歸有一個不尋常的特點:它有一個“冗餘”的參數集。爲了便於闡述這一特點,假設我們從參數向量中減去了向量,這時,每一個都變成了.此時假設函數變成了以下的式子:
\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}
換句話說,從中減去完全不影響假設函數的預測結果!這表明前面的 softmax 迴歸模型中存在冗餘的參數。更正式一點來說, Softmax 模型被過度參數化了。對於任意一個用於擬合數據的假設函數,可以求出多組參數值,這些參數得到的是完全相同的假設函數.
進一步而言,如果參數是代價函數的極小值點,那麼同樣也是它的極小值點,其中 可以爲任意向量。因此使最小化的解不是唯一的。(有趣的是,由於仍然是一個凸函數,因此梯度下降時不會遇到局部最優解的問題。但是 Hessian 矩陣是奇異的/不可逆的,這會直接導致採用牛頓法優化就遇到數值計算的問題).
注意,當時,我們總是可以將替換爲(即替換爲全零向量),並且這種變換不會影響假設函數。因此我們可以去掉參數向量 (或者其他 中的任意一個)而不影響假設函數的表達能力。實際上,與其優化全部的個參數(其中),,我們可以令,只優化剩餘的 個參數,這樣算法依然能夠正常工作。
在實際應用中,爲了使算法實現更簡單清楚,往往保留所有參數,而不任意地將某一參數設置爲 0。但此時我們需要對代價函數做一個改動:加入權重衰減。權重衰減可以解決 softmax 迴歸的參數冗餘所帶來的數值問題。
3.3.3 權重衰減
我們通過添加一個權重衰減項來修改代價函數,這個衰減項會懲罰過大的參數值,現在我們的代價函數變爲:
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
有了這個權重衰減項以後(),代價函數就變成了嚴格的凸函數,這樣就可以保證得到唯一的解了。 此時的 Hessian矩陣變爲可逆矩陣,並且因爲是凸函數,梯度下降法和 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))]+\lambda\theta_j,
通過最小化,我們就能實現一個可用的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,如下所示:
然後將這個變量轉換到指數上:
因爲C是一個隨機的常量,所以我們可以寫爲:
D也是一個任意常量。對任意D,這個公式等價於前面的式子,這讓我們能夠更好的進行計算。對於D,一個比較好的選擇是所有輸入的最大值的負數:
假定輸入本身彼此相差不大,這會使輸入轉換到接近於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%,損失函數迭代曲線如下:
實現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迴歸參數冗餘的特點,我們令,並且從兩個參數向量中都減去向量,得到:
\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}
因此,用來表示,我們就會發現 softmax 迴歸器預測其中一個類別的概率爲,另一個類別概率的爲 ,這與 logistic迴歸是一致的。
注:有點書上記,其中,還有的將z記爲