參考一:《Pytorch深度學習實踐》(第九集)
參考二:Otto-Neural-Net
注意:使用的數據來自kaggle,鏈接
由於上面給出的兩個參考鏈接,對代碼的講解都已經很詳細,所以這里不再贅述,下面按自己的理解整理了代碼如下:
Imports
import numpy as np import pandas as pd import os import time from xgboost import XGBClassifier import matplotlib.pyplot as plt import torch from torch.utils.data import Dataset, DataLoader import torch.nn as nn import torch.nn.functional as F import torch.optim as optim
Prepare Data
# 處理數據 csv_path = os.path.join('train.csv') datas = pd.read_csv(csv_path) datas = datas.copy() datas = datas.drop(columns='id') datas = datas.sample(frac=1) # 將category轉化為數字 datas.target = datas.target.astype('category').cat.codes
# 划分數據集 rows, _ = datas.shape # type(datas) 為 <class 'pandas.core.frame.DataFrame'> train_rows = int(rows*0.7) train_datas = datas.iloc[:train_rows, :] val_datas = datas.iloc[train_rows:, :] # 得到features和targets train_features = train_datas.loc[:, train_datas.columns!='target'].values # values 得到一個矩陣 train_targets = train_datas.target.values val_features = val_datas.loc[:, val_datas.columns!='target'].values val_targets = val_datas.target.values
# 封裝 繼承dataset class CustomDataset(Dataset): def __init__(self, features, targets): super(CustomDataset, self).__init__() self.features = features self.targets = targets def __len__(self): return len(self.features) def __getitem__(self, idx): return self.features[idx], self.targets[idx] # 得到Dataset類 train_ds = CustomDataset(train_features, train_targets) val_ds = CustomDataset(val_features, val_targets) # 得到DataLoader batch_size = 64 train_loader = DataLoader(train_ds, batch_size=batch_size) val_loader = DataLoader(val_ds, batch_size=batch_size)
Device
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
Design Model
class Net(torch.nn.Module): def __init__(self): super(Net, self).__init__() self.l1 = torch.nn.Linear(93, 64) self.bn = torch.nn.BatchNorm1d(num_features=64) self.l2 = torch.nn.Linear(64, 32) self.dropout = torch.nn.Dropout(p=0.1) self.l3 = torch.nn.Linear(32, 16) self.l4 = torch.nn.Linear(16, 9) def forward(self, x): # first layer x = self.l1(x) x = self.bn(x) x = torch.relu(x) # second layer x = self.l2(x) x = self.dropout(x) x = torch.relu(x) x = torch.relu(self.l3(x)) return self.l4(x) # 注意 這里不要加relu model = Net().to(device)
Construct Loss and Optimizer
criterion = torch.nn.CrossEntropyLoss().to(device)
optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.5)
Train and Validate
def train(): losses = 0.0 accs = 0.0 for idx, data in enumerate(train_loader, 0): inputs, targets = data inputs = inputs.to(device) targets = targets.to(device) optimizer.zero_grad() # forward + backward + update outputs = model(inputs.float()) loss = criterion(outputs, targets.long()) loss.backward() optimizer.step() losses += loss.item() _, predicted = torch.max(outputs.data, dim=1) accs += (predicted==targets).sum().item() losses /= len(train_loader) accs = accs * 100 / len(train_ds) print('Training: loss: %.2f accuracy: %.2f %%' %(losses, accs)) return losses, accs
def val(): losses = 0.0 accs = 0.0 with torch.no_grad(): for data in val_loader: inputs, labels = data inputs = inputs.to(device) labels = labels.to(device) outputs = model(inputs.float()) losses += criterion(outputs, labels.long()).item() _, predicted = torch.max(outputs.data, dim=1) accs += (predicted == labels).sum().item() losses /= len(val_loader) accs = accs * 100 / len(val_ds) print('Validating: loss: %.2f accuracy: %.2f %%' %(losses, accs)) return losses, accs
train_losses = [] val_losses = [] train_accs = [] val_accs = [] maxAcc = 0 # 記錄最高准確率 for epoch in range(100): print('[epoch: %d]' % (epoch+1)) losses, accs = train() train_losses.append(losses) train_accs.append(accs) losses, accs = val() val_losses.append(losses) val_accs.append(accs) if maxAcc < accs: maxAcc = accs check = np.greater(maxAcc, val_accs[-5:]) if (check.all()==True) and (epoch>20): print('Convergence met!\n') break print('Maximum validation accuracy: %.2f %%' % (maxAcc))
Plot Losses
# 這里采用了指數平滑 import math import matplotlib.pyplot as plt tmp_train_losses = [math.e**i for i in train_losses] tmp_val_losses = [math.e**i for i in val_losses] plt.figure(figsize=(10, 5)) plt.plot(tmp_train_losses, 'r', label='Training') plt.plot(tmp_val_losses, 'b', label='Validating') plt.xlabel('Epoch') plt.ylabel('Loss per epoch') plt.legend() plt.show()