python - tensorflow softmax如何添加未知类?
问题描述
我使用 Tensorflow 建立了一个 ocr 分类系统。
这是图表:
def build_graph(top_k):
# with tf.device('/cpu:0'):
keep_prob = tf.placeholder(dtype=tf.float32, shape=[], name='keep_prob')
images = tf.placeholder(dtype=tf.float32, shape=[None, 64, 64, 1], name='image_batch')
labels = tf.placeholder(dtype=tf.int64, shape=[None], name='label_batch')
conv_1 = slim.conv2d(images, 64, [3, 3], 1, padding='SAME', scope='conv1')
max_pool_1 = slim.max_pool2d(conv_1, [2, 2], [2, 2], padding='SAME')
conv_2 = slim.conv2d(max_pool_1, 128, [3, 3], padding='SAME', scope='conv2')
max_pool_2 = slim.max_pool2d(conv_2, [2, 2], [2, 2], padding='SAME')
conv_3 = slim.conv2d(max_pool_2, 256, [3, 3], padding='SAME', scope='conv3')
max_pool_3 = slim.max_pool2d(conv_3, [2, 2], [2, 2], padding='SAME')
flatten = slim.flatten(max_pool_3)
fc1 = slim.fully_connected(slim.dropout(flatten, keep_prob), 1024, activation_fn=tf.nn.tanh, scope='fc1')
logits = slim.fully_connected(slim.dropout(fc1, keep_prob), FLAGS.charset_size, activation_fn=None, scope='fc2')
loss = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits, labels=labels))
accuracy = tf.reduce_mean(tf.cast(tf.equal(tf.argmax(logits, 1), labels), tf.float32))
global_step = tf.get_variable("step", [], initializer=tf.constant_initializer(0.0), trainable=False)
rate = tf.train.exponential_decay(2e-4, global_step, decay_steps=2000, decay_rate=0.97, staircase=True)
train_op = tf.train.AdamOptimizer(learning_rate=rate).minimize(loss, global_step=global_step)
probabilities = tf.nn.softmax(logits)
tf.summary.scalar('loss', loss)
tf.summary.scalar('accuracy', accuracy)
merged_summary_op = tf.summary.merge_all()
predicted_val_top_k, predicted_index_top_k = tf.nn.top_k(probabilities, k=top_k, name="predicted_top_k")
accuracy_in_top_k = tf.reduce_mean(tf.cast(tf.nn.in_top_k(probabilities, labels, top_k), tf.float32))
return {'images': images,
'labels': labels,
'keep_prob': keep_prob,
'top_k': top_k,
'global_step': global_step,
'train_op': train_op,
'loss': loss,
'accuracy': accuracy,
'accuracy_top_k': accuracy_in_top_k,
'merged_summary_op': merged_summary_op,
'predicted_distribution': probabilities,
'predicted_index_top_k': predicted_index_top_k,
'predicted_val_top_k': predicted_val_top_k}
这是推理功能:
def inference(images, pbfile="pb/ocr.pb"):
print('inference')
start = time.time()
predicted_val_top_k = graph.get_tensor_by_name('ocr/predicted_top_k:0')
predicted_index_top_k = graph.get_tensor_by_name('ocr/predicted_top_k:1')
tensor_image = graph.get_tensor_by_name('ocr/image_batch:0')
keep_prob = graph.get_tensor_by_name('ocr/keep_prob:0')
probabilities = graph.get_tensor_by_name('ocr/Softmax:0')
logits = graph.get_tensor_by_name('ocr/fc2/BiasAdd:0')
end = time.time()
print('takes %s second to get tensor' % (start - end))
result = []
for image in images:
temp_image = Image.open(image).convert('L')
temp_image = temp_image.resize((IMAGE_SIZE, IMAGE_SIZE), Image.ANTIALIAS)
temp_image = np.asarray(temp_image) / 255.0
temp_image = temp_image.reshape([-1, 64, 64, 1])
start = time.time()
logit, prob, predict_val, predict_index = sess.run([logits, probabilities, predicted_val_top_k, predicted_index_top_k],
feed_dict={tensor_image: temp_image, keep_prob: 1.0})
end = time.time()
print('takes %s second to run tensor' % (start - end))
result.append({'image': image, 'val': predict_val, 'index': predict_index})
document_dict = {
0: 'V',
1: 'X',
2: 'U'
}
image_name = image.split('/')[-1]
return result
我们现在只有三个类,即'V','X','U',如果我们要检测的目标属于这三种类型,一切都OK。
然而,当我们检测到一个不属于候选类型的目标时,问题就出现了,例如,我们现在放置一个“A”进行推理,问题是,我们还得到了“A”的类“X”,这显然是不正确的。
然后,我想通过设置分数阈值来区分其他的。
我们知道 tf.nn.softmax 返回类似分数的东西,当我调试时,我发现目标“A”的类“X”的分数(推理函数中的预测值)几乎是 1(实际上是 0.9999..)。
那么,深挖softmax后我认为是合理的:
softmax = tf.exp(logits) / tf.reduce_sum(tf.exp(logits), axis)
它只对当前类 logits 执行操作。
那么,有没有办法为涉及所有其他目标的 softmax 添加一个未知类?
环境:Python3.6.5;张量流 1.8.0
谢谢。
卫斯理
解决方案
我会添加一个额外的输出类Unknown
,因为这应该允许您的模型学习对训练集中的项目进行分类,同时还有一个输出可以转储与目标之一不紧密匹配的任何项目。
猜测您的代码,因为您没有提供工作示例,我认为以下更改可以解决问题:
logits = slim.fully_connected(slim.dropout(fc1, keep_prob), FLAGS.charset_size+1, activation_fn=None, scope='fc2')
现在您的输出将有 4 个概率,因此document_dict
可以如下所示:
document_dict = {
0: 'V',
1: 'X',
2: 'U',
3: 'Unknown'
}
你需要看看它是如何训练的,但我希望你现在在面对未知输入时看到你关心的值(V、X、U)的分数要低得多。
推荐阅读
- json - 在postgres中将2列表转换为json对象
- kubernetes - 如何测量我的 pod 启动、最小和最大 CPU 和内存
- java - Java 和 UML:LinkedList 类和迭代器接口之间的关系
- python - 彩条不尊重限制值
- woocommerce - Woocommerce 脚本未加载
- machine-learning - 如何解决 StanfordCoreNLP 中的“树未正确二值化”错误?
- javascript - 处理一些 JSON 以输出一个表示文件夹结构的 JSON 对象
- python - 如何将分类变量添加到数据框?
- javascript - 如何在 javascript 中根据名称显示 png 图像?
- python-3.x - 在 BeautifulSoup 中,使用带有 lxml 解析的过滤器的正确方法是什么?