iT邦幫忙

2021 iThome 鐵人賽

DAY 22
0
AI & Data

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

Day-21 實際重現神經元是可做到的嗎? Feed-Forward Neural Network Building

  • 我們昨天利用 Iris Dataset + Logistic Regression 把所有的 Pytorch Framework 在 Training 的過程中會需要的所以東西都示範過一遍了,所以今天,就來建立我們的第一個神經網路吧~
  • 我們回顧一下下面這張圖

  • 我們今天就來試著建立看看圖片中最簡單的 Feed Forward Neural Network 吧~

Feed Forward Neural Network

  • Feed Forward Neural Network(前饋神經網路),屬於最早發明的神經網路之一
  • 那這種神經網路的概念非常單純,就是資料一層一層的往下傳遞,從輸入層一陸輸出到輸出層
  • 概念上神經網路分成三個大部分
    • 輸入層(Input Layer)
    • 隱藏層(Hidden Layer)
    • 輸出層(Output Layer)
  • 輸入層的大小會受到 feature size(特徵數量)影響
  • 輸出層的大小會受到 classes(分類數量)影響
  • 至於隱藏層,也就是中間的部分,就沒有任何特別的限制
  • 那我們今天就來時做一個 feed forward neural network 看看吧~

Code

  • 這邊一樣用 Iris Dataset 作為示範
  • Iris Dataset 共有四個不同的特徵,和總共三種不同的品種,那我們今天把隱藏層的神經元設為 4 個看看,所以我們的 feedforward neural network 會長成

  • 先來撰寫看看吧~
class FeedForwardNeuralNet(nn.Module):

    def __init__(self, input_size, hidden_size, num_classes):
        super(FeedForwardNeuralNet, self).__init__()
        # define first layer
        self.l1 = nn.Linear(input_size, hidden_size)
        # activation function
        self.relu = nn.ReLU()
        # define second layer
        self.l2 = nn.Linear(hidden_size, num_classes)

    def forward(self, x):
        out = self.l1(x)
        out = self.relu(out)
        out = self.l2(out)

        return out


model = FeedForwardNeuralNet(input_size, hidden_size, num_classes)
  • 我們可以看到第一層 Layer 就是接收 input 資料並輸出成 hidden layer 有的神經元數量,然後接了一個 Activation function(後面會再解釋),然後再傳遞給 Output layer,也就是第二層 layer 的狀況
  • 這樣我們就等於建立了 Feedforward network 的結構了,就讓我們看看完整的程式長怎樣吧~

完整 code

  • import 的部分就是一樣的 torchtorch.nnDatasetDataloader
import numpy as np
import pandas as pd

import torch
import torch.nn as nn
from torch.utils.data import Dataset, DataLoader
from torch.utils.data.sampler import SubsetRandomSampler
  • 設定基本參數
# base data inform and network data
input_size = 4
hidden_size = 4
num_classes = 3
num_epochs = 10
batch_size = 4
learning_rate = 0.001
  • 最前面的資料處理部分,就跟之前都一樣,只是這次我們可以把所有三個類別都使用了
  • 這邊提醒一下,資料呈現的方式有點不一樣了,我們希望呈現的樣子會變成類似下面這樣
    # tensor([[5.5000, 2.4000, 3.8000, 1.1000],
    #         [6.0000, 3.4000, 4.5000, 1.6000],
    #         [5.2000, 3.5000, 1.5000, 0.2000],
    #         [5.3000, 3.7000, 1.5000, 0.2000]]) tensor([1, 1, 0, 0])
    
  • 所以我們再 Dataset 裡面有做資料型態跟格式的轉換
# 0) data import and set as pytorch dataset
from sklearn import datasets

class IrisDataset(Dataset):

    # data loading
    def __init__(self):
        iris = datasets.load_iris()
        feature = pd.DataFrame(iris.data, columns=iris.feature_names)
        target = pd.DataFrame(iris.target, columns=['target'])
        iris_data = pd.concat([target, feature], axis=1)
        # Data type change and flatten targets
        self.x = torch.from_numpy(np.array(iris_data)[:, 1:].astype(np.float32))
        self.y = torch.from_numpy(np.array(iris_data)[:, [0]].astype(np.longlong).flatten())
        self.n_samples = self.x.shape[0]

    # working for indexing
    def __getitem__(self, index):
        
        return self.x[index], self.y[index]

    # return the length of our dataset
    def __len__(self):

        return self.n_samples


