AI Cho Mọi Người

AI Cho Mọi Người

Softmax Regression

 

 

Ở bài học trước, chúng ta dùng logistic regression cho bài toán phân loại nhị phân (binary classification). Hàm sigmoid được dùng để ánh xạ giá trị output o (\(o = X \cdot W\)) về (0,1).

Trong bài này, chúng ta sẽ học các phương pháp phân loại cho bài toán có nhiều loại (multi-class classification). Ví dụ, chúng ta muốn cài đặt chương trình để phân loại các loài hoa Iris dựa vào IRIS dataset. IRIS dataset có 3 loài hoa, và mỗi loài hoa có 4 đặc trưng.

 

Sepal_LengthSepal_WidthPetal_LengthPetal_WidthLabel
5.13.51.40.20.0
4.93.01.40.20.0
4.73.21.30.20.0
4.63.11.50.20.0
5.03.61.40.20.0
5.43.91.70.40.0
4.63.41.40.30.0
5.03.41.50.20.0
4.42.91.40.20.0
4.93.11.50.10.0
5.43.71.50.20.0
4.83.41.60.20.0
4.83.01.40.10.0
4.33.01.10.10.0
5.84.01.20.20.0
5.74.41.50.40.0
5.43.91.30.40.0
5.13.51.40.30.0
5.73.81.70.30.0
5.13.81.50.30.0
5.43.41.70.20.0
5.13.71.50.40.0
4.63.61.00.20.0
5.13.31.70.50.0
4.83.41.90.20.0
5.03.01.60.20.0
5.03.41.60.40.0
5.23.51.50.20.0
5.23.41.40.20.0
4.73.21.60.20.0
4.83.11.60.20.0
5.43.41.50.40.0
5.24.11.50.10.0
5.54.21.40.20.0
4.93.11.50.10.0
5.03.21.20.20.0
5.53.51.30.20.0
4.93.11.50.10.0
4.43.01.30.20.0
5.13.41.50.20.0
5.03.51.30.30.0
4.52.31.30.30.0
4.43.21.30.20.0
5.03.51.60.60.0
5.13.81.90.40.0
4.83.01.40.30.0
5.13.81.60.20.0
4.63.21.40.20.0
5.33.71.50.20.0
5.03.31.40.20.0
7.03.24.71.41.0
6.43.24.51.51.0
6.93.14.91.51.0
5.52.34.01.31.0
6.52.84.61.51.0
5.72.84.51.31.0
6.33.34.71.61.0
4.92.43.31.01.0
6.62.94.61.31.0
5.22.73.91.41.0
5.02.03.51.01.0
5.93.04.21.51.0
6.02.24.01.01.0
6.12.94.71.41.0
5.62.93.61.31.0
6.73.14.41.41.0
5.63.04.51.51.0
5.82.74.11.01.0
6.22.24.51.51.0
5.62.53.91.11.0
5.93.24.81.81.0
6.12.84.01.31.0
6.32.54.91.51.0
6.12.84.71.21.0
6.42.94.31.31.0
6.63.04.41.41.0
6.82.84.81.41.0
6.73.05.01.71.0
6.02.94.51.51.0
5.72.63.51.01.0
5.52.43.81.11.0
5.52.43.71.01.0
5.82.73.91.21.0
6.02.75.11.61.0
5.43.04.51.51.0
6.03.44.51.61.0
6.73.14.71.51.0
6.32.34.41.31.0
5.63.04.11.31.0
5.52.54.01.31.0
5.52.64.41.21.0
6.13.04.61.41.0
5.82.64.01.21.0
5.02.33.31.01.0
5.62.74.21.31.0
5.73.04.21.21.0
5.72.94.21.31.0
6.22.94.31.31.0
5.12.53.01.11.0
5.72.84.11.31.0
6.33.36.02.52.0
5.82.75.11.92.0
7.13.05.92.12.0
6.32.95.61.82.0
6.53.05.82.22.0
7.63.06.62.12.0
4.92.54.51.72.0
7.32.96.31.82.0
6.72.55.81.82.0
7.23.66.12.52.0
6.53.25.12.02.0
6.42.75.31.92.0
6.83.05.52.12.0
5.72.55.02.02.0
5.82.85.12.42.0
6.43.25.32.32.0
6.53.05.51.82.0
7.73.86.72.22.0
7.72.66.92.32.0
6.02.25.01.52.0
6.93.25.72.32.0
5.62.84.92.02.0
7.72.86.72.02.0
6.32.74.91.82.0
6.73.35.72.12.0
7.23.26.01.82.0
6.22.84.81.82.0
6.13.04.91.82.0
6.42.85.62.12.0
7.23.05.81.62.0
7.42.86.11.92.0
7.93.86.42.02.0
6.42.85.62.22.0
6.32.85.11.52.0
6.12.65.61.42.0
7.73.06.12.32.0
6.33.45.62.42.0
6.43.15.51.82.0
6.03.04.81.82.0
6.93.15.42.12.0
6.73.15.62.42.0
6.93.15.12.32.0
5.82.75.11.92.0
6.83.25.92.32.0
6.73.35.72.52.0
6.73.05.22.32.0
6.32.55.01.92.0
6.53.05.22.02.0
6.23.45.42.32.0
5.93.05.11.82.0

 

