try this version :

def dice_loss(output, target, weights=None, ignore_index=None):
    smooth = 1.
    loss = 0.

    output = output.exp() # because output = logsoftmax(output)
    encode_target = output.detach()*0
    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 = Variable(mask.unsqueeze(1)).type_as(encoded_target)  # no need to expand, thanks to array broadcasting
        output *= mask
        encoded_target *= mask
    else:
       encoded_target.scatter_(1, target.unsqueeze(1),1)

    if weights is None:
        weights = Variable(torch.ones(1, output.size(1)).type_as(output))
    intersection = output * encoded_target
    numerator = 2 * intersection.sum(3).sum(2) + smooth
    denominator = (output + encoded_target).sum(3).sum(2) + smooth
    loss_per_channel = weights * (1 - (numerator / denominator))

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


Some comments (others might correct me):

AFAIK Variable creation and typing is expensive but can be avoided using the detach() function (you are basically cloning a Variable without its dynamic graph)
FloatTensor[ByteTensor] is also expensive (be it on cpu or gpu). I understand the first one is not avoidable but the rest can be avoided using multiplications with super fast BLAS implementation.

.sum(0) can be avoided and absorbed by the last sum. not sure it actually speeds things up but I personnally prefer to keep things batch-wise the longest possible for the sake of readability

If things are still slow, you can try to profile the time used for each function, be sure to set cuda calls to be blocking :
CUDA_LAUNCH_BLOCKING=1 python -m cProfile -o myscript.cprof myscript.py
More info here and here 1 (I personally like SnakeViz)