class_docstr: Computes Structural Similarity Index Measure
  
  - ``update`` must receive output of the form ``(y_pred, y)``. They have to be of the same type.
      Valid :class:`torch.dtype` are the following:
      - on CPU: `torch.float32`, `torch.float64`.
      - on CUDA: `torch.float16`, `torch.bfloat16`, `torch.float32`, `torch.float64`.
  
  Args:
      data_range: Range of the image. Typically, ``1.0`` or ``255``.
      kernel_size: Size of the kernel. Default: (11, 11)
      sigma: Standard deviation of the gaussian kernel.
          Argument is used if ``gaussian=True``. Default: (1.5, 1.5)
      k1: Parameter of SSIM. Default: 0.01
      k2: Parameter of SSIM. Default: 0.03
      gaussian: ``True`` to use gaussian kernel, ``False`` to use uniform kernel
      output_transform: A callable that is used to transform the
          :class:`~ignite.engine.engine.Engine`'s ``process_function``'s output into the
          form expected by the metric.
      device: specifies which device updates are accumulated on. Setting the metric's
          device to be the same as your ``update`` arguments ensures the ``update`` method is non-blocking. By
          default, CPU.
  
  Examples:
      To use with ``Engine`` and ``process_function``, simply attach the metric instance to the engine.
      The output of the engine's ``process_function`` needs to be in the format of
      ``(y_pred, y)`` or ``{'y_pred': y_pred, 'y': y, ...}``. If not, ``output_tranform`` can be added
      to the metric to transform the output into the form expected by the metric.
  
      ``y_pred`` and ``y`` can be un-normalized or normalized image tensors. Depending on that, the user might need
      to adjust ``data_range``. ``y_pred`` and ``y`` should have the same shape.
  
      For more information on how metric works with :class:`~ignite.engine.engine.Engine`, visit :ref:`attach-engine`.
  
      .. include:: defaults.rst
          :start-after: :orphan:
  
      .. testcode::
  
          metric = SSIM(data_range=1.0)
          metric.attach(default_evaluator, 'ssim')
          preds = torch.rand([4, 3, 16, 16])
          target = preds * 0.75
          state = default_evaluator.run([[preds, target]])
          print(state.metrics['ssim'])
  
      .. testoutput::
  
          0.9218971...
  
  .. versionadded:: 0.4.2
