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 是一个非常好的举例,我们可以很好的看到这个神经网路的结构状况,也非常简洁的就可以去呈现,因此在这边我们先提出来了,让大家去理解一下神经网路的状况
  • 那明天我们来稍微聊聊神经网路的灵活性,和可以变化的部分

<<:  学习笔记:一起进入 PixiJS 的世界 (二)

>>:  Day21-Kubernetes 那些事 - Volume

【没钱买ps,PyQt自己写】Day 3 - 用 pyinstaller 将 python 程序打包,把每天的成果分享给你的亲朋好友

看完这篇文章你会得到的成果图 因为 PyQt5 要学的东西太多, 我们先来学打包 python 好了...

#28 No-code 之旅 — 客制化 Next.js 的错误页面

嗨!因为最近系列文快要结束了,所以也准备把专案推上去 production 了。Next.js 有列...

第六天:在 Windows 上安装 Gradle

在 Windows(在这系列里指的是 Windows 10 以上的版本)上除非您使用 WSL 环境,...

[Day 05] Swift 简单入门

由於目前只是想做一个跨 Android手机以及 iOS手机的 APP,所以目前是想先用之前 稍微摸过...

[12] 增加 input 输入功能

接着 input 输入的各种功能才可以制作介面互动 所以这边我们使用套件input npm i in...