作者供图
当你训练一个监督式机器学习模型时,你会输入数据并进行实时预测。将这些预测与训练样本的实际目标进行比较,可以帮助优化模型。
但是怎么比较呢?这是一个很好的问题。
现在有几种所谓的损失函数可以有效地展示真实目标和预测之间的差异。一个例子是Kullback-Leibler散度(简称KL散度)。这让我产生了许多疑问。什么是KL散度?它作为损失函数的表现如何?它能用来解决哪些机器学习或深度学习问题?我又该如何实际应用它?
所有这些都是很好的问题,我将在我的博客文章中尝试解答。首先,我将定义KL散度,这是一个(剧透预警)用于比较两个概率分布的衡量标准。然后,我将讨论KL散度在深度学习问题中的使用示例。接下来,我将介绍Keras API中的KL散度,在该API的损失函数部分中指定了KL散度。最后,我们将创建一个具有KL散度损失值的Keras模型,看看它表现如何。
准备好了没?走啦!
比较两个概率分布的KL距离好的,我们来检查第一个问题:什么是K-L散度?
当我开始研究这个问题的时候,我很快就找到了一篇非常有启发性的文章。Count Bayesie网站上的文章《Kullback-Leibler Divergence Explained》,这篇文章用简单易懂但又不失严谨性的语言解释了KL散度,这为我解释KL散度提供了很好的基础,并参考了其他一些资料。我非常推荐你也抽时间看一下!
小注:与Count Bayesie的文章不同,我将从监督学习的角度出发开始解释。
机器学习的概率分布模型假设你有一个模型输出的概率分布。某些激活函数,例如 "softmax",会为你监督学习模型的分类提供一个概率分布。
不像在使用Softmax时通常使用的类别交叉熵损失函数那样,只考虑预测结果中的最大值,你想比较预测的概率分布和实际的概率分布。
正如我们将会看到的,确实存在这种类型的案例。在这种情况下,你可以使用Kullback-Leibler散度,这是一种在信息论中使用的熵度量的变体(Count Bayesie,无日期记录)。
从熵信息大小到预期信息损失但是,什么是熵呢?从数学的角度来看,它的定义是(维基百科,2001)——
简单来说,它表示数据分布概率的平均值。换句话说,定义它为(假设使用 log₂):“编码我们信息所需最少的比特数”(Count Bayesie, 2017)。
概率分布的熵(即随机变量的不确定性度量)可以告诉你一组数据中包含的信息量有多少。了解这一点,我们就可以计算出分布变化时丢失了多少信息量。
因为当你在做深度学习时,你的模型预测实际上形成了一种概率分布(“某个值落在x和y之间或y取值为x的概率”),然后就可以把这种概率分布跟样本的真实分布(也就是你的训练数据集)做比较。
现在,当优化器调整其权重时,预测也随之改变,模型的概率分布也随之改变。如果你能衡量模型概率分布与实际训练数据集分布之间的差异,你就可以做些优化了。
KL 散度行吧,你能行!
Kullback-Leibler 散度只是对我们的熵公式进行了一点修改。除了概率分布 p 外,还包括了一个近似分布 q。我们比较每个值的对数差异:
本质上,KL散度(Kullback-Leibler散度)是原始分布中的数据相对于近似分布时,数据概率对数差的期望。用log2来表示,这可以理解为“我们期望丢失的信息位数”。我们根据期望来重新表述我们的公式。
KL散度最常见的写法如下所示:
从那时起
KL散度(Kullback-Leibler 散度)这允许我们,精确测量当我们用一个分布来近似另一个分布时丢失了哪些信息。
毫不令人惊讶的是,KL散度也被称为相对熵。它衡量了当从一个分布转换到另一个分布时熵的变化(根据维基百科(2004年)),这使我们能够对比两个概率分布。
让我们看看在哪些机器学习场景中需要用到KL散度损失函数,以便更好地了解何时使用它会更有效。
KL 散度在机器学习中的应用
在自己的机器学习项目中,什么时候应该使用KL距离?
- 它也是现在广泛用于生成人类图像的生成模型之一。这些自编码器学习将样本编码为潜在的概率分布。这个潜在的分布可以用于生成一个样本,该样本可以输入到解码器中,从而生成一张图像。它也是现在流行用于生成这类图像的生成模型之一。
- KL散度也可以应用于多类分类的情景中(Moreno, n.d.)。这些通常使用Softmax函数和one-hot编码的目标数据的问题,非常适合使用KL散度,因为Softmax将数据“归一化为一个由K个概率组成的概率分布,这些概率与输入数字的指数成比例”(维基百科,2006)。简单说来,它给出的是给定样本x出现在输入图像中的概率。由于KL散度是在概率分布层面工作的,因此在这里非常有用。
- 有趣的是,KL散度也被用来替代模型中的最小二乘损失(Kosheleva & Kreinovich, 2018)。在回归模型中,通常最小化的目标函数是误差(预测值与目标值的差异),一般情况下误差会被平方。虽然这种损失函数的简单性在效果上有所回报,但它们在预测值偏离正常时特别噪声大。尽管KL散度是在概率分布层面而不是单一样本层面工作的,但它作为一种引人注目的替代方案已经越来越受欢迎。
Keras API 如下定义 KL 散度(KL 散度是):
keras.losses.kl 散度(y_true, y_pred)
这意味着你可以在你的模型中直接定义它为“相对熵”或“kullback_leibler_divergence”。
基于KL散度(即Kullback-Leibler散度)构建Keras模型让我们试试看能否用Keras构建一个使用KL散度的模型。正如我们之前提到的,KL散度可以在多种机器学习任务中发挥作用,包括使用Softmax函数进行多类分类,该函数可以生成概率分布。这些分布可以与KL散度进行比较,因此可以利用这些分布来进行训练。
在编译 Keras 时配置损失模型实际上这很简单。它只需要在模型编译过程中指定所用的损失函数。
# 编译模型,让它准备好运行
model.compile(loss=keras.losses.kullback_leibler_divergence, # K-L散度
optimizer=keras.optimizers.Adam() # Adam优化器
metrics=['准确率'] # 使用准确率作为评估指标
)
行了!
完整的Keras CNN代码示例这里有一个完整的ConvNet代码链接,其中包括了 KL 散度。
import keras
from keras.datasets import cifar10
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras import backend as K
# 模型配置参数
img_width, img_height = 32, 32
batch_size = 250
no_epochs = 25
no_classes = 10
validation_split = 0.2
verbosity = 1
# 加载CIFAR10数据集
(input_train, target_train), (input_test, target_test) = cifar10.load_data()
# 根据通道顺序调整数据格式
# 这取决于您使用的后端是TF、Theano还是CNTK
# 来源: https://github.com/keras-team/keras/blob/master/examples/mnist_cnn.py
if K.image_data_format() == 'channels_first':
input_train = input_train.reshape(input_train.shape[0], 3, img_width, img_height)
input_test = input_test.reshape(input_test.shape[0], 3, img_width, img_height)
input_shape = (3, img_width, img_height)
else:
input_train = input_train.reshape(input_train.shape[0], img_width, img_height, 3)
input_test = input_test.reshape(input_test.shape[0], img_width, img_height, 3)
input_shape = (img_width, img_height, 3)
# 解析为浮点数
input_train = input_train.astype('float32')
input_test = input_test.astype('float32')
# 归一化数据
input_train = input_train / 255
input_test = input_test / 255
# 将目标向量转换为分类目标
target_train = keras.utils.to_categorical(target_train, no_classes)
target_test = keras.utils.to_categorical(target_test, no_classes)
# 创建模型
model = Sequential()
model.add(Conv2D(32, kernel_size=(3, 3), activation='relu', input_shape=input_shape))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.50))
model.add(Conv2D(64, kernel_size=(3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.50))
model.add(Flatten())
model.add(Dense(256, activation='relu'))
model.add(Dense(no_classes, activation='softmax'))
# 编译模型
model.compile(loss=keras.losses.kullback_leibler_divergence,
optimizer=keras.optimizers.Adam(),
metrics=['accuracy'])
# 将数据拟合到模型
model.fit(input_train, target_train,
batch_size=batch_size,
epochs=no_epochs,
verbose=verbosity,
validation_split=validation_split
)
# 计算泛化性能指标
score = model.evaluate(input_test, target_test, verbose=0)
print(f'测试损失: {score[0]} / 测试准确率: {score[1]}')
结果部分
我先运行了模型两次,然后切换到分类交叉熵损失,再运行两次。这使我们能够对比KL散度与分类交叉熵损失,后者常用于多类分类任务,其中类别被编码为one-hot向量。
在整个25个阶段中,表现相差不大。因此,如果你要在类别交叉熵和KL散度之间做出选择的话,我觉得你可以用任何一种。
概要
在这篇博客中,我们讨论了KL距离以及如何在神经网络中使用它。为了展示这一点,我们使用Python的Keras深度学习框架构建了一个卷积神经网络的例子。这个例子使用了KL散度作为损失函数,表现与常用的类别交叉熵损失差不多。
希望今天的文章给你带来了一些收获。对于任何问题、评论或建议,我们都非常欢迎。感谢您的阅读,希望您喜欢!
参考文献Count Bayesie. (2017年5月10日). Kullback-Leibler 散度解释. 来自 https://www.countbayesie.com/blog/2017/5/9/kullback-leibler-divergence-explained
维基百科。 (2004年2月13日). Kullback–Leibler 信息散度。来自 https://en.wikipedia.org/wiki/Kullback%E2%80%93Leibler_divergence
维基百科(Wikipedia)。(2001年7月9日). 信息理论中的熵。参见 https://en.wikipedia.org/wiki/Entropy_(information_theory)
Shafkat, I. (2018年4月5日). 直观理解变分自编码器. 来源 https://towardsdatascience.com/intuitively-understanding-variational-autoencoders-1bfe67eb5daf
Kosheleva, O., & Kreinovich, V. (2018). 为什么不用最小二乘法,而选择使用KL散度?这可能是一种教学说明。 https://digitalcommons.utep.edu/cs_techrep/1192
Moreno. (未注明日期). 亚历山大·莫雷诺关于“机器学习中KL距离的应用”的解答。来源自 https://www.quora.com/What-are-some-applications-of-the-KL-divergence-in-machine-learning/answer/Alexander-Moreno-1
Keras. (日期不详). 损失. 参见 https://keras.io/losses/kullback_leibler_divergence
维基百科(英文)。(2006年7月28日)。Softmax函数(softmax function)。参见 https://en.wikipedia.org/wiki/Softmax_function
共同學習,寫下你的評論
評論加載中...
作者其他優質文章