text_focus_loss.py 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  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. """
  15. This code is refer from:
  16. https://github.com/FudanVI/FudanOCR/blob/main/scene-text-telescope/loss/text_focus_loss.py
  17. """
  18. import paddle.nn as nn
  19. import paddle
  20. import numpy as np
  21. import pickle as pkl
  22. standard_alphebet = "-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
  23. standard_dict = {}
  24. for index in range(len(standard_alphebet)):
  25. standard_dict[standard_alphebet[index]] = index
  26. def load_confuse_matrix(confuse_dict_path):
  27. f = open(confuse_dict_path, "rb")
  28. data = pkl.load(f)
  29. f.close()
  30. number = data[:10]
  31. upper = data[10:36]
  32. lower = data[36:]
  33. end = np.ones((1, 62))
  34. pad = np.ones((63, 1))
  35. rearrange_data = np.concatenate((end, number, lower, upper), axis=0)
  36. rearrange_data = np.concatenate((pad, rearrange_data), axis=1)
  37. rearrange_data = 1 / rearrange_data
  38. rearrange_data[rearrange_data == np.inf] = 1
  39. rearrange_data = paddle.to_tensor(rearrange_data)
  40. lower_alpha = "abcdefghijklmnopqrstuvwxyz"
  41. # upper_alpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
  42. for i in range(63):
  43. for j in range(63):
  44. if i != j and standard_alphebet[j] in lower_alpha:
  45. rearrange_data[i][j] = max(
  46. rearrange_data[i][j], rearrange_data[i][j + 26]
  47. )
  48. rearrange_data = rearrange_data[:37, :37]
  49. return rearrange_data
  50. def weight_cross_entropy(pred, gt, weight_table):
  51. batch = gt.shape[0]
  52. weight = weight_table[gt]
  53. pred_exp = paddle.exp(pred)
  54. pred_exp_weight = weight * pred_exp
  55. loss = 0
  56. for i in range(len(gt)):
  57. loss -= paddle.log(
  58. pred_exp_weight[i][gt[i]] / paddle.sum(pred_exp_weight, 1)[i]
  59. )
  60. return loss / batch
  61. class TelescopeLoss(nn.Layer):
  62. def __init__(self, confuse_dict_path):
  63. super(TelescopeLoss, self).__init__()
  64. self.weight_table = load_confuse_matrix(confuse_dict_path)
  65. self.mse_loss = nn.MSELoss()
  66. self.ce_loss = nn.CrossEntropyLoss()
  67. self.l1_loss = nn.L1Loss()
  68. def forward(self, pred, data):
  69. sr_img = pred["sr_img"]
  70. hr_img = pred["hr_img"]
  71. sr_pred = pred["sr_pred"]
  72. text_gt = pred["text_gt"]
  73. word_attention_map_gt = pred["word_attention_map_gt"]
  74. word_attention_map_pred = pred["word_attention_map_pred"]
  75. mse_loss = self.mse_loss(sr_img, hr_img)
  76. attention_loss = self.l1_loss(word_attention_map_gt, word_attention_map_pred)
  77. recognition_loss = weight_cross_entropy(sr_pred, text_gt, self.weight_table)
  78. loss = mse_loss + attention_loss * 10 + recognition_loss * 0.0005
  79. return {"mse_loss": mse_loss, "attention_loss": attention_loss, "loss": loss}