7

że patrzy na kod przykład dla gradientów przetwarzania, TensorFlow posiada:Czy można zaimplementować pochylenie gradientowe, takie jak optymalizatory, za pomocą przykładu kodu z przetwarzania gradientów w TensorFlow?

# Create an optimizer. 
opt = GradientDescentOptimizer(learning_rate=0.1) 

# Compute the gradients for a list of variables. 
grads_and_vars = opt.compute_gradients(loss, <list of variables>) 

# grads_and_vars is a list of tuples (gradient, variable). Do whatever you 
# need to the 'gradient' part, for example cap them, etc. 
capped_grads_and_vars = [(MyCapper(gv[0]), gv[1]) for gv in grads_and_vars] 

# Ask the optimizer to apply the capped gradients. 
opt.apply_gradients(capped_grads_and_vars) 

Jednakże, zauważyliśmy, że funkcja apply_gradients pochodzi od GradientDescentOptimizer. Czy to oznacza, że ​​używając przykładowego kodu z góry, można wdrożyć tylko reguły gradientowe, takie jak zejście (zauważmy, że możemy zmienić opt = GradientDescentOptimizer lublub którykolwiek z pozostałych optymalizatorów)? W szczególności, co robi apply_gradients? Zdecydowanie sprawdzam kod w tf github page, ale był to garść pytonów, które nie miały nic wspólnego z wyrażeń matematycznych, więc trudno było powiedzieć, co to było i jak się zmieniło z optymalizatora na optymalizator.

Na przykład, jeśli chciałem zaimplementować własny niestandardowy optymalizator, który mógłby wykorzystywać gradienty (lub może np. Zmienić wagi bezpośrednio z pewną regułą, być może bardziej biologicznie prawdopodobną regułą), nie jest to możliwe z powyższym przykładowym kodem?


W szczególności chciałem wdrożyć wersję gradient zniżania, który jest sztucznie ograniczony w kompaktowej domenie. W szczególności chciałem zaimplementować następujące równanie:

w := (w - mu*grad + eps) mod B 

w TensorFlow. Zdałem sobie sprawę, że prawdziwe są następujące:

w := w mod B - mu*grad mod B + eps mod B 

więc pomyślałem, że może po prostu wdrożyć go wykonując:

def Process_grads(g,mu_noise,stddev_noise,B): 
    return (g+tf.random_normal(tf.shape(g),mean=mu_noise,stddev=stddev_noise)) % B 

a potem po prostu mający:

processed_grads_and_vars = [(Process_grads(gv[0]), gv[1]) for gv in grads_and_vars] 
# Ask the optimizer to apply the processed gradients. 
opt.apply_gradients(processed_grads_and_vars) 

jednak zdałem sobie sprawę, to nie było wystarczająco dobre, ponieważ nie mam dostępu do w, więc nie mogę wykonać:

w mod B 

przynajmniej nie tak, jak próbowałem. Czy jest jakiś sposób na zrobienie tego? tj. faktycznie bezpośrednio zmienić regułę aktualizacji? Przynajmniej tak, jak próbowałem?

Znam jego rodzaj hacky reguły aktualizacji, ale moim celem jest bardziej zmienić równanie aktualizacji niż faktycznie dbając o wiele o tej zasadzie aktualizacji (więc nie dajcie się zwiesić, jeśli to trochę dziwne).


wymyśliłem rozwiązanie Super Hacky:

def manual_update_GDL(arg,learning_rate,g,mu_noise,stddev_noise): 
    with tf.variable_scope(arg.mdl_scope_name,reuse=True): 
     W_var = tf.get_variable(name='W') 
     eps = tf.random_normal(tf.shape(g),mean=mu_noise,stddev=stddev_noise) 
     # 
     W_new = tf.mod(W_var - learning_rate*g + eps , 20) 
     sess.run(W_var.assign(W_new)) 

def manual_GDL(arg,loss,learning_rate,mu_noise,stddev_noise,compact,B): 
    # Compute the gradients for a list of variables. 
    grads_and_vars = opt.compute_gradients(loss) 
    # process gradients 
    processed_grads_and_vars = [(manual_update_GDL(arg,learning_rate,g,mu_noise,stddev_noise), v) for g,v in grads_and_vars] 

nie wiem, czy to działa, ale coś takiego powinno działać w ogóle. Chodzi o to, aby zapisać równanie, które chce się wykorzystać (w TensorFlow) dla szybkości uczenia się, a następnie zaktualizować wagi ręcznie przy użyciu sesji.

Niestety, takie rozwiązanie oznacza, że ​​musimy zadbać o wyżarzanie (rozkładanie tempa uczenia się ręcznie, co wydaje się denerwujące). To rozwiązanie prawdopodobnie ma wiele innych problemów, możesz je wskazać (i dać rozwiązania, jeśli możesz).


Do tego bardzo prostego problemu zdałem sobie sprawę, można po prostu zrobić normalne reguły aktualizacji Optimizer, a następnie po prostu wziąć mod ciężarami i ponownie przypisać je do ich wartości:

sess.run(fetches=train_step) 
if arg.compact: 
    # apply w := (w - mu*g + eps) mod B 
    W_val = W_var.eval() 
    W_new = tf.mod(W_var,arg.B).eval() 
    W_var.assign(W_new).eval() 

