iT邦幫忙

2021 iThome 鐵人賽

DAY 10
0
AI & Data

Deep Learning 從零開始到放棄的 30 天 PyTorch 數字辨識模型系列 第 10

Day-09 Logistic Regression 實作

  • 我們今天就要利用 sklearn 提供的 Iris(鳶尾花)資料,並且手工撰寫 logistic regression 來分類他們,並且利用今天的實作,解釋一下整個從零開始的模型訓練跟測試,完整的示範一遍基礎的流程

資料取得、資料前處理和目標訂定

  • 首先當然是先取得資料,然後來看看我們的目標是什麼
  • 所以這邊先引入鳶尾花資料集,並且作基礎的資料判斷
from sklearn import datasets

iris = datasets.load_iris()
print(iris.DESCR)
  • 可以看到我們的資料有三個種類,且有四種不同的參數特徵
  • 為了方便示範,我們就取兩個類別,且只留兩種特徵做判斷
  • 所以下面的操作會是取兩種資料特徵跟四個特徵
import pandas as pd
import numpy as np

# use pandas as dataframe and merge features and targets
feature = pd.DataFrame(iris.data, columns=iris.feature_names)

target = pd.DataFrame(iris.target, columns=['target'])
iris_data = pd.concat([feature, target], axis=1)

# keep only sepal length in cm, sepal width in cm and target
iris_data = iris_data[['sepal length (cm)', 'sepal width (cm)', 'target']]

# keep only Iris-Setosa and Iris-Versicolour classes
iris_data = iris_data[iris_data.target <= 1]
iris_data.head(5)
  • 那我們的目標就是基於兩個特徵,去判斷品種
  • 我們先把訓練資料跟測試資料分類出來,在這邊可以使用 sklearn 提供的 model_selection 函式把資料分為兩群 train、test
  • 那這邊要注意 Logistic Regression 我們還會先對資料做特徵的縮放(為了避免梯度下降時,因為資料特徵數值差異過大而造成不必要的效率問題,可以想像成 normalize),因此會用到 sklearn 的 StandardScaler 套件
from sklearn.model_selection import train_test_split

feature_train, feature_test, target_train, target_test = train_test_split(
    iris_data[['sepal length (cm)', 'sepal width (cm)']], iris_data[['target']],\
    test_size=0.3, random_state=4
)

from sklearn.preprocessing import StandardScaler

sc = StandardScaler()
feature_train = sc.fit_transform(feature_train)
feature_test = sc.fit_transform(feature_test)
target_train = np.array(target_train)
target_test = np.array(target_test)

Logistic Regression

  • 前面我們有資料了,那就是開始撰寫我們的 Logistic Regrssion 吧~
  • 我們前面有提到說 Logistic Regession 其實跟 Linear Regression 差別就只差了 sigmoid function,所以我們來看看程式會怎麼寫
# 1) model
# f = wx, sigmoid at the end
class LogisticRegression():
    def __init__(self):
        super(LogisticRegression, self).__init__()

    def linear(self, x, w):

        return np.dot(x, w)

    def sigmoid(self, x):
        
        return 1/(1 + np.exp(-x))

    def forward(self, x, w):
        y_predicted = self.sigmoid(self.linear(x, w))

        return y_predicted


model = LogisticRegression()

檢查參數 & 更新程式

  • 前面有提到說 Logistic Regression 的 Loss check 不能是 MSE,因此這邊我們用 CrossEntropy 作為 loss function,那筆者相信自己數學解釋的不是那麼好 QQ,所以想了解詳細數學的可能麻煩自己去查一下了
  • 那這邊的參數更新(這邊我們就開始稱呼為優化,因為確實是希望把參數更新的越來越好),就選擇跟 Linear Regression 一樣的 Gradient Descent
# 2) loss and optimizer
learning_rate = 0.01

# CrossEntropy
class CrossEntropy():
    def __init__(self):
        super(CrossEntropy, self).__init__()

    def func(self, f_x, y_head):
        
        return y_head * np.log(f_x) + (1 - y_head) * np.log(1 - f_x)

    def forward(self, f_x, y_head):
        
        return -(self.func( f_x, y_head ))


# GradientDescent
class GradientDescent():
    def __init__(self):
        super(GradientDescent, self).__init__()
    
    def func(self, w, lr, y_hat, sg, x):
        
        return w + lr * (y_hat - sg) * x

    def forward(self, w, lr, y_hat, sg, x):
        
        return self.func(w, lr, y_hat, sg, x)


criterion = CrossEntropy()
optimizer = GradientDescent()

開始訓練

  • 一樣依照 檢查錯誤率 -> 更新參數 的方式去修正資料,並且操作想要的次數
# 3) training loop
w = np.array([0, 0])
num_epochs = 100
for epoch in range(num_epochs):
    for i, data in enumerate(feature_train):
        # forward pass and loss
        y_predicted = model.forward(data, w)
        loss = criterion.forward(y_predicted, target_train[i])

        # update
        w = optimizer.forward(w, learning_rate, target_train[i], y_predicted, data)

    if (epoch+1) % 10 == 0:
        print(f'epoch {epoch + 1}: loss = {loss}')

完整程式示範可以看下面~

https://gist.github.com/fdff87554/48304f0db97167d2960cff9d5880fb05

每日小結

  • 從上面可以看到撰寫的流程並不是那們的簡單,所以就讓我們之後再感受 Framework 的威力吧~
  • 明天就來聊聊深度學習吧~

上一篇
Day-08 比訓練更重要的事情,Dataset
下一篇
Day-10 深度學習的介紹
系列文
Deep Learning 從零開始到放棄的 30 天 PyTorch 數字辨識模型31

尚未有邦友留言

立即登入留言