如何在Tensorflow中拥有多个Softmax输出?

7
我正在尝试在Tensorflow中创建一个具有多个softmax输出的网络,每个softmax具有不同的大小。 网络架构是:输入 -> LSTM -> Dropout。然后我有2个softmax层:10个输出的softmax和20个输出的softmax。这样做的原因是因为我想生成两组输出(10个和20个),然后将它们组合以产生最终输出。我不确定如何在Tensorflow中实现这一点。
以前,要创建一个与描述相似但只有一个softmax的网络,我认为我可以这样做。
inputs = tf.placeholder(tf.float32, [batch_size, maxlength, vocabsize])
lengths = tf.placeholders(tf.int32, [batch_size])
embeddings = tf.Variable(tf.random_uniform([vocabsize, 256], -1, 1))
lstm = {}
lstm[0] = tf.contrib.rnn.LSTMCell(hidden_layer_size, state_is_tuple=True, initializer=tf.contrib.layers.xavier_initializer(seed=random_seed))
lstm[0] = tf.contrib.rnn.DropoutWrapper(lstm[0], output_keep_prob=0.5)
lstm[0] = tf.contrib.rnn.MultiRNNCell(cells=[lstm[0]] * 1, state_is_tuple=True)
output_layer = {}
output_layer[0] = Layer.W(1 * hidden_layer_size, 20, 'OutputLayer')
output_bias = {}
output_bias[0] = Layer.b(20, 'OutputBias')
outputs = {}
fstate = {}
with tf.variable_scope("lstm0"):
    # create the rnn graph at run time
  outputs[0], fstate[0] = tf.nn.dynamic_rnn(lstm[0], tf.nn.embedding_lookup(embeddings, inputs),
                                      sequence_length=lengths, 
                                      dtype=tf.float32)
logits = {}
logits[0] = tf.matmul(tf.concat([f.h for f in fstate[0]], 1), output_layer[0]) + output_bias[0]
loss = {}
loss[0] = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=logits[0], labels=labels[0]))

然而,现在,我希望我的RNN输出(经过dropout后)流入大小为10和20的两个softmax层。有人知道如何做到这一点吗?
谢谢。
编辑:理想情况下,我想使用类似于Knet Julia库中定义的softmax版本。Tensorflow有相应的功能吗? https://github.com/denizyuret/Knet.jl/blob/1ef934cc58f9671f2d85063f88a3d6959a49d088/deprecated/src7/op/actf.jl#L103

我现在有一个关于大小问题的问题,请查看我作为评论添加到正确选择答案的问题。 - hockeybro
2个回答

5

你的代码中没有为尺寸为10的softmax层定义logits,你需要明确地进行定义。

完成之后,你可以使用tf.nn.softmax,将其分别应用于两个logit张量。

例如,对于包含20个类别的softmax张量:

softmax20 = tf.nn.softmax(logits[0])

对于另一层,您可以执行以下操作:

output_layer[1] = Layer.W(1 * hidden_layer_size, 10, 'OutputLayer10')
output_bias[1] = Layer.b(10, 'OutputBias10')

logits[1] = tf.matmul(tf.concat([f.h for f in fstate[0]], 1), 
output_layer[1]) + output_bias[1]

softmax10 = tf.nn.softmax(logits[1])

此外,还有一个tf.contrib.layers.softmax函数可用于在高于二维的张量的最后一维上应用softmax,但看起来您不需要这样的内容。在这里,tf.nn.softmax函数可以使用。

另外需要说明:output_layer并不是那个列表的最佳名称,应该包含权重值的名称才更为合适。这些权重和偏差项(output_layeroutput_bias)也不能代表您的网络的输出层(因为它将来自于对softmax输出所做的任何处理,对吧?)[抱歉,我控制不了自己。]


