1

对于相同的输入和标签:

  • 的输出pytorch.nn.CTCLoss为 5.74,
  • 的输出tf.nn.ctc_loss为 129.69,
  • 但输出math.log(tf ctc loss)是 4.86

pytorch.nn.CTCLoss那么with 和有什么区别tf.nn.ctc_loss

tf: 1.13.1
pytorch: 1.1.0

我曾尝试过这些:

  1. log_softmax输入,然后将其发送到pytorch.nn.CTCLoss,

  2. tf.nn.log_softmax输入,然后将其发送到tf.nn.ctc_loss

  3. 直接将输入发送到tf.nn.ctc_loss

  4. 直接将输入发送到tf.nn.ctc_loss, 然后math.log(output of tf.nn.ctc_loss)

在案例 2、案例 3 和案例 4 中,计算结果与pytorch.nn.CTCLoss

from torch import nn
import torch
import tensorflow as tf
import math

time_step = 50  # Input sequence length
vocab_size = 20  # Number of classes
batch_size = 16  # Batch size
target_sequence_length = 30  # Target sequence length


def dense_to_sparse(dense_tensor, sequence_length):
    indices = tf.where(tf.sequence_mask(sequence_length))
    values = tf.gather_nd(dense_tensor, indices)
    shape = tf.shape(dense_tensor, out_type=tf.int64)
    return tf.SparseTensor(indices, values, shape)


def compute_loss(x, y, x_len):
    ctclosses = tf.nn.ctc_loss(
        y,
        tf.cast(x, dtype=tf.float32),
        x_len,
        preprocess_collapse_repeated=False,
        ctc_merge_repeated=False,
        ignore_longer_outputs_than_inputs=False
    )
    ctclosses = tf.reduce_mean(ctclosses)

    with tf.Session() as sess:
        ctclosses = sess.run(ctclosses)
        print(f"tf ctc loss: {ctclosses}")
        print(f"tf log(ctc loss): {math.log(ctclosses)}")


minimum_target_length = 10

ctc_loss = nn.CTCLoss(blank=vocab_size - 1)
x = torch.randn(time_step, batch_size, vocab_size)  # [size] = T,N,C
y = torch.randint(0, vocab_size - 2, (batch_size, target_sequence_length), dtype=torch.long)  # low, high, [size]

x_lengths = torch.full((batch_size,), time_step, dtype=torch.long)  # Length of inputs
y_lengths = torch.randint(minimum_target_length, target_sequence_length, (batch_size,),
                          dtype=torch.long)  # Length of targets can be variable (even if target sequences are constant length)

loss = ctc_loss(x.log_softmax(2).detach(), y, x_lengths, y_lengths)
print(f"torch ctc loss: {loss}")

x = x.numpy()
y = y.numpy()
x_lengths = x_lengths.numpy()
y_lengths = y_lengths.numpy()
x = tf.cast(x, dtype=tf.float32)
y = tf.cast(dense_to_sparse(y, y_lengths), dtype=tf.int32)
compute_loss(x, y, x_lengths)

我希望 的输出tf.nn.ctc_loss与 的输出相同pytorch.nn.CTCLoss,但实际上它们不是,但我怎样才能使它们相同?

4

1 回答 1

2

pytorch 的 CTCLoss 的自动平均减少与计算所有单独的损失,然后做平均值不同(就像你在 Tensorflow 实现中所做的那样)。确实来自 CTCLoss (pytorch) 的文档:

``'mean'``: the output losses will be divided by the target lengths and
            then the mean over the batch is taken.

要获得相同的值:

1-将减少方法更改为总和:

ctc_loss = nn.CTCLoss(reduction='sum')

2-除以batch_size计算的损失:

loss = ctc_loss(x.log_softmax(2).detach(), y, x_lengths, y_lengths)
loss = (loss.item())/batch_size

3-将Tensorflow的参数ctc_merge_repeated更改为True(我假设在pytorch CTC中也是如此)

    ctclosses = tf.nn.ctc_loss(
    y,
    tf.cast(x, dtype=tf.float32),
    x_len,
    preprocess_collapse_repeated=False,
    ctc_merge_repeated=True,
    ignore_longer_outputs_than_inputs=False
)

现在,您将在 pytorch 损失和 tensorflow 损失之间获得非常接近的结果(不记录值的对数)。剩余的微小差异可能来自实现之间的细微差异。在我的最后三轮运行中,我得到了以下值:

pytorch loss : 113.33 vs tf loss = 113.52
pytorch loss : 116.30 vs tf loss = 115.57
pytorch loss : 115.67 vs tf loss = 114.54
于 2020-03-04T17:46:02.420 回答