mindspore模型訓(xùn)練混合精度算法

      網(wǎng)友投稿 1107 2022-05-30

      **概述**:深度學(xué)習(xí)模型的計算任務(wù)分為訓(xùn)練和推理.訓(xùn)練往往是放在云端或者超算集群中,利用GPU強大的浮點計算能力,來完成網(wǎng)絡(luò)模型參數(shù)的學(xué)習(xí)過程.一般來說訓(xùn)練時,計算資源往往非常充足,基本上受限于顯存資源/多節(jié)點擴展/通訊庫效率的問題。相對于訓(xùn)練過程,推理往往被應(yīng)用于終端設(shè)備,如手機,計算資源/功耗都收到嚴格的限制,為了解決這樣的問題,提出了很多不同的方法來減少模型的大小以及所需的計算資源/存儲資源。模型壓縮除了剪枝以外,還有一個方法就是降低模型參數(shù)的數(shù)值精度。隨著網(wǎng)絡(luò)深度的加大,帶來的參數(shù)數(shù)量也呈現(xiàn)指數(shù)級增長,如何將最終學(xué)習(xí)好的網(wǎng)絡(luò)模型塞入到終端設(shè)備有限的空間中是目前很多性能優(yōu)良的網(wǎng)絡(luò)真正應(yīng)用到日常生活中的一大阻礙。

      大多數(shù)的深度學(xué)習(xí)模型使用的是32位單精度浮點數(shù)(FP32)來進行訓(xùn)練,而混合精度訓(xùn)練的方法中則增加了通過16位浮點數(shù)(FP16)進行深度學(xué)習(xí)模型訓(xùn)練,從而減少了訓(xùn)練深度學(xué)習(xí)模型所需的內(nèi)存,同時由于FP16的運算比FP32運算更快,從而也進一步提高了硬件效率。

      **混合精度訓(xùn)練方法**是通過混合使用單精度和半精度數(shù)據(jù)格式來加速深度神經(jīng)網(wǎng)絡(luò)訓(xùn)練的過程,同時保持了單精度訓(xùn)練所能達到的網(wǎng)絡(luò)精度。即在盡可能減少精度損失的情況下利用半精度浮點數(shù)加速訓(xùn)練。

      使用FP16即半精度浮點數(shù)存儲權(quán)重和梯度。在減少占用內(nèi)存的同時起到了加速訓(xùn)練的效果。混合精度訓(xùn)練能夠加速計算過程,同時減少內(nèi)存使用和存取,并使得在特定的硬件上可以訓(xùn)練更大的模型或batch size。

      **缺陷:**

      訓(xùn)練采用低精度數(shù)據(jù)在一定程度上會造成精度損失,詳情如下:

      一個FP16數(shù)據(jù)占據(jù)兩個字節(jié),其中1位符號位,5位指數(shù)位,10位有效精度,取值范圍是5.96× 10?8 ~ 65504,而FP32則是1.4×10-45 ~ 3.4×1038。從FP16的范圍可以看出,用FP16代替原FP32神經(jīng)網(wǎng)絡(luò)計算的最大問題就是精度損失。

      **MindSpore新版本可支持圖神經(jīng)網(wǎng)絡(luò)的訓(xùn)練**,最典型的GCN和GAT網(wǎng)絡(luò)在Cora和Citeseer數(shù)據(jù)集上做混合精度訓(xùn)練,對于mindspore混合精度模型訓(xùn)練而言,主要分為自動混合精度和手動混合精度,具體計算流程如下(圖片來源https://zhuanlan.zhihu.com/p/352746002)

      (1)自動混合精度

      使用自動混合精度,需要調(diào)用相應(yīng)的接口,將待訓(xùn)練網(wǎng)絡(luò)和優(yōu)化器作為輸入傳進去;該接口會將整張網(wǎng)絡(luò)的算子轉(zhuǎn)換成FP16算子(除BatchNorm算子和Loss涉及到的算子外)。可以使用amp接口和Model接口兩種方式實現(xiàn)混合精度。

      使用mindspore\train\amp.build_train_network接口封裝網(wǎng)絡(luò)模型、優(yōu)化器和損失函數(shù),設(shè)置level參數(shù),在該步驟中,MindSpore會將有需要的算子自動進行類型轉(zhuǎn)換。

      mindspore模型訓(xùn)練—混合精度算法

      def build_train_network(network, optimizer, loss_fn=None, level='O0', **kwargs): """ Build the mixed precision training cell automatically. 自動構(gòu)建混合精度訓(xùn)練單元。 Args: network (Cell): 網(wǎng)絡(luò)的定義 loss_fn (Union[None, Cell]): loss_fn的定義。如果沒有,則“網(wǎng)絡(luò)”中應(yīng)該有損失。 Default: None. optimizer (Optimizer): 優(yōu)化器更新參數(shù)。 level (str): Supports ["O0", "O2", "O3", "auto"]. Default: "O0". - O0: 無改變 - O2: 將網(wǎng)絡(luò)轉(zhuǎn)換為float16,保持batchnorm和'loss_fn'(如果設(shè)置)為float32類型, 使用動態(tài)損耗量表。 - O3: 轉(zhuǎn)換網(wǎng)絡(luò)為float16, 附加屬性 'keep_batchnorm_fp32=False'. - auto: Set to level to recommended level in different devices. Set level to O2 on GPU, Set level to O3 Ascend. The recommended level is choose by the export experience, cannot always generalize. User should specify the level for special network. 在不同的設(shè)備中將“級別”設(shè)置為 建議 的級別。在GPU上將級別設(shè)置為O2,建議在ascend級別使用O3。 建議的級別由導(dǎo)出經(jīng)驗選擇,不能總是一概而論。用戶應(yīng)指定特殊網(wǎng)絡(luò)的級別。 O2 is recommended on GPU, O3 is recommended on Ascend. cast_model_type (:class:`mindspore.dtype`): 支持 `mstype.float16` or `mstype.float32`. If set to `mstype.float16`, use `float16` mode to train. If set, 覆蓋級別設(shè)置。 keep_batchnorm_fp32 (bool): Keep Batchnorm run in `float32`. If set, 覆蓋級別設(shè)置。 Only `cast_model_type` is `float16`, `keep_batchnorm_fp32` 將生效。 loss_scale_manager (Union[None, LossScaleManager]): 如果沒有,則不按比例計算損失,否則 通過“LossCaleManager”衡量損失。如果已設(shè)置,則覆蓋級別設(shè)置。 """ validator.check_value_type('network', network, nn.Cell) #檢查network類型是否為nn.cell validator.check_value_type('optimizer', optimizer, (nn.Optimizer, acc.FreezeOpt)) validator.check('level', level, "", ['O0', 'O2', 'O3', "auto"], Rel.IN) #同理 if level == "auto": device_target = context.get_context('device_target') #get_context() 定義于 mindspore\mindspore\context.py #根據(jù)輸入鍵獲取上下文屬性值。 if device_target == "GPU": level = "O2" elif device_target == "Ascend": level = "O3" else: raise ValueError("Level `auto` only support when `device_target` is GPU or Ascend.") _check_kwargs(kwargs) #檢查參數(shù) config = dict(_config_level[level], **kwargs) #**kwargs常用于有key值的輸入 ''' def test(**kwargs): print(kwargs) keys = kwargs.keys() value = kwargs.values() print(keys) print(value) test(a=1,b=2,c=3,d=4) # 輸出值分別為 # {'a': 1, 'b': 2, 'c': 3, 'd': 4} # dict_keys(['a', 'b', 'c', 'd']) # dict_values([1, 2, 3, 4]) ''' config = edict(config) #from easydict import EasyDict as edict #EasyDict可以讓你像訪問屬性一樣訪問dict里的變量 ''' #實例如下: from easydict import EasyDict as edict easy = edict(d = {'foo':3, 'bar':{'x':1, 'y':2}}) # 將普通的字典傳入到edict() print(easy['foo']) # 這是傳統(tǒng)的方法 print(easy.foo) # 這是我們使用easydict輸出二者結(jié)果是一樣的,但是可以更為方便的使用字典了 print(easy.bar.x) # 我們也是可以很方便的使用字典中字典的元素了 ''' if config.cast_model_type == mstype.float16: network.to_float(mstype.float16)#若格式不符則進行格式轉(zhuǎn)換 if config.keep_batchnorm_fp32:#config已經(jīng)轉(zhuǎn)化為EasyDict 如果對應(yīng)keep_batchnorm_fp32屬性參數(shù)為真 _do_keep_batchnorm_fp32(network) if loss_fn: network = _add_loss_network(network, loss_fn, config.cast_model_type) if _get_parallel_mode() in (ParallelMode.SEMI_AUTO_PARALLEL, ParallelMode.AUTO_PARALLEL): network = _VirtualDatasetCell(network) loss_scale = 1.0 if config.loss_scale_manager is not None: loss_scale_manager = config.loss_scale_manager loss_scale = loss_scale_manager.get_loss_scale() update_cell = loss_scale_manager.get_update_cell() if update_cell is not None: # 只有cpu不支持 `TrainOneStepWithLossScaleCell` 控制流 if not context.get_context("enable_ge") and context.get_context("device_target") == "CPU": raise ValueError("Only `loss_scale_manager=None` and " "`loss_scale_manager=FixedLossScaleManager(drop_overflow_update=False)`" "are supported in current version. If you use `O2` option, please" "use `loss_scale_manager=None` or `FixedLossScaleManager`") network = nn.TrainOneStepWithLossScaleCell(network, optimizer, scale_sense=update_cell).set_train() return network network = nn.TrainOneStepCell(network, optimizer, loss_scale).set_train() #TrainOneStepCell繼承nn.Cell,包含大量網(wǎng)絡(luò)訓(xùn)練的庫函數(shù)的類 ''' set_train():model參數(shù)默認為true 將單元格設(shè)置為訓(xùn)練模式。單元本身和所有子單元將設(shè)置為訓(xùn)練模式。 具有不同構(gòu)造的層對于訓(xùn)練和預(yù)測,例如“BatchNorm”,將通過此屬性區(qū)分分支。 如果設(shè)置為True時,將執(zhí)行訓(xùn)練分支,否則將執(zhí)行另一個分支。 ''' return network ```

      (2)手動混合精度

      MindSpore還支持手動混合精度。假定在網(wǎng)絡(luò)中只有一個Dense Layer要用FP32計算,其他Layer都用FP16計算。混合精度配置以Cell為粒度,Cell默認是FP32類型。

      (3)約束條件:

      使用混合精度時,只能由自動微分功能生成反向網(wǎng)絡(luò),不能由用戶自定義生成反向網(wǎng)絡(luò),否則可能會導(dǎo)致MindSpore產(chǎn)生數(shù)據(jù)格式不匹配的異常信息。

      ![混合精度訓(xùn)練概述圖](/api/attachments/368994)

      定義于mindspore\mindspore\train\amp.py中的三種規(guī)范

      _config_level = {#初始化三種配置級別 "O0": { "keep_batchnorm_fp32": False,#是否遵守fp32規(guī)范 "cast_model_type" :mstype.float32, "loss_scale_manager": None}, "O2": { "keep_batchnorm_fp32": True, "cast_model_type": mstype.float16,#半精度 "loss_scale_manager": DynamicLossScaleManager()}, "O3": { "keep_batchnorm_fp32": False, "cast_model_type": mstype.float16, "loss_scale_manager": None}}

      **混合精度訓(xùn)練實現(xiàn)關(guān)鍵技術(shù):**

      第一項關(guān)鍵技術(shù)被稱為“混合精密鑰匙”(mixed precision key)。在MT模型中仍然保留FP32格式的主副本,將FP16用于正向和反向傳播,優(yōu)化器中的梯度更新將被添加到主FP32副本當中,該FP32副本被簡化為一個FP16副本在訓(xùn)練期間使用,這個過程在每次訓(xùn)練迭代中重復(fù),直至模型收斂且足以恢復(fù)損失的精度,從而達到較低內(nèi)存使用、內(nèi)存帶寬壓力更低和更快速執(zhí)行的優(yōu)點。

      第二種關(guān)鍵技術(shù)則是“損耗縮放”(loss-scaling)。該技術(shù)可以夠恢復(fù)一些小數(shù)值的梯度。在訓(xùn)練期間,一些權(quán)重梯度具有非常小的指數(shù),其FP16格式可能會變?yōu)榱恪榱丝朔@個問題,我們使用縮放因子在反向傳播開始時縮放損失,通過連鎖規(guī)則,梯度也逐漸擴大,并在FP16中可表示。在將其更新應(yīng)用于權(quán)重之前,梯度確實需要縮小;而為了恢復(fù)某些型號的精度損失,必須進行損耗調(diào)整。

      MindSpore主要運用的是第二種,所定義抽象類函數(shù)(mindspore\mindspore\train\loss_scale_manager.py)詳情如下:

      """損失規(guī)模管理器抽象類。""" from .._checkparam import Validator as validator#常用于參數(shù)驗證 from .. import nn class LossScaleManager: """損失規(guī)模管理器抽象類""" def get_loss_scale(self): """獲取損失比例值。""" def update_loss_scale(self, overflow): """ 更新?lián)p失比例值。 Args: overflow (bool): 是否溢出. """ def get_update_cell(self): """Get the loss scaling update logic cell.獲取損耗縮放更新邏輯單元。""" class FixedLossScaleManager(LossScaleManager): """ Fixed loss-scale manager固定損失規(guī)模管理器. Args: loss_scale (float): Loss scale. Note that if `drop_overflow_update` is set to False, the value of `loss_scale` in optimizer that you used need to be set to the same value as here. Default: 128.0. 損失規(guī)模。請注意,如果“drop_overflow_update”設(shè)置為False,則需要將優(yōu)化器中使用的“l(fā)oss_scale”的值設(shè)置為與此處相同的值。 drop_overflow_update (bool): Whether to execute optimizer if there is an overflow. If True, the optimizer will not executed when overflow occurs. Default: True. 出現(xiàn)溢出時,是否執(zhí)行優(yōu)化器。如果為True,則優(yōu)化器發(fā)生溢出時將不執(zhí)行。 Examples: >>> from mindspore import Model, nn, FixedLossScaleManager >>> >>> net = Net()#初始化網(wǎng)絡(luò) >>> #1) Drop the parameter update if there is an overflow如果出現(xiàn)溢出,請刪除參數(shù)更新 >>> loss_scale_manager = FixedLossScaleManager()#固定損失規(guī)模管理器 >>> optim = nn.Momentum(params=net.trainable_params(), learning_rate=0.1, momentum=0.9) >>> model = Model(net, loss_scale_manager=loss_scale_manager, optimizer=optim)#模型初始化 >>> >>> #2) Execute parameter update even if overflow occurs >>> loss_scale = 1024 >>> loss_scale_manager = FixedLossScaleManager(loss_scale, False) >>> optim = nn.Momentum(params=net.trainable_params(), learning_rate=0.1, momentum=0.9, loss_scale=loss_scale) >>> model = Model(net, loss_scale_manager=loss_scale_manager, optimizer=optim) """ def __init__(self, loss_scale=128.0, drop_overflow_update=True): if loss_scale < 1: raise ValueError("loss_scale must be at least 1, " "but got loss_scale {}".format(loss_scale)) self._loss_scale = loss_scale self._drop_overflow_update = drop_overflow_update def get_loss_scale(self): """獲取損耗縮放值""" return self._loss_scale def get_drop_overflow_update(self): """獲取當出現(xiàn)溢出時是否刪除優(yōu)化器更新的標志。""" return self._drop_overflow_update def update_loss_scale(self, overflow): """ 更新?lián)p耗縮放值. Args參數(shù): overflow (bool): 是否溢出的標志. """ def get_update_cell(self): "Returns the cell返回單元格 for `TrainOneStepWithLossScaleCell`" if not self._drop_overflow_update: return None return nn.FixedLossScaleUpdateCell(self._loss_scale) class DynamicLossScaleManager(LossScaleManager): """ 動態(tài)損失規(guī)模管理器。 Args: init_loss_scale (float): Initialize loss scale初始化損失規(guī)模(比例). Default: 2**24. scale_factor (int): Coefficient of increase and decrease增減系數(shù). Default: 2. scale_window (int): Maximum continuous normal steps when there is no overflow無溢出時的最大連續(xù)正常步數(shù). Default: 2000. Examples: >>> from mindspore import Model, nn >>> from mindspore.train.loss_scale_manager import DynamicLossScaleManager >>> >>> net = Net()#初始化網(wǎng)絡(luò) >>> loss_scale_manager = DynamicLossScaleManager()#實例化 >>> optim = nn.Momentum(params=net.trainable_params(), learning_rate=0.1, momentum=0.9) >>> model = Model(net, loss_scale_manager=loss_scale_manager, optimizer=optim) """ def __init__(self, init_loss_scale=2 ** 24, scale_factor=2, scale_window=2000): if init_loss_scale < 1.0: raise ValueError("Loss scale value should be > 1") self.loss_scale = init_loss_scale validator.check_positive_int(scale_window, "scale_window", self.__class__.__name__) self.scale_window = scale_window if scale_factor <= 0: raise ValueError("Scale factor should be > 1") self.scale_factor = scale_factor self.increase_ratio = scale_factor self.decrease_ratio = 1 / scale_factor self.cur_iter = 1 self.last_overflow_iter = 0 self.bad_step_max = 1000 self.bad_step = 0 def get_loss_scale(self): """Get loss scale value.""" return self.loss_scale def update_loss_scale(self, overflow): """ Update loss scale value. Args: overflow: Boolean. Whether it overflows.布爾值 1/0 """ if overflow: self.loss_scale = max(self.loss_scale * self.decrease_ratio, 1) self.last_overflow_iter = self.cur_iter self.bad_step += 1 else: if (self.cur_iter - self.last_overflow_iter) % self.scale_window == 0: self.loss_scale *= self.increase_ratio self.bad_step = 0 if self.bad_step > self.bad_step_max: raise RuntimeError("Dynamic loss scale Continuous overflow ", self.bad_step, " times") self.cur_iter += 1 def get_drop_overflow_update(self): """Get the flag whether to drop optimizer update when there is an overflow.""" return True def get_update_cell(self): "Returns the cell for `TrainOneStepWithLossScaleCell`" return nn.DynamicLossScaleUpdateCell(self.loss_scale, self.scale_factor, self.scale_window)

      **MindSpore相關(guān)新特性舉例**:

      **多跳知識推理問答(TPRR)**:TPRR是華為泊松實驗室與華為MindSpore團隊提出的解決開放域多跳問題的通用模型。相比于傳統(tǒng)問答僅需從單個文檔中檢索答案,多跳知識推理問答需要從多個佐證文檔得到最終答案,并返回問題到答案的推理鏈。TPRR基于MindSpore混合精度特性,可以高效地完成多跳問答推理過程。

      全路徑建模:TPRR模型在多跳問題推理鏈的每一個環(huán)節(jié)中基于全部推理路徑的條件概率建模,模型以“全局視角”進行知識推理。動態(tài)樣本選取:TPRR模型采用動態(tài)樣本的建模方式,通過更強的對比學(xué)習(xí)提升模型多跳問答的能力

      MindSpore 機器學(xué)習(xí) 深度學(xué)習(xí)

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:OpenCV中的圖像處理 —— 圖像梯度+Canny邊緣檢測+圖像金字塔
      下一篇:【鯤鵬經(jīng)典直播征文】+【畢昇編譯器】編譯優(yōu)化與軟硬協(xié)同釋放鯤鵬澎湃算力
      相關(guān)文章
      亚洲av日韩av高潮潮喷无码| 亚洲天堂在线视频| 亚洲日本va在线视频观看| 亚洲AⅤ永久无码精品AA| 亚洲欧美自偷自拍另类视| 亚洲无码一区二区三区| 亚洲综合精品伊人久久| 亚洲一区二区观看播放| 亚洲七久久之综合七久久| 亚洲人成色777777老人头| 国产成人亚洲综合网站不卡| 亚洲人成网站看在线播放| 亚洲av无码专区在线| 亚洲一区中文字幕在线观看| 亚洲人成伊人成综合网久久| 中文字幕亚洲男人的天堂网络 | 国产乱辈通伦影片在线播放亚洲| 亚洲国产成人VA在线观看| 亚洲精品麻豆av| 亚洲一区二区三区香蕉| 国产亚洲精品va在线| 亚洲av午夜福利精品一区人妖| 亚洲av无码乱码国产精品| 亚洲视频在线一区| 亚洲欧洲尹人香蕉综合| 99热亚洲色精品国产88| 亚洲欧美日韩综合久久久| 国产午夜亚洲精品不卡免下载 | 国产成人综合亚洲绿色| 亚洲综合精品网站| 亚洲Av综合色区无码专区桃色| 亚洲伦理一区二区| 亚洲中字慕日产2021| 亚洲色www永久网站| 亚洲av麻豆aⅴ无码电影| 国产国拍精品亚洲AV片| 久久国产亚洲观看| 亚洲国产成人综合| 亚洲国产午夜精品理论片在线播放 | 亚洲综合无码AV一区二区| 亚洲AV无码成人专区片在线观看|