1 問題
在學習深度學習的過程中,欲探究激活函數(shù)Relu對精度和損失的影響。
2 方法
測試設(shè)置激活函數(shù)時和沒有設(shè)置激活函數(shù)時網(wǎng)絡(luò)的性能。
控制其余變量:
Beach_size=128
optimizer = torch.optim.SGD
網(wǎng)絡(luò)為三層全連接網(wǎng)絡(luò)(784->512->10)
訓練周期=50
測試代碼如下
from torchvision import datasets from torchvision.transforms import ToTensor from torch import nn import torch from torch.utils.data import DataLoader import torch.nn.functional as F import matplotlib.pyplot as plt from collections import defaultdict # (5)定義三層全連接網(wǎng)絡(luò) # (5.1)創(chuàng)建一個新的類繼承nn.Module class MyNet(nn.Module): # (5.2) 定義網(wǎng)絡(luò)有哪些層,這些層都作為成員變量 def __init__(self) -> None: super().__init__() # 第一層,第一個全連接層Full Connection(FC) # in_features表示該層的前面一層神經(jīng)元個數(shù) # out_features表示當前這的一層神經(jīng)元個數(shù) # 對應(yīng)圖里面layer2 self.fc1 = nn.Linear(in_features=784, out_features=512) # in_features就是這一層的輸入是多少緯的向量, # 對應(yīng)layer3 也是就輸出層 self.fc2 = nn.Linear(in_features=512, out_features=10) # feature特征 # (5.3) 定義數(shù)據(jù)在網(wǎng)絡(luò)中的流動 x就表示輸入 # x - 28*28的圖像 def forward(self, x): x=torch.flatten(x,1) x = self.fc1(x) # 輸出:512,Layer 2 # x=F.relu(x) out = self.fc2(x) # 輸出:10,Layer 3 return out #(7)訓練網(wǎng)絡(luò) #loss_list:記錄每一個周期的平均loss數(shù)據(jù) def train(dataloader,net,loss_fn,optimizer): size = len((dataloader.dataset)) epoch_loss=0.0 batch_num=len(dataloader)#有多少個batch net.train() correct = 0 #準確率 #一個batch一個batch的訓練網(wǎng)絡(luò) for batch_ind, (X,y) in enumerate(dataloader): X,y=X.to(device),y.to(device) #gpu上運行X,y pred = net(X) #衡量y與y_hat之前的loss #y:128 ,pred:128*10 CrossEntropyLoss處理的 loss=loss_fn(pred,y) #基于loss信息利用優(yōu)化器從后向前更新網(wǎng)絡(luò)的全部參數(shù) optimizer.zero_grad() loss.backward() optimizer.step() # print(f"batch index: {ind},loss:{loss.item()}")#item()方法將單個tensor轉(zhuǎn)化成一個數(shù)字 epoch_loss+=loss.item() #每一個batch產(chǎn)生一個loss correct+=(pred.argmax(1)==y).type(torch.float).sum().item() #f-str if batch_ind % 100==0: print(f'[{batch_ind+1 :>5d} / {batch_num :>5d}], loss:{loss.item()}') #統(tǒng)計一個周期的平均loss avg_loss=epoch_loss/batch_num avg_accurcy = correct / size return avg_accurcy,avg_loss def test(dataloder,net,loss): size=len(dataloder.dataset) batch_num = len(dataloder) net.eval() losses=0 correct = 0 with torch.no_grad(): for X,y in dataloder: X,y = X.to(device),y.to(device) pred = net(X) loss = loss_fn(pred,y) losses+=loss.item() #一個batch產(chǎn)生一個loss correct+=(pred.argmax(1) ==y).type(torch.int).sum().item() accuracy = correct / size avg_loss = losses /batch_num print(f'accuracy is {accuracy*100}%') return accuracy,avg_loss #數(shù)據(jù)的獲取 class getData: def __init__(self): self.train_ds = datasets.MNIST( root='data', download=True, train=True, transform=ToTensor(), # 將原始的數(shù)據(jù)格式(PIL)轉(zhuǎn)換為Tensor格式 ) # 測試集:評估模型的性能/效果 self.text_ds = datasets.MNIST( root='data', download=True, train=False, transform=ToTensor(), ) # print(train_ds[0]) # print(text_ds[0]) # (3) self.train_loader = DataLoader( dataset=self.train_ds, batch_size=128, # 將60000個數(shù)據(jù)分成每一段的大小是128 shuffle=True, # 每一次我去拿那個128的數(shù)據(jù)都是打亂的,不是有序的。1-60000 打亂數(shù)據(jù)的次序,一般用于訓練集,不需要在測試集 ) # (4) # 訓練集共有469個batch 469*128 # print("訓練集的batch{}".format(len(train_loader))) self.test_loader = DataLoader( dataset=self.text_ds, batch_size=128, ) if __name__=='__main__': #(0)測試機器是否支持GPU batch_size=128 device='cuda' if torch.cuda.is_available() else 'cpu' # print(device) train_ds = datasets.MNIST( root='data', download=True, train=True, transform=ToTensor(), # 將原始的數(shù)據(jù)格式(PIL)轉(zhuǎn)換為Tensor格式 ) # 測試集:評估模型的性能/效果 text_ds = datasets.MNIST( root='data', download=True, train=False, transform=ToTensor(), ) #(1.1)將訓練集劃分為訓練集+驗證集 train_ds,val_ds= torch.utils.data.random_split(train_ds,[50000,10000]) # (3) train_loader = DataLoader( dataset=train_ds, batch_size=batch_size, # 將60000個數(shù)據(jù)分成每一段的大小是128 shuffle=True, # 每一次我去拿那個128的數(shù)據(jù)都是打亂的,不是有序的。1-60000 打亂數(shù)據(jù)的次序,一般用于訓練集,不需要在測試集 ) val_loder = DataLoader( dataset=val_ds, batch_size=batch_size, ) # (4) # 訓練集共有469個batch 469*128 # print("訓練集的batch{}".format(len(train_loader))) test_loader = DataLoader( dataset=text_ds, batch_size=batch_size, ) #(6)網(wǎng)絡(luò)的輸入、輸出以及測試網(wǎng)絡(luò)的性能(不經(jīng)過任何訓練的網(wǎng)絡(luò)) net=MyNet().to(device)#to()GPU上運行該網(wǎng)絡(luò) #網(wǎng)絡(luò)訓練模型 #X, 真實的標簽y, 網(wǎng)絡(luò)預(yù)測的標簽y_hat #目標: y_hat越來越接近y #算法:mini-bacth 梯度下降 #優(yōu)化器 #具體實現(xiàn)梯度下降算法的傳播 #SGD隨機梯度下降學習度 #y=ax+b optimizer=torch.optim.SGD(net.parameters(),lr=0.15) #損失函數(shù) #衡量yy與y_hat之前的差異 loss_fn=nn.CrossEntropyLoss() #訓練一下 # train(train_loader,net,loss_fn,optimizer) #一個周期表示一個完整的訓練集 #訓練100個周期epoch train_loss=[] #記錄所有周期的平均loss train_acc_list,train_loss_list,val_acc_list,val_loss_list=[],[],[],[] #找出周期內(nèi)最好的模型 #評價標準:驗證集的精度 best_acc=0 for epoch in range(50): print('-'*50) print(f'eopch:{epoch+1}') train_accuracy,train_loss=train(train_loader,net,loss_fn,optimizer) val_accuracy,val_loss =test(train_loader,net,loss_fn) print(f'train acc:{train_accuracy},train_val:{train_loss}') train_acc_list.append(train_accuracy) train_loss_list.append(train_loss) val_acc_list.append(val_accuracy) val_loss_list.append(val_loss) if val_accuracy > best_acc: best_acc = val_accuracy #保存當前模型 torch.save(net.state_dict(),'model_best.pth') #(7)評估模型` #加載最好的模型 net.load_state_dict(torch.load('model_best.pth')) print('the best val_acc is:') test(test_loader,net,loss_fn) plt.figure() ax1=plt.subplot(121) plt.plot([i for i in range(len(train_acc_list))],train_acc_list,ls='-',c='b') plt.title('accuracy') plt.xlabel('epoch') plt.ylabel('number') ax = plt.subplot(122) plt.plot([i for i in range(len(train_loss_list))], train_loss_list, ls='-', c='b') plt.title('loss') plt.xlabel('epoch') plt.ylabel('number') plt.show() |
最后無激活函數(shù)時結(jié)果如圖所示:
有激活函數(shù)時結(jié)果如圖所示:
3 結(jié)語
通過實驗發(fā)現(xiàn),在未使用激活函數(shù)時,通過不斷地訓練模型,模型的準確率和損失率都時比較穩(wěn)定地上升和下降,但是在上升和下降地過程中會出現(xiàn)抖動地情況,但是使用激活函數(shù)之后,模型的準確率和損失率就會上升和下降的非常平滑,更有利于實驗的進行,以及對模型行為的預(yù)測。
聯(lián)系客服