
    i/                     ~   d dl Z d dlmZ d dlZd dlmZmZ d dlmZ d dl	m
Z
 d dlmZmZ erd dlmZ d dlmZ d	d
dZe
d   ZdZeresdgZ G d dej,                        Z G d de      Z	 ddedej,                  dededeeeeef   f   f
dZ	 d dedeeef   de
d   defdZ	 	 	 	 d!dedede
d   dededefdZy)"    N)Union)Tensornn	normalize)Literal)_TORCH_GREATER_EQUAL_2_2_TORCHVISION_AVAILABLE)
transforms)resnet50)      )r   d   )kadid10kkoniq10kz=https://github.com/miccunifi/ARNIQA/releases/download/weightsarniqac            	       |     e Zd ZdZddeddf fdZddZddedede	eef   fd	Z
d
edefdZddededefdZ xZS )_ARNIQAzInitializes a No-Reference Image Quality Assessment ARNIQA torch.nn.Module.

    Args:
        regressor_dataset: dataset used for training the regressor, choose between [``koniq10k``, ``kadid10k``]

    regressor_datasetreturnNc                    t         |           t        st        d      t        st        d      t        j                         }||vrt        d| d| d      || _	        g d| _
        g d| _        t               }|j                  j                  | _        t!        j"                  t%        |j'                               d d  }|| _        t!        j*                  | j                  d	z  d
      | _        | j/                          dt         j0                  dd fd} || j(                          || j,                         y )Nz'ARNIQA metric requires PyTorch >= 2.2.0zARNIQA metric requires that torchvision is installed. Either install as `pip install torchmetrics[image]` or `pip install torchvision`.z,Argument `regressor_dataset` must be one of 
, but got .)g
ףp=
?gv/?gCl?)gZd;O?gy&1?g?   r   moduler   c                 \    | j                          | j                         D ]	  }d|_         y )NF)eval
parametersrequires_grad)r   ps     y/Volumes/fast/ai/experiments/voice-extract-mac/.venv/lib/python3.12/site-packages/torchmetrics/functional/image/arniqa.py_freezez!_ARNIQA.__init__.<locals>._freezeU   s%    KKM&&("' )    )super__init__r	   RuntimeErrorr
   ModuleNotFoundError_AVAILABLE_REGRESSOR_DATASETSkeys
ValueErrorr   imagenet_norm_meanimagenet_norm_stdr   fcin_featuresfeat_dimr   
SequentiallistchildrenencoderLinear	regressor_load_weightsModule)selfr   valid_regressor_datasetsr4   r#   	__class__s        r"   r&   z_ARNIQA.__init__8   s'   'HII%%e 
 $A#E#E#G $<<>?W>XXbctbuuvw  "3"7!6*

..--g&6&6&8!9#2!>?4==1#4a8	(BII 	($ 	(
 	r$   c                    t         j                  j                  t         ddd      }|j	                         D ci c]  \  }}d|vs|j                  dd      | }}}| j                  j                  |d       t        j                         5  t        j                  d	t        d
       t         j                  j                  t         d| j                   ddd      j                         }|j                  d      |d<   |j                  d      j                  d      |d<   | j                   j                  |d       ddd       yc c}}w # 1 sw Y   yxY w)z/Loads the weights of the encoder and regressor.z/ARNIQA.pthTcpu)progressmap_location	projectorzmodel. )strictignoreztorch.serialization)categoryr   z/regressor_z.pthweightsweightbiasesr   biasN)torchhubload_state_dict_from_url	_base_urlitemsreplacer4   load_state_dictwarningscatch_warningsfilterwarningsUserWarningr   
state_dictpop	unsqueezer6   )r9   encoder_state_dictkvfiltered_encoder_state_dictregressor_state_dicts         r"   r7   z_ARNIQA._load_weights]   sT   "YY??k%5 @ 
 4F3K3K3M'
3M41aQ\deQeAIIh#Q&3M 	$ '
 	$$%@$N$$&##H{K`a#(99#E#E+[)?)?(@EPTch $F $jl ! .B-E-Ei-P *+?+C+CH+M+W+WXY+Z (NN**+?*M '&'

 '&s   E
EB5EE imgr   c                 <   |j                   dd \  }} t        j                  |dz  |dz  f      |      }|rb t        j                  | j                  | j
                        |      } t        j                  | j                  | j
                        |      }||fS )zPreprocesses the input to the model.

        Obtains the half-scale version of the input image and applies normalization if needed.

        Nr   )meanstd)shaper   Resize	Normalizer,   r-   )r9   r\   r   hwimg_dss         r"   _preprocess_inputz_ARNIQA._preprocess_inputq   s     yy~14""AFAF#34S9`*&&D,C,CI_I_`adeCcZ))t/F/FDLbLbcdjkFF{r$   scorec                 D    t         | j                     \  }}||z
  ||z
  z  S )zKScales the quality score to be in the [0, 1] range, where higher is better.)r)   r   )r9   rh   	min_score	max_scores       r"   _scale_scorez_ARNIQA._scale_score~   s,    <T=S=ST	9	!i)&;<<r$   c                    | j                  ||      \  }}| j                  |      }|j                  d| j                        }t	        |d      }| j                  |      }|j                  d| j                        }t	        |d      }t        j                  ||f      }| j                  |      }| j                  |      S )Nr   r   )dim)	rg   r4   viewr0   normalize_fnrI   hstackr6   rl   )r9   r\   r   rf   img_fimg_ds_ffrh   s           r"   forwardz_ARNIQA.forward   s    ,,S)<V S!

2t}}-U*<<'==T]]3a0LL%*+ q!  ''r$   )r   )r   NF)__name__
__module____qualname____doc___TYPE_REGRESSOR_DATASETr&   r7   r   booltuplerg   rl   ru   __classcell__r;   s   @r"   r   r   0   su    # *A # SW # JN(V  vW]~I^ =& =V =
(6 (d (v (r$   r   c                   ,     e Zd ZdZdedd f fdZ xZS )_NoTrainArniqaz9Wrapper to make sure ARNIQA never leaves evaluation mode.moder   c                 "    t         |   d      S )z.Force network to always be in evaluation mode.F)r%   train)r9   r   r;   s     r"   r   z_NoTrainArniqa.train   s    w}U##r$   )rw   rx   ry   rz   r|   r   r~   r   s   @r"   r   r      s    C$$ $#3 $ $r$   r   r\   modelr   autocastr   c                 j   | j                   dk(  r| j                  d   dk(  st        d| j                   d      | j                         dk  r| j	                         dk\  s0|r.t        d| j	                          d	| j                          d      |rSt
        j                  j                  | j                  j                  | j                  
      5   || |      }ddd       n$ |j                  | j                        | |      }j                         | j                  d   fS # 1 sw Y   (xY w)a  Update step for ARNIQA metric.

    Args:
        img: the input image
        model: the pre-trained model
        normalize: boolean indicating whether the input image is normalized
        autocast: boolean indicating whether to use automatic mixed precision

       r      z?Input image must have shape [N, 3, H, W]. Got input with shape r   g      ?g        zdInput image values must be in the [0, 1] range when normalize==True. Got input with values in range z and )device_typedtyper   N)r   r   )ndimra   r+   maxminrI   ampr   devicetyper   tosqueeze)r\   r   r   r   losss        r"   _arniqa_updater      s    HHMciila/Z[^[d[dZeefghhGGIc!1y516
 	

 YYCJJOO399M	2D NM )uxxciix(	B<<>399Q<''	 NMs   D))D2scores
