從學生時期開始接觸機器學習,當初以為的 Machine learning 就只要會處理資料、訓練模型、得到比較高的準確率,然後就此結束,但出社會後發現,從 Jupyter 到 Production 的路還有段距離,那該怎麼辦呢?
因此,接下來將會分幾個章節來介紹:
專案挑戰:化妝品分類
敘述:是否能分辨一張圖片有出現哪一個種類的化妝品,而化妝品的種類粗類為 → 口紅、眼線筆、指甲油、粉底液、粉餅、刷具、眼影盤
Pytorch 前言
Pytorch 為 Facebook 的深度學習框架,目前網路上也有相當多的資源以及介紹,因此在此不在多加贅述,那我這邊要介紹什麼呢?有許多的範例與教學都是以 MNIST 的資料集當作範例,但只要當我們想要開始客製化要修改資料集、Loss function等等,就會開始遇到貧頸,因此這邊會直接利用客製化搜集的資料集,來當作範例,供大家修改以及使用。
基本框架
基本上 Pytorch 可以把程式碼分成幾個段落,並且我們會依序來介紹如何建立
0. 事前準備
程式碼: github (本章節會用到的為 cosmetics-classification.ipynb 以及 split-train-test.ipynb )
資料集:下載連結
整體的資料夾結構為:
./
├── script
│ ├─ split_data.py
│ ├─ train.py
│ ├─ evaluate.py
│ ├─ config.py
│ └─ server.py
├── dataset
│ ├── cosmetics-category
│ │ ├── train
│ │ │ ├─ Compact_foundation
│ │ │ ├─ Eyebrow_pencil
│ │ │ ├─ Foundation
│ │ │ ├─ Lipstick
│ │ │ ├─ Makeup_brushes
│ │ │ ├─ Nail_Polish
│ │ │ └─ Palette
│ │ └── valid
│ │ ├─ Compact_foundation
│ │ ├─ Eyebrow_pencil
│ │ ├─ Foundation
│ │ ├─ Lipstick
│ │ ├─ Makeup_brushes
│ │ ├─ Nail_Polish
│ │ └─ Palette
│ ├── cosmetics-all
│ │ ├─ _PRrlNrSLhHGaUTfduYgQ6eOAdI.jpg
│ │ ├─ -b2cugUzKg6IIHIJjfXGcDnKsZA.jpg
│ │ ├─ -FK0wRGzJZ5NirgLw0CbvUf-7Og.jpg
│ │ └─ ...
│ ├── train.csv
│ ├── test.csv
│ └── annotation.csv
├── model
│ ├── model.pth
│ └── evaluate.txt
├── Dockerfile
├── cosmetics-classification.ipynb
└── split-train-test.ipynb
1. 資料搜集
利用 Google 的 Extension 叫做 Image downloader 來批次的下載 Pinterest 以及 Instagram 上的圖片,下面是我搜集的化妝品
總共為 7 個類別,分別為「口紅、眼線筆、指甲油、粉底液、粉餅、刷具以及眼影盤」,每個分類的圖片數量為:
粉餅: 161
眼線筆: 190
粉底液: 129
口紅: 431
刷具: 156
指甲油: 275
眼影盤: 61
資料集:下載連結
dataset
├── cosmetics-category
│ ├─ train
│ │ ├─ Compact_foundation
│ │ ├─ Eyebrow_pencil
│ │ ├─ Foundation
│ │ ├─ Lipstick
│ │ ├─ Makeup_brushes
│ │ ├─ Nail_Polish
│ │ └─ Palette
│ └─ valid
│ ├─ Compact_foundation
│ ├─ Eyebrow_pencil
│ ├─ Foundation
│ ├─ Lipstick
│ ├─ Makeup_brushes
│ ├─ Nail_Polish
│ └─ Palette
├── cosmetics-all
└── annotation.csv
解壓縮後資料節同上, cosmetics-category
為每個化妝品種類個別的圖片, cosmetics-all
為全部圖片都混在一起、而標記的 label
為 annotation.csv
,會區分兩個資料夾的原因,是因為在後續我們會分別利用這兩個資料夾來練習 pytorch
的 dataloader
。
2. 資料切割
這邊用的資料夾為 cosmetics-all
以及 annotation.csv
來做資料集的切割,程式碼的使用方式為 python split_data.py (Testing data 的比例) (random seed)
,例如我是切 80% 以及 20%:python split_data.py 0.2 10
。
3. 訓練模型
訓練模型這邊分五個部分
A. 匯入套件
這邊我們使用到的所以套件為:requirement.txt
B. 製作 Dataset
Dataset 的製作在 Pytorch 中的格式為:
class customize_dataset(Dataset):
def __init__(self):
# 初始化變數,這邊會一次將 Data 做處理 def __getitem__(self, index):
# 後續 Dataloader 會自動傳遞 index 變數
# 當 index = N 時,可以想像是要回傳資料集中的第 N 筆資料 def __len__(self):
# 資料集的長度
我們後續會將 train.csv
以及 test.csv
丟進 csvFile
的欄位當中,而 rootPath
為圖片所在位置的根目錄,transform
為是否將圖片做擴增的函示。
由於目前的 label
為 [Compact_foundation, Eyebrow_pencil, Foundation, Lipstick, Makeup_brushes, Nail_Polish, Palette]
,所以需先轉成數字類別 0 ~ 6
,這邊使用的方法是 pd.factorize()
。(注意:pytorch 的 crossentropy
函數,不需將 label 轉乘 one-hot-encoding
)
C. VGG16 模型
Pytorch 的模型製作格式為:
class customize_model(nn.Module):
def __init__(self):
super(customize_model, self).__init__() # 繼承
# 設定每一層的函數 def forward(self, x):
# 此時的 x 為輸入 (以此例則為 (batch_size, 224, 224, 3))
為了讓大家更好的去學習模型製作,這邊是將 VGG16 的模型展開,而更多的函數可以參考 torch.nn 。
倘若我們想要用 Pretrained 好的模型再做 Finetuning 則可參考:FINETUNING TORCHVISION MODELS,而我們這邊是利用 VGG16 在 imagenet pretrained 好的模型再進一步做 Finetuning。
C. 訓練函數
訓練函數的格式為:
def train(net, dataloader, optimizer, criterion, epochs):
net.train()
for i in range(epochs):
for x, label in dataloader:
x = x.to(device)
label = label.to(device, dtype=torch.long)
optimizer.zero_grad()
output = net(x)
# 預留位置01
loss = criterion(output, label)
loss.backward()
optimizer.step()
return net
上面的 script 為最基本的格式,如果需要近一步計算 accuracy
則可在預留位置01加上:
_, predicted = torch.max(output.data, 1)
accuracy = (predicted == label).sum().item()
D. 測試函數
測試函數的格式為:
def test(net, dataLoader, criterion):
net.eval()
for x, label in dataLoader:
x = x.to(device)
label = label.to(device, dtype=torch.long)
output = net(x)
loss = criterion(output, label)
# 預留位置01
這邊需注意的地方是,第一行需要先設定 net.eval()
,這樣的話會在模型遇到 Dropout
以及 Batch normalization
時有不一樣的調整。
E. 損失函數
損失函數的格式為:
class custom_loss(nn.Module):
def __init__(self):
super(custom_loss, self).__init__()
# 初始化變數設定 def forward(self, output, target):
# output 為模型預測出來的結果,target 為資料的 label
在實際上,蠻少的機會會需要客製化損失函數,通常會直接利用 pytorch 提供的,可以參考:TORCH.NN.MODULES.LOSS
F. 彙整 main()
這邊會將所有東西串在一起,並且會去呼叫上述的函數
4. Inference
在 inference 的時候,會需要將原本 Data transform 時的函數加入,如果只有一張圖的話,需要用 unsqueeze_(0)
將三維的陣列擴增為四維。
如果喜歡我的文章內容,請幫我多多鼓掌
1 個鼓掌:喜歡這篇的內容
10個鼓掌:期待這一系列的課程
30個鼓掌:希望未來能有更多相關文章