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(rearrange_data[i][j], rearrange_data[i][j + 26])
  46. rearrange_data = rearrange_data[:37, :37]
  47. return rearrange_data
  48. def weight_cross_entropy(pred, gt, weight_table):
  49. batch = gt.shape[0]
  50. weight = weight_table[gt]
  51. pred_exp = paddle.exp(pred)
  52. pred_exp_weight = weight * pred_exp
  53. loss = 0
  54. for i in range(len(gt)):
  55. loss -= paddle.log(pred_exp_weight[i][gt[i]] / paddle.sum(pred_exp_weight, 1)[i])
  56. return loss / batch
  57. class TelescopeLoss(nn.Layer):
  58. def __init__(self, confuse_dict_path):
  59. super(TelescopeLoss, self).__init__()
  60. self.weight_table = load_confuse_matrix(confuse_dict_path)
  61. self.mse_loss = nn.MSELoss()
  62. self.ce_loss = nn.CrossEntropyLoss()
  63. self.l1_loss = nn.L1Loss()
  64. def forward(self, pred, data):
  65. sr_img = pred["sr_img"]
  66. hr_img = pred["hr_img"]
  67. sr_pred = pred["sr_pred"]
  68. text_gt = pred["text_gt"]
  69. word_attention_map_gt = pred["word_attention_map_gt"]
  70. word_attention_map_pred = pred["word_attention_map_pred"]
  71. mse_loss = self.mse_loss(sr_img, hr_img)
  72. attention_loss = self.l1_loss(word_attention_map_gt, word_attention_map_pred)
  73. recognition_loss = weight_cross_entropy(sr_pred, text_gt, self.weight_table)
  74. loss = mse_loss + attention_loss * 10 + recognition_loss * 0.0005
  75. return {
  76. "mse_loss": mse_loss,
  77. "attention_loss": attention_loss,
  78. "loss": loss
  79. }