Your logic is right, the dice for a binary problem is defined as
dice = 2* (output * target).sum() / (output.sum() + target.sum())
where output * target is the intersection of the two sets.
You are correct about the output values, I use output.exp() because output = logsoftmax(output) so logsoftmax(output).exp() = softmax(output). I finally got something to work with ignore_label.
def dice_loss(output, target, weights=None, ignore_index=None):
    smooth = 1.
    loss = 0.

    output = output.exp() # because output = logsoftmax(output)
    encoded_target = output.data.clone().zero_()
    if ignore_index is not None:
        mask = target == ignore_index
        target = target.clone()
        target[mask] = 0
        encoded_target.scatter_(1, target.unsqueeze(1), 1)
        mask = mask.unsqueeze(1).expand_as(encoded_target)
        encoded_target[mask] = 0
    else:
        encoded_target.scatter_(1, target.unsqueeze(1), 1)
    encoded_target = Variable(encoded_target)

    if weights is None:
        weights = Variable(torch.ones(output.size(1)).type_as(output.data))

    intersection = output * encoded_target
    numerator = 2 * intersection.sum(3).sum(2).sum(0) + smooth
    denominator = (output + encoded_target).sum(3).sum(2).sum(0) + smooth
    loss_per_channel = weights * (1 - (numerator / denominator))

    return loss_per_channel.sum() / output.size(1)

Though the code is slow.