ale w w tym przypadku jest przypadkiem, że takie proste rozwiązanie istnieje (niestety, omija cały punkt mojego pytania).

Właściwie to rozwiązanie znacznie spowalnia kod. Na razie jest najlepszy, jaki mam.


Jako odniesienie, widziałem to pytanie: How to create an optimizer in Tensorflow, ale nie znalazł on odpowiedział bezpośrednio na moje pytanie.

+2

Co jeśli modyfikować wszystkie gradienty być 'grad = W - (w mod B - MU * Grad mod b + EPS mod B) 'i mają wskaźnik uczenia się' 1.0', z 'tf.train.GradientDescentOptimizer'? To powinno stosować gradienty jako 'w - = grad', czyli' w = w mod B - mu * grad mod B + eps mod B'. –

Odpowiedz

3

Rzeczywiście jesteś nieco ograniczony i nie możesz nic zrobić. Jednak to, co chcesz zrobić, można łatwo zrobić, tworząc klasę potomną klasy tensorflow Optimizer.

Wszystko, co musisz zrobić, to napisać metodę klasy _apply_dense. Metoda _apply_dense przyjmuje argumenty w postaci grad i w, więc wszystko, co chcesz zrobić z tymi zmiennymi, możesz zrobić.

Spójrz na przykład: https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/training/adam.py To jest realizacja Adam tensorflow, wszystko co musisz zrobić, to zmienić _apply_dense na linii 131, jak również metod _prepare i _finish.

Tak na przykład:

def _apply_dense(self, grad, var): 
    B = math_ops.cast(self.B, var.dtype.base_dtype) 
    eps = math_ops.cast(self.eps, var.dtype.base_dtype) 
    mu = math_ops.cast(self.mu, var.dtype.base_dtype) 


    var_update = state_ops.assign(var, tf.floormod(var - mu*grad + eps,B), 
          use_locking=self._use_locking) 

    return var_update 
3

Twoje rozwiązanie spowalnia kodu ponieważ używasz sess.run i .eval() kod podczas „train_step” stworzenia. Zamiast tego powinieneś utworzyć wykres train_step używając tylko wewnętrznych funkcji tensorflow (bez użycia sesji sess.run i .eval()). Następnie ocenisz tylko pociąg w pętli.

Jeśli nie chcesz używać żadnego standardowego optymalizatora, możesz napisać własny wykres "Zastosuj gradient". Oto jeden z możliwych rozwiązań, które:

learning_rate = tf.Variable(tf.constant(0.1)) 
mu_noise = 0. 
stddev_noise = 0.01 

#add all your W variables here when you have more than one: 
train_w_vars_list = [W] 
grad = tf.gradients(some_loss, train_w_vars_list) 

assign_list = [] 
for g, v in zip(grad, train_w_vars_list): 
    eps = tf.random_normal(tf.shape(g), mean=mu_noise, stddev=stddev_noise) 
    assign_list.append(v.assign(tf.mod(v - learning_rate*g + eps, 20))) 

#also update the learning rate here if you want to: 
assign_list.append(learning_rate.assign(learning_rate - 0.001)) 

train_step = tf.group(*assign_list) 

Można również użyć jednego standardowego optymalizator do utworzenia listy grads_and_vars (używać go zamiast zamek (Grad, train_w_vars_list) potem).

Oto prosty przykład dla MNIST z utratą:

from __future__ import absolute_import 
from __future__ import division 
from __future__ import print_function 

from tensorflow.examples.tutorials.mnist import input_data 

import tensorflow as tf 

# Import data 
mnist = input_data.read_data_sets('PATH TO MNIST_data', one_hot=True) 

# Create the model 
x = tf.placeholder(tf.float32, [None, 784]) 
W = tf.Variable(tf.zeros([784, 10])) 
y = tf.matmul(x, W) 


# Define loss and optimizer 
y_ = tf.placeholder(tf.float32, [None, 10]) 

cross_entropy = tf.reduce_mean(
    tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y)) 

learning_rate = tf.Variable(tf.constant(0.1)) 
mu_noise = 0. 
stddev_noise = 0.01 

#add all your W variables here when you have more than one: 
train_w_vars_list = [W] 
grad = tf.gradients(cross_entropy, train_w_vars_list) 

assign_list = [] 
for g, v in zip(grad, train_w_vars_list): 
    eps = tf.random_normal(tf.shape(g), mean=mu_noise, stddev=stddev_noise) 
    assign_list.append(v.assign(tf.mod(v - learning_rate*g + eps, 20))) 

#also update the learning rate here if you want to: 
assign_list.append(learning_rate.assign(learning_rate - 0.001)) 

train_step = tf.group(*assign_list) 


sess = tf.InteractiveSession() 
tf.global_variables_initializer().run() 


# Train 
for _ in range(1000): 
    batch_xs, batch_ys = mnist.train.next_batch(100) 
    sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys}) 


# Test trained model 
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1)) 
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) 
print(sess.run(accuracy, feed_dict={x: mnist.test.images, 
            y_: mnist.test.labels}))