训练提速60%!只需5行代码,PyTorch 1.6即将原生支持自动混合精度训练
self.train() X = torch.tensor(X, dtype=torch.float32) y = torch.tensor(y, dtype=torch.float32) optimizer = torch.optim.Adam(self.parameters(), lr=self.max_lr) scheduler = torch.optim.lr_scheduler.OneCycleLR( optimizer, self.max_lr, cycle_momentum=False, epochs=self.n_epochs, steps_per_epoch=int(np.ceil(len(X) / self.batch_size)), ) batches = torch.utils.data.DataLoader( torch.utils.data.TensorDataset(X, y), batch_size=self.batch_size, shuffle=True ) # NEW scaler = torch.cuda.amp.GradScaler() for epoch in range(self.n_epochs): for i, (X_batch, y_batch) in enumerate(batches): X_batch = X_batch.cuda() y_batch = y_batch.cuda() optimizer.zero_grad() # NEW with torch.cuda.amp.autocast(): y_pred = model(X_batch).squeeze() loss = self.loss_fn(y_pred, y_batch) # NEW scaler.scale(loss).backward() lv = loss.detach().cpu().numpy() if i % 100 == 0: print(f"Epoch {epoch + 1}/{self.n_epochs}; Batch {i}; Loss {lv}") # NEW scaler.step(optimizer) scaler.update() scheduler.s 新的 PyTorch GradScaler 工具是 PyTorch 实现的丧失缩放。追念一下在“殽杂精度怎样事变”一节中提到,在实习时代,为了防备梯度变小到0,某种情势的缩放是须要的。最佳的丧失乘数得足够高以保存很是小的梯度,同时不能太高以至于导致很是大的梯度四舍五入到 inf发生相反的题目。 PyTorch行使指数退避(exponential backoff)来办理这个题目。Gradscalar 以一个小的丧失乘数开始,这个乘数每次会翻倍。这种逐渐更加的举动一向一连到 GradScalar 碰着包括 inf 值的梯度更新。Gradscalar 扬弃这批数据(譬喻跳过梯度更新) ,将丧失乘数减半,并重置其倍增时刻。 通过这种方法逐级上下移动丧失乘数,PyTorch 可以跟着时刻的推移近似获得吻合的丧失乘数。认识 TCP 拥塞节制的读者应该会发明这里的焦点头脑很是认识!该算法行使的精确数字是可设置的,你可以直接从docstring中看到默认值: torch.cuda.amp.GradScaler( init_scale=65536.0, growth_factor=2.0, backoff_factor=0.5, growth_interval=2000, enabled=True ) Gradscalar 必要对梯度更新计较(搜查是否溢出)和优化器(将扬弃的batches转换为 no-op)举办节制,以实现其操纵。这就是为什么 loss.backwards()被 scaler.scale(loss).backwards()代替, 以及 optimizer.step()被 scaler.step(optimizer)替代的缘故起因。 值得留意的是,GradScalar 可以检测并遏制overflows(由于 inf 老是坏的) ,可是它无法检测和遏制underflows(由于0凡是是一个正当值)。假如你选择的初始值太低,增添隔断太长,你的收集也许会在 GradScalar 参与之前underflow并发散。因为这个缘故起因,选择一个很是大的初始值也许是一个好主意。 最后,留意 GradScalar 是一个有状态工具。行使此成果生涯模子checkpoint必要和模子权重一路写入和读取磁盘。用 state _ dict 和 load _ state _ dict 工具要领(在 PyTorch 文档中有先容)可以很轻易地做到这一点。 自动殽杂精度实习拼图的另一半是 torch.cuda.amp.autocast 上下文打点器。Autocast实现了 fp32-> fp16转换。追念一下“殽杂精度是怎样事变的“中的内容,因为差异的操纵以差异的速度累积偏差,并非全部的操纵都可以在 fp16中安详运行。下面的截图来自 amp 模块文档,先容了autocast如那里理赏罚 PyTorch 中可用的各类操纵: 这个列表首要由矩阵乘法和卷积两部门构成,尚有简朴的线性函数。 这些操纵在 fp16中是安详的,可是在输入有 fp16和 fp32殽杂的环境下,这些操纵具有向上适配(up-casting)法则,以确保它们不会出题目。留意,这个列表还包罗其它两个根基的线性代数运算: 矩阵/向量点积和向量叉积。 对数、指数、三角函数、正规函数、离散函数和(大)和在 fp16中是不安详的,必需在 fp32中执行。 通过赏识这个列表,在我看来,大大都层城市从autocasting中受益,这要归功于它们内部对根基线性代数操纵的依靠,但大大都激活函数却不是。卷积层是最大赢家。 启用sutocasting很是简朴。你只必要做的就是行使autocast上下文打点器包好模子的正向撒播: (编辑:湖南网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |