def DINO_inference(model: Any, transform: Any, img: ImageType = None, 
                        patch_size: int = None, device: str = None) -> FloatTensor:
    """runs inference for a model, transform and image

    Args:
        model (Any): ('vit_small', 'vit_base')
        transform (Any): _get_DINO_transform
        img (ImageType, optional): the image to infer on. Defaults to None.
        patch_size (int, optional): the patch size the model architecture uses. Defaults to None.
        device (str): device for the model to run on. Required to be set

    Returns:
        FloatTensor: returns N x w x h tensor
    """
    
    if not device:
        raise InternalError("`device` is required for DINO inference!")

    img = transform(img)

    # make the image divisible by the patch size
    w, h = img.shape[1] - img.shape[1] % patch_size, img.shape[2] - img.shape[2] % patch_size
    img = img[:, :w, :h].unsqueeze(0)

    w_featmap = img.shape[-2] // patch_size
    h_featmap = img.shape[-1] // patch_size

    with torch.no_grad():
        attentions = model.get_last_selfattention(img.to(device))

    nh = attentions.shape[1] # number of head

    # we keep only the output patch attention
    attentions = attentions[0, :, 0, 1:].reshape(nh, -1)

    attentions = attentions.reshape(nh, w_featmap, h_featmap)
    attentions = nn.functional.interpolate(attentions.unsqueeze(0), scale_factor=patch_size, mode="nearest")[0].cpu().numpy()

    return attentions
runs inference for a model, transform and image

    Args:
        model (Any): ('vit_small', 'vit_base')
        transform (Any): _get_DINO_transform
        img (ImageType, optional): the image to infer on. Defaults to None.
        patch_size (int, optional): the patch size the model architecture uses. Defaults to None.
        device (str): device for the model to run on. Required to be set

    Returns:
        FloatTensor: returns N x w x h tensor
    
src/marqo/s2_inference/processing/DINO_utils.py