Pytorch框架學習---(7)常見的4大歸一化、模型保存與加載、模型微調、多GPU的使用


本節簡單總結Pytorch中常見的4大歸一化、模型如何保存並加載、以及模型如何實現微調,pytorch中多GPU的使用。【文中思維導圖采用MindMaster軟件,Latex公式采用在線編碼器

1.Pytorch中封裝的4大歸一化(BN、LN、IN、GN)

(1)為什么要采用Normalization?

  都是為了解決Internal Covariate Shift(ICS)問題,即數據分布出現異常而導致的網絡訓練困難。ICS問題在《Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift》中提到。

(2)這4大歸一化之間的異同點

① 相同點

  都是類似 \(\gamma \times \frac{x- mean }{\sqrt{var^{2}+ \varepsilon } } + \beta\) 這樣的形式,即“加減乘除”。

② 不同點

  均值mean和方差variance的求取方式不同,具體以下圖為例:

  • (a)BN:對一個batch下的樣本數的同一channel下的特征做歸一化;
  • (b)LN:由於BN不適合變長的網絡,例如RNN,所以LN對單獨一個樣本計算均值和方差,注意:gamma和beta是逐元素計算
  • (c)IN:由於BN不適合圖像生成領域,即每一個圖像都有自身的風格,不能夠將一個batch中的樣本混為一談,,故對每一個樣本逐通道歸一化;
  • (d)GN:對於某些情況,batch_size較小,此時易知歸一化值不准(類似無法代替全局),故GN對通道數(很多的通道)進行分組,用通道數去彌補小數據量問題。注意:gamma和beta是逐通道計算

(3)具體使用

① BatchNorm

'''BatchNorm基類'''
class _BatchNorm(Module):
    def __init__(self, num_features, eps=1e-5, momentum=0.1, affine=True,
                 track_running_stats=True):

# 參數:
      # num_features:一個樣本的特征數量(或者是通道數量)
      # eps:分母修正項
      # momentum:指數加權平均 估計當前的mean/var!!!!!!!
      # affine:是否進行affine transform,即gamma、beta的scale and shift
      # track_running_stats:是訓練狀態 or 測試狀態

注意:測試狀態,mean和var只計算當前batch,而訓練狀態,當前時刻的mean和var會受之前的batch影響,即下面的公式(momentum):

\[running\_mean= \left ( 1- momentum \right )\ast pre\_running\_mean+ momentum\ast mean\_t \]

\[running\_var= \left ( 1- momentum \right )\ast pre\_running\_var+ momentum\ast var\_t \]

  上面的momentum在之前的博客中有提及。

② LayerNorm

class LayerNorm(Module):
    def __init__(self, normalized_shape, eps=1e-5, elementwise_affine=True):

# 參數:
      # normalized_shape:該樣本的特征形狀
      # eps:分母修正項
      # elementwise_affine:是否要對每個元素進行affine transform操作

注意:實例化LN時,要注意normalized_shape這一項,必須從size末尾寫,例如:

        >>> input = torch.randn(20, 5, 4, 10)
        >>> m = nn.LayerNorm(input.size()[1:])
        >>> m = nn.LayerNorm([4, 10])
        >>> m = nn.LayerNorm([5,4, 10])
        >>> m = nn.LayerNorm([10])
        # 但不可以是:
        >>> m = nn.LayerNorm([5, 4])

③ InstanceNorm

'''InstanceNorm基類'''
class _InstanceNorm(_BatchNorm):
    def __init__(self, num_features, eps=1e-5, momentum=0.1, affine=False,
                 track_running_stats=False):

# 參數:
      # num_features:一個樣本的特征數量(或者是通道數量)
      # eps:分母修正項
      # momentum:指數加權平均 估計當前的mean/var!!!!!!!
      # affine:是否進行affine transform,即gamma、beta的scale and shift
      # track_running_stats:是訓練狀態 or 測試狀態

④ GroupNorm

class GroupNorm(Module):
    def __init__(self, num_groups, num_channels, eps=1e-5, affine=True):

