Python 神经网络:神秘的ReLu

Python 神经网络:神秘的ReLu,python,tensorflow,machine-learning,neural-network,deep-learning,Python,Tensorflow,Machine Learning,Neural Network,Deep Learning,作为一个更大项目的一部分,我一直在构建一个编程语言检测器,即代码片段的分类器。 我的基线模型非常简单:将输入标记化,并将片段编码为一袋单词或, 在这种情况下,您可以打包令牌,并在这些功能的基础上创建一个简单的NN NN的输入是一个固定长度的计数器数组,其中包含最独特的令牌,例如“def”, “self”,“function”,“->”,“const”,“#include”,等等,这些都是从语料库中自动提取的。 其想法是,这些标记对于编程语言来说是非常独特的,因此即使是这种幼稚的方法也应该得到支

作为一个更大项目的一部分,我一直在构建一个编程语言检测器,即代码片段的分类器。 我的基线模型非常简单:将输入标记化,并将片段编码为一袋单词或, 在这种情况下,您可以打包令牌,并在这些功能的基础上创建一个简单的NN

NN的输入是一个固定长度的计数器数组,其中包含最独特的令牌,例如
“def”
“self”
“function”
“->”
“const”
“#include”
,等等,这些都是从语料库中自动提取的。 其想法是,这些标记对于编程语言来说是非常独特的,因此即使是这种幼稚的方法也应该得到支持 准确率高

Input:
  def   1
  for   2
  in    2
  True  1
  ):    3
  ,:    1

  ...

Output: python
安装程序 我很快就得到了99%的准确率,并认为这是它正常工作的标志。这是模型 (完整的可运行脚本如下所示):

#占位符
x=tf.placeholder(shape=[None,vocab_size],dtype=tf.float32,name='x')
y=tf.placeholder(shape=[None],dtype=tf.int32,name='y')
training=tf.placeholder_,默认值为(False,shape=[],name='training')
#一个隐藏层与辍学
reg=tf.contrib.layers.l2_正则化器(0.01)
hidden1=tf.layers.dense(x,units=96,kernel_regulazer=reg,
激活=tf.nn.elu,name='hidden1')
dropout1=tf.layers.dropout(hidden1,rate=0.2,training=training,name='dropout1')
#输出层
logits=tf.layers.dense(dropout1,units=classes,kernel\u regulazer=reg,
激活=tf.nn.relu,name='logits')
#交叉熵损失
损失=tf.reduce_平均值(
tf.nn.sparse\u softmax\u cross\u entropy\u with\u logits(logits=logits,abels=y))
#杂项报告:准确性、正确/错误分类样本等。
correct_predicted=tf.nn.in_top_k(logits,y,1,name='in-top-k')
预测=tf.argmax(logits,轴=1)
错误的\u预测=tf.逻辑的\u不(正确的\u预测,name='not-in-top-k')
x_misclassified=tf.boolean_掩码(x,预测错误,name='misclassified')
准确度=tf.reduce\u平均值(tf.cast(正确预测,tf.float32),name='accurity')
产出相当令人鼓舞:

迭代=5损失=2.580列车acc=0.34277
迭代=10损失=2.029列车acc=0.69434
迭代=15损失=2.054列车acc=0.92383
迭代=20损失=1.934列车acc=0.98926
迭代=25损失=1.942列车acc=0.99609
Files.VAL平均精度=0.99121预测分布
在玩了一段时间后,我决定可视化两个模型的实际预测分布:

predicted_distribution = tf.nn.softmax(logits, name='distribution')
下面是分布的直方图,以及它们是如何随时间演变的

带ReLu(错误型号)

不带ReLu(正确型号)

第一个直方图是有意义的,大多数概率接近
0
。 但ReLu模型的直方图是可疑的:经过几次迭代后,值似乎集中在
0.15
附近。打印实际预测证实了这一想法:

[0.14286 0.14286 0.14286 0.14286 0.14286 0.14286 0.14286]
[0.14286 0.14286 0.14286 0.14286 0.14286 0.14286 0.14286]
我有7门课(当时有7种不同的语言),而且
0.14286
1/7
。事实证明,“完美”模型学会了输出
0
logits,这反过来转化为统一预测

但是,如何才能将此分布报告为99%的准确率

tf.nn.in\u top\u k
在深入研究之前,我检查了另一种计算精度的方法:

true_correct = tf.equal(tf.argmax(logits, 1), tf.cast(y, tf.int64))
alternative_accuracy = tf.reduce_mean(tf.cast(true_correct, tf.float32))
。。。对最高预测等级和基本事实进行诚实的比较。结果是:

iteration=2  loss=3.992  train-acc=0.13086  train-alt-acc=0.13086
iteration=4  loss=3.590  train-acc=0.13086  train-alt-acc=0.12207
iteration=6  loss=2.871  train-acc=0.21777  train-alt-acc=0.13672
iteration=8  loss=2.466  train-acc=0.37695  train-alt-acc=0.16211
iteration=10  loss=2.099  train-acc=0.62305  train-alt-acc=0.10742
iteration=12  loss=2.066  train-acc=0.79980  train-alt-acc=0.17090
iteration=14  loss=2.016  train-acc=0.84277  train-alt-acc=0.17285
iteration=16  loss=1.954  train-acc=0.91309  train-alt-acc=0.13574
iteration=18  loss=1.956  train-acc=0.95508  train-alt-acc=0.06445
iteration=20  loss=1.923  train-acc=0.97754  train-alt-acc=0.11328
事实上,
tf.nn.in_top_k
with
k=1
很快偏离了正确的准确度,并开始报告幻想的99%值。 那么它实际上是做什么的呢?这是什么 他说:

说明目标是否在前K预测中

这将输出一个
batch\u size
bool数组,如果目标类的预测值在前k中,则条目
out[i]
为真 所有预测中的预测,例如i。 注意,
InTopK
的行为与
TopK
op在处理领带时的行为不同; 如果多个类具有相同的预测值并跨越top-k边界, 所有这些类别都被视为前k名

就是这样。如果概率是一致的(这实际上意味着“我不知道”),那么它们都是正确的。情况更糟,因为如果logits分布几乎是均匀的,softmax可能会将其转换为完全均匀的分布,如本简单示例所示:

x = tf.constant([0, 1e-8, 1e-8, 1e-9])
tf.nn.softmax(x).eval()
# >>> array([0.25, 0.25, 0.25, 0.25], dtype=float32)
。。。这意味着,根据规范中的
tf.nn.,每个几乎一致的预测都可以被认为是“正确的”

结论 在tensorflow中,tf.nn.in_top_k
是一个危险的精度度量选择,因为它可能会默默地吞噬错误的预测 并报告为“正确”。相反,您应该始终使用以下长而可信的表达式:

accuracy = tf.reduce_mean(tf.cast(tf.equal(tf.argmax(logits, 1), tf.cast(y, tf.int64)), tf.float32))