将神经网络输出限制为受训类的子集

时间:2017-05-24 02:05:33

标签: python tensorflow neural-network keras

是否可以将矢量传递给经过训练的神经网络,因此它只能从训练过的类的子集中进行选择。例如,我有一个训练有素的网络来识别数字和字母,但我知道我在下一次运行它的图像不会包含小写字母(例如序列号的图像)。然后我传递了一个向量,告诉它不要猜任何小写字母。由于类是独占的,因此网络以softmax函数结束。以下只是我想到的尝试的例子,但没有一个真正起作用。

import numpy as np

def softmax(arr):
    return np.exp(arr)/np.exp(arr).sum()

#Stand ins for previous layer/NN output and vector of allowed answers.
output = np.array([ 0.15885351,0.94527385,0.33977026,-0.27237907,0.32012873,
       0.44839673,-0.52375875,-0.99423903,-0.06391236,0.82529586])
restrictions = np.array([1,1,0,0,1,1,1,0,1,1])

#Ideas -----

'''First: Multilpy restricted before sending it through softmax.
I stupidly tried this one.'''
results = softmax(output*restrictions)

'''Second: Multiply the results of the softmax by the restrictions.'''
results = softmax(output)
results = results*restrictions

'''Third: Remove invalid entries before calculating the softmax.'''
result = output*restrictions
result[result != 0] = softmax(result[result != 0])

所有这些都有问题。第一个导致无效选择默认为:

1/np.exp(arr).sum()

由于对softmax的输入可能是负的,这可能会增加给予无效选择的概率并使答案变得更糟。 (我应该在尝试之前对其进行调查。)

第二个和第三个都有类似的问题,因为他们等到答复给予应用限制之前。例如,如果网络正在查看字母l,但它开始确定它是数字1,那么这将不会被纠正,直到这些方法结束。因此,如果它以0.80的概率给出1的输出,但随后该选项被删除,似乎剩余的选项将重新分配,并且最高有效答案不会像80%那样自信。其余选项最终更加同质化。 我试图说的一个例子:

output
Out[75]: array([ 5.39413513,  3.81445419,  3.75369546,  1.02716988,  0.39189373])

softmax(output)
Out[76]: array([ 0.70454877,  0.14516581,  0.13660832,  0.00894051,  0.00473658])

softmax(output[1:])
Out[77]: array([ 0.49133596,  0.46237183,  0.03026052,  0.01603169])

(阵列被命令使其更容易。) 在原始输出中,softmax给出.70,答案是[1,0,0,0,0],但如果这是一个无效的答案,从而删除了再分配,那么如何以低于50%的概率分配剩余的4个选项因为太低而无法使用,很容易被忽略。

我之前考虑过将一个矢量作为另一个输入传递到网络中,但是我不确定如何做到这一点而不要求它知道矢量告诉它做什么,我认为会增加训练所需的时间。

编辑:我在评论中写得过多,所以我只是在这里发布更新。我最终尝试将限制作为网络的输入。我采用了一个热编码的答案并随机添加了额外的启用类来模拟答案密钥,并确保正确的答案始终在密钥中。当密钥具有非常少的启用类别时,网络严重依赖它并且它干扰图像的学习特征。当密钥有很多启用的类别时,它似乎完全忽略了密钥。这可能是一个需要优化的问题,我的网络架构问题,或者只需要对培训进行调整,但我从来没有解决过这个问题。

我确实发现,当我最终减去np.inf而不是乘以0时,删除答案和归零几乎是一样的。我知道合奏但是在对我的网络正在处理的第一个回复的评论中提到使用CJK字符(字母表只是为了使示例更容易)并且有3000多个类。网络已经过于笨重,这就是为什么我想研究这种方法。对于每个单独的类别使用二进制网络是我没有想到的,但是3000多个网络似乎也有问题(如果我理解你正确说的话),尽管我可能会在以后查看。

2 个答案:

答案 0 :(得分:3)

首先,我将轻松地列出您列出的可用选项,并添加一些可行和可行的替代方案。构造这个答案有点困难,但我希望您能得到我要提出的建议:

1。通过softmax发送之前,请先进行乘以限制。

很显然,如您所写的那样,清零条目的机会更大,一开始似乎是一种错误的方法。

