kie_sdmgr_loss.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. # copyright (c) 2022 PaddlePaddle Authors. All Rights Reserve.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. # reference from : https://github.com/open-mmlab/mmocr/blob/main/mmocr/models/kie/losses/sdmgr_loss.py
  15. from __future__ import absolute_import
  16. from __future__ import division
  17. from __future__ import print_function
  18. from paddle import nn
  19. import paddle
  20. class SDMGRLoss(nn.Layer):
  21. def __init__(self, node_weight=1.0, edge_weight=1.0, ignore=0):
  22. super().__init__()
  23. self.loss_node = nn.CrossEntropyLoss(ignore_index=ignore)
  24. self.loss_edge = nn.CrossEntropyLoss(ignore_index=-1)
  25. self.node_weight = node_weight
  26. self.edge_weight = edge_weight
  27. self.ignore = ignore
  28. def pre_process(self, gts, tag):
  29. gts, tag = gts.numpy(), tag.numpy().tolist()
  30. temp_gts = []
  31. batch = len(tag)
  32. for i in range(batch):
  33. num, recoder_len = tag[i][0], tag[i][1]
  34. temp_gts.append(
  35. paddle.to_tensor(
  36. gts[i, :num, :num + 1], dtype='int64'))
  37. return temp_gts
  38. def accuracy(self, pred, target, topk=1, thresh=None):
  39. """Calculate accuracy according to the prediction and target.
  40. Args:
  41. pred (torch.Tensor): The model prediction, shape (N, num_class)
  42. target (torch.Tensor): The target of each prediction, shape (N, )
  43. topk (int | tuple[int], optional): If the predictions in ``topk``
  44. matches the target, the predictions will be regarded as
  45. correct ones. Defaults to 1.
  46. thresh (float, optional): If not None, predictions with scores under
  47. this threshold are considered incorrect. Default to None.
  48. Returns:
  49. float | tuple[float]: If the input ``topk`` is a single integer,
  50. the function will return a single float as accuracy. If
  51. ``topk`` is a tuple containing multiple integers, the
  52. function will return a tuple containing accuracies of
  53. each ``topk`` number.
  54. """
  55. assert isinstance(topk, (int, tuple))
  56. if isinstance(topk, int):
  57. topk = (topk, )
  58. return_single = True
  59. else:
  60. return_single = False
  61. maxk = max(topk)
  62. if pred.shape[0] == 0:
  63. accu = [pred.new_tensor(0.) for i in range(len(topk))]
  64. return accu[0] if return_single else accu
  65. pred_value, pred_label = paddle.topk(pred, maxk, axis=1)
  66. pred_label = pred_label.transpose(
  67. [1, 0]) # transpose to shape (maxk, N)
  68. correct = paddle.equal(pred_label,
  69. (target.reshape([1, -1]).expand_as(pred_label)))
  70. res = []
  71. for k in topk:
  72. correct_k = paddle.sum(correct[:k].reshape([-1]).astype('float32'),
  73. axis=0,
  74. keepdim=True)
  75. res.append(
  76. paddle.multiply(correct_k,
  77. paddle.to_tensor(100.0 / pred.shape[0])))
  78. return res[0] if return_single else res
  79. def forward(self, pred, batch):
  80. node_preds, edge_preds = pred
  81. gts, tag = batch[4], batch[5]
  82. gts = self.pre_process(gts, tag)
  83. node_gts, edge_gts = [], []
  84. for gt in gts:
  85. node_gts.append(gt[:, 0])
  86. edge_gts.append(gt[:, 1:].reshape([-1]))
  87. node_gts = paddle.concat(node_gts)
  88. edge_gts = paddle.concat(edge_gts)
  89. node_valids = paddle.nonzero(node_gts != self.ignore).reshape([-1])
  90. edge_valids = paddle.nonzero(edge_gts != -1).reshape([-1])
  91. loss_node = self.loss_node(node_preds, node_gts)
  92. loss_edge = self.loss_edge(edge_preds, edge_gts)
  93. loss = self.node_weight * loss_node + self.edge_weight * loss_edge
  94. return dict(
  95. loss=loss,
  96. loss_node=loss_node,
  97. loss_edge=loss_edge,
  98. acc_node=self.accuracy(
  99. paddle.gather(node_preds, node_valids),
  100. paddle.gather(node_gts, node_valids)),
  101. acc_edge=self.accuracy(
  102. paddle.gather(edge_preds, edge_valids),
  103. paddle.gather(edge_gts, edge_valids)))