dataset = IrisDataset()

# create data spliter
def dataSplit(dataset, val_split=0.25, shuffle=False, random_seed=0):

    dataset_size = len(dataset)
    indices = list(range(dataset_size))
    split = int(np.floor(val_split * dataset_size))
    if shuffle:
        np.random.seed(random_seed)
        np.random.shuffle(indices)
    
    train_indices, val_indices = indices[split:], indices[:split]
    train_sampler = SubsetRandomSampler(train_indices)
    valid_sampler = SubsetRandomSampler(val_indices)

    return train_sampler, valid_sampler

# base split parameters
val_split = 0.25
shuffle_dataset = True
random_seed= 42

train_sampler, valid_sampler = \
    dataSplit(dataset=dataset, val_split=val_split, shuffle=shuffle_dataset, random_seed=random_seed)

train_loader = DataLoader(dataset, batch_size=batch_size, sampler=train_sampler)
val_loader = DataLoader(dataset, batch_size=batch_size, sampler=valid_sampler)
  • 建立 FeedForward
# 1) model build
class FeedForwardNeuralNet(nn.Module):

    def __init__(self, input_size, hidden_size, num_classes):
        super(FeedForwardNeuralNet, self).__init__()
        # define first layer
        self.l1 = nn.Linear(input_size, hidden_size)
        # activation function
        self.relu = nn.ReLU()
        # define second layer
        self.l2 = nn.Linear(hidden_size, num_classes)

    def forward(self, x):
        out = self.l1(x)
        out = self.relu(out)
        out = self.l2(out)

        return out


model = FeedForwardNeuralNet(input_size, hidden_size, num_classes)
  • 選擇適合的 loss function 和 optimizer
# 2) loss and optimizer
learning_rate = 0.01
# Cross Entropy
criterion = nn.CrossEntropyLoss()
# adam algorithm
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
  • 開始 Training
# 3) Training loop
n_total_steps = len(train_loader)
for epoch in range(num_epochs):
    for i, (datas, labels) in enumerate(train_loader):
        
        # init optimizer
        optimizer.zero_grad()
        
        # forward -> backward -> update
        outputs = model(datas)
        loss = criterion(outputs, labels)
        
        loss.backward()

        optimizer.step()

        if (i + 1) % 19 == 0:
            print(f'epoch {epoch+1}/{num_epochs}, step {i+1}/{n_total_steps}, loss = {loss.item():.4f}')
  • 那最後再執行 Testing 做檢查
# 4) Testing
with torch.no_grad():
    n_correct = 0
    n_samples = 0
    for datas, labels in val_loader:
        outputs = model(datas.float())
        _, predictions = torch.max(outputs, 1)
        n_samples += labels.shape[0]
        n_correct += (predictions == labels).sum().item()

    acc = 100.0 * n_correct / n_samples
    print(f'accuracy = {acc}')

完整程式碼

{%gist b496dc1b5e907e9335517b6942f41eda%}

每日小結

  • Neural Network 的建立其實會發現沒有想像中的複雜,甚至可以說很單純,就是依照想達到的行為,排列組合出來就可以了
  • Feed Forward Neural Network 是一個非常好的舉例,我們可以很好的看到這個神經網路的結構狀況,也非常簡潔的就可以去呈現,因此在這邊我們先提出來了,讓大家去理解一下神經網路的狀況
  • 那明天我們來稍微聊聊神經網路的靈活性,和可以變化的部分

上一篇
Day-20 用 Pytorch 的最後一個塊拼圖
下一篇
Day-22 更加靈活的神經網路,我們可以做哪些變化
系列文
Deep Learning 從零開始到放棄的 30 天 PyTorch 數字辨識模型31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言