Paper · 2023-03-27 · cs.CV, cs.LG
Blind Image Quality Assessment via Vision-Language Correspondence: A Multitask Learning Perspective
LIQE fine-tunes CLIP ViT-B/32 to score image quality without a reference. Each image is matched to 495 joint text labels (5 quality levels x 9 scenes x 11 distortions); the marginals give a quality score plus scene and distortion heads, trained with fidelity losses and dynamic loss weights. Author-reported median SRCC 0.970 on LIVE, 0.930 on KADID-10k and 0.919 on KonIQ-10k over ten splits.
Image quality assessmentVision-language pre-trainingMulti-task learningAdaptive loss weightingno-reference-iqaclipvision-languagemultitask-learningfidelity-lossdynamic-weight-average
arXivPDFCodeMarkdown15 min read
AI-compiled by claude-haiku-5-5 on 2026-10-31, not yet reviewed by a human. Every claim cites its source; check it when a detail matters.
In plain words
Image quality models try to guess how good a photo looks to a person, usually without a clean original to compare it with. They have many parameters but only a small number of human quality scores to learn from.
This paper builds on CLIP, a model that learned to match pictures with text. Instead of predicting one number directly, the model checks how well an image fits many short sentences such as "a photo of a city with blur artifacts, which is of good quality". Each sentence bundles three things: how good the photo is, what kind of scene it shows, and what kind of damage it has. The model learns all three at once, and the quality answer is read off the same match scores. Training weights the three goals automatically, so no one has to tune them by hand. The authors report that the extra scene and damage labels help the quality score, and that one set of weights works across several quality datasets.
TL;DR
LIQE is a no-reference image quality model built by fine-tuning CLIP ViT-B/32 §4.1. It scores each image against 495 joint text labels (5 quality levels, 9 scenes, 11 distortion types) and reads quality, scene and distortion from the same softmax §3.2 eq. 3. The authors report median SRCC of 0.970 on LIVE and 0.919 on KonIQ-10k over ten random splits tab. 1. The numbers are author-reported, and several training details differ between the paper and the official code (see Paper vs code).
Problem
Blind image quality assessment (BIQA) predicts perceived quality with no reference image §1. Deep BIQA models have many parameters but few human quality annotations (mean opinion scores, MOS) §1. Training tricks that rely on synthetic distortions or pseudo-labels assume that pristine references exist and that distortions can be simulated, and these assumptions do not hold for realistic camera distortion §1. Multi-dataset joint training is one route. The paper asks whether auxiliary tasks, such as scene classification and distortion identification, can help BIQA in a multitask setting §1. Scene classification looks conceptually at odds with quality (distortion-insensitive versus distortion-sensitive features), while distortion identification looks related §1 fig. 1.
Method
The model is one CLIP image encoder and one CLIP text encoder, both trained end to end. All parameters of the image encoder are shared across the three tasks §2.3.
- Label space. Quality is a Likert scale of five levels, bad, poor, fair, good and perfect. The predicted quality is the expected level under the marginal distribution §3.1 eq. 1. There are nine scene categories, where an image may carry several labels, and eleven dominant distortion types including "others", which covers pristine images §3.1. Each combination becomes the text "a photo of a(n) {scene} with {distortion} artifacts, which is of {quality} quality", giving 5 x 9 x 11 = 495 candidates §3.1.
- Visual embedding. The paper crops U sub-images of 224 x 224 pixels without resizing, because resizing can change perceived quality §3.2. The cosine similarity of each crop with each text embedding is averaged over the U crops §3.2 eq. 2. Texts are lower-cased byte-pair encoded §3.2.
- Joint distribution. A softmax over all 495 scores with a temperature tau_1 gives the joint probability. The paper calls tau_1 learnable §3.2 eq. 3.
- Marginals. Summing the joint over the other two tasks gives the quality, scene and distortion marginals §3.2.
- Quality loss. For each pair of images from the same dataset, the label is 1 if the first image has a MOS at least as high as the second, and 0 otherwise §3.2 eq. 4. The model probability is a Thurstone model with unit variance §3.2 eq. 5. The loss is the fidelity loss §3.2 eq. 6.
- Scene loss. A multi-label fidelity loss averaged over the nine scene categories §3.2 eq. 7. A softmax variant was also tried with similar results §3.2 eq. 8.
- Distortion loss. A multi-class fidelity loss over the eleven distortion types, using the marginal of the joint §3.2 eq. 9.
- Total loss. The quality term averages over pairs, and the scene and distortion terms average over the batch. Each term has its own weight lambda(t) §3.2 eq. 10.
- Loss weights. Dynamic weight average: each weight is a softmax over the relative descent rate of the three losses, with a fixed temperature tau_2 §3.2 eq. 11. The paper does not give tau_2.
- Multi-dataset training. One mini-batch per dataset is sampled per iteration, and the pairs come only from within a dataset §3.2 §4.1.
# Training step for LIQE [§3.2] [eq. 2-10]
# Input: one mini-batch per IQA dataset; each sample has U crops
# Output: scalar loss
def training_step(batches, text_embeds, weights):
# Stack the samples of all datasets into one batch [§4.1]
crops = concatenate_over_datasets(batches) # (N, U, 3, 224, 224)
# Cosine similarity of each crop with the 495 texts, averaged [eq. 2]
logits = mean_over_crops(cosine(crops, text_embeds)) # (N, 495)
# Softmax over the 5 x 9 x 11 joint labels [eq. 3]
joint = softmax(logits / tau_1) # tau_1 is learnable in the paper
# Marginalise the joint over the other two tasks [§3.2]
p_quality = sum_over_scene_and_distortion(joint) # (N, 5)
p_scene = sum_over_quality_and_distortion(joint) # (N, 9)
p_distortion = sum_over_quality_and_scene(joint) # (N, 11)
# Quality score is the expected level, 1 to 5 [eq. 1]
quality = p_quality @ [1, 2, 3, 4, 5]
# Quality loss over same-dataset pairs of the batch [eq. 4-6] [eq. 10]
pairs = same_dataset_pairs(batches)
loss_quality = mean(pairwise_fidelity(quality, pair) for pair in pairs)
# Scene loss: mean of binary fidelity over the 9 categories [eq. 7]
loss_scene = mean(binary_fidelity(p_scene, scene_targets))
# Distortion loss: multi-class fidelity over the 11 types [eq. 9]
loss_distortion = 1 - sum(sqrt(p_distortion * distortion_targets))
# Weighted sum of the three losses [eq. 10]
losses = [loss_quality, loss_scene, loss_distortion]
return dot(weights, losses)# Pairwise fidelity loss for two images [eq. 4-6]
# Input: predicted quality and MOS of images i and j
# Output: scalar loss
def pairwise_fidelity(quality_i, quality_j, mos_i, mos_j):
# Label is 1 if image i is at least as good as image j [eq. 4]
target = 1 if mos_i >= mos_j else 0
# Thurstone probability with unit variance [eq. 5]
predicted = Phi((quality_i - quality_j) / sqrt(2))
# Fidelity loss [eq. 6]
loss = 1 - sqrt(target * predicted)
loss = loss - sqrt((1 - target) * (1 - predicted))
return loss# Loss weights from the descent rate of each task [eq. 11]
# Input: mean loss per task in the last two epochs, temperature tau_2
# Output: one weight per task
def dwa_weights(losses_last, losses_before, tau_2):
# Ratio of each task's mean loss over the last two epochs [eq. 11]
descent = losses_last / losses_before
# Softmax over tasks at temperature tau_2 [eq. 11]
weights = softmax(descent / tau_2)
return weightsKey equations, as in the paper:
\hat{q}(\bm{x}) = \sum_{c=1}^{5} \hat{p}(c \mid \bm{x})\, c eq. 1
\mathrm{logit}(c,s,d \mid \bm{x}) = \frac{1}{U}\sum_{u=1}^{U} \cos\!\big(\bm{F}_{u\bullet}(\bm{x}),\, \bm{G}_{v\bullet}\big) eq. 2
\hat{p}(c,s,d \mid \bm{x}) = \frac{\exp\big(\mathrm{logit}(c,s,d \mid \bm{x})/\tau_1\big)}{\sum_{c,s,d}\exp\big(\mathrm{logit}(c,s,d \mid \bm{x})/\tau_1\big)} eq. 3
\hat{p}(\bm{x},\bm{y}) = \Phi\!\left(\frac{\hat{q}(\bm{x}) - \hat{q}(\bm{y})}{\sqrt{2}}\right) eq. 5
\ell_q(\bm{x},\bm{y}) = 1 - \sqrt{p(\bm{x},\bm{y})\,\hat{p}(\bm{x},\bm{y})} - \sqrt{\big(1-p(\bm{x},\bm{y})\big)\big(1-\hat{p}(\bm{x},\bm{y})\big)} eq. 6
\ell_s(\bm{x}) = \frac{1}{|\mathcal{S}|}\sum_{s\in\mathcal{S}} \Big(1 - \sqrt{p(s\mid\bm{x})\,\hat{p}(s\mid\bm{x})} - \sqrt{\big(1-p(s\mid\bm{x})\big)\big(1-\hat{p}(s\mid\bm{x})\big)}\Big) eq. 7
\ell_d(\bm{x}) = 1 - \sum_{d\in\mathcal{D}} \sqrt{p(d\mid\bm{x})\,\hat{p}(d\mid\bm{x})} eq. 9
\ell(\mathcal{B},t) = \frac{1}{|\mathcal{P}|}\sum_{(\bm{x},\bm{y})\in\mathcal{P}} \lambda_q(t)\,\ell_q(\bm{x},\bm{y}) + \frac{1}{|\mathcal{B}|}\sum_{\bm{x}\in\mathcal{B}} \big(\lambda_s(t)\,\ell_s(\bm{x}) + \lambda_d(t)\,\ell_d(\bm{x})\big) eq. 10
\lambda_j(t) = \frac{\exp\big(w_j(t-1)/\tau_2\big)}{\sum_i \exp\big(w_i(t-1)/\tau_2\big)}, \qquad w_j(t-1) = \frac{\ell_j(t-1)}{\ell_j(t-2)} eq. 11
Figures: fig. 1 shows why scene and distortion can conflict: a blurred parrot photo is easy for humans, but blur is what a quality model must detect §1. fig. 2 is the system diagram §3. fig. 3 shows gMAD results against UNIQUE §4.4. No figures are reproduced here.
Hyperparameters
Values in the paper and in the official training script. Where they differ, both are given; see Paper vs code.
| Name | Value | Where | Notes |
|---|---|---|---|
| Visual encoder | CLIP ViT-B/32, fine-tuned | §4.1 train_unique_clip_weight.py | all CLIP parameters trainable (freeze option 0) train_unique_clip_weight.py |
| Text encoder | "GPT-2 ... base size of 63M parameters" | §4.1 | code loads CLIP's own text encoder instead; see Paper vs code |
| Input crops, training | U = 3, 224 x 224 | §4.1 train_unique_clip_weight.py | randomly sampled on a stride-32 grid, with replacement ImageDataset2.py |
| Input crops, testing | 15, 224 x 224 | §4.1 ImageDataset2.py | paper says random; code uses 15 evenly spaced crops |
| Quality levels C | 5 (2 levels in ablation) | §3.1 §4.5 | |
| Scene categories | 9 | §3.1 | |
| Distortion types | 11 | §3.1 | 33 dataset labels mapped to 11 classes train_unique_clip_weight.py |
| Joint labels | 495 | §3.1 | 5 x 9 x 11 |
| Optimizer | AdamW | §4.1 train_unique_clip_weight.py | |
| Weight decay | 1e-3 | §4.1 train_unique_clip_weight.py | decoupled |
| Learning rate | 5e-6 | §4.1 train_unique_clip_weight.py | |
| LR schedule | cosine annealing | §4.1 train_unique_clip_weight.py | paper gives no T_max; code uses T_max=5 |
| Epochs | 80 | §4.1 train_unique_clip_weight.py | code epoch = 200 steps train_unique_clip_weight.py |
| Batch size, LIVE, CSIQ, BID, CLIVE | 4 images per dataset per step | §4.1 train_unique_clip_weight.py | |
| Batch size, KonIQ-10k, KADID-10k | 16 images per dataset per step | §4.1 train_unique_clip_weight.py | |
| Datasets | 6 (LIVE, CSIQ, KADID-10k, BID, CLIVE, KonIQ-10k) | §4.1 | jointly trained |
| Split | 70 / 10 / 20 random, repeated 10 times | §4.1 | synthetic sets split by reference image |
| Repetitions | 10 sessions | §4.1 train_unique_clip_weight.py | |
| tau_1 (joint softmax) | learnable in the paper | §3.2 | code freezes CLIP's logit scale; see Paper vs code |
| tau_2 (DWA) | not stated | §3.2 | code uses 2.0 train_unique_clip_weight.py |
| DWA alpha | not in the paper | — | passed as 1.5 but unused by the DWA class weight_methods.py |
| DWA steps per epoch | 200 | — | train_unique_clip_weight.py |
| Loss weights, first two epochs | not stated | — | code fixes them to 1 weight_methods.py |
| Pixel normalisation | CLIP mean and std | — | utils.py |
| Random seed | not stated | — | code uses 20200626 train_unique_clip_weight.py |
| Hardware | one NVIDIA GeForce RTX 3090 | §4.1 |
Results
Author-reported. Setup: six IQA datasets, 70/10/20 random splits repeated ten times, median over the ten sessions §4.1 tab. 1. Baselines: three opinion-unaware methods and seven deep methods §4.2. The table reports the median and the standard deviation (in brackets) over ten sessions tab. 1. The model selection rule is not stated in the paper (see Paper vs code).
Table 1: SRCC (median, SD in brackets) tab. 1
| Method | LIVE | CSIQ | KADID-10k | BID | CLIVE | KonIQ-10k |
|---|---|---|---|---|---|---|
| NIQE | 0.908 (0.017) | 0.631 (0.038) | 0.389 (0.019) | 0.573 (0.044) | 0.446 (0.065) | 0.415 (0.019) |
| ILNIQE | 0.887 (0.032) | 0.808 (0.039) | 0.565 (0.013) | 0.548 (0.044) | 0.469 (0.063) | 0.509 (0.021) |
| Ma19 | 0.922 (0.024) | 0.926 (0.017) | 0.465 (0.019) | 0.373 (0.059) | 0.336 (0.038) | 0.360 (0.013) |
| PaQ2PiQ | 0.544 (0.033) | 0.697 (0.040) | 0.403 (0.021) | 0.719 (0.043) | 0.732 (0.036) | 0.722 (0.012) |
| KonCept | 0.673 (0.040) | 0.631 (0.064) | 0.503 (0.025) | 0.816 (0.029) | 0.778 (0.024) | 0.911 (0.005) |
| MUSIQ | 0.837 (0.011) | 0.697 (0.040) | 0.572 (0.027) | 0.744 (0.038) | 0.785 (0.029) | 0.915 (0.003) |
| DBCNN | 0.963 (0.012) | 0.940 (0.015) | 0.878 (0.023) | 0.864 (0.016) | 0.835 (0.022) | 0.864 (0.007) |
| HyperIQA | 0.966 (0.012) | 0.934 (0.031) | 0.872 (0.017) | 0.848 (0.033) | 0.855 (0.021) | 0.900 (0.006) |
| TreS | 0.965 (0.019) | 0.902 (0.041) | 0.881 (0.019) | 0.853 (0.031) | 0.846 (0.020) | 0.907 (0.007) |
| UNIQUE | 0.961 (0.005) | 0.902 (0.052) | 0.884 (0.013) | 0.852 (0.027) | 0.854 (0.020) | 0.895 (0.008) |
| LIQE | 0.970 (0.004) | 0.936 (0.025) | 0.930 (0.009) | 0.875 (0.020) | 0.904 (0.014) | 0.919 (0.004) |
Table 1: PLCC (median, SD in brackets) tab. 1
| Method | LIVE | CSIQ | KADID-10k | BID | CLIVE | KonIQ-10k |
|---|---|---|---|---|---|---|
| NIQE | 0.904 (0.089) | 0.719 (0.022) | 0.442 (0.019) | 0.618 (0.045) | 0.507 (0.054) | 0.438 (0.015) |
| ILNIQE | 0.894 (0.025) | 0.851 (0.029) | 0.611 (0.027) | 0.494 (0.046) | 0.518 (0.051) | 0.534 (0.020) |
| Ma19 | 0.923 (0.019) | 0.929 (0.011) | 0.501 (0.013) | 0.399 (0.059) | 0.405 (0.033) | 0.398 (0.009) |
| PaQ2PiQ | 0.558 (0.023) | 0.766 (0.028) | 0.448 (0.012) | 0.700 (0.032) | 0.755 (0.022) | 0.716 (0.009) |
| KonCept | 0.619 (0.039) | 0.645 (0.043) | 0.515 (0.018) | 0.825 (0.026) | 0.799 (0.016) | 0.924 (0.003) |
| MUSIQ | 0.818 (0.011) | 0.766 (0.028) | 0.584 (0.016) | 0.774 (0.030) | 0.828 (0.017) | 0.937 (0.003) |
| DBCNN | 0.966 (0.010) | 0.954 (0.013) | 0.878 (0.022) | 0.883 (0.017) | 0.854 (0.015) | 0.868 (0.006) |
| HyperIQA | 0.968 (0.011) | 0.946 (0.022) | 0.869 (0.018) | 0.868 (0.027) | 0.878 (0.015) | 0.915 (0.004) |
| TreS | 0.963 (0.016) | 0.923 (0.031) | 0.879 (0.019) | 0.871 (0.028) | 0.877 (0.016) | 0.924 (0.006) |
| UNIQUE | 0.952 (0.007) | 0.921 (0.048) | 0.885 (0.011) | 0.875 (0.019) | 0.884 (0.014) | 0.900 (0.005) |
| LIQE | 0.951 (0.006) | 0.939 (0.024) | 0.931 (0.009) | 0.900 (0.016) | 0.910 (0.013) | 0.908 (0.002) |
On PLCC, LIQE is not the top method on LIVE, CSIQ or KonIQ-10k in this table (for example, HyperIQA 0.968 and DBCNN 0.966 on LIVE) tab. 1. The paper's bold marks follow its own table.
Table 2: SRCC under the cross-dataset setup (models trained on KADID-10k and KonIQ-10k as in the subscripts) tab. 2
| Method | TID2013 | SPAQ | PIPAL |
|---|---|---|---|
| NIQE | 0.314 | 0.578 | 0.153 |
| DBCNN_r | 0.471 | 0.801 | 0.413 |
| DBCNN_s | 0.686 | 0.412 | 0.321 |
| PaQ2PiQ | 0.423 | 0.823 | 0.400 |
| MUSIQ_r | 0.584 | 0.853 | 0.450 |
| UNIQUE | 0.768 | 0.838 | 0.444 |
| LIQE | 0.811 | 0.881 | 0.478 |
The paper states that none of the methods performs well on PIPAL §4.3 tab. 2.
Table 3: Median SRCC in the multi-dataset realignment experiment tab. 3
| Method | SRCC |
|---|---|
| UNIQUE | 0.851 |
| LIQE | 0.879 |
Table 4: Ablation, median SRCC over ten sessions tab. 4
| Variant | LIVE | CSIQ | KADID-10k | BID | CLIVE | KonIQ-10k | Mean |
|---|---|---|---|---|---|---|---|
| (1) Pretrained CLIP, C=2 | 0.801 | 0.777 | 0.642 | 0.668 | 0.595 | 0.677 | 0.693 |
| (2) Fine-tuned CLIP, C=2 | 0.934 | 0.900 | 0.901 | 0.841 | 0.868 | 0.898 | 0.890 |
| (3) Frozen text encoder | 0.968 | 0.933 | 0.926 | 0.866 | 0.901 | 0.916 | 0.918 |
| (4) Separate task templates | 0.969 | 0.937 | 0.924 | 0.856 | 0.903 | 0.905 | 0.916 |
| (5) Equal task weightings | 0.968 | 0.938 | 0.927 | 0.870 | 0.899 | 0.917 | 0.920 |
| (6) Fine-tuned visual encoder only | 0.969 | 0.923 | 0.921 | 0.863 | 0.901 | 0.910 | 0.915 |
| LIQE | 0.970 | 0.936 | 0.930 | 0.875 | 0.904 | 0.919 | 0.922 |
The gap between LIQE and equal weighting is 0.002 in mean SRCC tab. 4. The paper reports no spread for the ablation.
Table 5: Task combinations, mean over six datasets tab. 5
| Task combination | SRCC | ACC_s | ACC_d |
|---|---|---|---|
| Quality | 0.915 | -- | -- |
| Scene | -- | 0.908 | -- |
| Distortion | -- | -- | 0.847 |
| Quality + Scene | 0.915 | 0.898 | -- |
| Quality + Distortion | 0.920 | -- | 0.829 |
| All tasks (LIQE) | 0.922 | 0.894 | 0.831 |
The paper's realignment check uses 150 sampled images and six monotone mappings §4.4.
Paper vs code
Code: zwx8981/LIQE at
a64655f7b84b9543b513394472851884cde5b257. The paper links it from the abstract,
and its owner is the first author, Weixia Zhang. MIT licence, copyright Weixia
Zhang. The paper's main results come from train_unique_clip_weight.py, and
the evaluation from BIQA_benchmark.py.
- Joint temperature. The paper treats tau_1 as learnable §3.2 eq. 3.
The code freezes CLIP's
logit_scalefor every option [code: train_unique_clip_weight.py#L129] and callsfreeze_model(opt)with opt=0 train_unique_clip_weight.py. The effective scale is fixed at CLIP's pretrained value. - DWA weights. Eq. 11 has no factor for the number of tasks §3.2 eq. 11.
The code multiplies each softmax weight by
n_tasks, so the three weights sum to 3 weight_methods.py. The first two epochs use weight 1 weight_methods.py, which the paper does not mention. The loss averages used in the ratio are epoch means of per-step losses [code: weight_methods.py#L185-L186, #L192-L193]. - DWA temperature and alpha. The paper gives no tau_2 value §3.2. The code uses temp = 2.0 train_unique_clip_weight.py and passes alpha = 1.5, which the DWA class does not use weight_methods.py.
- Tied MOS in pair labels. Eq. 4 gives label 1 when q(x) >= q(y) §3.2
eq. 4. The code sets the label to 0.5 for ties (
0.5 * (sign + 1)) [code: MNL_Loss.py#L151]. - Pair averaging. Eq. 10 averages over all pairs of the union §3.2 [eq. 10]. The code averages the pairs within each dataset, then divides by the number of datasets MNL_Loss.py. A 4-image dataset gives 6 pairs, a 16-image dataset gives 120. In the code a pair from a 4-image dataset therefore carries weight 1/36 and a pair from a 16-image dataset weight 1/720, against 1/264 under eq. 10 for the batch in this setup.
- Scene loss form. The paper also tries a softmax form §3.2 eq. 8. The code only has the binary multi-label form averaged over nine categories [code: MNL_Loss.py#L42-L59].
- Text encoder. The paper names GPT-2 with 63M parameters as the text encoder
§4.1. The code calls
clip.load("ViT-B/32")and so uses CLIP's own text transformer train_unique_clip_weight.py. - Label names. The paper writes "indoor scene", "night scene" and "still-life" §3.1. The code uses "indoor", "night" and "still_life" [code: train_unique_clip_weight.py#L19-L26] train_unique_clip_weight.py. The paper's "spatially-localized" is "spatial" in the code [code: train_unique_clip_weight.py#L35-L46].
- Distortion labels. The paper gives only the eleven classes §3.1. The mapping from the 33 dataset-specific labels to those classes is in the code train_unique_clip_weight.py.
- Resizing. The paper avoids resizing, because it changes perceived quality §3.2. The code resizes images whose two sides are both at least 768 pixels so that the shorter side is 768 utils.py utils.py. Smaller images are not resized.
- Training crops. The paper says "randomly crop" §4.1. The code takes crops from a grid with stride 32, or stride 48 when one side is at least 1024 pixels, and draws the indices with replacement ImageDataset2.py [code: ImageDataset2.py#L88].
- Training flip. The training preprocessing adds a random horizontal flip utils.py, which the paper does not mention.
- Test crops. The paper says "randomly crop" 15 sub-images at inference §4.1. The evaluation code takes 15 evenly spaced crops [code: ImageDataset2.py#L81-L86].
- Stand-alone inference.
LIQE.pyalways uses stride 32, never resizes, and takes 15 evenly spaced crops LIQE.py LIQE.py [code: LIQE.py#L72-L77]. The benchmark pipeline resizes and uses stride 48 for large images utils.py ImageDataset2.py. Scores from the two paths need not match. - Epoch. The paper uses 80 epochs §4.1. In the code an epoch is 200 iterations; each iteration draws one mini-batch from each of the six loaders, 48 images in total train_unique_clip_weight.py [code: train_unique_clip_weight.py#L183-L197].
- Learning-rate schedule. Cosine annealing with T_max = 5 is stepped once per epoch train_unique_clip_weight.py train_unique_clip_weight.py. The script also steps the scheduler again when the learning rate is exactly zero train_unique_clip_weight.py. Under T_max = 5 the cosine reaches zero at epoch 5 and rises again. This is inferred from the code and was not run.
- Model selection. The paper does not say which checkpoint the table uses.
The code picks the epoch by the average validation SRCC over the six datasets
and saves
quality_best_ckpt.pttrain_unique_clip_weight.py train_unique_clip_weight.py [code: train_unique_clip_weight.py#L417-L448]. The benchmark loads that checkpoint BIQA_benchmark.py. - Median or mean. The paper reports median SRCC over ten sessions tab. 1.
The code's
final_avgcallsnp.meanand labels the result "median" [code: BIQA_benchmark.py#L377-L385]. - PLCC. The code's PLCC and RMSE are computed after a four-parameter logistic fit to the test set BIQA_benchmark.py. The paper does not state this for its main table.
- Mixed precision. On CUDA the code casts weights to fp32 for the optimiser
step, then calls
clip.model.convert_weightsto cast them back [code: train_unique_clip_weight.py#L303-L308]. The CLIP package is not in the repo, so the effect of that call was not checked here. - Checkpoint format. The training script saves a dict with
model_state_dicttrain_unique_clip_weight.py.LIQE.pyloads the file as a raw state dict LIQE.py. The benchmark loads the dict form BIQA_benchmark.py. - Logged distortion accuracy. In the test record for KADID-10k the distortion
entry uses the validation value
dist_acc6train_unique_clip_weight.py. The model weights are unaffected, but theall_resultsdict saved in each checkpoint carries the wrong value train_unique_clip_weight.py. - Fidelity epsilon. The code adds 1e-8 inside each square root [code: MNL_Loss.py#L9] MNL_Loss.py. The paper writes no epsilon §3.2.
- Pretrained weights and data. The README links the pretrained weights on Google Drive and Baidu README.md. The IQA image folders are not in the repository, only the split files train_unique_clip_weight.py.
- Third-party re-training. The README points to IQA-PyTorch
liqe(re-trained on KonIQ-10k) andliqe_mix(multi-dataset) README.md. Neither is the paper's model.
Pitfalls
- Text tower cost. The text encoder is trained, so all 495 prompts go through it on every training step train_unique_clip_weight.py train_unique_clip_weight.py. This is a per-step cost that the abstract does not mention.
- Crops per image. Training uses 3 crops and testing uses 15 §4.1. The cost of inference is 15 forward passes per image, each with all 495 texts scored.
- Pair weights. A 4-image dataset and a 16-image dataset weigh their pairs very differently under the code's averaging (see Paper vs code).
- Numerical precision. Updates are cast back to half precision after each step on CUDA train_unique_clip_weight.py. With a learning rate of 5e-6, small updates may round away. Verify this in your setup before copying the schedule.
- Scene and distortion labels per image. The training loader sets every valid scene label to 1, so multi-label targets are used [code: train_unique_clip_weight.py#L210-L219]. The paper's binary form is the same §3.2. The per-image labels sit in the split files shipped with the repo, but the images they point to are not in the repo.
- Reported spread. The table reports medians and SDs over ten sessions [tab. 1]. The selection rule is not stated in the paper, so the reported epoch cannot be reproduced exactly from the text.
- Ablation margins. Several ablation differences are small (for example 0.920 against 0.922 mean SRCC) and the paper reports no per-variant spread tab. 4.
- Unstated constants. tau_2, the cosine T_max and the seed are not in the paper. The code's values are listed under Hyperparameters.
- Intermediate checks. The validation SRCC is computed with the same 15 crops used at test time train_unique_clip_weight.py. Use this to check your run, not as an independent test score.
Lineage
- Builds on: CLIP §2.2 §3.2. Named in the paper, with no arXiv id in the source, so not linked here.
- Builds on: UNIQUE's joint training with pairwise learning-to-rank over several datasets §3.2 §4.5. Named in the paper, no card here.
- Closest prior work: Wang et al., who use CLIP for quality through prompt engineering with two quality levels §2.2 §4.5.
- Compared against: NIQE, ILNIQE, Ma19, PaQ2PiQ, KonCept, MUSIQ, DBCNN, HyperIQA, TreS and UNIQUE §4.2.
- Loss weighting: dynamic weight average (Liu et al.) §2.3 eq. 11.
Source and license
Adapted from “Blind Image Quality Assessment via Vision-Language Correspondence: A Multitask Learning Perspective” by Weixia Zhang, Guangtao Zhai, Ying Wei, Xiaokang Yang, Kede Ma (arXiv:2303.14968), used under CC BY 4.0. Changes: condensed and restructured for implementation, with tables, equations and algorithms taken from the paper and its code, each cited to its source. Not affiliated with or endorsed by the authors. Code citations refer to https://github.com/zwx8981/LIQE at commit a64655f7b84b (MIT). Any quoted code is shown under that license.