[ML] 機器學習技法:第十四講 Radial Basis Function Network

ML:基礎技法學習
Package:scikit-learn
課程:機器學習技法
簡介:第十四講 Radial Basis Function Network

RBF Network Hypothesis

$$ h(\mathbf{x})=\mathrm{Output}(\sum_{m=1}^{M}\beta _m\mathrm{RBF}(\mathbf{x},\boldsymbol\mu _m)+b)\\ $$ centers:\(\boldsymbol\mu _m\),votes:\(\beta _m\)
\(b\) 通常為 0
  • radial
    • 只跟 \(\mathbf{x}\) 和中心點 \(\boldsymbol\mu_m\) 的距離有關
  • basis function
    • 拿來做線性組合的基本 function
故 Radial Basis Function (RBF) Network 就是 radial hypotheses 的線性組合

而 RBF Network 在歷史上其實只是 NNet 的其中一個分支
如下圖,內積 + tanh (NNet) vs 與中心的距離 + RBF (RBF Network)
$$ g_{SVM}(\mathbf{x})=sign\left (\sum _{SV} \alpha _ny_ne^{(-\gamma \left \| \mathbf{x}-\mathbf{x}_n \right \|^2)+b} \right ) $$ Gaussian kernel 為其中一種 Radial Basis Function (RBF) kernel
所以將 \(g_{SVM}\) 套進 RBF 基本模型,可參考 [ML] 機器學習技法:第三講 Kernel SVM
  • RBF:Gaussian 
  • Output:sign
  • M:SV 的數量
  • \(\boldsymbol\mu _m\):SVM SVs \(\mathbf{x}_n\)
  • \(\beta _m\):\(\alpha _ny_n\)
