[Serie de aprendizaje profundo (6)]: Serie RNN (5): enrutamiento dinámico de modelos RNN

El enrutamiento dinámico es similar al mecanismo de atención y su propósito principal es asignar el parámetro correspondiente c a los datos de secuencia, algo similar al mecanismo de atención. Se ha demostrado en la práctica que, en comparación con el mecanismo de atención, el algoritmo de enrutamiento dinámico ha mejorado la precisión. A diferencia del algoritmo de similitud utilizado en el mecanismo de atención para calcular los pesos, este artículo utiliza un algoritmo de enrutamiento dinámico para asignar pesos. El algoritmo de enrutamiento dinámico se utiliza en la red de cápsulas. Este algoritmo se utiliza principalmente como referencia aquí y se utiliza en el RNN. En la práctica, se ha demostrado que algunos algoritmos de CNN o RNN pueden aprender unos de otros y, a veces, tener efectos milagrosos. Eche un vistazo a este artículo para obtener detalles prácticos específicos. . .


Tabla de contenido

Un algoritmo de enrutamiento dinámico

En segundo lugar, la práctica del algoritmo de enrutamiento dinámico en RNN

3. La práctica del modelo RNN basado en la clasificación dinámica de enrutamiento de las noticias de Reuters

3.1, carga de datos

3.2. Utilice la unidad IndyLSTM para construir el modelo RNN


 

Un algoritmo de enrutamiento dinámico

Geoffrey Hinton, uno de los pioneros del aprendizaje profundo e inventor de los algoritmos clásicos de redes neuronales como la retropropagación, propuso una red de cápsulas. La red de cápsulas es un nuevo tipo de red neuronal basada en cápsulas. La red de cápsulas se entrena con un enrutamiento dinámico algoritmo entre cápsulas. El diagrama esquemático que describe el enrutamiento de cápsulas e intercápsulas en el informe inicial de Hinton et al. Se muestra en la siguiente figura:

Aquí hay una breve introducción al algoritmo de enrutamiento en la siguiente red de cápsulas: En la red de cápsulas, el enrutamiento dinámico agrupa las cápsulas en cápsulas de bajo nivel y cápsulas principales, y calcula la salida de la cápsula principal. ¿Cómo calcularlo? En el enrutamiento dinámico, usamos una matriz de transformación para transformar el vector de la cápsula de entrada para formar un voto y usamos grupos de votación similares. Estos votos eventualmente se convierten en el vector de salida de la cápsula madre. El cálculo específico es el siguiente:

  • Calcular el peso de similitud (coeficiente de acoplamiento)c_ {ij}

                                                   c_ {ij} = \ frac {exp (b_ {ij})} {\ sum_ {K} exp (b_ {ij})}

Entre ellos se b_ {ij}encuentra la similitud entre la cápsula de la capa inferior y la cápsula de la capa superior, que se inicializa a 0 de forma predeterminada antes de cada iteración. Aquí, Softmax se usa para normalizar la similitud, y finalmente se obtiene el peso de similitud. El uso de Softmax puede garantizar que todos los pesos cij no sean negativos y que su suma sea igual a uno. En esencia, softmax refuerza la naturaleza probabilística del coeficiente cij I descrito anteriormente. Conceptualmente, el cálculo del peso de similitud c_ {ij}mide la probabilidad de que la cápsula active la cápsula.

  • Calcular la salida de la cápsula (vector de activación)v_ {j}

En primer lugar, sabemos que la salida (vector de predicción) de la red de cápsulas de bajo nivel es u_ {i}, aquí necesitamos multiplicar la matriz de transformación con la salida de la cápsula de bajo nivel para transformar la dimensión y obtener una nueva salida (predicción vector) \ widehat {u} _ {j | i}.

                                                   \ widehat {u} _ {j | i} = W_ {ji} u_ {i}

Luego c_ {ij}calcule la suma ponderada de acuerdo con el peso de similitud (coeficiente de acoplamiento) y, finalmente, obtenga la salida de la cápsula s_ {j}.

                                                  s_ {j} = \ sum _ {i} {c_ {ji} \ widehat {u} _ {j | i}}

Además, necesitamos pasar la función de aplastamiento no lineal, que asegura que se conserva la dirección de salida de la cápsula y que la longitud se limita a menos de 1. Esta función puede comprimir un vector pequeño a cero y un vector grande a un vector unitario. .

                                                  v_ {j} = \ frac {\ left \ |  s_ {j} \ right \ | ^ {2}} {1+ \ left \ |  s_ {j} \ right \ | ^ {2}} \ frac {s_ {j}} {\ left \ |  s_ {j} \ right \ | ^ {2}}

  • Actualizar el peso de similitudb_ {ij}

Intuitivamente, el vector de predicción es la predicción (votación) de la cápsula y afecta la salida de la cápsula. Si el vector de activación y el vector de predicción tienen un alto grado de similitud, podemos concluir que las dos cápsulas están altamente correlacionadas. Esta similitud se mide por el producto escalar del vector de predicción y el vector de activación. b_ {ij}El cálculo de la actualización es el siguiente:

                                                  b_ {ji} \ flecha izquierda b_ {ji} + \ widehat {u} _ {j | i} \ cdot v_ {j}

Por lo tanto, la puntuación de similitud considerará tanto la posibilidad como los atributos característicos, en lugar de considerar solo la posibilidad como la neurona. Aquí está el pseudocódigo final para el enrutamiento dinámico:

Conexión de referencia:

Introducción a CapsNet Serie tres: algoritmo de enrutamiento dinámico entre cápsulas

Comprensión del enrutamiento dinámico entre cápsulas (basado en la red de cápsulas de Hinton)

¿Cómo tratar el artículo de Hinton "Enrutamiento dinámico entre cápsulas"?

Aprenda lentamente NLP / Capsule Net

En segundo lugar, la práctica del algoritmo de enrutamiento dinámico en RNN

Se necesitan ciertos cambios para aplicar el algoritmo de enrutamiento dinámico en la red de cápsulas al modelo RNN, de la siguiente manera:

(1) Utilice la red totalmente vinculada para convertir el resultado de salida de RNN en un vector de predicción \ widehat {u} _ {j | i}, consulte la función shared_routing_uhat ()

(2) Enmascare la longitud de la secuencia de entrada, use un algoritmo de enrutamiento dinámico para admitir la entrada de datos de secuencia de longitud dinámica, consulte la función masked_routing_iter ()

(3) Realice la agregación de información sobre los resultados de la salida RNN y realice el procesamiento de abandono de los resultados de los cálculos de enrutamiento dinámico, para que tenga capacidades de normalización más sólidas, consulte la clase routing_mask

El código de implementación específico es el siguiente:

def mkMask(input_tensor,maxLen):
    '''
    计算变长RNN模型的掩码,根据序列长度生成对应的掩码
    :param input_tensor:输入标签文本序列的长度list,(batch_size)
    :param maxLen:输入标签文本的最大长度
    :return:
    '''
    shape_of_input=tf.shape(input_tensor)
    shape_of_output=tf.concat(axis=0,values=[shape_of_input,[maxLen]])

    oneDtensor=tf.reshape(input_tensor,shape=(-1,))
    flat_mask=tf.sequence_mask(oneDtensor,maxlen=maxLen)

    return tf.reshape(flat_mask,shape_of_output)

def shared_routing_uhat(caps,out_caps_num,out_caps_dim):
    '''
    定义函数,将输入转化成uhat
    :param caps: 输入向量,[batch_size,max_len,cap_dims]
    :param out_caps_num:输出胶囊的个数
    :param out_cap_dim:输出胶囊的维度
    :return:
    '''
    batch_size,max_len=caps.shape[0],caps.shape[1]

    caps_uchat=tf.keras.layers.Dense(out_caps_num*out_caps_dim,activation='tanh')(caps)
    caps_uchat=tf.reshape(caps_uchat,[batch_size,max_len,out_caps_num,out_caps_dim])

    return caps_uchat

def _squash(in_caps,axes):
    '''
    定义_squash激活函数
    :param in_caps:
    :param axes:
    :return:
    '''
    _EPSILON=1e-9
    vec_squared_norm=tf.reduce_sum(tf.square(in_caps),axis=axes,keepdims=True)
    scalar_factor=vec_squared_norm/(1+vec_squared_norm)/tf.sqrt(vec_squared_norm+_EPSILON)
    vec_squared=scalar_factor*in_caps
    return vec_squared

