hw1例题-李宏毅老师课后作业
寫在前面
跟著李宏毅老師從頭開始學習深度學習,因此這里用CSDN記錄深度學習的課后例題,需要注意的是以下代碼來源于網上,應該是李老師的代碼,版權不屬于我,寫這篇博客主要為了鞏固自己關于機器(深度)學習的知識。
問題描述
hw1是Kaggle原題(https://www.kaggle.com/competitions/ml2021spring-hw1/overview),簡單來說是預測Covid19的陽性人數。提供的文件有covid.train.csv,covid.test.csv 和sampleSubmission.csv。顯然任務是根據訓練集的數據訓練一個模型,并實現測試集的預測。
代碼部分
導入庫
import pandas as pd from torch import nn import numpy as np from torch.utils.data import Dataset, DataLoader, random_split from torch.utils.tensorboard import SummaryWriter import math from tqdm import tqdm #tqdm庫用于生成訓練時的進度條展示 import os import csv這里的庫只有tqdm庫不太了解,注釋說是用于進度條展示,所以應該是類似于用戶友好的圖形處理界面。
建立數據集函數
class COVID19Dataset(Dataset):def __init__(self,x,y=None):if y is None:self.y=yelse:self.y=torch.FloatTensor(y)self.x=torch.FloatTensor(x)def __getitem__(self,idx):if self.y is None:return self.x[idx]else:return self.x[idx],self.y[idx]def __len__(self):return len(self.x)上述函數建立了covid19dataset的類,繼承于torch庫里的dataset類并覆寫了其中的內嵌函數__getitem,添加了函數__len__。(在此之前我一般做法都是直接讀取csv文件獲取數據集,這里學習到了)
特征提取
def select_feature(train_data,valid_data,test_data,select_all=True):y_train,y_valid=train_data[:,-1],valid_data[:,-1]raw_x_train,raw_x_valid,raw_x_test=train_data[:,:-1],valid_data[:,:-1],test_dataif select_all:feature_idx=list(range(raw_x_train.shape[1]))else:feature_idx=[0,1,2,3,4]#print(raw_x_train)return raw_x_train[:,feature_idx],raw_x_valid[:,feature_idx],raw_x_test[:,feature_idx],y_train,y_valid感覺這里寫的簡單了很多,對于特征提取應該可以更精細一點。雖然這個代碼塊可以實現特征選擇,但是選擇哪些特征并沒有給出,應該對這些特征做一個比較細致的分析例如相關系數分析。
設置隨機種子
def same_seed(seed):torch.backends.cudnn.deterministic=Truetorch.backends.cudnn.benchmark=Falsenp.random.seed(seed)torch.manual_seed(seed)if torch.cuda.is_avaliable():torch.cuda.manual_seed_all(seed)隨機劃分訓練集和驗證集
def train_valid_split(dataset,ratio,seed):valid_set_size=int(ratio*len(dataset))train_set_size=len(dataset)-valid_set_sizetrain_set,valid_set=random_split(dataset,[train_set_size,valid_set_size],generator=torch.Generator().manual_seed(seed))return np.array(train_set.dataset.iloc[train_set.indices,:]), np.array(valid_set.dataset.iloc[valid_set.indices,:])這里我寫的與原始代碼不同,主要是最后的返回值,按常理來看這里應該是返回訓練集和驗證集的矩陣形式,但按照原代碼的結果返回的卻是兩個torch.utils.data.dataset.Subset對象。
定義模型
class My_Model(nn.Module):def __init__(self,input_dim):super(My_Model,self).__init__()self.layers=nn.Sequential(nn.Linear(input_dim,16),nn.ReLU(),nn.Linear(16,8),nn.ReLU(),nn.Linear(8,1))def forward(self,x):x=self.layers(x)x=x.squeeze(1)return x顯然這部分代碼是定義了一個神經網絡,有2個隱藏層,神經元個數分別為16和8,ReLU為激活函數。
定義訓練函數
def trainer(train_loader,valid_loader,model,config,device):criterion=nn.MSELoss(reduction='mean')optimizer=torch.optim.SGD(model.parameters(),lr=config['learning_rate'],momentum=0.9)writer=SummaryWriter()if not os.path.isdir('./models'):os.mkdir('./models')n_epochs,best_loss,step,early_stop_count=config['n_epochs'],math.inf,0,0for epoch in range(n_epochs):model.train()loss_record=[]train_pbar=tqdm(train_loader,position=0,leave=True)for x,y in train_pbar:optimizer.zero_grad()x,y=x.to(device),y.to(device)pred=model(x)loss=criterion(pred,y)loss.backward()optimizer.step()step+=1loss_record.append(loss.detach().item())train_pbar.set_description(f'Epoch [{epoch+1}/{n_epochs}]')train_pbar.set_postfix({'loss':loss.detach().item()})mean_train_loss=sum(loss_record)/len(loss_record)writer.add_scalar('Loss/train', mean_train_loss, step) #tensoboard畫出loss曲線model.eval()loss_record=[]for x,y in valid_loader:x,y=x.to(device),y.to(device)with torch.no_grad():pred=model(x)loss=criterion(pred,y)loss_record.append(loss.item())mean_valid_loss=sum(loss_record)/len(loss_record)print(f'Epoch [{epoch+1}/{n_epochs}]: Train loss: {mean_train_loss:.4f}, Valid loss: {mean_valid_loss:.4f}')writer.add_scalar('Loss/valid', mean_valid_loss, step)if mean_valid_loss<best_loss:best_loss=mean_valid_losstorch.save(model.state_dict(),config['save_path'])print(f'Saving model with loss {best_loss:.3f}...')early_stop_count=0else:early_stop_count+=1if early_stop_count>=config['early_stop_count']:print('\nModel is mot improving, so we halt the training session.')return該部分十分重要,可以說是核心代碼了,所以有必要進行詳細的說明。這部分代碼即是為了完成模型的訓練。函數的參數有訓練集、驗證集、自定義配置和設備(cpu or gpu)。首先定義了損失函數和優化器,算是常見的操作了,SummaryWriter是我第一次見到,與tensorboard相關,后續會仔細再看看。之后定義了存儲位置和epoch,best_loss以及early_stop_count。early_stop_count在我用XGBoost時經常遇到,主要是為了停止損失基本不下降模型的訓練。下面正式進入epoch,在每一個epoch中:首先model.train(),表明模型開啟訓練模式,打開batch normalization和drop out,與之對應的是model.eval(),即將對應的設置關閉,在驗證集上使用。train_pbar用到了tqdm類,可視化了遍歷訓練集的進度,position設置了打印進度條的位置,leave是表示執行完成后是否保留進度條。隨后開始遍歷訓練集,將輸入與輸出分別轉移到相應的device上,之后定義損失函數,同時將得到的損失記錄下來,遍歷完之后,計算平均損失。之后進入模型驗證,這里就要關閉模型的訓練模式,因為模型驗證是為了觀察模型在訓練之后在驗證集的表現,所以這里torch.no_grad()表明無需對模型計算梯度,只需要計算損失即可。最后比較驗證集上的平均損失與最低損失,如果小于則更新最低損失為當前平均損失并將early_stop_count設為0,否則early_stop_count+=1。
開始:
框架已經搭好,后面就是正式開始訓練模型,這部分內容比較簡單易懂,就不多贅述。
讀取并劃分數據
device = 'cuda' if torch.cuda.is_available() else 'cpu' config={'seed':0,'select_all':True,'valid_ratio':0.2,'n_epochs':3000,'batch_size':256,'learning_rate':1e-5,'early_stop_count':400,'save_path': './models/model.ckpt' }train_data=pd.read_csv(r'D:\Work Studio\Python 3.8.6\My secret base\hw\hw1\ml2021spring-hw1\covid.train.csv').iloc[:,1:] test_data=np.array(pd.read_csv(r'D:\Work Studio\Python 3.8.6\My secret base\hw\hw1\ml2021spring-hw1\covid.test.csv').iloc[:,1:])train_data, valid_data = train_valid_split(train_data, config['valid_ratio'], config['seed']) x_train, x_valid, x_test, y_train, y_valid = select_feature(train_data, valid_data, test_data, config['select_all']) train_dataset, valid_dataset, test_dataset = COVID19Dataset(x_train, y_train), \COVID19Dataset(x_valid, y_valid), \COVID19Dataset(x_test) train_loader = DataLoader(train_dataset, batch_size=config['batch_size'], shuffle=True, pin_memory=True) #pin_memory默認false,打開后更快 valid_loader = DataLoader(valid_dataset, batch_size=config['batch_size'], shuffle=True, pin_memory=True) test_loader = DataLoader(test_dataset, batch_size=config['batch_size'], shuffle=False, pin_memory=True)訓練模型
model = My_Model(input_dim=x_train.shape[1]).to(device) # put your model and data on the same computation device. trainer(train_loader, valid_loader, model, config, device)保存模型并預測數據
def save_pred(preds, file):''' Save predictions to specified file '''with open(file, 'w') as fp:writer = csv.writer(fp)writer.writerow(['id', 'tested_positive'])for i, p in enumerate(preds):writer.writerow([i, p])model = My_Model(input_dim=x_train.shape[1]).to(device) model.load_state_dict(torch.load(config['save_path'])) preds = predict(test_loader, model, device) save_pred(preds, 'pred.csv')總結
以上即是hw1例題的基本內容,經過這一次的學習和探討,我對機器學習框架的建立有了更深刻的了解。后續如果有新的感悟和思考,會繼續更新補充,也歡迎大家批評指正。
總結
以上是生活随笔為你收集整理的hw1例题-李宏毅老师课后作业的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: BZOJ3668[NOI2014] 起床
- 下一篇: 统筹方法 -- 华罗庚