一、Inception Score的基础概念和定义
Inception Score,简称IS,是用于评估生成模型质量的一种指标,由Salimans等人在2016年提出。IS是基于对图像生成模型的激活层进行统计计算得出的结果。其核心思想是通过计算每张图像在模型内部的复杂程度以及不确定性,从而评判模型的生成能力。
在英文论文中,IS的定义如下:
Let p(y|x) be the class predicted by the inception model when generating the image x. The inception score is then defined to be:
$$exp(\mathbb{E}_{x∼p_g}[KL(p(y|x)∥p(y))])$$
其中 p(y) 是在不同的输入图像上经验统计的类别分布。也就是说,在不同的输入图像样本中,IS计算使用的是真实标签的分布。
二、Inception Score的优点
相比与其他评价指标来说,Inception Score有以下几个优点:
1、适用性广,可以很好地应用于不同类型的图像生成模型,如GAN、VAE等。
2、不依赖于训练数据的特定特征,也就意味着对于不同数据集的生成模型,IS的评估方式可以保持不变。
3、IS的结果可以用来比较不同模型的泛化能力,也就是说在对数据的生成能力评价上能够更全面的描述模型的生成能力。
三、计算Inception Score的具体步骤
1、首先需要下载预训练的Inception模型权重,这个可以在TensorFlow源码中找到。在 TensorFlow 源代码中可找到已经训练好的 Inception 模型,运行以下命令来下载这些模型(以下命令需联网操作):
python download_and_preprocess_imagenet.py
2、准备样本集,并且生成图像。对样本集生成的图片需要做如下处理,即:
- 将生成器依次运行 $n$ 次,每次得到 $m$ 张图片。
- 将所有得到的图片灰度标准化,使得像素点值在 0 到1 之间。
- 对于每张生成图像 x,通过预训练的 Inception 模型计算其在嵌套的回归输出层上每一个类的概率值(也就是对应分类标签的概率值)。
3、根据每个 $x$ 的类别分布计算每个 $M$ 个样本的Inception score。 具体地,对于第 $i$ 个样本集,其 Inception Score 的计算公式为:
$$exp(\mathbb{E}_{x∼p_g}[KL(p(y|x)∥p(y))])$$
这里的 $p(y|x)$ 表示样本 $x$ 属于第 $y$ 个类别的概率,其中 $p(y|x)$ 是已知概率分布,均值及方差的,于是根据推断理论,可以使用重新参数化技巧从已知分布中生成 $y_{1,...,m}$ 的 i.i.d 样本。然后统计每个类别在样本集中出现的概率,得到概率分布 $p(y)$,最后代入上述公式即可得到IS的值。
四、计算Inception Score的示例代码
import numpy as np
import tensorflow as tf
from tensorflow.contrib.slim import arg_scope
from tensorflow.contrib.layers import softmax
from scipy.stats import entropy
def inception_score(images, num_splits=1):
'''
Compute the inception score of the generated images
images : numpy array, generated images whose inception scores are being calculated
num_splits : int, the number of splits of images
'''
# Load inception v1 pre-trained model
inception_v1 = tf.keras.applications.InceptionV1(
weights=None, include_top=True, input_shape=images.shape[1:]
)
# Obtain the final prediction layer of inception model
output_layer = inception_v1.get_layer("predictions")
# Define the computational Graph for Obtaining the softmax (class probabilities) Output
num_outputs = output_layer.output_shape[-1]
m = images.shape[0]
with tf.Session() as sess:
preds = output_layer.output.op.inputs[0]
preds = tf.reshape(preds, [-1, num_outputs])
softmax_out = softmax(preds)
# Perform the split computing for enhancing the stability and diversity of the obtained samples
classes = []
for i in range(num_splits):
print('Split', i)
# Compute the split interval
lower_bound = i * np.floor(m / num_splits).astype(int)
upper_bound = (i + 1) * np.floor(m / num_splits).astype(int)
# Obtain the softmax Output for the split
split_softmax_out = sess.run(softmax_out, feed_dict={inception_v1.input: images[lower_bound:upper_bound]})
# Compute the mean of the softmax Output for the split - class probabilities are averaged across the different splits
p_y_given_x_split = np.mean(split_softmax_out, axis=0)
# Compute entropy for split - entropy measures the amount of randomness
KL = np.sum(p_y_given_x_split * (np.log(p_y_given_x_split + 1e-8) - np.log(np.repeat(np.expand_dims(np.mean(p_y_given_x_split, axis=0), 0), p_y_given_x_split.shape[0]) + 1e-8) ), axis=1)
# Add the Inception Score
IS = np.exp(np.mean(KL))
# Record the Predicted Class Probabilities and Entropies for the Split
classes.append(p_y_given_x_split)
print('Split {}. Inception Score: {}'.format(i, IS))
# Compute the average class probabilities across the different splits
classes = np.concatenate(classes, axis=0)
p_y = np.mean(classes, axis=0)
# Compute entropy for all samples
entropy_final = entropy(p_y)
# Compute Inception Score
inception_score_val = np.exp(entropy_final)
return inception_score_val