Repository: open-mmlab/mmocr

Issue:
Improve DRRG
* Divide by 0 in L160
![image](https://user-images.githubusercontent.com/9464825/118633182-c685c400-b803-11eb-9ad2-933c53967ad3.png)
* d might be negative at L22
![image](https://user-images.githubusercontent.com/9464825/118633671-4b70dd80-b804-11eb-8a4f-610f1b005ddd.png)



Discussion:

Resolving patch:
diff --git a/mmocr/models/textdet/modules/local_graph.py b/mmocr/models/textdet/modules/local_graph.py
--- a/mmocr/models/textdet/modules/local_graph.py
+++ b/mmocr/models/textdet/modules/local_graph.py
@@ -183,13 +183,13 @@ def generate_gcn_input(self, node_feat_batch, node_label_batch,
                             adjacent_matrix[node2ind_map[neighbor],
                                             node2ind_map[node]] = 1
 
-                adjacent_matrix = normalize_adjacent_matrix(
-                    adjacent_matrix, mode='DAD')
+                adjacent_matrix = normalize_adjacent_matrix(adjacent_matrix)
                 pad_adjacent_matrix = torch.zeros(
                     (num_max_nodes, num_max_nodes),
                     dtype=torch.float,
                     device=device)
-                pad_adjacent_matrix[:num_nodes, :num_nodes] = adjacent_matrix
+                pad_adjacent_matrix[:num_nodes, :num_nodes] = torch.from_numpy(
+                    adjacent_matrix)
 
                 pad_normalized_feats = torch.cat([
                     normalized_feats,
diff --git a/mmocr/models/textdet/modules/proposal_local_graph.py b/mmocr/models/textdet/modules/proposal_local_graph.py
--- a/mmocr/models/textdet/modules/proposal_local_graph.py
+++ b/mmocr/models/textdet/modules/proposal_local_graph.py
@@ -157,7 +157,7 @@ def propose_comps_and_attribs(self, text_region_map, center_region_map,
         center_region_mask = (center_region_map >
                               self.center_region_thr) * text_mask
 
-        scale = np.sqrt(1.0 / (sin_map**2 + cos_map**2))
+        scale = np.sqrt(1.0 / (sin_map**2 + cos_map**2 + 1e-8))
         sin_map, cos_map = sin_map * scale, cos_map * scale
 
         center_region_mask = fill_hole(center_region_mask)
@@ -309,12 +309,12 @@ def generate_local_graphs(self, sorted_dist_inds, node_feats):
                         adjacent_matrix[node2ind_map[neighbor],
                                         node2ind_map[node]] = 1
 
-            adjacent_matrix = normalize_adjacent_matrix(
-                adjacent_matrix, mode='DAD')
+            adjacent_matrix = normalize_adjacent_matrix(adjacent_matrix)
             pad_adjacent_matrix = torch.zeros((num_max_nodes, num_max_nodes),
                                               dtype=torch.float,
                                               device=device)
-            pad_adjacent_matrix[:num_nodes, :num_nodes] = adjacent_matrix
+            pad_adjacent_matrix[:num_nodes, :num_nodes] = torch.from_numpy(
+                adjacent_matrix)
 
             pad_normalized_feats = torch.cat([
                 normalized_feats,
diff --git a/mmocr/models/textdet/modules/utils.py b/mmocr/models/textdet/modules/utils.py
--- a/mmocr/models/textdet/modules/utils.py
+++ b/mmocr/models/textdet/modules/utils.py
@@ -1,14 +1,12 @@
 import numpy as np
-import torch
 
 
-def normalize_adjacent_matrix(A, mode='AD'):
+def normalize_adjacent_matrix(A):
     """Normalize adjacent matrix for GCN. This code was partially adapted from
     https://github.com/GXYM/DRRG licensed under the MIT license.
 
     Args:
         A (ndarray): The adjacent matrix.
-        mode (string): The normalize mode.
 
     returns:
         G (ndarray): The normalized adjacent matrix.
@@ -16,21 +14,13 @@ def normalize_adjacent_matrix(A, mode='AD'):
     assert A.ndim == 2
     assert A.shape[0] == A.shape[1]
 
-    if mode == 'DAD':
-        A = A + np.eye(A.shape[0])
-        d = np.sum(A, axis=0)
-        d_inv = np.power(d, -0.5).flatten()
-        d_inv[np.isinf(d_inv)] = 0.0
-        d_inv = np.diag(d_inv)
-        G = A.dot(d_inv).transpose().dot(d_inv)
-        G = torch.from_numpy(G)
-    elif mode == 'AD':
-        A = A + np.eye(A.shape[0])
-        A = torch.from_numpy(A)
-        D = A.sum(1, keepdim=True)
-        G = A.div(D)
-    else:
-        raise NotImplementedError
+    A = A + np.eye(A.shape[0])
+    d = np.sum(A, axis=0)
+    d = np.clip(d, 0, None)
+    d_inv = np.power(d, -0.5).flatten()
+    d_inv[np.isinf(d_inv)] = 0.0
+    d_inv = np.diag(d_inv)
+    G = A.dot(d_inv).transpose().dot(d_inv)
     return G
 
 


Test patch:
diff --git a/tests/test_models/test_modules.py b/tests/test_models/test_modules.py
--- a/tests/test_models/test_modules.py
+++ b/tests/test_models/test_modules.py
@@ -1,5 +1,4 @@
 import numpy as np
-import pytest
 import torch
 
 from mmocr.models.textdet.modules import GCN, LocalGraphs, ProposalLocalGraphs
@@ -114,17 +113,10 @@ def test_gcn():
 
 
 def test_normalize_adjacent_matrix():
-    adjacent_matrix = np.random.randn(32, 32)
-    normalized_matrix = normalize_adjacent_matrix(adjacent_matrix, mode='AD')
+    adjacent_matrix = np.random.randint(0, 2, (16, 16))
+    normalized_matrix = normalize_adjacent_matrix(adjacent_matrix)
     assert normalized_matrix.shape == adjacent_matrix.shape
 
-    normalized_matrix = normalize_adjacent_matrix(adjacent_matrix, mode='DAD')
-    assert normalized_matrix.shape == adjacent_matrix.shape
-
-    with pytest.raises(NotImplementedError):
-        normalized_matrix = normalize_adjacent_matrix(
-            adjacent_matrix, mode='DA')
-
 
 def test_feature_embedding():
     out_feat_len = 48