Machine Learning

Full Course

講師 - 呂家睿

  • 建中資訊38屆學術長+副社
  • 玩雀魂
  • 頭像是應急食品
  • 被電爛
  • 有問題歡迎來問我啊
  • Fastapi
  • Qt(C++)
  • 數學好難
  • 一點點sandbox
  • Machine Learning
  • discord bot
  • 打開電腦

學術力

講師 - 林瑋浩

成功電研38屆教學

  • 擅長寫O(2ⁿ)演算法
  • 不會數學
  • 回訊息很快
  • C++
  • Python
  • little Web前端
  • Discord bot
  • Bongosort
  • Machine Learning
  • Godot

學術力

CNN

CNN

Convolutional Neural Network

  • 卷基層
  • 池化層
  • 全連接層

一種專門處理圖像的神經網路,中文叫做「卷積」神經網路

CNN - 卷積層

在上次的課程中我們做mnist資料集(手寫數字)時我們是把每個像素都傳進去分析

28 * 28 = 724 px

6904 * 4609 = 31866626

CNN - 卷積層

卷積是一種數學運算,一種有點恐怖的數學運算

\displaystyle (f*g)(t)\triangleq \int _{-\infty }^{\infty }f(\tau )g(t-\tau )\,\mathrm {d} \tau

在這一層我們會把我們的圖像跟特徵檢測器做卷積運算,然後得到一個特徵圖

這裡我們指的卷積嚴格來說不是數學的這個卷積

CNN - 卷積層

其實我們人在看照片的時候並不是一個像素一個像素看,而是以小圖形判斷大圖形,以大圖形判斷圖像內容

BAD

GOOD

CNN - 卷積層

所以我們會用不只一種特徵偵測器來幫我們找不同的小形狀

然後我們用一次ReLU去掉負值

ReLU 

  • 最常用的激活函數
  • 非常快
  • 導數為1是個好東西

CNN - 池化層

雖然我們現在已經改成用小圖形來判斷,但資料量還是太大了需要減少

Max Pooling:

非常簡單,在2x2的格子裡面取值最大的

Average Pooling:

在2x2的格子裡面平均值

CNN 

我們會把前面兩部重複好幾次再把它攤平,建構普通的神經網路

Code

conv

恩正常來講不會這樣寫,但我還是展示一下最原始的寫法幫助你們了解

import numpy as np

image = np.random.rand(5, 5)
kernel = np.array([[1, 0, -1], 
                   [1, 0, -1], 
                   [1, 0, -1]])
output = np.zeros((3, 3))

for i in range(3):
    for j in range(3):
        chunk = image[i:i+3, j:j+3]
        
        output[i, j] = np.sum(chunk * kernel)

image

10-1
10-1
​10-1

pool

恩正常來講不會這樣寫,但我還是展示一下最原始的寫法幫助你們了解

import numpy as np

feature_map = np.random.rand(4, 4)

output = np.zeros((2, 2))

for i in range(0, 4, 2):
    for j in range(0, 4, 2):
        block = feature_map[i:i+2, j:j+2]
        
        output[i//2, j//2] = np.max(block)

真正在寫的時候feature_map會是上一頁得到的output

實作

實作

我們今天要來用CIFAR-10資料集,這是一個很經典的圖像資料集,包含10個類別的圖像

Code

pip install torchvision

首先我們要取得資料集

這裡面有一些常用資料集

import torch
import torch.nn as nn
import torchvision
from torchvision.transforms import transforms

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

num_epochs = 5
batch_size = 4
learning_rate = 0.001

transform = transforms.Compose(
    [transforms.ToTensor(),
     transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])


train_dataset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)

test_dataset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform)

train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True)

test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=batch_size, shuffle=False)

epoch 世代

batch size 資料分群

learning rate 學習率

建立一個把圖片變成張量的工具,0.5是標準差

取得訓練和測試的資料集

Code

簡單處理一下資料內容還有讓資料可以呈現

classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')

def imshow(img):
    img = img / 2 + 0.5  
    npimg = img.numpy()
    plt.imshow(np.transpose(npimg, (1, 2, 0)))
    plt.show()


dataiter = iter(train_loader)
images, labels = next(dataiter)

imshow(torchvision.utils.make_grid(images))

資料的十種類別

把資料轉換成numpy形式(才能用pyplot呈現)

從訓練資料中抓出幾張圖片

Code

class ConvNet(nn.Module):
    def __init__(self):
        self.conv1 = nn.Conv2d(3, 6, 5)
        self.pool = nn.MaxPool2d(2, 2)
        self.conv2 = nn.Conv2d(6, 16, 5)
        self.fc1 = nn.Linear(16*5*5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)
        
        
    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))  # -> n, 6, 14, 14
        x = self.pool(F.relu(self.conv2(x)))  # -> n, 16, 5, 5
        x = x.view(-1, 16 * 5 * 5)            # -> n, 400
        x = F.relu(self.fc1(x))               # -> n, 120
        x = F.relu(self.fc2(x))               # -> n, 84
        x = self.fc3(x)                       # -> n, 10
        return x

接下來我們要搞定核心的部分,也就是我們的模型

結構

前向傳播

卷積

池化

卷積

全連接層x3

Code

model = ConvNet().to(device)

criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)

n_total_steps = len(train_loader)
for epoch in range(num_epochs):
    for i, (images, labels) in enumerate(train_loader):
        images = images.to(device)
        labels = labels.to(device)

        outputs = model(images)
        loss = criterion(outputs, labels)

        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        if (i+1) % 2000 == 0:
            print (f'Epoch [{epoch+1}/{num_epochs}], Step [{i+1}/{n_total_steps}], Loss: {loss.item():.4f}')

print('Finished Training')
PATH = './cnn.pth'
torch.save(model.state_dict(), PATH)

有了模型之後我們可以開始訓練

接模型

optim跟損失函數

前向傳播

後向傳播

可以把我們的模型存起來

拿資料

Code

with torch.no_grad():
    n_correct = 0
    n_samples = 0
    n_class_correct = [0 for i in range(10)]
    n_class_samples = [0 for i in range(10)]
    for images, labels in test_loader:
        images = images.to(device)
        labels = labels.to(device)
        outputs = model(images)
        # max returns (value ,index)
        _, predicted = torch.max(outputs, 1)
        n_samples += labels.size(0)
        n_correct += (predicted == labels).sum().item()
        
        for i in range(batch_size):
            label = labels[i]
            pred = predicted[i]
            if (label == pred):
                n_class_correct[label] += 1
            n_class_samples[label] += 1

    acc = 100.0 * n_correct / n_samples
    print(f'Accuracy of the network: {acc} %')

    for i in range(10):
        acc = 100.0 * n_class_correct[i] / n_class_samples[i]
        print(f'Accuracy of {classes[i]}: {acc} %')

最後可以來測試

Code

如果電腦沒有gpu的話建議使用google colab,不然大概率會等到天荒地老

現在模型的預測率偏低,可以調調看參數或模型來看成效

看看能不能把accuracy調到80%以上

Code

import torchvision.models as models
import torch.nn as nn

model = models.resnet18(weights=models.ResNet18_Weights.DEFAULT)

for param in model.parameters():
    param.requires_grad = False


model.fc = nn.Linear(in_features=model.fc.in_features, out_features=10)

偷模型的部分

下課!!!!!

Made with Slides.com