def __call__(self, scores, align, target):
// Compute unks in align and target for readability
align_unk = align.eq(0).float()
align_not_unk = align.ne(0).float()
target_unk = target.eq(0).float()
target_not_unk = target.ne(0).float()
// Copy probability of tokens in source
out = scores.gather(1, align.view(-1, 1) + self.offset).view(-1)
// Set scores for unk to 0 and add eps
out = out.mul(align_not_unk) + self.eps
// Get scores for tokens in target
tmp = scores.gather(1, target.view(-1, 1)).view(-1)
// Regular prob (no unks and unks that can"t be copied)
if not self.force_copy:
// Add score for non-unks in target
out = out + tmp.mul(target_not_unk)
// Add score for when word is unk in both align and tgt
out = out + tmp.mul(align_unk).mul(target_unk)
else:
// Forced copy. Add only probability for not-copied tokens
out = out + tmp.mul(align_unk)
// Drop padding.
loss = -out.log().mul(target.ne(self.pad).float())
return loss