谢谢您的回答。现在我对如何处理这些softmax结果的损失感到困惑,因为我不是试图将它们作为结果输出,而是要对它们进行一些操作以计算实际结果。请参见我在其他答案中的评论,您有什么想法吗? - hockeybro
@MehtaiPhoneApps:您能提供更多关于您想使用的损失的细节吗?一般来说,您需要使用TensorFlow ops表示您的损失函数,并使用优化器来最小化/最大化它。 - Neeraj Kashyap
好的,在你的回答中有两个softmax层,我可以通过矩阵乘法和权重向量分别对它们进行操作(使用(W*x)运算),然后得到两个输出,比如prediction_1prediction_2。我可以将这些矩阵相加以获得最终输出prediction。然后,我会在此基础上使用一个损失函数,例如:loss = tf.reduce_mean(tf.squared_difference(prediction, label))。我很好奇,这样做是否能够正确地反向传播梯度,即使是通过softmax层,因为我没有直接在softmax上使用损失函数。 - hockeybro
这对于反向传播来说不是问题,但这样你就失去了softmax的兴趣,因为你的最终输出“prediction”不再受限制。 - Pop
为什么你会说我对softmax失去了兴趣?softmax仍然可以预测10和20个事物,对吗?只是想弄清楚而已。 - hockeybro

4
以下是关于您调用的名为 output[0]dynamic_rnn 输出,可以进行以下操作以计算两个 softmax 和相应的损失:
with tf.variable_scope("softmax_0"):
    # Transform you RNN output to the right output size = 10
    W = tf.get_variable("kernel_0", [output[0].get_shape()[1], 10])
    logits_0 = tf.matmul(inputs, W)
    # Apply the softmax function to the logits (of size 10)
    output_0 = tf.nn.softmax(logits_0, name = "softmax_0")
    # Compute the loss (as you did in your question) with softmax_cross_entropy_with_logits directly applied on logits
    loss_0 = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=logits_0, labels=labels[0]))

with tf.variable_scope("softmax_1"):  
    # Transform you RNN output to the right output size = 20
    W = tf.get_variable("kernel_1", [output[0].get_shape()[1], 20])
    logits_1 = tf.matmul(inputs, W)
    # Apply the softmax function to the logits (of size 20)
    output_1 = tf.nn.softmax(logits_1, name = "softmax_1")
    # Compute the loss (as you did in your question) with softmax_cross_entropy_with_logits directly applied on logits
    loss_1 = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=logits_1, labels=labels[1]))

如果与您的应用程序相关,您可以将这两个损失组合在一起:

total_loss = loss_0 + loss_1

编辑 为了回答你在评论中提出的问题,关于你需要如何处理这两个softmax输出:你可以做以下近似操作:

with tf.variable_scope("second_part"):
    W1 = tf.get_variable("W_1", [output_1.get_shape()[1], n])
    W2 = tf.get_variable("W_2", [output_2.get_shape()[1], n])
    prediction = tf.matmul(output_1, W1) + tf.matmul(output_2, W2)
with tf.variable_scope("optimization_part"):
    loss = tf.reduce_mean(tf.squared_difference(prediction, label))

您只需要定义n,即W1和W2的列数即可。


谢谢你的回答。如果我想要扩展这个功能,通过将每个softmax的输出与另一个矩阵相乘,然后将结果矩阵相加以得到我的最终输出(也是一个矩阵),我会怎么做呢?我对如何处理与最终输出相关的损失感到困惑。我应该只在output_0output_1上进行操作,然后将结果相加吗?我如何确保最小化这个损失?在你的回答中,你使用了两组标签(labels[0]labels[1])计算每个softmax的损失,但我只有一个输出标签,即最终结果。 - hockeybro
谢谢你的帮助。我现在有一个相关但不同的问题。Tensorflow的RNN cell文档中提到,输入张量应该是一个形状为[batch_size x input_size]的张量。然而,我的输入张量的大小是[batch_size x maxlength x features],因为我正在尝试逐个传入单词来理解一句话。Maxlength代表最长句子的长度。在这种情况下,这将如何工作呢?目前它给我抛出一个错误,说我必须要有2个维度?Embeddings是一个大小为features x 256的标准矩阵,在LSTM之前使用。我的代码就是我在原始帖子中提到的那些内容。 - hockeybro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接