1. 程式人生 > >pytorch 訓練資料以及測試 全部程式碼(3)

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']的作用是用來控制迭代多少次就更新一次模型引數