r"""Execute backward pass on the loss Arguments: loss: Torch tensor on which to execute backward propagation retain_graph: bool, default: false forward on user defined choice of retain_graph scale_wrt_gas: bool, default: true
(self, loss, retain_graph=False, scale_wrt_gas=True)
| 3301 | |
| 3302 | @instrument_w_nvtx |
| 3303 | def backward(self, loss, retain_graph=False, scale_wrt_gas=True): |
| 3304 | r"""Execute backward pass on the loss |
| 3305 | Arguments: |
| 3306 | loss: Torch tensor on which to execute backward propagation |
| 3307 | retain_graph: bool, default: false |
| 3308 | forward on user defined choice of retain_graph |
| 3309 | scale_wrt_gas: bool, default: true |
| 3310 | whether to scale gradients and return value by gradient accumulation steps |
| 3311 | |
| 3312 | With ``managed_gradient_accumulation=false``, ``backward()`` only accumulates |
| 3313 | gradients locally (it does not trigger the accumulation-boundary reduction); the |
| 3314 | reduction and optimizer update happen in ``step()``. |
| 3315 | """ |
| 3316 | assert self.optimizer is not None and not isinstance(self.optimizer, DummyOptim), \ |
| 3317 | "must provide optimizer during init in order to use backward" |
| 3318 | assert maybe_loss_for_backward( |
| 3319 | loss), "loss must be a scalar tensor. If you need to pass output gradients, backward() of output tensors" |
| 3320 | |
| 3321 | with self._running_engine_backward_lock: |
| 3322 | self._running_engine_backward_count += 1 |
| 3323 | self._running_engine_backward = True |
| 3324 | engine_backward_graph_state = _ENGINE_BACKWARD_GRAPH_TRACKER.new_state() |
| 3325 | engine_backward_graph_hook = None |
| 3326 | try: |
| 3327 | # Unmanaged mode: count this backward so step() can advance global_samples by the actual micro-batch count. |
| 3328 | if not self.managed_gradient_accumulation(): |
| 3329 | self._unmanaged_backward_count += 1 |
| 3330 | |
| 3331 | # Set flag to prevent hooks from firing (we'll manually call prologue/epilogue) |
| 3332 | backward_kwargs = {"retain_graph": retain_graph} |
| 3333 | if self.eigenvalue_enabled(): |
| 3334 | backward_kwargs["create_graph"] = True |
| 3335 | backward_kwargs["retain_graph"] = True |
| 3336 | |
| 3337 | loss = loss / self.gradient_accumulation_steps() if scale_wrt_gas else loss |
| 3338 | gas_scaled_loss = loss |
| 3339 | |
| 3340 | # TODO: handle these scaling with direct calls to loss.backward() |
| 3341 | if isinstance(self.optimizer, ZeROOptimizer): |
| 3342 | loss = self.optimizer.scale_if_loss(loss) |
| 3343 | elif self.torch_autocast_z0_gradscaler: |
| 3344 | loss = self.torch_autocast_z0_gradscaler.scale(loss) |
| 3345 | |
| 3346 | if loss.requires_grad: |
| 3347 | engine_backward_graph_hook = loss.register_hook( |
| 3348 | lambda grad: _ENGINE_BACKWARD_GRAPH_TRACKER.register_current_graph( |
| 3349 | grad, engine_backward_graph_state)) |
| 3350 | |
| 3351 | with compiled_autograd(self._is_compiled_autograd_enabled, self._compile_kwargs): |
| 3352 | if self.zero_optimization() or not self.amp_enabled(): |
| 3353 | loss.backward(**backward_kwargs) |
| 3354 | elif self.amp_enabled(): |
| 3355 | # AMP requires delaying unscale when inside gradient accumulation boundaries |
| 3356 | # https://nvidia.github.io/apex/advanced.html#gradient-accumulation-across-iterations |
| 3357 | delay_unscale = not self.is_gradient_accumulation_boundary() |
| 3358 | with amp.scale_loss(loss, self.optimizer, delay_unscale=delay_unscale) as scaled_loss: |
| 3359 | scaled_loss.backward(**backward_kwargs) |
| 3360 |
nothing calls this directly
no test coverage detected