Renormalizar la matriz de peso utilizando TensorFlow

Me gustaría agregar una restricción de norma máxima a varias de las matrices de peso en mi gráfico TensorFlow, al método de renorm de Torch.

Si la norma L2 de cualquier matriz de peso de una neurona excede max_norm , me gustaría reducir su peso para que su norma L2 sea exactamente max_norm .

¿Cuál es la mejor manera de express esto usando TensorFlow?

Aquí hay una posible implementación:

 import tensorflow as tf def maxnorm_regularizer(threshold, axes=1, name="maxnorm", collection="maxnorm"): def maxnorm(weights): clipped = tf.clip_by_norm(weights, clip_norm=threshold, axes=axes) clip_weights = tf.assign(weights, clipped, name=name) tf.add_to_collection(collection, clip_weights) return None # there is no regularization loss term return maxnorm 

Así es como lo usarías:

 from tensorflow.contrib.layers import fully_connected from tensorflow.contrib.framework import arg_scope with arg_scope( [fully_connected], weights_regularizer=max_norm_regularizer(1.5)): hidden1 = fully_connected(X, 200, scope="hidden1") hidden2 = fully_connected(hidden1, 100, scope="hidden2") outputs = fully_connected(hidden2, 5, activation_fn=None, scope="outs") max_norm_ops = tf.get_collection("max_norm") [...] with tf.Session() as sess: sess.run(init) for epoch in range(n_epochs): for X_batch, y_batch in load_next_batch(): sess.run(training_op, feed_dict={X: X_batch, y: y_batch}) sess.run(max_norm_ops) 

Esto crea una neural network de 3 capas y la entrena con la máxima normalización de normas en cada capa (con un umbral de 1.5). Acabo de probarlo, parece funcionar. ¡Espero que esto ayude! Sugerencias para mejorar son bienvenidas. 🙂

Notas

Este código se basa en tf.clip_by_norm() :

 >>> x = tf.constant([0., 0., 3., 4., 30., 40., 300., 400.], shape=(4, 2)) >>> print(x.eval()) [[ 0. 0.] [ 3. 4.] [ 30. 40.] [ 300. 400.]] >>> clip_rows = tf.clip_by_norm(x, clip_norm=10, axes=1) >>> print(clip_rows.eval()) [[ 0. 0. ] [ 3. 4. ] [ 6. 8. ] # clipped! [ 6.00000048 8. ]] # clipped! 

También puede recortar columnas si necesita:

 >>> clip_cols = tf.clip_by_norm(x, clip_norm=350, axes=0) >>> print(clip_cols.eval()) [[ 0. 0. ] [ 3. 3.48245788] [ 30. 34.82457733] [ 300. 348.24578857]] # clipped! 

Usando la sugerencia de Rafał y la implementación de TensorFlow de clip_by_norm , esto es lo que se me ocurrió:

 def renorm(x, axis, max_norm): '''Renormalizes the sub-tensors along axis such that they do not exceed norm max_norm.''' # This elaborate dance avoids empty slices, which TF dislikes. rank = tf.rank(x) bigrange = tf.range(-1, rank + 1) dims = tf.slice( tf.concat(0, [tf.slice(bigrange, [0], [1 + axis]), tf.slice(bigrange, [axis + 2], [-1])]), [1], rank - [1]) # Determine which columns need to be renormalized. l2norm_inv = tf.rsqrt(tf.reduce_sum(x * x, dims, keep_dims=True)) scale = max_norm * tf.minimum(l2norm_inv, tf.constant(1.0 / max_norm)) # Broadcast the scalings return tf.mul(scale, x) 

Parece tener el comportamiento deseado para matrices bidimensionales y debería generalizarse a los tensores:

 > x = tf.constant([0., 0., 3., 4., 30., 40., 300., 400.], shape=(4, 2)) > print x.eval() [[ 0. 0.] # rows have norms of 0, 5, 50, 500 [ 3. 4.] # cols have norms of ~302, ~402 [ 30. 40.] [ 300. 400.]] > print renorm(x, 0, 10).eval() [[ 0. 0. ] # unaffected [ 3. 4. ] # unaffected [ 5.99999952 7.99999952] # rescaled [ 6.00000048 8.00000095]] # rescaled > print renorm(x, 1, 350).eval() [[ 0. 0. ] # col 0 is unaffected [ 3. 3.48245788] # col 1 is rescaled [ 30. 34.82457733] [ 300. 348.24578857]] 

Eche un vistazo a la función clip_by_norm , que hace exactamente esto. Toma un solo tensor como entrada y devuelve un tensor reducido.