事實上,機器學習一直在對相似性進行處理
  • \(Neuron(\mathbf{x}, {\mathbf{x}}') = tanh(\gamma \mathbf{x}^T \mathbf{w}')\)
    • NNet:\(\mathbf{w}\) 與 \(\mathbf{x}\) 的相似
  • \(DNASim(\mathbf{x}, {\mathbf{x}}') = EditDistance(\mathbf{x}, {\mathbf{x}}')\)
    • 使兩個 DNA 字串相同,最少修改的步驟
  • kernel
    • Poly:\(K_Q(\mathbf{x},{\mathbf{x}}')=(\zeta +\gamma \mathbf{x}^T\mathbf{{x}'})^Q\)
    • \(Gaussian(\mathbf{x},{\mathbf{x}}')=e^{(-\gamma \left \| \mathbf{x}-{\mathbf{x}}' \right \|^2)}\)
      • 同時符合 kernel & RBF 
  • RBF
    • 借由 \(X\) 空間的距離決定相似,越近越大,越遠越小
    • \(Gaussian(\mathbf{x},{\mathbf{x}}')=e^{(-\gamma \left \| \mathbf{x}-{\mathbf{x}}' \right \|^2)}\)
      • 同時符合 kernel & RBF
    • \(Truncated(\mathbf{x},{\mathbf{x}}')=\left [\left \| \mathbf{x}-{\mathbf{x}}' \right \|\le 1  \right ](1-\left \| \mathbf{x}-{\mathbf{x}}' \right \|^2)\)

Regularized Full RBF Network

full RBF Network for ridge regression
\(M=N\),也就是將所有的訓練點 \(\mathbf{x}\) 皆為中心點 \(\boldsymbol\mu_m = \mathbf{x}_n\)
$$ \begin{align*} h(\mathbf{x})&=\sum_{m=1}^{N}\beta _m \mathrm{RBF}(\mathbf{x},\mathbf{x}_m)\\ \mathbf{z}_n &= \begin{bmatrix}\mathrm{RBF}(\mathbf{x}_n,\mathbf{x}_1) & \mathrm{RBF}(\mathbf{x}_n,\mathbf{x}_2) & \cdots & \mathrm{RBF}(\mathbf{x}_n,\mathbf{x}_N)\end{bmatrix}^T\\ \mathbf{Z} &= \begin{bmatrix} \mathbf{z}_1^T\\ \mathbf{z}_2^T\\ \vdots \\ \mathbf{z}_N^T \end{bmatrix}\\ \boldsymbol\beta&=(\mathbf{Z}^T\mathbf{Z}+\lambda \mathbf{I})^{-1}\mathbf{Z}^T\mathbf{y} \end{align*} $$
$$ h(\mathbf{x})=\mathrm{Output}\left (\sum_{m=1}^{M}\beta _m\mathrm{RBF}(\mathbf{x},\boldsymbol\mu _m) \right ) $$ 這邊將 \(b=0\),且為了偷懶,將所有的訓練點 \(\mathbf{x}\) 都當作中心點 \(\boldsymbol\mu _m\)
所有點都有影響力,決定輸入 \(\mathbf{x}\) 的 \(y\)

先討論一個特殊的情況,假設 \(\beta _m=1\cdot y_m\),且 RBF 為 Gaussian
$$ g_{uniform}(\mathbf{x})=sign\left ( \sum_{m=1}^{N}y_m e^{-\gamma \left \| \mathbf{x}-\mathbf{x}_m \right \|^2} \right ) $$ 這就是一個 uniform 形式的 RBF,取每個點的平均意見
但因為 RBF 是 Gaussian ,通常最靠近的 \(\mathbf{x}_m\) 將決定絕大部分的結果
那麼何不直接挑 \(e^{-\gamma \left \| \mathbf{x}-\mathbf{x}_m \right \|^2}\) 最大值的 \(\mathbf{x}_m\)
$$ g_{nbor}(\mathbf{x})=y_m\ s.t.\ \mathbf{x}\ closest\ to\ \mathbf{x}_m $$ 這也就是 nearest neighbor model
只用一個 \(\mathbf{x}_m\) 決定似乎不保險,那用 k 個呢?k nearest neighbor (KNN)
這是個偷懶的方法,訓練時很簡單,記住 \(\mathbf{x}_m\) 就好,但預測時就得找出最接近的幾個值了

回過頭來,若取 square error
$$ h(\mathbf{x})=\sum_{m=1}^{M}\beta _m\mathrm{RBF}(\mathbf{x},\boldsymbol\mu _m) $$ 先轉換訓練資料 \(\mathbf{x}_n\) $$ \mathbf{z}_n = \begin{bmatrix}\mathrm{RBF}(\mathbf{x}_n,\mathbf{x}_1) & \mathrm{RBF}(\mathbf{x}_n,\mathbf{x}_2) & \cdots & \mathrm{RBF}(\mathbf{x}_n,\mathbf{x}_N)\end{bmatrix}^T\\ $$ $$ \mathbf{Z} = \begin{bmatrix} \mathbf{z}_1^T\\ \mathbf{z}_2^T\\ \vdots \\ \mathbf{z}_N^T \end{bmatrix}\\ $$ 可得
$$ \begin{align*} E_{in}(\boldsymbol\beta) &= \frac{1}{N}\left \| \underset{\mathrm{N\times N\ }}{\underbrace{\mathbf{Z}}}\underset{\mathrm{N\times 1}}{\underbrace{\boldsymbol\beta}}-\underset{\mathrm{N\times 1}}{\underbrace{\mathbf{y}}} \right \|^2 \end{align*} $$ 借由 [ML] 機器學習基石:第九講 Linear Regression
可得 \(\boldsymbol\beta=(\mathbf{Z}^T\mathbf{Z})^{-1}\mathbf{Z}^T\mathbf{y}\)
\(\mathbf{Z}\) 為對稱矩陣,且當 \(\mathbf{x}_n\) 都不一樣時,\(\mathbf{Z}\) 必有其 inverse
$$ \begin{align*} \boldsymbol\beta&=(\mathbf{Z}^T\mathbf{Z})^{-1}\mathbf{Z}^T\mathbf{y} \\ &= (\mathbf{Z}\mathbf{Z})^{-1}\mathbf{Z}\mathbf{y}\\ &= \mathbf{Z}^{-1}\mathbf{Z}^{-1}\mathbf{Z}\mathbf{y}\\ &= \mathbf{Z}^{-1}\mathbf{y}\\ \end{align*} $$ 將其代入 \(E_{in}\)
$$ \begin{align*} E_{in}(\boldsymbol\beta) &= \frac{1}{N}\left \| \mathbf{Z}\boldsymbol\beta-\mathbf{y} \right \|^2\\ &=\frac{1}{N}\left \| \mathbf{Z}\mathbf{Z}^{-1}\mathbf{y}-\mathbf{y} \right \|^2\\ &=\frac{1}{N}\left \| \mathbf{y}-\mathbf{y} \right \|^2\\ &=0 \end{align*} $$ 看起來很完美,但記得,對於 Machine learning 這將造成 overfitting

所以加入 ridge regression 也就是 regularization 為 L2
$$ \begin{align*} \underset{\boldsymbol\beta}{min}\ \ E_{in}(\boldsymbol\beta) &= \underset{\boldsymbol\beta}{min}\ \ E_{in}(\boldsymbol\beta) + \frac{\lambda}{N}\boldsymbol\beta^T\boldsymbol\beta\\ &= \underset{\boldsymbol\beta}{min}\ \ \frac{1}{N}\left \| \mathbf{Z}\boldsymbol\beta-\mathbf{y}\right \|^2 + \frac{\lambda}{N}\boldsymbol\beta^T\boldsymbol\beta\\ \end{align*} $$ 借由矩陣微分
$$ \begin{align*} \triangledown E_{in}(\boldsymbol\beta) &= \frac{\partial }{\partial \boldsymbol\beta}\left (\frac{1}{N}\left \| \mathbf{Z}\boldsymbol\beta-\mathbf{y}\right \|^2 + \frac{\lambda}{N}\boldsymbol\beta^T\boldsymbol\beta \right )\\ &= \frac{\partial }{\partial \boldsymbol\beta}\left (\frac{1}{N}( \mathbf{Z}\boldsymbol\beta-\mathbf{y})^T( \mathbf{Z}\boldsymbol\beta-\mathbf{y}) + \frac{\lambda}{N}\boldsymbol\beta^T\boldsymbol\beta \right )\\ &= \frac{\partial }{\partial \boldsymbol\beta}\left (\frac{1}{N}( \boldsymbol\beta^T\mathbf{Z}^T-\mathbf{y}^T)( \mathbf{Z}\boldsymbol\beta-\mathbf{y}) + \frac{\lambda}{N}\boldsymbol\beta^T\boldsymbol\beta \right )\\ &= \frac{\partial }{\partial \boldsymbol\beta}\left (\frac{1}{N}( \boldsymbol\beta^T\mathbf{Z}^T\mathbf{Z}\boldsymbol\beta -\boldsymbol\beta^T\mathbf{Z}^T\mathbf{y}-\mathbf{y}^T\mathbf{Z}\boldsymbol\beta+\mathbf{y}^T\mathbf{y}) + \frac{\lambda}{N}\boldsymbol\beta^T\boldsymbol\beta \right )\\ &= \frac{\partial }{\partial \boldsymbol\beta}\left (\frac{1}{N}( \boldsymbol\beta^T\mathbf{Z}^T\mathbf{Z}\boldsymbol\beta -2\boldsymbol\beta^T\mathbf{Z}^T\mathbf{y}+\mathbf{y}^T\mathbf{y}) + \frac{\lambda}{N}\boldsymbol\beta^T\boldsymbol\beta \right )\\ &=\frac{1}{N}\left ( 2\mathbf{Z}^T\mathbf{Z}\boldsymbol\beta-2\mathbf{Z}^T\mathbf{y}\right ) + \frac{2\lambda}{N}\boldsymbol\beta\\ &=\frac{2}{N}\mathbf{Z}^T\mathbf{Z}\boldsymbol\beta-\frac{2}{N}\mathbf{Z}^T\mathbf{y} + \frac{2\lambda}{N}\boldsymbol\beta\\ &=\frac{2}{N}\mathbf{Z}^T\mathbf{Z}\boldsymbol\beta+\frac{2\lambda}{N}\boldsymbol\beta-\frac{2}{N}\mathbf{Z}^T\mathbf{y}\\ &=\frac{2}{N}(\mathbf{Z}^T\mathbf{Z}+\lambda \mathbf{I})\boldsymbol\beta-\frac{2}{N}\mathbf{Z}^T\mathbf{y}\\ \end{align*} $$ 區域最佳解,微分等於 0,故
$$ \begin{align*} \triangledown E_{in}(\boldsymbol\beta) &=\frac{2}{N}(\mathbf{Z}^T\mathbf{Z}+\lambda \mathbf{I})\boldsymbol\beta-\frac{2}{N}\mathbf{Z}^T\mathbf{y} =0\\ \frac{2}{N}(\mathbf{Z}^T\mathbf{Z}+\lambda \mathbf{I})\boldsymbol\beta &=\frac{2}{N}\mathbf{Z}^T\mathbf{y}\\ (\mathbf{Z}^T\mathbf{Z}+\lambda \mathbf{I})\boldsymbol\beta &=\mathbf{Z}^T\mathbf{y}\\ \boldsymbol\beta &=(\mathbf{Z}^T\mathbf{Z}+\lambda \mathbf{I})^{-1}\mathbf{Z}^T\mathbf{y}\\ \end{align*} $$ 這個解與 KRR 的解 \(\boldsymbol\beta =(K+\lambda \mathbf{I})^{-1}\mathbf{y}\) 極度相似
可參考 [ML] 機器學習技法:第六講 Support Vector Regression (SVR)
事實上 \(\mathbf{Z} = [Gaussian(\mathbf{x}_n, \mathbf{x}_m)] = Gaussian\ kernel\ matrix\ \mathbf{K}\)
兩者差異的原因在於 regularization 針對 \(\boldsymbol\beta\) 的維度不同
KRR 是在無限維度上處理,而 regularized full RBFNet 是在有限維度上處理的
無限維度的原因,可參考 [ML] 機器學習技法:第三講 Kernel SVM
全部的點都拿來當中心點,容易 overfitting,且計算量又太大
適當的只選擇其中的點做為代表,像是 SVM 的 support vectors
並且限制 \(\boldsymbol\beta\) 的大小,才會更加準確

k-Means Algorithm

  1. 初始化 \(\boldsymbol\mu_1,\boldsymbol\mu_2,\cdots ,\boldsymbol\mu_k\)
    • 隨機從 \(\mathbf{x}_n\) 挑選出 k 個, k 用 validation 決定
  2. 交替優化 \(E_{in}\),直到 \(S_1,S_2,\cdots ,S_k\) 不再有改變
    1. 最佳化 \(S_1,S_2,\cdots ,S_k\)
      將每個 \(\mathbf{x}_n\) 都個別分類至最近的 \(\boldsymbol\mu_n\)
    2. 最佳化 \(\boldsymbol\mu_1,\boldsymbol\mu_2,\cdots ,\boldsymbol\mu_k\)
      從分完類的 \(S_n\) 計算出 \(\boldsymbol\mu_n\)
此為 unsupervised learning,且非常受歡迎
希望將 \(\mathbf{x}_n\) 分群 M 個,並從其中選出代表
$$ E_{in}(S_1,\cdots ,S_M;\boldsymbol\mu_1,\cdots ,\boldsymbol\mu_M)=\frac{1}{N}\sum_{n=1}^{N}\sum_{m=1}^{M}[\mathbf{x}_n \in S_m]\left \| \mathbf{x}_n-\boldsymbol\mu_m \right \|^2\\ \underset{\{S_1,\cdots ,S_M;\boldsymbol\mu_1,\cdots ,\boldsymbol\mu_M\}}{min} E_{in}(S_1,\cdots ,S_M;\boldsymbol\mu_1,\cdots ,\boldsymbol\mu_M) $$ 這個最佳化很困難,因為同時具有數值的最佳化 \(\mu_m\),還需分群的最佳化 \(S_m\)
數值的最佳化需要的是微分,但分群的最佳化需要的是所有的排列組合找出最好的
那是否可以個別最佳化呢?
假設 \(\boldsymbol\mu_1,\cdots ,\boldsymbol\mu_M\) 固定
那麼只需要決定 \(S_1,\cdots ,S_M\),怎麼決定 \(\mathbf{x}_n\) 屬於哪個群呢?
很簡單,\(\mathbf{x}_n\) 離哪個 \(\boldsymbol\mu_m\) 最近,就是屬於那個 \(S_m\)
再來 \(S_1,\cdots ,S_M\) 固定
$$ \begin{align*} \triangledown_{\boldsymbol\mu_m} E_{in}&=\frac{\partial }{\partial \boldsymbol\mu_m} \left (\frac{1}{N}\sum_{n=1}^{N}\sum_{m=1}^{M}[\mathbf{x}_n \in S_m]\left \| \mathbf{x}_n-\boldsymbol\mu_m \right \|^2 \right )\\ &= \frac{-2}{N}\sum_{n=1}^{N}[\mathbf{x}_n \in S_m](\mathbf{x}_n-\boldsymbol\mu_m )\\ &= \frac{-2}{N}\left (\sum_{n=1}^{N}[\mathbf{x}_n \in S_m]\mathbf{x}_n-\sum_{n=1}^{N}[\mathbf{x}_n \in S_m]\boldsymbol\mu_m \right ) \\ &= \frac{-2}{N}\left (\sum_{\mathbf{x}_n \in S_m}\mathbf{x}_n-| S_m|\boldsymbol\mu_m \right ) \\ \\ \triangledown_{\boldsymbol\mu_m} E_{in}&=\frac{-2}{N}\left (\sum_{\mathbf{x}_n \in S_m}\mathbf{x}_n-|S_m|\boldsymbol\mu_m \right )=0\\ \sum_{\mathbf{x}_n \in S_m}\mathbf{x}_n&=|S_m|\boldsymbol\mu_m\\ \boldsymbol\mu_m&=\frac{\sum_{\mathbf{x}_n \in S_m}\mathbf{x}_n}{|S_m|} \end{align*} $$ \(|S_m|\) 為集合共有幾個 \(\mathbf{x}_n\),所以 \(\boldsymbol\mu_m\) 其實就是 \(S_m\) 的平均
因為在過程中,\(E_{in}\) 是逐漸往下的,而 \(E_{in}\) 的下限為 0,故確定會收斂
歷史上,最先是用 k,所以將 M 改為 k
此為 unsupervised learning,因跟 \(y_n\) 無關
對 k 與初始值非常敏感,需特別注意

RBF Network Using k-Means

  1. 執行 k-Means,將 k=M 得到 \(\left \{ \boldsymbol\mu_m \right \}\) 
  2. 建立 \(\Phi (\mathbf{x})\) ,利用 RBF(例:Gaussian) 和 \(\boldsymbol\mu_m\)
    $$ \Phi (\mathbf{x}) = \begin{bmatrix}\mathrm{RBF}(\mathbf{x},\boldsymbol\mu_1) & \mathrm{RBF}(\mathbf{x},\boldsymbol\mu_2) & \cdots & \mathrm{RBF}(\mathbf{x},\boldsymbol\mu_M)\end{bmatrix}^T $$
  3. 建立 linear mode \(\{ \Phi (\mathbf{x}_n),y_n \}\) 得到 \(\boldsymbol\beta\)
  4. 回傳 \(g_{RBFNET}(\mathbf{x})=LinearHypothesis(\boldsymbol\beta,\Phi (\mathbf{x}))\)
需適當的選擇中心點的數目,不然可能會像第一張圖,都認為是叉叉
比較,但因為 Full RBF Network 以及 nearest neighbor 計算複雜,實務上並不常用
實務上並不常用 RBF Network,因與 Gaussian SVM or NNet 的表現差不多,但仍不失為一個好的想法

程式碼

k-Means 不見得適用所有情況,視情況需使用 Autoencoder
可參考 [ML] 機器學習技法:第十三講 Deep Learning
import numpy as np
import matplotlib.pyplot as plt

from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs

plt.figure(figsize=(8, 8))
# 用来正常顯示中文標簽
plt.rcParams['font.sans-serif']=['SimHei']
# 用来正常顯示負號
plt.rcParams['axes.unicode_minus']=False

n_samples = 1500
random_state = 170
# 產生 1500 筆資料,共有三群
X, y = make_blobs(n_samples=n_samples, random_state=random_state)

# 不正確的群數
y_pred = KMeans(n_clusters=2, random_state=random_state).fit_predict(X)

plt.subplot(221)
plt.scatter(X[:, 0], X[:, 1], c=y_pred)
plt.title("Incorrect Number of Blobs (錯誤的 k)")

# Anisotropically distributed data
# 非同方向縮放一致的分佈
transformation = [[0.60834549, -0.63667341], [-0.40887718, 0.85253229]]
X_aniso = np.dot(X, transformation)
y_pred = KMeans(n_clusters=3, random_state=random_state).fit_predict(X_aniso)

plt.subplot(222)
plt.scatter(X_aniso[:, 0], X_aniso[:, 1], c=y_pred)
plt.title("Anisotropically Distributed Blobs (非等比例分佈)")

# 不同標準差
X_varied, y_varied = make_blobs(n_samples=n_samples, cluster_std=[1.0, 2.5, 0.5], random_state=random_state)
y_pred = KMeans(n_clusters=3, random_state=random_state).fit_predict(X_varied)

plt.subplot(223)
plt.scatter(X_varied[:, 0], X_varied[:, 1], c=y_pred)
plt.title("Unequal Variance (不同標準差)")

# Unevenly sized blobs
# >>> a = np.array([1, 2, 3])
# >>> b = np.array([2, 3, 4])
# >>> np.vstack((a,b))
# array([[1, 2, 3],
#        [2, 3, 4]])
# vstack 在第二個維度堆疊
X_filtered = np.vstack((X[y == 0][:500], X[y == 1][:100], X[y == 2][:10]))
y_pred = KMeans(n_clusters=3, random_state=random_state).fit_predict(X_filtered)

plt.subplot(224)
plt.scatter(X_filtered[:, 0], X_filtered[:, 1], c=y_pred)
plt.title("Unevenly Sized Blobs (數量不同)")

plt.show()
k-Means 壓縮圖片
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.metrics import pairwise_distances_argmin
from sklearn.datasets import load_sample_image
from sklearn.utils import shuffle
from time import time

# 壓縮為 64 個顏色
n_colors = 64

# 讀取照片
china = load_sample_image("china.jpg")

# 轉換為浮點數,範圍為 [0-1]
china = np.array(china, dtype=np.float64) / 255

# 讀取長寬與一個 pixel 的顏色數目
w, h, d = original_shape = tuple(china.shape)
assert d == 3
# 轉成 array
image_array = np.reshape(china, (w * h, d))

print("用原圖的小部分當樣本訓練 model")
t0 = time()
image_array_sample = shuffle(image_array, random_state=0)[:1000]
kmeans = KMeans(init='random', n_clusters=n_colors, random_state=0).fit(image_array_sample)
print("done in %0.3fs." % (time() - t0))

# 處理整張圖
print("在整張圖上預測顏色")
t0 = time()
# 預測,只會回傳中心點對應的 index
labels = kmeans.predict(image_array)
print("done in %0.3fs." % (time() - t0))

# 處理整張圖,但從原圖隨機挑出顏色
codebook_random = shuffle(image_array, random_state=0)[:n_colors + 1]
print("在整張圖上預測顏色 (隨機版)")
t0 = time()
# 挑選出 X 最接近 Y 的顏色,並送出 Y 的 index
labels_random = pairwise_distances_argmin(X=image_array, Y=codebook_random)
print("done in %0.3fs." % (time() - t0))

def recreate_image(codebook, labels, w, h):
    """用 codebook 和 labels 重新建立圖"""
    d = codebook.shape[1]
    image = np.zeros((w, h, d))
    label_idx = 0
    for i in range(w):
        for j in range(h):
            image[i][j] = codebook[labels[label_idx]]
            label_idx += 1
    return image

# 畫圖
# 用来正常顯示中文標簽
plt.rcParams['font.sans-serif']=['SimHei']
fig, axes = plt.subplots(1, 3)

axes[0].xaxis.set_visible(False)
axes[0].yaxis.set_visible(False)
axes[0].set_title('原始圖 (96,615 colors)')
axes[0].imshow(china)

axes[1].xaxis.set_visible(False)
axes[1].yaxis.set_visible(False)
axes[1].set_title('壓縮圖 (64 colors, K-Means)')
axes[1].imshow(recreate_image(kmeans.cluster_centers_, labels, w, h))

axes[2].xaxis.set_visible(False)
axes[2].yaxis.set_visible(False)
axes[2].set_title('壓縮圖 (64 colors, Random)')
axes[2].imshow(recreate_image(codebook_random, labels_random, w, h))

plt.show()

參考

sklearn.cluster.KMeans

留言