num_scores	reduction)sumr_   nonec                 H    | j                         }|dk(  r| S |dk(  r||z  S |S )zCompute step for ARNIQA metric.r   r_   )r   )r   r   r   
sum_scoress       r"   _arniqa_computer      s5     JFFJ&&r$   r   c                    d}||vrt        d| d|       t        |t              st        d|       t        |      j	                  | j
                  | j                        }t        | |||      \  }}t        |||      S )a  ARNIQA: leArning distoRtion maNifold for Image Quality Assessment metric.

    `ARNIQA`_ is a No-Reference Image Quality Assessment metric that predicts the technical quality of an image with
    a high correlation with human opinions. ARNIQA consists of an encoder and a regressor. The encoder is a ResNet-50
    model trained in a self-supervised way to model the image distortion manifold to generate similar representation for
    images with similar distortions, regardless of the image content. The regressor is a linear model trained on IQA
    datasets using the ground-truth quality scores. ARNIQA extracts the features from the full- and half-scale versions
    of the input image and then outputs a quality score in the [0, 1] range, where higher is better.

    The input image is expected to have shape ``(N, 3, H, W)``. The image should be in the [0, 1] range if `normalize`
    is set to ``True``, otherwise it should be normalized with the ImageNet mean and standard deviation.

    .. note::
        Using this metric requires you to have ``torchvision`` package installed. Either install as
        ``pip install torchmetrics[image]`` or ``pip install torchvision``.

    Args:
        img: the input image
        regressor_dataset: dataset used for training the regressor. Choose between [``koniq10k``, ``kadid10k``].
            ``koniq10k`` corresponds to the `KonIQ-10k`_ dataset, which consists of real-world images with authentic
            distortions. ``kadid10k`` corresponds to the `KADID-10k`_ dataset, which consists of images with
            synthetically generated distortions.
        reduction: indicates how to reduce over the batch dimension. Choose between [``sum``, ``mean``, ``none``].
        normalize: by default this is ``True`` meaning that the input is expected to be in the [0, 1] range. If set
            to ``False`` will instead expect input to be already normalized with the ImageNet mean and standard
            deviation.
        autocast: boolean indicating whether to use automatic mixed precision

    Returns:
        A tensor in the [0, 1] range, where higher is better, representing the ARNIQA score of the input image. If
        `reduction` is set to ``none``, the output will have shape ``(N,)``, otherwise it will be a scalar tensor.

    Raises:
        ModuleNotFoundError:
            If ``torchvision`` package is not installed
        ValueError:
            If ``regressor_dataset`` is not in [``"kadid10k"``, ``"koniq10k"``]
        ValueError:
            If ``reduction`` is not in [``"sum"``, ``"mean"``, ``"none"``]
        ValueError:
            If ``normalize`` is not a bool
        ValueError:
            If the input image is not a valid image tensor with shape [N, 3, H, W].
        ValueError:
            If the input image values are not in the [0, 1] range when ``normalize`` is set to ``True``

    Examples:
        >>> from torch import rand
        >>> from torchmetrics.functional.image.arniqa import arniqa
        >>> img = rand(8, 3, 224, 224)
        >>> # Non-normalized input
        >>> arniqa(img, regressor_dataset='koniq10k', normalize=True)
        tensor(0.5308)


        >>> from torch import rand
        >>> from torchmetrics.functional.image.arniqa import arniqa
        >>> from torchvision.transforms import Normalize
        >>> img = rand(8, 3, 224, 224)
        >>> img = Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])(img)
        >>> # Normalized input
        >>> arniqa(img, regressor_dataset='koniq10k', normalize=False)
        tensor(0.5065)

    )r_   r   r   z$Argument `reduction` must be one of r   z.Argument `normalize` should be a bool but got )r   )r   r   )r   r   )	r+   
isinstancer|   r   r   r   r   r   r   )	r\   r   r   r   r   valid_reductionr   r   r   s	            r"   r   r      s    P .O'??PPZ[dZefggi&I)UVV->?BB#**\_\e\eBfE%c5IPXYD*4Y77r$   rv   )r_   )r   r_   TF)rP   typingr   rI   r   r   torch.nn.functionalr   rp   typing_extensionsr   torchmetrics.utilities.importsr	   r
   torchvisionr   torchvision.modelsr   r)   r{   rL   __doctest_skip__r8   r   r   r|   r}   intr   r   r    r$   r"   <module>r      sU  (     9 % [&+ ! 
 ""89 K	 	!%; zb(bii b(J$W $ FK(	(		(.2(>B(
65f%%&(< ag		 %fck 2	?FG\?]		 2<06Q8	Q8.Q8 ,-Q8 	Q8
 Q8 Q8r$   