2016-01-21 3 views
6

Я хотел бы добавить ограничение максимальной нормы на несколько весовых матриц на моем графике TensorFlow, метод renorm ala Torch.Перенормировать весовую матрицу с помощью TensorFlow

Если норма L2 любой весовой матрицы нейрона превышает max_norm, я хотел бы уменьшить вес, чтобы их норма L2 была точно равна max_norm.

Каков наилучший способ выразить это с помощью TensorFlow?

ответ

1

Посмотрите на функцию clip_by_norm, которая выполняет именно это. Он принимает один тензор в качестве входного сигнала и возвращает уменьшенный тензор.

+0

Спасибо за указатель! Это выглядит очень близко к тому, что я хочу, только применительно ко всей матрице, тогда как я хотел бы перенормировать каждый столбец независимо (ala Torch's renorm). Это возможно? – danvk

+0

Возможно, заменив вызов '' reduce_sum'' (https://github.com/tensorflow/tensorflow/blob/b11337ea5719a8799f279a41c2cd5c9e75a8acf7/tensorflow/python/ops/clip_ops.py#L90-L93) в 'clip_by_norm' с чем-то, что устанавливает [ 'reduction_indices'] (https://www.tensorflow.org/versions/master/api_docs/python/math_ops.html#reduce_sum)? – danvk

+0

Ах, из вопроса, похоже, вы хотите нормализовать всю матрицу, используя ее норму, а не столбцы отдельно. –

2

Используя предложение и TensorFlow-х implementation из clip_by_norm Рафал, вот что я придумал:

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) 

Это, кажется, желаемое поведение для 2-мерных матриц и должны обобщать тензоров:

> 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

Возможна реализация:

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 

Вот как вы будете использовать его:

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) 

Это создает 3 слоя нейронной сети и тренирует его с максимальной нормой регуляризации на каждом слое (с порогом 1,5). Я просто попробовал, похоже, работает. Надеюсь это поможет! Предложения по улучшению приветствуются. :)

Примечания

Этот код основан на 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! 

Вы также можете закрепить столбцы, если вам нужно:

>>> 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! 
Смежные вопросы