# 參數:
      # num_groups:分組數(必須能將通道數整除!!!!!!!!)
      # num_channels:通道數
      # eps:分母修正項
      # affine:是否進行affine transform,這里是對每個通道進行!!!!

2.模型的保存與加載

(1)pytorch提供的方法

  主要參數如下:(torch.save(obj, f))

  • obj:要保存的對象(模型,張量,參數等);

  • f:保存的路徑。

(2)模型的加載 torch.load

  主要參數如下:(torch.load(f, map_location=None))

  • f:讀取路徑;

  • map_location:決定該文件放在GPU上還是cpu位置上,當想要加載的模型是GPU上的,此時機子沒有GPU,則可以將map_location='cpu',將該模型放置在cpu上。

(3)兩種保存模型的方式

# 保存整個網絡
torch.save(net, PATH) 
# 保存網絡中的參數
torch.save(net.state_dict(),PATH)

#對應上面的保存方式:
model_dict=torch.load(PATH)

model_dict=model.load_state_dict(torch.load(PATH))

(4)端點續訓練(其實就是把優化器、模型的參數,以及epoch保存下來,方便后續繼續訓練)

'''保存'''
checkpoint = {"model_state_dict": net.state_dict(),
              "optimizer_state_dict": optimizer.state_dict(),
              "epoch": epoch}

torch.save(checkpoint, path_checkpoint)

'''加載'''
checkpoint = torch.load(path_checkpoint)

net.load_state_dict(checkpoint['model_state_dict'])

optimizer.load_state_dict(checkpoint['optimizer_state_dict'])

start_epoch = checkpoint['epoch']

scheduler.last_epoch = start_epoch  # 用於更新優化器的學習率

3.模型微調

  模型finetune感覺這里對python編程較高 ( 咳咳。。。——>_——>。。。只怪本人python編程目前還比較low ),其實主要要對字典、列表等高級操作要熟悉!!

  在這里本人就不獻丑了,等后續用到finetune再來補充。大家可以先參考知乎Pytorch自由載入部分模型參數並凍結

4.GPU的使用

(1)to函數 (用於轉換類型/設備)

  to函數可以用於tensor和module:

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

'''對於張量tensor'''
# 張量不執行原位inplace操作,即必須賦值
a = torch.ones((5, 5))
a = a.to(torch.float64)
a = a.to(device)

'''對於模型moudle'''
# 模型執行inplace
net.to(device)

(2)torch.cuda常用方法

  上圖中設置GPU對應的os.environ.setdefault操作,可以有效防止多人使用GPU沖突問題,或者多程序在不同的GPU上跑的沖突,可用可見的GPU(邏輯GPU)與物理GPU的對應關系可以理解為:(對應圖3os.environ粉色方塊的操作)

(3)多GPU運算的分發並行機制

① 發並行機制的流程圖

  這里一般利用torch.nn.DataParallel操作,例如batch_size=16,我們利用4個GPU並行運算,分配給每個GPU的batch_size=4該機制主要流程為:

② torch.nn.DataParallel

class DataParallel(Module):
    def __init__(self, module, device_ids=None, output_device=None, dim=0):

# 參數:
      # module:需要處理的模型;
      # device_ids:可分法的GPU,默認分發到所有可見可用的GPU;(通過設置上述os.environ.setdefault操作,即可默認)
      # output_device:最后結果輸出設備,默認主GPU

(4)在多GPU上運行的模型,其pkl文件加載時的問題

  當我們加載多GPU模型參數,print load后的pkl文件,會發現較原始模型linear.0,多了一個module,即module.linear.0,因而我們需要取出module之后的參數,可以參考github上的代碼:

'''state_dict_load為OrderedDict形式,無法直接操作'''

    state_dict_load = torch.load(path, map_location="cpu")
    from collections import OrderedDict
    new_state_dict = OrderedDict()
    for k, v in state_dict_load.items():
        namekey = k[7:] if k.startswith('module.') else k  # 重新取出module后層信息,作為新的key
        new_state_dict[namekey] = v

    net.load_state_dict(new_state_dict)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM