[Red neuronal gráfica] Análisis de código de red de relaciones con reconocimiento de relaciones espaciales (SGRN)

! ! ! Este artículo no implica la implementación, solo comprenda la idea del procesamiento de salida del código oficial, si existe la posibilidad, se implementará y se publicará la dirección del código oficial y la interpretación de los documentos escritos anteriormente. como siempre:

Dirección del proyecto github de la red SGRN icono-predeterminado.png?t=N2N8https://github.com/simblah/SGRN_torch [Graph Neural Network] Red relacional de percepción de relación espacial (SGRN) - Interpretación del papel icono-predeterminado.png?t=N2N8https://blog.csdn.net/weixin_37878740/article/details/129837774? spm=1001.2014.3001.5501

1. Revisión del marco de la red

         Se puede ver claramente que la red SGRN mencionada en el documento incorpora un aprendiz de gráfico relacional y un módulo de razonamiento consciente del espacio en Faster R-CNN , y cambia RoI Pooling a RoI Align , por lo que nos enfocamos en estas partes del código.

Dos, interpretación del código

        El código interpretado se encuentra en el proyecto: lib->nets->network_gcn . La estructura de la función de transferencia directa es la siguiente:

    def forward(self, image, im_info, gt_boxes=None, mode='TRAIN'):
        #.....
        rois, cls_prob, bbox_pred = self._predict()
        #....

        El resto del código en la función de transferencia directa es el preprocesamiento de datos y el cálculo de la función de pérdida En segundo lugar, rois, cls_prob y bbox_pred se calculan mediante la función self._predict(). Así que salta a la función _predict ( )

# This is just _build_network in tf-faster-rcnn
net_conv = self._image_to_head()          #骨干网络提取

# build the anchors for the image
self._anchor_component(net_conv.size(2), net_conv.size(3))

rois = self._region_proposal(net_conv)    #获取候选区域
if cfg.POOLING_MODE == 'align':           #兴趣域池化
    pool5 = self._roi_align_layer(net_conv, rois)
else:
    pool5 = self._roi_pool_layer(net_conv, rois)

fc7 = self._head_to_tail(pool5)

cls_prob, bbox_pred = self._region_classification(fc7)

         Este es el código que originalmente pertenecía a Faster R-CNN, y se ha modificado el RoI Pooling, correspondiente a esta parte del diagrama:

        1.RoI Alinear

def _roi_align_layer(self, bottom, rois):
    return RoIAlign((cfg.POOLING_SIZE, cfg.POOLING_SIZE), 1.0 / 16.0,0)(bottom, rois)
def _roi_pool_layer(self, bottom, rois):
    return RoIPool((cfg.POOLING_SIZE, cfg.POOLING_SIZE),1.0 / 16.0)(bottom, rois)

        En comparación con RoI Pool, RoI Align tiene un parámetro más al final, que se utiliza para controlar el número de puntos de muestreo en la interpolación bilineal . El valor predeterminado es -1 y se establece en 0 en el código.

        2. Aprendiz relacional

        Se utiliza para construir un gráfico (matriz de adyacencia) a partir de pesos, correspondiente a esta parte del diagrama:

num_rois = rois.shape[0]    #通道数
z = self.relation_fc_1(fc7)
z = F.relu(self.relation_fc_2(z))
eps = torch.mm(z, z.t())
_, indices = torch.topk(eps, k=32, dim=0)

        Entre ellos, relación_fc_1() y relación_fc_2() son capas totalmente conectadas. Las dos capas totalmente conectadas se superponen y son seguidas por una función de activación relu . Después de que fc7 (es decir, el área sugerida) es procesada por el módulo, una secuencia z de longitud 256 se obtiene.

self.relation_fc_1 = nn.Linear(self._fc7_channels, 256)
self.relation_fc_2 = nn.Linear(256, 256)

        Luego, después de torch.mm() <el propósito es multiplicar dos matrices >, multiplique z y su transpuesta para obtener la matriz de adyacencia eps .

        La matriz de adyacencia eps pasa a través de torch.topk() . La función de torch.topk es encontrar los primeros k elementos en la secuencia para ordenar .Hay dos valores de retorno: el primer valor es la matriz ordenada y el segundo valor es en la matriz La etiqueta de posición del elemento obtenido en la matriz original. El propósito de esta función es construir un gráfico disperso (correspondiente al texto original para tomar los 3 valores más grandes) .

        Las reglas de clasificación son: los datos más grandes de la columna, y así sucesivamente:

tensor1=torch.tensor([  [9,1,2,1,9,1],
                        [3,4,5,1,1,1],
                        [7,8,9,1,1,1],
                        [1,4,7,1,1,2]])

values,indices=torch.topk(tensor1, k=3, dim=0)

print(values)
print(indices)

        Como resultado del experimento, se puede ver que los datos k más grandes en cada fila se mencionan al frente.

tensor([[9, 8, 9, 1, 9, 2],
        [7, 4, 7, 1, 1, 1],
        [3, 4, 5, 1, 1, 1]])

tensor([[0, 2, 2, 0, 0, 3],
        [2, 1, 3, 1, 1, 0],
        [1, 3, 1, 2, 2, 1]])

        3. Módulo de razonamiento de percepción espacial

                ① Obtenga el vector de incrustación incrustado

                Se utiliza para incrustar las características del gráfico en el gráfico (matriz de adyacencia), correspondiente a esta parte del diagrama:

                La estructura específica es la siguiente, que consta de tres ramas (gráfico/ matriz de adyacencia , peso de clasificación , cuadro de predicción , que representan respectivamente: relación de conexión, relación de categoría, relación de posición)

cls_w = self.cls_score_net.weight
represent = torch.mm(cls_prob, cls_w)

                Multiplique cls_prob (el peso de predicción de tipo derivado del clasificador) y cls_w (fc7 pasa por un clasificador lineal )

self.cls_score_net = nn.Linear(self._fc7_channels, self._num_classes)

                 ② Obtener la función de distancia

cls_pred = torch.max(cls_prob, 1)[1]
bbox_pred_reshape = bbox_pred.view(-1, 1001, 4)
bbox_pred_cls = torch.zeros(num_rois, 4)
for i, cls in enumerate(cls_pred):
    bbox_pred_cls[i] = bbox_pred_reshape[i][cls]
bbox_pred_ctr = bbox_pred_cls[:, 0:2] + bbox_pred_cls[:, 2:4]

        torch.max()[1] devuelve el índice del valor máximo, el experimento es el siguiente:

x = torch.max(tensor1,1)[1]    #tensor1同上例
print(x)
tensor([0, 2, 2, 2])    #得到每一列最大值的索引

        bbox_pred es la predicción del cuadro de destino obtenida después de procesar fc7 por el clasificador relacional, reconstruirlo usando view, luego atravesar cls_pred y sacar el elemento más grande (cuatro coordenadas ) de cada columna; luego calcular de acuerdo con la fórmula (a continuación)

                d=\sqrt{(c_a-c_b)^2+(y_a-y_b)^2} ,\theta=arctan(\frac{y_b-y_a}{c_b-c_a})

relation = torch.empty(2, 32 * num_rois, dtype=torch.long).to(self._device)
# U = torch.empty(32*128, 2).to(self._device)

relation[0] = torch.Tensor(list(range(num_rois)) * 32)  # , type=torch.long)
relation[1] = indices.view(-1)

coord_i = bbox_pred_ctr[relation[0]]
coord_j = bbox_pred_ctr[relation[1]]

d = torch.sqrt((coord_i[:, 0] - coord_j[:, 0]) ** 2 + (coord_i[:, 1] - coord_j[:, 1]) ** 2)
#距离
theta = torch.atan2((coord_j[:, 1] - coord_i[:, 1]), (coord_j[:, 0] - coord_i[:, 0]))
#角度

U = torch.stack([d, theta], dim=1).to(self._device)
#位置嵌入

                ③Gráfico de convolución

                La definición de convolución de gráfico es que los parámetros son: tamaño del gráfico de entrada, tamaño del gráfico de salida, profundidad, tamaño del kernel de convolución

self.gaussian = GMMConv(self._fc7_channels, self._fc7_channels, dim=2, kernel_size = 25)

                Utilice este procesamiento de convolución de gráfico: gráfico/ matriz de adyacencia , peso de clasificación , cuadro de predicción (las tres entradas son en realidad: gráfico ( gráfico ), característica ( hazaña  ), pseudocoordenada ( pseudo ), donde el tamaño de la característica/hazaña es ( N,D_{en})< respectivamente: el número de nodos, el tamaño de la característica de entrada>; el tamaño de la pseudo-coordenada / pseudoE,D_u es ( )<respectivamente: el número de aristas, la dimensión de la pseudo-coordenada>)

f = self.gaussian(represent, relation, U)

                Procese incrustaciones de gráficos utilizando funciones de activación y totalmente conectadas:

f2 = F.relu(self.sg_conv_1(f))
h = F.relu(self.sg_conv_2(f2))

                Dos de los sg_conv completamente conectados son:

self.sg_conv_1 = nn.Linear(self._fc7_channels, 512)
self.sg_conv_2 = nn.Linear(512, 256)

        4. Gráfico de fusión con regiones candidatas

                Después de fusionar el vector de incrustación obtenido del gráfico con el área candidata, se obtienen un nuevo marco de predicción y datos de clasificación.

new_f = torch.cat([fc7, h], dim=1)
new_cls_prob, new_bbox_pred = self._new_region_classification(new_f)

for k in self._predictions.keys():
    self._score_summaries[k] = self._predictions[k]

return rois, new_cls_prob, new_bbox_pred

                La implementación de _new_region_classification() utilizada anteriormente es:

def _new_region_classification(self, f):
    cls_score = self.new_cls_score_net(f)
    cls_pred = torch.max(cls_score, 1)[1]
    cls_prob = F.softmax(cls_score, dim=1)
    bbox_pred = self.new_bbox_pred_net(f)

    self._predictions["cls_score"] = cls_score
    self._predictions["cls_pred"] = cls_pred
    self._predictions["cls_prob"] = cls_prob
    self._predictions["bbox_pred"] = bbox_pred

    return cls_prob, bbox_pred

Supongo que te gusta

Origin blog.csdn.net/weixin_37878740/article/details/130087145
Recomendado
Clasificación