def masked_routing_iter(caps_uhat,seqLen,iter_num):
    '''
    动态路由计算
    :param caps_uhat:输入向量,(batch_size,max_len,out_caps_num,out_caps_dim)
    :param seqLen:
    :param iter_num:
    :return:
    '''
    assert iter_num>0

    #获取批次和长度
    batch_size,max_len=tf.shape(caps_uhat)[0],tf.shape(caps_uhat)[1]
    #获取胶囊的个数
    out_caps_num=int(tf.shape(caps_uhat)[2])
    seqLen=tf.where(tf.equal(seqLen,0),tf.ones_like(seqLen),seqLen)
    mask=mkMask(seqLen,max_len) #(batch_size,max_len)
    float_mask=tf.cast(tf.expand_dims(mask,axis=-1),dtype=tf.float32)#(batch_size,max_len,1)

    #初始化相似度权重b
    B=tf.zeros([batch_size,max_len,out_caps_num],dtype=tf.float32)

    #迭代更新相似度权重b
    for i in range(iter_num):
        #计算相似度权重(耦合系数)c
        c=tf.keras.layers.Softmax(axis=2)(B)#(batch_size,max_len,out_caps_num)
        c=tf.expand_dims(c*float_mask,axis=-1)#(batch_size,max_len,out_caps_num,1)

        #计算胶囊的输出(激活向量)v
        weighted_uhat=c*caps_uhat#(batch_size,max_Len,out_caps_num, out_caps_dim)
        s=tf.reduce_sum(weighted_uhat,axis=1)# (batch_size, out_caps_num, out_caps_dim)
        #squash非线性函数
        v=_squash(s,axes=[2])#(batch_size, out_caps_num, out_caps_dim)
        v=tf.expand_dims(v,axis=1)#(batch_size, 1, out_caps_num, out_caps_dim)

        #更新相似度权重b
        B=tf.reduce_sum(caps_uhat*v,axis=-1)+B#(batch_size, maxlen, out_caps_num)

    v_ret = tf.squeeze(v, axis=[1])  # shape(batch_size, out_caps_num, out_caps_dim)
    s_ret = s
    return v_ret, s_ret

#定义函数,使用动态路由对RNN结果信息聚合
def routing_masked(in_x, xLen, out_caps_dim, out_caps_num, iter_num=3,
                                dropout=None, is_train=False, scope=None):
    assert len(in_x.get_shape()) == 3 and in_x.get_shape()[-1].value is not None
    b_sz = tf.shape(in_x)[0]
    with tf.variable_scope(scope or 'routing'):
        caps_uhat = shared_routing_uhat(in_x, out_caps_num, out_caps_dim, scope='rnn_caps_uhat')
        attn_ctx, S = masked_routing_iter(caps_uhat, xLen, iter_num)
        attn_ctx = tf.reshape(attn_ctx, shape=[b_sz, out_caps_num*out_caps_dim])
        if dropout is not None:
            attn_ctx = tf.layers.dropout(attn_ctx, rate=dropout, training=is_train)
    return attn_ctx

3. La práctica del modelo RNN basado en la clasificación dinámica de enrutamiento de las noticias de Reuters

3.1, carga de datos

El conjunto de datos que se utiliza aquí es la interfaz tf.keras, que incluye 11228 noticias y un total de 46 temas. La interfaz específica es:

tf.keras.datasets.reuters

La principal realización es la siguiente:

  • Cargar datos usando la  función tf.keras.datasets.reuters.load_data
  • Utilice la función tf.keras.preprocessing.sequence.pad_sequences para alinear los datos

La implementación del código específico es la siguiente:

#定义参数
NUM_WORDS=2000 #字典的最大长度
MAXLEN=80 #设置句子的最大长度