替代:用smallest logit值替换不可能的值。尽管网络对结果的不确定性更高,但它与softmax(output[1:])类似。示例pytorch的实现:

import torch

logits = torch.Tensor([5.39413513, 3.81445419, 3.75369546, 1.02716988, 0.39189373])
minimum, _ = torch.min(logits, dim=0)
logits[0] = minimum
print(torch.nn.functional.softmax(logits))

产生:

tensor([0.0158, 0.4836, 0.4551, 0.0298, 0.0158])

讨论

  • 引用您:“ 在原始输出中,softmax给出.70的答案是[1,0,0,0,0],但是如果这是无效的答案,则删除了重新分配如何分配剩余的4可能性低于50%的选项,由于使用率太低而很容易被忽略。

是的,您这样做的权利。更甚者,此类的实际概率实际上要低得多,大约为14%tensor([0.7045, 0.1452, 0.1366, 0.0089, 0.0047]))。通过手动更改输出,您实际上是在破坏该NN所学习的属性(及其输出分布),从而使计算的某些部分变得毫无意义。这指向了这次赏金中提到的另一个问题:

2。众所周知,NN对于分类问题过于自信

我可以想象这可以通过多种方式解决:

2.1合奏

创建多个神经网络,并通过对最后加argmax(或softmax然后是argmax)的对数进行求和来集成它们。 3个不同模型不同的预测的假设情况:

import torch

predicted_logits_1 = torch.Tensor([5.39413513, 3.81419, 3.7546, 1.02716988, 0.39189373])
predicted_logits_2 = torch.Tensor([3.357895, 4.0165, 4.569546, 0.02716988, -0.189373])
predicted_logits_3 = torch.Tensor([2.989513, 5.814459, 3.55369546, 3.06988, -5.89473])

combined_logits = predicted_logits_1 + predicted_logits_2 + predicted_logits_3
print(combined_logits)
print(torch.nn.functional.softmax(combined_logits))

softmax之后,这将为我们提供以下概率:

[0.11291057 0.7576356 0.1293983 0.00005554 0.]

(请注意,现在头等舱最有可能)

您可以使用bootstrap aggregating和其他汇总技术来改善预测。这种方法使分类决策表面更加平滑,并修复了分类器之间的相互误差(假设它们的预测相差很大)。可能需要花很多篇幅来详细描述(或者需要单独的问题和特定的问题),herehere可能会让您入门。

仍然我不会将这种方法与手动选择输出混合使用。

2.2将问题转换为二进制

如果您可以将其分布在多个GPU上,则此方法可能会产生更好的推理时间,甚至可能会得到更好的训练时间。

基本上,您的每个班级都可以出席(1)或不出席(0)。原则上,您可以为N类训练N神经网络,每个神经网络输出一个无界数(logit)。这个数字告诉网络是否认为此示例应归类为该类。

如果您确定某些课程不会成为结果,那么您不会运行负责该课程检测的网络。 从所有网络(或网络子集)获得预测后,您选择最高值(或者,如果使用sigmoid激活,则选择最高概率,尽管这会在计算上造成浪费)。

另外的好处是该网络的简单性(易于培训和微调)和容易的switch-like行为(如果需要)。

结论

如果我是我,我会采用 2.2 中概述的方法,因为您可以轻松地节省一些推理时间,并允许您以明智的方式“选择输出”。

如果这种方法还不够,您可以考虑使用N个网络集成,因此可以使用 2.2 2.1 的混合,一些引导程序或其他集成技术。这样也可以提高您的准确性。

答案 1 :(得分:0)

首先问自己:基于外部数据排除某些输出的好处是什么?在您的帖子中,我没有看到为什么确切地想要排除它们。

保存它们不会节省计算,因为连接(或神经元)对多个输出有影响:你无法禁用连接/神经元。

是否真的有必要排除某些类?如果您的网络训练得足够好,它就会知道它是不是资本。

所以我的答案是:我认为你不应该在之前使用操作。这会给你错误的结论。所以你有以下选择:

  • 将softmax的结果乘以限制。
  • 如果最高等级是'a',则不要相乘,将其转换为'A'作为输出(将输出转换为小写)
  • 培训一个看不出资本和非大写字母差异的网络