import math import unittest import torch import torch as tc import torch.nn.functional as F import fastNLP.core.losses as loss from fastNLP.core.losses import LossFunc class TestLoss(unittest.TestCase): def test_case_1(self): loss_func = loss.LossFunc(F.nll_loss) nll_loss = loss.NLLLoss() y = tc.Tensor( [ [.3, .4, .3], [.5, .3, .2], [.3, .6, .1], ] ) gy = tc.LongTensor( [ 0, 1, 2, ] ) y = tc.log(y) los = loss_func({'input': y}, {'target': gy}) losses = nll_loss({'input': y}, {'target': gy}) r = -math.log(.3) - math.log(.3) - math.log(.1) r /= 3 print("loss = %f" % (los)) print("r = %f" % (r)) print("nll_loss = %f" % (losses)) self.assertEqual(int(los * 1000), int(r * 1000)) def test_case_2(self): # 验证squash()的正确性 log = math.log loss_func = loss.Loss("nll") y = tc.Tensor( [ [[.3, .4, .3], [.3, .4, .3], ], [[.5, .3, .2], [.1, .2, .7], ], [[.3, .6, .1], [.2, .1, .7], ], ] ) gy = tc.LongTensor( [ [0, 2], [1, 2], [2, 1], ] ) y = tc.log(y) # los = loss_func({'input': y}, {'target': gy}) los = loss_func(y, gy) r = -log(.3) - log(.3) - log(.1) - log(.3) - log(.7) - log(.1) r /= 6 self.assertEqual(int(los * 1000), int(r * 1000)) def test_case_3(self): # 验证pack_padded_sequence()的正确性 log = math.log loss_func = loss.NLLLoss() y = tc.Tensor( [ [[.3, .4, .3], [.3, .2, .5], [.4, .5, .1, ], ], [[.5, .3, .2], [.1, .2, .7], [.0, .0, .0, ], ], [[.3, .6, .1], [.0, .0, .0], [.0, .0, .0, ], ], ] ) gy = tc.LongTensor( [ [0, 2, 1, ], [1, 2, 0, ], [2, 0, 0, ], ] ) lens = [3, 2, 1] # pdb.set_trace() y = tc.log(y) yy = tc.nn.utils.rnn.pack_padded_sequence(y, lens, batch_first=True).data gyy = tc.nn.utils.rnn.pack_padded_sequence(gy, lens, batch_first=True).data los = loss_func({'input': yy}, {'target': gyy}) r = -log(.3) - log(.5) - log(.5) - log(.3) - log(.7) - log(.1) r /= 6 self.assertEqual(int(los * 1000), int(r * 1000)) def test_case_4(self): # 验证unpad()的正确性 log = math.log y = tc.Tensor( [ [[.3, .4, .3], [.3, .2, .5], [.4, .5, .1, ], [.6, .3, .1, ], ], [[.5, .3, .2], [.1, .2, .7], [.0, .0, .0, ], [.0, .0, .0, ], ], [[.3, .6, .1], [.0, .0, .0], [.0, .0, .0, ], [.0, .0, .0, ], ], ] ) gy = tc.LongTensor( [ [0, 2, 1, 2, ], [1, 2, 0, 0, ], [2, 0, 0, 0, ], ] ) lens = [4, 2, 1] y = tc.log(y) loss_func = loss.Loss("nll", pre_pro=["unpad"]) los = loss_func(y, gy, lens=lens) r = -log(.1) - log(.3) - log(.5) - log(.5) - log(.3) - log(.7) - log(.1) r /= 7 self.assertEqual(int(los * 1000), int(r * 1000)) def test_case_5(self): # 验证mask()和make_mask()的正确性 log = math.log y = tc.Tensor( [ [[.5, .3, .2], [.1, .2, .7], [.0, .0, .0, ], [.0, .0, .0, ], ], [[.5, .4, .1], [.3, .2, .5], [.4, .5, .1, ], [.6, .1, .3, ], ], [[.3, .6, .1], [.3, .2, .5], [.0, .0, .0, ], [.0, .0, .0, ], ], ] ) gy = tc.LongTensor( [ [1, 2, 0, 0, ], [0, 2, 1, 2, ], [2, 1, 0, 0, ], ] ) mask = tc.ByteTensor( [ [1, 1, 0, 0, ], [1, 1, 1, 1, ], [1, 1, 0, 0, ], ] ) y = tc.log(y) lens = [2, 4, 2] loss_func = loss.Loss("nll", pre_pro=["mask"]) los = loss_func(y, gy, mask=mask) los2 = loss_func(y, gy, mask=loss.make_mask(lens, gy.size()[-1])) r = -log(.3) - log(.7) - log(.5) - log(.5) - log(.5) - log(.3) - log(.1) - log(.2) r /= 8 self.assertEqual(int(los * 1000), int(r * 1000)) self.assertEqual(int(los2 * 1000), int(r * 1000)) def test_case_6(self): # 验证unpad_mask()的正确性 log = math.log y = tc.Tensor( [ [[.3, .4, .3], [.3, .2, .5], [.4, .5, .1, ], [.6, .3, .1, ], ], [[.5, .3, .2], [.1, .2, .7], [.0, .0, .0, ], [.0, .0, .0, ], ], [[.3, .6, .1], [.0, .0, .0], [.0, .0, .0, ], [.0, .0, .0, ], ], ] ) gy = tc.LongTensor( [ [0, 2, 1, 2, ], [1, 2, 0, 0, ], [2, 0, 0, 0, ], ] ) lens = [4, 2, 1] # pdb.set_trace() y = tc.log(y) loss_func = loss.Loss("nll", pre_pro=["unpad_mask"]) los = loss_func(y, gy, lens=lens) r = -log(.1) - log(.3) - log(.5) - log(.5) - log(.3) - log(.7) - log(.1) r /= 7 self.assertEqual(int(los * 1000), int(r * 1000)) def test_case_7(self): # 验证一些其他东西 log = math.log y = tc.Tensor( [ [[.3, .4, .3], [.3, .2, .5], [.4, .5, .1, ], [.6, .3, .1, ], ], [[.5, .3, .2], [.1, .2, .7], [.0, .0, .0, ], [.0, .0, .0, ], ], [[.3, .6, .1], [.0, .0, .0], [.0, .0, .0, ], [.0, .0, .0, ], ], ] ) gy = tc.LongTensor( [ [0, 2, 1, 2, ], [1, 2, 0, 0, ], [2, 0, 0, 0, ], ] ) lens = [4, 2, 1] y = tc.log(y) loss_func = loss.Loss("nll", pre_pro=[], weight=tc.Tensor([1, 1, 0])) loss_func.add_pre_pro("unpad_mask") los = loss_func(y, gy, lens=lens) r = - log(.3) - log(.5) - log(.3) r /= 3 self.assertEqual(int(los * 1000), int(r * 1000)) def test_case_8(self): def func(a, b): return F.cross_entropy(a, b) def func2(a, truth): return func(a, truth) def func3(predict, truth): return func(predict, truth) def func4(a, b, c=2): return (a + b) * c def func6(a, b, **kwargs): c = kwargs['c'] return (a + b) * c get_loss = LossFunc(func, {'a': 'predict', 'b': 'truth'}) predict = torch.randn(5, 3) truth = torch.LongTensor([1, 0, 1, 2, 1]) loss1 = get_loss({'predict': predict}, {'truth': truth}) get_loss_2 = LossFunc(func2, {'a': 'predict'}) loss2 = get_loss_2({'predict': predict}, {'truth': truth}) get_loss_3 = LossFunc(func3) loss3 = get_loss_3({'predict': predict}, {'truth': truth}) assert loss1 == loss2 and loss1 == loss3 """ get_loss_4 = LossFunc(func4) loss4 = get_loss_4({'a': 1, 'b': 3}, {}) print(loss4) assert loss4 == (1 + 3) * 2 get_loss_5 = LossFunc(func4) loss5 = get_loss_5({'a': 1, 'b': 3}, {'c': 4}) print(loss5) assert loss5 == (1 + 3) * 4 get_loss_6 = LossFunc(func6) loss6 = get_loss_6({'a': 1, 'b': 3}, {'c': 4}) print(loss6) assert loss6 == (1 + 3) * 4 get_loss_7 = LossFunc(func6, c='cc') loss7 = get_loss_7({'a': 1, 'b': 3}, {'cc': 4}) print(loss7) assert loss7 == (1 + 3) * 4 """ class TestLoss_v2(unittest.TestCase): def test_CrossEntropyLoss(self): ce = loss.CrossEntropyLoss(input="my_predict", target="my_truth") a = torch.randn(3, 5, requires_grad=False) b = torch.empty(3, dtype=torch.long).random_(5) ans = ce({"my_predict": a}, {"my_truth": b}) self.assertEqual(ans, torch.nn.functional.cross_entropy(a, b)) def test_BCELoss(self): bce = loss.BCELoss(input="my_predict", target="my_truth") a = torch.sigmoid(torch.randn((3, 5), requires_grad=False)) b = torch.randn((3, 5), requires_grad=False) ans = bce({"my_predict": a}, {"my_truth": b}) self.assertEqual(ans, torch.nn.functional.binary_cross_entropy(a, b))