class_docstr_tok: ["Computes","Structural","Similarity","Index","Measure","-","``","update","``","must","receive","output","of","the","form","``","(","y_pred",",","y",")","``",".","They","have","to","be","of","the","same","type",".","Valid",":","class",":","`","torch.dtype","`","are","the","following",":","-","on","CPU",":","`","torch.float32","`",",","`","torch.float64","`",".","-","on","CUDA",":","`","torch.float16","`",",","`","torch.bfloat16","`",",","`","torch.float32","`",",","`","torch.float64","`",".","Args",":","data_range",":","Range","of","the","image",".","Typically",",","``","1.0","``","or","``","255","``",".","kernel_size",":","Size","of","the","kernel",".","Default",":","(","11",",","11",")","sigma",":","Standard","deviation","of","the","gaussian","kernel",".","Argument","is","used","if","``","gaussian=True","``",".","Default",":","(","1.5",",","1.5",")","k1",":","Parameter","of","SSIM",".","Default",":","0.01","k2",":","Parameter","of","SSIM",".","Default",":","0.03","gaussian",":","``","True","``","to","use","gaussian","kernel",",","``","False","``","to","use","uniform","kernel","output_transform",":","A","callable","that","is","used","to","transform","the",":","class",":","`","~ignite.engine.engine.Engine","`","'s","``","process_function","``","'s","output","into","the","form","expected","by","the","metric",".","device",":","specifies","which","device","updates","are","accumulated","on",".","Setting","the","metric's","device","to","be","the","same","as","your","``","update","``","arguments","ensures","the","``","update","``","method","is","non-blocking",".","By","default",",","CPU",".","Examples",":","To","use","with","``","Engine","``","and","``","process_function","``",",","simply","attach","the","metric","instance","to","the","engine",".","The","output","of","the","engine","'s","``","process_function","``","needs","to","be","in","the","format","of","``","(","y_pred",",","y",")","``","or","``","{","'y_pred","'",":","y_pred",",","'","y","'",":","y",",","...","}","``",".","If","not",",","``","output_tranform","``","can","be","added","to","the","metric","to","transform","the","output","into","the","form","expected","by","the","metric",".","``","y_pred","``","and","``","y","``","can","be","un-normalized","or","normalized","image","tensors",".","Depending","on","that",",","the","user","might","need","to","adjust","``","data_range","``",".","``","y_pred","``","and","``","y","``","should","have","the","same","shape",".","For","more","information","on","how","metric","works","with",":","class",":","`","~ignite.engine.engine.Engine","`",",","visit",":","ref",":","`","attach-engine","`",".","..","include",":",":","defaults.rst",":","start-after",":",":","orphan",":","..","testcode",":",":","metric","=","SSIM","(","data_range=1.0",")","metric.attach","(","default_evaluator",",","'ssim","'",")","preds","=","torch.rand","(","[","4",",","3",",","16",",","16","]",")","target","=","preds","*","0.75","state","=","default_evaluator.run","(","[","[","preds",",","target","]","]",")","print","(","state.metrics","[","'ssim","'","]",")","..","testoutput",":",":","0.9218971","...","..","versionadded",":",":","0.4.2"]
code: def update(self, output: Sequence[torch.Tensor]) -> None:
      y_pred, y = output[0].detach(), output[1].detach()
  
      if y_pred.dtype != y.dtype:
          raise TypeError(
              f"Expected y_pred and y to have the same data type. Got y_pred: {y_pred.dtype} and y: {y.dtype}."
          )
  
      if y_pred.shape != y.shape:
          raise ValueError(
              f"Expected y_pred and y to have the same shape. Got y_pred: {y_pred.shape} and y: {y.shape}."
          )
  
      if len(y_pred.shape) != 4 or len(y.shape) != 4:
          raise ValueError(
              f"Expected y_pred and y to have BxCxHxW shape. Got y_pred: {y_pred.shape} and y: {y.shape}."
          )
  
      # converts potential integer tensor to fp
      if not y.is_floating_point():
          y = y.float()
      if not y_pred.is_floating_point():
          y_pred = y_pred.float()
  
      nb_channel = y_pred.size(1)
      if self._kernel is None or self._kernel.shape[0] != nb_channel:
          self._kernel = self._kernel_2d.expand(nb_channel, 1, -1, -1)
  
      if y_pred.device != self._kernel.device:
          if self._kernel.device == torch.device("cpu"):
              self._kernel = self._kernel.to(device=y_pred.device)
  
          elif y_pred.device == torch.device("cpu"):
              warnings.warn(
                  "y_pred tensor is on cpu device but previous computation was on another device: "
                  f"{self._kernel.device}. To avoid having a performance hit, please ensure that all "
                  "y and y_pred tensors are on the same device.",
              )
              y_pred = y_pred.to(device=self._kernel.device)
              y = y.to(device=self._kernel.device)
  
      y_pred = F.pad(
          y_pred,
          [self.pad_w, self.pad_w, self.pad_h, self.pad_h],
          mode="reflect",
      )
      y = F.pad(
          y,
          [self.pad_w, self.pad_w, self.pad_h, self.pad_h],
          mode="reflect",
      )
  
      if y_pred.dtype != self._kernel.dtype:
          self._kernel = self._kernel.to(dtype=y_pred.dtype)
  
      input_list = [y_pred, y, y_pred * y_pred, y * y, y_pred * y]
      outputs = F.conv2d(
          torch.cat(input_list), self._kernel, groups=nb_channel
      )
      batch_size = y_pred.size(0)
      output_list = [
          outputs[x * batch_size : (x + 1) * batch_size]
          for x in range(len(input_list))
      ]
  
      mu_pred_sq = output_list[0].pow(2)
      mu_target_sq = output_list[1].pow(2)
      mu_pred_target = output_list[0] * output_list[1]
  
      sigma_pred_sq = output_list[2] - mu_pred_sq
      sigma_target_sq = output_list[3] - mu_target_sq
      sigma_pred_target = output_list[4] - mu_pred_target
  
      a1 = 2 * mu_pred_target + self.c1
      a2 = 2 * sigma_pred_target + self.c2
      b1 = mu_pred_sq + mu_target_sq + self.c1
      b2 = sigma_pred_sq + sigma_target_sq + self.c2
  
      ssim_idx = (a1 * a2) / (b1 * b2)
      self._sum_of_ssim += (
          torch.mean(ssim_idx, (1, 2, 3), dtype=torch.float64)
          .sum()
          .to(device=self._device)
      )
  
      self._num_examples += y.shape[0]
  
file_path: ignite/ignite/metrics/ssim.py
imports: import warnings
  from typing import Callable, Optional, Sequence, Union
  import torch
  import torch.nn.functional
  from ignite.exceptions import NotComputableError
  from ignite.metrics.metric import Metric, reinit__is_reduced, sync_all_reduce
label_desc: Use image node_id 6 for calling the SSIM obj's underlying member method code with example usage: obj.update(output) without return types