def load_data(num_words=NUM_WORDS,maxlen=MAXLEN):
    '''加载数据'''
    # 加载数据
    print("load datasets ...")
    (x_train, y_train), (x_test, y_test) = \
        tf.keras.datasets.reuters.load_data(path='./reuters.npz', num_words=num_words)

    #数据预处理:对齐序列数据并计算长度
    #使用tf.keras.preprocessing.sequence函数对齐标签
    # 对于句子长度大于maxlen的,从前面截断,只保留前maxlen个数据;
    #对于句子长度小于maxlen的,需要在句子后面补零
    x_train=tf.keras.preprocessing.sequence.pad_sequences(x_train,maxlen=maxlen,padding='post')
    x_test=tf.keras.preprocessing.sequence.pad_sequences(x_test,maxlen,'post')
    print('Pad sequences x_train shape:', x_train.shape)

    #计算每个句子的真实长度
    len_train=np.count_nonzero(x_train,axis=1)
    len_test = np.count_nonzero(x_test, axis=1)
    
    return  (x_train,y_train,len_train),(x_test,y_test,len_test)

def dataset(batch_size):
    (x_train,y_train,len),_=load_data()
    
    dataset=tf.data.Dataset.from_tensor_slices(((x_train,len),y_train))
    
    dataset=dataset.shuffle(1000).batch(batch_size,drop_remainder=True)#丢弃剩余数据
    
    return dataset

3.2. Utilice la unidad IndyLSTM para construir el modelo RNN

Los pasos principales son los siguientes:

(1) Pase la unidad IndyLSTM de 3 capas a la función tf.nn.dynamic_rnn () para construir un modelo RNN dinámico;

(2) Utilice la función routing_masked () para agregar los resultados de salida del modelo RNN basado en el enrutamiento dinámico;

(3) Calcule el valor de pérdida con el resultado clasificado y defina el optimizador para el entrenamiento.

x = tf.placeholder("float", [None, maxlen]) #定义输入占位符
x_len = tf.placeholder(tf.int32, [None, ])#定义输入序列长度占位符
y = tf.placeholder(tf.int32, [None, ])#定义输入分类标签占位符

nb_features = 128   #词嵌入维度  
embeddings = tf.keras.layers.Embedding(num_words, nb_features)(x)

#定义带有IndyLSTMCell的RNN网络
hidden = [100,50,30]#RNN单元个数
stacked_rnn = []
for i in range(3):
    cell = tf.contrib.rnn.IndyLSTMCell(hidden[i])
    stacked_rnn.append(tf.nn.rnn_cell.DropoutWrapper(cell, output_keep_prob=0.8))
mcell = tf.nn.rnn_cell.MultiRNNCell(stacked_rnn)

rnnoutputs,_  = tf.nn.dynamic_rnn(mcell,embeddings,dtype=tf.float32)
out_caps_num = 5 #定义输出的胶囊个数
n_classes = 46#分类个数

outputs = routing_masked(rnnoutputs, x_len,int(rnnoutputs.get_shape()[-1]), out_caps_num, iter_num=3)
print(outputs.get_shape())
pred =tf.layers.dense(outputs,n_classes,activation = tf.nn.relu)



#定义优化器
learning_rate = 0.001
cost = tf.reduce_mean(tf.losses.sparse_softmax_cross_entropy(logits=pred, labels=y))
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)

iterator1 = tf.data.Iterator.from_structure(dataset.output_types,dataset.output_shapes)
one_element1 = iterator1.get_next()							#获取一个元素


#训练网络
with tf.Session()  as sess:
    sess.run( iterator1.make_initializer(dataset) )		#初始化迭代器
    sess.run(tf.global_variables_initializer())
    EPOCHS = 20
    for ii in range(EPOCHS):
        alloss = []  									#数据集迭代两次
        while True:											#通过for循环打印所有的数据
            try:
                inp, target = sess.run(one_element1)
                _,loss =sess.run([optimizer,cost], feed_dict={x: inp[0],x_len:inp[1], y: target})
                alloss.append(loss)

            except tf.errors.OutOfRangeError:
                #print("遍历结束")
                print("step",ii+1,": loss=",np.mean(alloss))
                sess.run( iterator1.make_initializer(dataset) )	#从头再来一遍
                break

Los resultados finales del entrenamiento son los siguientes:

Supongo que te gusta

Origin blog.csdn.net/wxplol/article/details/104484067
Recomendado
Clasificación