DeepChem教程25:深度学习的不确定性

对于深度学习模型的常见批评是它们像黑盒子一样工作。一个模型产生输出,但并没有足够的内容来解释它们的正确性。模型的预测的结果是否可靠?是否有一些预测结果比另一些结果更可靠?如果对于有些数值模型的预测结果为5.372,你会认为这个值是5.3715.373的中间值?还是2 8?在某些领域这情况可能足够好,但要科学领域并不足够好。对于模型预测的值我们需要也想要评估这个值的不确定性以致我们知道我们能基于它做什么结论。

DeepChem让评估预测输出的不确定性评估很容易。(起码对于它所支持的模型是这样不是所有的模型)。我们加载数据,创建模型,用训练集来训练它,用测试集来预测输出,然后进行一些不确定性评估。

本教程我们用MoleculeNetDelaney数据集来进行实验。我们来加载我们的数据集,然后做一些不确定性预测。

In [1]:

import deepchem as dc

import numpy as np

import matplotlib.pyplot as plot

tasks, datasets, transformers = dc.molnet.load_delaney()

train_dataset, valid_dataset, test_dataset = datasets

 

model = dc.models.MultitaskRegressor(len(tasks), 1024, uncertainty=True)

model.fit(train_dataset, nb_epoch=20)

y_pred, y_std = model.predict_uncertainty(test_dataset)

所有这些看起来与其它例子一样,只有两点不同。第一,创建模型时我们增加了uncertainty=True选项。这指示为模增加特征来评估不确定性。第二,我们调用predict_uncertainty()而不是predict()来产生输出。y_pred 是预测的输出。y_std是同样形状的数组,每一个元素是与y_pred相应的不确定性(标准偏差)。这就是所有这些,很简单,是不是?

当然,实际上并没有那么简单。DeepChem要做很多工作来完成不确定性。所以我们打开窗帘看发生了什么事。(对于计算不确定性的数学细节请见https://arxiv.org/abs/1703.04977

开始,什么是不确定性?直观的,它测量的是我们能多大程度相信预测值。更正式地,我们希望真实值会落在预测值的标准偏差范围内。但是不确定性有许多来源,如噪音训练数据和不好的模型选择,不同的来源有不同的表现。有两种不确定性需要我们考虑。

偶然不确定性

考虑以下的图。它表示了10个点的最佳线性回归拟合。

In [2]:

# Generate some fake data and plot a regression line.

x = np.linspace(0, 5, 10)

y = 0.15*x + np.random.random(10)

plot.scatter(x, y)

fit = np.polyfit(x, y, 1)

line_x = np.linspace(-1, 6, 2)

plot.plot(line_x, np.poly1d(fit)(line_x))

plot.show()

很明这条线并没有很好的拟合数据。这可能有很多原因。可能是捕捉数据的测装置不够准确。可能y 依赖于x以外的因子,如果我们知道每个点的那种因子值,我们就可以更准确的预测 y。可能x  y并不是简单的线性,我们需要更复杂的模型来捕捉它。

不管如何,模型没有很好的预测训练数据,这是我们要注意的。我们不能希望它对测试集的预测结果会比训练集好。这就是偶然不确定性。

 我们如何评估不确定性的大小?当然是通过训练模型来完成。在学习预测输出的同时,它也学习预测输出与训练集的准确度如何。对于模型的每个输出,我们增加第二个输出来产生相应的不确定性。我们修改损失函数使它同时学习两种输出。

认知不确定性

现在考虑三种曲线。它们拟合上面的数据,但是这次我们用10次多项式进行拟合。

In [3]:

plot.figure(figsize=(12, 3))

line_x = np.linspace(0, 5, 50)

for i in range(3):

    plot.subplot(1, 3, i+1)

    plot.scatter(x, y)

    fit = np.polyfit(np.concatenate([x, [3]]), np.concatenate([y, [i]]), 10)

    plot.plot(line_x, np.poly1d(fit)(line_x))

plot.show()

他们都很好的插值数据,然而它们都是不同的模型。(事实上我无穷多的10次多项式可以插值任意10个数据点)。对于我们拟合的数据它们都可以很好的预测,但是对于其它不同的x它们会产生不同的预测值。这就是认知不确定性。它意味着数据不能完全约束模型。对于给定的数据我们可以发现很多不同的模型,这些模型会产生不同的预测结果。

测量认知不确定性的理想方法是训练许多不同的模型,每次使用不同的随机种子,并改变超参数。然后每次输入使用它们看看预测的变化。这样做很昂贵,因为重复训练过程很多次。幸运的,我们可以近似同样的效果而用更便宜的方法:使用dropout

记得你训练模型时使用过dropout,你一次性训练大量相似而不同的模型。每次训练样本用不同的dropout掩膜,相应的有不同的随机子集与完整的模型相连。通常我们只是在训练时使用dropout,并用一个平均的掩膜来预测。但是,我们也可以用dropout来预测。我们可以为许多不同的dropout掩码计算输出,然后看预测变化多少。这证明可以很好的评估输出的认知不确定性。

不确定性的不确定

现在我们联合两种不确定性来每个输出的总的评估:

这是DeepChem报告的值。但是多大程序我们可以相信它呢?记住我们是如何开始这个教程的:深度学习模型不应该使用黑盒子。我们想知道输出的可靠性。增加不确定性评估并不能完全解决问题,它只会增加一个不直接的层。现在我们评估了输出的可靠性,但并不能保证评估是可靠的。

我们回到开始的例子。我们用样本训练集训练模型,然后产生测试集的预测和不确定性。因为我们知道所有测试样本的准确输出,我们可以评估我们做得多好。这里是预测输出的绝对误差与预测不确定性作图。

In [4]:

abs_error = np.abs(y_pred.flatten()-test_dataset.y.flatten())

plot.scatter(y_std.flatten(), abs_error)

plot.xlabel('Standard Deviation')

plot.ylabel('Absolute Error')

plot.show()

第一个我们注意到的事情是坐标轴有相似的范围。模型已学习了预测误差的所有范围。明显不同的轴有相关性。大的不确定性趋于平均化以有更大的误差。(严格的说,我们希望绝对误差小于预测不确定性。即便有小部分仍接近正确值。如果模型工作得很好,会有更多的点在对角线下相比对角线上)

现在我们来看一下值是否满足期望的分布。如果标准偏差是正确的,并且误差是正态分布的(当然不能保证是真的),我们希望95%的值在两个标准偏差内,99%值在3个标准偏差内。变里是误差的直方图用于测量标准偏差。

In [5]:

plot.hist(abs_error/y_std.flatten(), 20)

plot.show()

所有的值都在期望的范围内,分布也看起来接近正态,虽然不是严格的。这可能提示误差不正态分布,但它也可能反映不确定性的不准确。这是一个重要的问题:不确定性只是评估的,不是严格测量的。它们中大部分很好,但是你不应该过分相信单一的值。

下载全文请到www.data-vision.net,技术联系电话13712566524

猜你喜欢

转载自blog.csdn.net/lishaoan77/article/details/114376749