Để thuận tiện cho việc minh họa trực quan, chúng ta sẽ chỉ dùng 2 đặc trưng đầu từ IRIS dataset. Phương pháp đơn giản để giải quyết bài toán multi-class classification là dùng softmax regression. Softmax regression và logistic regression tương đối giống nhau, ngoại trừ hai điểm sau.

– Softmax regression có số node output bằng với số class của bài toán
– Softmax regression dùng hàm softmax (thay vì hàm sigmoid trong logistic regression)

 

Hàm softmax

Đầu vào của hàm softmax là một vector các giá trị số thực và cho ra các giá trị thuộc khoảng (0,1). Tổng các giá trị đầu ra của hàm softmax là 1. Gọi o là giá trị output (\(o = X \cdot W\); o là vector có độ dài N) được tính tương tự theo bài toán linear regression, giá trị softmax cho output \(o_i\) được tính như sau

$$
p_i = softmax(o_i) = \frac{e^{o_i}}{\sum_{k=1}^N e^{o_k} }
$$

Sau khi tính softmax cho output o, softmax regression trả về một vector các giá trị nằm trong khoảng (0, 1). Input X được phân loại vào class \(i\) có giá trị p_i lớn nhất.

Đạo hàm của hàm softmax có dạng sau

$$
\frac{\partial p_i}{\partial o_j} = \left\{\begin{matrix}
p_i(1 – p_j) & i = j\\
– p_j\cdot p_i & i \neq j
\end{matrix}\right.
$$

 

Source code cho hàm softmax

def softmax(X):
    exps = np.exp(X)
    return exps / np.sum(exps)

 

Cross Entropy Loss

Cross entropy thường đi cùng với hàm softmax để tính loss. Gọi p là vector được tình từ hàm softmax và y là label ở dạng one-hot encoding. Giá trị loss L được tính như sau
$$
L = H(y,p) = -\sum_i y_ilog(p_i)
$$

Đạo hàm của L theo \(o_i\) có dạng sau
$$
\frac{\partial L}{\partial o_i} = p_i – y_i
$$

Chứng minh công thức đạo hàm của L theo \(o_i\) như sau
$$
\frac{\partial L}{\partial o_i}=-\sum_ky_k\frac{\partial \log p_k}{\partial o_i}\\
\,\,\,\,\,\,=-\sum_ky_k\frac{1}{p_k}\frac{\partial p_k}{\partial o_i}\\
\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,=-y_i(1-p_i)-\sum_{k\neq i}y_k\frac{1}{p_k}({-p_kp_i})\\
\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,=-y_i(1-p_i)+\sum_{k\neq i}y_k({p_i})\\
\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,=-y_i+y_ip_i+\sum_{k\neq i}y_k({p_i})\\
\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,=p_i\left(\sum_ky_k\right)-y_i=p_i-y_i
$$

 

Source code cho hàm cross entropy

def cross_entropy(X,y):    
    m = y.shape[0]
    p = softmax(X)
    
    log_likelihood = -np.log(p[range(m),y])
    loss = np.sum(log_likelihood) / m
    
    return loss

 

Áp dụng softmax regression cho bài toán phân loại hoa Iris

Bộ dữ liệu Iris có 150 mẫu dữ liệu cho 3 loài hoa, và có 4 đặc trưng. Trong phần này, chúng ta sẽ sử dụng 2 đặc trưng ở cột 3 và 4 để phân loại 3 loài hoa Iris. Source code để đọc bộ dữ liệu Iris và hiển thị như sau

import numpy as np
import matplotlib.pyplot as plt
from sklearn import preprocessing

iris = np.genfromtxt('iris_full.csv', dtype=None, delimiter=',', skip_header=1) 
X = iris[:, 2:4]
y = iris[:, 4]

X = preprocessing.scale(X)
y = y.astype('uint8')

plt.figure(figsize=(10, 6))
plt.scatter(X[y == 0][:, 0], X[y == 0][:, 1], color='b', label='0')
plt.scatter(X[y == 1][:, 0], X[y == 1][:, 1], color='r', label='1')
plt.scatter(X[y == 2][:, 0], X[y == 2][:, 1], color='g', label='2')
plt.legend()

Chú ý là chúng ta chỉ dùng 2 đặc trưng ở cột dữ liệu thứ 3 và 4. Do đó, vector đặc trưng X có shape là (150, 2). Sau đó, X được chuẩn hóa dùng hàm scale().

 

Kết quả hiện thị dữ liệu Iris sau khi được chuẩn hóa như sau.

 

Source code để huấn luyện softmax regression như sau

N = 50 # number of points per class
D = 2  # dimensionality
K = 3  # number of classes

# initialize parameters randomly
W = 0.01 * np.random.randn(D,K)
b = np.zeros((1,K))

# gradient descent loop
num_examples = X.shape[0]
learning_rate = 0.05

losses = []
for i in range(1000):  
    # evaluate class scores
    scores = np.dot(X, W) + b 

    # compute the class probabilities
    exp_scores = np.exp(scores)
    probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)

    # compute the loss: average cross-entropy loss and regularization
    corect_logprobs = -np.log(probs[range(num_examples),y])
    loss = np.sum(corect_logprobs)/num_examples
    if i % 5 == 0:        
        losses.append(loss)

    # compute the gradient on scores
    dscores = probs
    dscores[range(num_examples),y] -= 1
    dscores /= num_examples

    # backpropate the gradient to the parameters (W,b)
    dW = np.dot(X.T, dscores)
    db = np.sum(dscores, axis=0, keepdims=True)

    # perform a parameter update
    W += -learning_rate * dW
    b += -learning_rate * db

Ở đây, softmax regression được huấn luyện với 1000 epochlearning_rate = 0.05. Giá trị loss được lưu sau 5 epoch. Hình sau hiển thị giá trị loss giảm qua quá trình huấn luyện

 

Chúng ta có thể tính độ chính xác bằng cách so sánh kết quả phân loại với label y như sau

Để có cái nhìn trực quan hơn về kết quả phân loại, chúng ta có thể hiển thị miền phân loại như sau

h = 0.01
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
Z = np.dot(np.c_[xx.ravel(), yy.ravel()], W) + b
Z = np.argmax(Z, axis=1)
Z = Z.reshape(xx.shape)

fig = plt.figure()
plt.contourf(xx, yy, Z, cmap=plt.cm.Spectral, alpha=0.8)
plt.scatter(X[:, 0], X[:, 1], c=y, s=40, cmap=plt.cm.Spectral)
plt.xlim(xx.min(), xx.max())
plt.ylim(yy.min(), yy.max())

 

Kết quả miền phân loại