PQMass: Probabilistic Assessment of the Quality of Generative Models using Probability Mass Estimation
PQMass is a new sample-based method for evaluating the quality of generative models as well as assessing distribution shifts to determine if two datasets come from the same underlying distribution.
To install PQMass, run the following:
pip install pqm
PQMass takes in
PQMass partitions the space by taking reference points from
$$\chi_{PQM}^2 \equiv \sum_{i = 1}^{n_R} \left[ \frac{(k({\bf x}, R_i) - \hat{N}{x, i})^2}{\hat{N}{x, i}} + \frac{(k({\bf y}, R_i) - \hat{N}{y, i})^2}{\hat{N}{y, i}} \right]$$
and the second is the
For DoF = num_refs - 1
The
peak of this distribution will be at DoF - 2
, the mean will equal DoF
, and
the standard deviation will be sqrt(2 * DoF)
. If your chi^2 / DoF > 1
), it suggests that the samples are out of distribution.
Conversely, if the values are too low (chi^2 / DoF < 1
), it indicates
potential duplication of samples between x
and y
.
If your two samples are drawn from the same distribution, then the x
and y
.
PQMass can work for any two datasets as it measures the distribution shift between the
We are using 100 regions. Thus, the DoF is 99, our expected
Our expected p-value should be around 0.5 to pass the null hypothesis test; any significant deviation away from this would indicate failure of the null hypothesis test.
Given two distributions,
from pqm import pqm_pvalue, pqm_chi2
import numpy as np
p = np.random.normal(size = (500, 10))
q = np.random.normal(size = (400, 10))
# To get chi^2 from PQMass
chi2_stat = pqm_chi2(p, q, re_tessellation = 1000)
print(np.mean(chi2_stat), np.std(chi2_stat)) # 98.51, 11.334
# To get pvalues from PQMass
pvalues = pqm_pvalue(p, q, re_tessellation = 1000)
print(np.mean(pvalues), np.std(pvalues)) # 0.50, 0.26
We see that both
Another such example in which we do
from pqm import pqm_pvalue, pqm_chi2
import numpy as np
p = np.random.normal(size = (500, 10))
q = np.random.uniform(size = (400, 10))
# To get chi^2 from PQMass
chi2_stat = pqm_chi2(p, q, re_tessellation = 1000)
print(np.mean(chi2_stat), np.std(chi2_stat)) # 577.29, 25.74
# To get pvalues from PQMass
pvalues = pqm_pvalue(p, q, re_tessellation = 1000)
print(np.mean(pvalues), np.std(pvalues)) # 3.53e-56, 8.436e-55
Here it is clear that both
Thus, PQMass can be used to identify if any two distributions come from the same underlying distributions if enough samples are given. We encourage users to look through the paper to see the varying experiments and use cases for PQMass!
We have shown what to expect for PQMass when working with
- For Generative Models; 0's indicate memorization. Samples are duplicates of the data it has been trained on.
- For non generative model scenario, it is typically due to lack of samples espically in high dimensions. Increasing samples should alleviate the issue.
- Another scenario in which one could get 0's in a non generative model case is that it can also be an inidcator of duplicate samples in
$x$ and$y$ .
Depending on the data you are working with we show other uses of the parameters for PQMass.
If you determine that you need to normalize z_score_norm = True
:
chi2_stat = pqm_chi2(p, q, re_tessellation = 1000, z_score_norm = True)
pvalues = pqm_pvalue(p, q, re_tessellation = 1000, z_score_norm = True)
The default setup for selecting reference points is to take the number of regions and then sample from x_frac = 1.0
:
chi2_stat = pqm_chi2(p, q, re_tessellation = 1000, x_frac = 1.0)
pvalues = pqm_pvalue(p, q, re_tessellation = 1000, x_frac = 1.0)
Alternatively, you can sample the reference points only from x_frac = 0
:
chi2_stat = pqm_chi2(p, q, re_tessellation = 1000, x_frac = 0)
pvalues = pqm_pvalue(p, q, re_tessellation = 1000, x_frac = 0)
Similary you can sample reference points equally from both x_frac = 0.5
:
chi2_stat = pqm_chi2(p, q, re_tessellation = 1000, x_frac = 0.5)
pvalues = pqm_pvalue(p, q, re_tessellation = 1000, x_frac = 0.5)
Lastly one could not sample reference points from either guass_frac = 1.0
:
chi2_stat = pqm_chi2(p, q, re_tessellation = 1000, guass_frac = 1.0)
pvalues = pqm_pvalue(p, q, re_tessellation = 1000, guass_frac = 1.0)
PQMass now works on both CPU and GPU. All that is needed is to pass the x_samples
and y_samples
as a PyTorch Tensor on the appropriate device.
If you're a developer then:
git clone git@github.com:Ciela-Institute/PQM.git
cd PQM
git checkout -b my-new-branch
pip install -e .
But make an issue first so we can discuss implementation ideas.