code: def test_qlinear_gradient(
      tokens, embeddings, activations, weights, device
  ):
      # We use a batch size of 1 to simplify gradient manual calculations
      batch_size = 1
      linear = torch.nn.Linear(embeddings, embeddings).to(device)
      qlinear = QLinear.from_module(
          linear, weights=weights, activations=activations
      )
      assert qlinear.weight.requires_grad is True
      assert qlinear.bias.requires_grad is True
      qinputs = random_qtensor(
          (batch_size,) + (tokens, embeddings), dtype=torch.float32
      ).to(device)
      qout = qlinear(qinputs)
      gradient = torch.randn(qout.size()).to(device)
      qout.backward(gradient)
      # Compute gradients manually and compare
      bias_gradient = torch.sum(gradient, axis=[0, 1])
      assert torch.allclose(qlinear.bias.grad, bias_gradient)
      weight_gradient = torch.matmul(
          gradient.squeeze().t(), qinputs.dequantize().squeeze()
      )
      assert torch.allclose(qlinear.weight.grad, weight_gradient)
  
file_path: quanto/test/nn/test_qlinear.py
imports: import pytest
  import torch
  from helpers import assert_similar, random_qtensor
  from quanto import Calibration, QTensor, int4
  from quanto.nn import QLinear
label_desc: Use image node_id 8 for calling a global function with example usage: test_qlinear_gradient(tokens, embeddings, activations, weights, device) without return types