code: def quaternion_raw_multiply(
      a: torch.Tensor, b: torch.Tensor
  ) -> torch.Tensor:
      """
      Multiply two quaternions.
      Usual torch rules for broadcasting apply.
  
      Args:
          a: Quaternions as tensor of shape (..., 4), real part first.
          b: Quaternions as tensor of shape (..., 4), real part first.
  
      Returns:
          The product of a and b, a tensor of quaternions shape (..., 4).
      """
      aw, ax, ay, az = torch.unbind(a, -1)
      bw, bx, by, bz = torch.unbind(b, -1)
      ow = aw * bw - ax * bx - ay * by - az * bz
      ox = aw * bx + ax * bw + ay * bz - az * by
      oy = aw * by - ax * bz + ay * bw + az * bx
      oz = aw * bz + ax * by - ay * bx + az * bw
      return torch.stack((ow, ox, oy, oz), -1)
  
imports: from typing import Optional
  import torch
  import torch.nn.functional
  from ..common.datatypes import Device
label_desc: Use image node_id 14 for calling a global function with example usage: quaternion_raw_multiply(a, b) and returns: torch