2016-01-21 10 views
6

Vorrei aggiungere un limite massimo di norme a diverse matrici di peso nel mio grafico TensorFlow, il metodo renorm di ala Torch.Ridenormalizza matrice di peso utilizzando TensorFlow

Se la norma L2 della matrice di peso di qualsiasi neurone supera max_norm, desidero ridimensionare i pesi in modo che la loro norma L2 sia esattamente max_norm.

Qual è il modo migliore per esprimere questo utilizzando TensorFlow?

risposta

1

Dai un'occhiata alla funzione clip_by_norm, che fa esattamente questo. Richiede un singolo tensore come input e restituisce un tensore ridimensionato.

+0

Grazie per il puntatore! Sembra molto vicino a quello che voglio, si applica solo all'intera matrice, mentre vorrei rinormalizzare ogni colonna in modo indipendente (ala Torch's renorm). È possibile? – danvk

+0

Forse sostituendo la chiamata ['reduce_sum'] (https://github.com/tensorflow/tensorflow/blob/b11337ea5719a8799f279a41c2cd5c9e75a8acf7/tensorflow/python/ops/clip_ops.py#L90-L93) in' clip_by_norm' con qualcosa che imposta [ 'reduction_indices'] (https://www.tensorflow.org/versions/master/api_docs/python/math_ops.html#reduce_sum)? – danvk

+0

Ah, dalla domanda sembra che tu voglia normalizzare l'intera matrice usando la sua norma e non le colonne separatamente. –

2

Utilizzando il suggerimento di Rafał e tensorflow di implementation di clip_by_norm, ecco cosa mi si avvicinò con:

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) 

Sembra di avere il comportamento desiderato per 2-dimensionali matrici e dovrebbe generalizzare tensori:

> 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]] 
4

Ecco una possibile implementazione:

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 

Ecco come si dovrebbe utilizzare:

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) 

Questo crea una rete neurale 3 strati e si allena con max norma regolarizzazione ad ogni livello (con una soglia di 1,5). L'ho appena provato, sembra funzionare. Spero che questo ti aiuti! Suggerimenti per miglioramenti sono i benvenuti. :)

Note

Questo codice si basa su 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! 

È possibile anche ritagliare le colonne se è necessario:

>>> 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! 
Problemi correlati