pytorch 訓練資料以及測試 全部程式碼(3)
if epoch % p['epoch_size'] == p['epoch_size'] - 1:
lr_ = utils.lr_poly(base_lr=p['lr'], iter_=epoch, max_iter=nEpochs, power=0.9)
print('(poly lr policy) learning rate: ', lr_)
optimizer = optim.SGD(net.parameters(), lr=lr_, momentum=p['momentum'], weight_decay=p['wd'])
epoch從0到99,每次到9,19,29,...也就是說每10次epoch就更改學習率見其應用到optim中,學習率的策略採用poly,其他策略可以在我的收藏裡面查詢
net.train() 進行模型的訓練
inputs, labels = sample_batched['image'], sample_batched['label'] 這裡的都是tensor,6x3x512x512和6x1x512x512,因為tensor不能求梯度,所以必須轉化成Variable: inputs, labels = Variable(inputs, requires_grad=True), Variable(labels),那為什麼lables不需要求梯度也需要轉化,原因在於lables參與了對inputs求梯度的運算,它必須也是一樣的型別否則會報錯.在這裡對於Variable的學習可以參見官方文件
inputs, labels = inputs.cuda(), labels.cuda() 將資料放在gpu0號上面,到目前為止,模型和資料都放在gpu上面了
outputs = net.forward(inputs) 將資料傳入模型裡面
loss = criterion(outputs, labels, size_average=False, batch_average=True)#計算loss,採用CrossEntropyLoss函式.
這個函式的定義如下,而且關於nn.CrossEntropyLoss可見https://mp.csdn.net/postedit/83041355
from dataloaders import utils criterion = utils.cross_entropy2d import torch.nn as nn def cross_entropy2d(logit, target, ignore_index=255, weight=None, size_average=True, batch_average=True): n, c, h, w = logit.size() # logit = logit.permute(0, 2, 3, 1) target = target.squeeze(1) if weight is None: criterion = nn.CrossEntropyLoss(weight=weight, ignore_index=ignore_index, size_average=False) else: criterion = nn.CrossEntropyLoss(weight=torch.from_numpy(np.array(weight)).float().cuda(), ignore_index=ignore_index, size_average=False) loss = criterion(logit, target.long()) if size_average: loss /= (h * w) if batch_average: loss /= n return loss
下面接著主線程式碼
running_loss_tr += loss.item() #得到的是python的float型別的常數值,該數值不能求導
if ii % num_img_tr == (num_img_tr - 1): #num_img_tr=1764=train batch num
running_loss_tr = running_loss_tr / num_img_tr
writer.add_scalar('data/total_loss_epoch', running_loss_tr, epoch)
print('[Epoch: %d, numImages: %5d]' % (epoch, ii * p['trainBatch'] + inputs.data.shape[0]))
print('Loss: %f' % running_loss_tr)
running_loss_tr = 0
stop_time = timeit.default_timer()
print("Execution time: " + str(stop_time - start_time) + "\n")
上面這個判斷在一定的條件下從主要輸出埠打印出一些的引數資訊.當歷經一個epoch也就是1764個batch的時候(注意上面計數是從0開始的)列印輸出第幾代,該代的總圖片數目;平均一個batch的loss數值是多少;執行該代總共需要多少時間.同時儲存資料:第幾代,該代的平均一個batch的loss數值是多少.這裡的時間是以秒為單位的,但是習慣上我們喜歡時分秒的檢視方式,所以可以將顯示部分進行修改可以參考https://www.cnblogs.com/gayhub/p/6154707.html
# Backward the averaged gradient in every batch
loss /= p['nAveGrad']
loss.backward()
aveGrad += 1
前面的到的loss是一個可以求導的tensor,一般情況下是直接loss.backward()反向傳播的,但是這裡採用了Average the gradient of several iterations,只不過p['nAveGrad']=1.還有就是這個loss 是每一個batch的loss.也就是,每經過一次batch就會反向傳導loss
# Update the weights once in p['nAveGrad'] forward passes
if aveGrad % p['nAveGrad'] == 0:
writer.add_scalar('data/total_loss_iter', loss.item(), ii + num_img_tr * epoch)
optimizer.step()
optimizer.zero_grad()
aveGrad = 0
上面這個也是核心程式碼.loss.backward()進行了求梯度運算得到梯度,optimizer.step()是進行模型引數的更新,更新完之後梯度要清空optimizer.zero_grad(),如此反覆將模型進行優化.同時儲存資料:第幾次迭代,該迭代的loss數值是多少.注意這裡的迭代不是epoch而是batch,一個batch就是迭代一次.引數p['nAveGrad']的作用是用來控制迭代多少次就更新一次模型引數