Pytorch原生AMP支持使用方法(1.6版本)

AMP:Automatic mixed precision,自動混合精度,能夠在神經網絡推理過程當中,針對不一樣的層,採用不一樣的數據精度進行計算,從而實現節省顯存和加快速度的目的。html

在Pytorch 1.5版本及之前,經過NVIDIA出品的插件apex,能夠實現amp功能。python

從Pytorch 1.6版本之後,Pytorch將amp的功能吸取入官方庫,位於torch.cuda.amp模塊下。git

本文爲針對官方文檔主要內容的簡要翻譯和本身的理解。github

1. Introduction

torch.cuda.amp提供了對混合精度的支持。爲實現自動混合精度訓練,須要結合使用以下兩個模塊:網絡

2. Typical Mixed Precision Training

一個典型的amp應用示例以下:函數

# 定義模型和優化器
model = Net().cuda()
optimizer = optim.SGD(model.parameters(), ...)

# 在訓練最開始定義GradScalar的實例
scaler = GradScaler()

for epoch in epochs:
    for input, target in data:
        optimizer.zero_grad()

        # 利用with語句,在autocast實例的上下文範圍內,進行模型的前向推理和loss計算
        with autocast():
            output = model(input)
            loss = loss_fn(output, target)

        # 對loss進行縮放,針對縮放後的loss進行反向傳播
        # (此部分計算在autocast()做用範圍之外)
        scaler.scale(loss).backward()

        # 將梯度值縮放回原尺度後,優化器進行一步優化
        scaler.step(optimizer)

        # 更新scalar的縮放信息
        scaler.update()

3. Working with Unscaled Gradients

待更新性能

4. Working with Scaled Gradients

待更新優化

5. Working with Multiple Models, Losses, and Optimizers

若是模型的Loss計算部分輸出多個loss,須要對每個loss值執行scaler.scale插件

若是網絡具備多個優化器,對任一個優化器執行scaler.unscale_,並對每個優化器執行scaler.stepscala

scaler.update只在最後執行一次。

應用示例以下:

scaler = torch.cuda.amp.GradScaler()

for epoch in epochs:
    for input, target in data:
        optimizer0.zero_grad()
        optimizer1.zero_grad()
        with autocast():
            output0 = model0(input)
            output1 = model1(input)
            loss0 = loss_fn(2 * output0 + 3 * output1, target)
            loss1 = loss_fn(3 * output0 - 5 * output1, target)

        scaler.scale(loss0).backward(retain_graph=True)
        scaler.scale(loss1).backward()

        # 選擇其中一個優化器執行顯式的unscaling
        scaler.unscale_(optimizer0)
		# 對每個優化器執行scaler.step
        scaler.step(optimizer0)
        scaler.step(optimizer1)
		# 完成全部梯度更新後,執行一次scaler.update
        scaler.update()

6. Working with Multiple GPUs

針對多卡訓練的狀況,隻影響autocast的使用方法,GradScaler的用法與以前一致。

6.1 DataParallel in a single process

在每個不一樣的cuda設備上,torch.nn.DataParallel在不一樣的進程中執行前向推理,而autocast只在當前進程中生效,所以,以下方式的調用是不生效的:

model = MyModel()
dp_model = nn.DataParallel(model)

# 在主進程中設置autocast
with autocast():
    # dp_model的內部進程並不會對autocast生效
    output = dp_model(input)
    # loss的計算在主進程中執行,autocast能夠生效,但因爲前面執行推理時已經失效,所以總體上是不正確的
    loss = loss_fn(output)

有效的調用方式以下所示:

# 方法1:在模型構建中,定義forwar函數時,採用裝飾器方式
MyModel(nn.Module):
    ...
    @autocast()
    def forward(self, input):
       ...

# 方法2:在模型構建中,定義forwar函數時,採用上下文管理器方式
MyModel(nn.Module):
    ...
    def forward(self, input):
        with autocast():
            ...

# DataParallel的使用方式不變
model = MyModel().cuda()
dp_model = nn.DataParallel(model)

# 在模型執行推理時,因爲前面模型定義時的修改,在各cuda設備上的子進程中autocast生效
# 在執行loss計算是,在主進程中,autocast生效
with autocast():
    output = dp_model(input)
    loss = loss_fn(output)

6.2 DistributedDataParallel, one GPU per process

torch.nn.parallel.DistributedDataParallel在官方文檔中推薦每一個GPU執行一個實例的方法,以達到最好的性能表現。

在這種模式下,DistributedDataParallel內部並不會再啓動子進程,所以對於autocastGradScaler的使用都沒有影響,與典型示例保持一致。

6.3 DistributedDataParallel, multiple GPUs per process

DataParallel 的使用相同,在模型構建時,對forward函數的定義方式進行修改,保證autocast在進程內部生效。

相關文章
相關標籤/搜索