2017-09-24 67 views
8

Robię eksperymenty z TensorFlow i wpadłem w pułapkę. Próbuję użyć TF do oszacowania zmiany w modelu, a następnie albo zatrzymać, albo przywrócić model, w oparciu o wynikową zmianę w funkcji straty. Mam trudną część (warunkową kontrolę) zorientowałem się, ale utknąłem na czymś, co powinno być dość proste: nie mogę przechowywać tf.trainable_variables dla iteracji, a następnie przywrócić ją w razie potrzeby.Jak mogę przywrócić Tensory do wartości z przeszłości, bez zapisywania wartości na dysku?

powiedzmy zbudować Op:

... 
store_trainable_vars = [] 

for v in tf.trainable_variables(): 

    store_trainable_vars.append(v) 
... 

Później, chcę przywrócić tf.trainable_variables do wartości jaką miał kiedy to op ostatniego uruchomienia. chciałbym zrobić coś takiego:

def reject_move(): 

    revert_state = [] 

    for (v, s) in zip(tf.trainable_variables(), store_trainable_vars): 

     revert_state.append(tf.assign(v, s, name="revert_state")) 

    return(revert_state) 

Oczywiście, ponownie oceni store_trainable_vars, co z kolei linki do wartości bieżącej tf.trainable_variables(), eliminując z revert_state op. Potrzebuję sposobu na zapisanie i odzyskanie wartości Tensorów bez zwracania się do aktualnej wartości tych Tensorów. Coś jak

... 
store_trainable_vars = [] 

for v in tf.trainable_variables(): 

    store_trainable_vars.append(v.value_right_now()) 
... 

gdzie v.value_right_now() zwraca stałą, która nie ulegnie zmianie aż nadpisane.

Wiem, że mógłbym używać Saver, ale to rozwiązanie zapisuje na dysku, co jest niedopuszczalne dla tej aplikacji, ponieważ będzie działać w pętli treningowej.

Prawdopodobnie brakuje mi czegoś oczywistego - wszelkie wskazówki będą mile widziane.

Odpowiedz

1

To nie był mój pierwotny zamiar, aby samodzielnie odpowiedzieć na to pytanie, ale wymyśliłem metodę, która działa całkiem dobrze. Tak więc, myślałem, że się nim podzielę. Kluczowy wgląd pochodził od bardzo sprytnej odpowiedzi od this. Podejście polega na ponownym wykorzystaniu węzłów przypisania utworzonych w celu przypisania zmiennej initalnej. Pełna klasa implementująca to podejście jest podana poniżej.

import tensorflow as tf 


class TensorFlowState(object): 

    def __init__(self): 

     # Get the graph. 
     graph = tf.get_default_graph() 

     # Extract the global varibles from the graph. 
     self.gvars = graph.get_collection(tf.GraphKeys.GLOBAL_VARIABLES) 

     # Exract the Assign operations for later use. 
     self.assign_ops = [graph.get_operation_by_name(v.op.name + "/Assign") 
          for v in self.gvars] 

     # Extract the initial value ops from each Assign op for later use. 
     self.init_values = [op.inputs[1] for op in self.assign_ops] 

    def start(self, sess): 

     self.sess = sess 

    def store(self): 

     # Record the current state of the TF global varaibles 
     self.state = self.sess.run(self.gvars) 

    def restore(self): 
    # Create a dictionary of the iniailizers and stored state of globals. 
    feed_dict = {init_value: val 
       for init_value, val in zip(self.init_values, self.state)} 

    # Use the initializer ops for each variable to load the stored values. 
    return(self.sess.run(self.assign_ops, feed_dict=feed_dict)) 

Aby go wykorzystać, po prostu instancję klasy, wywołać metodę start zdać tf.Session i wywołać metody store i restore ile potrzeba bezwzględnej wewnątrz pętli treningowej. Użyłem tej implementacji do zbudowania optymalizatora, który działa tak szybko, jak optymalizatory gradientu zejścia zawarte w TensorFlow.

5

ręcznie przywrócić stan wykresu trzeba użyć tf.tuple lub tf.group operacji, które będą zmiany przepływu dla zasadniczej zmiany:

Stwarza to krotka tensorów o takich samych wartościach jak tensorów argumentów , z tą różnicą, że wartość każdego tensora jest zwracana dopiero po obliczeniu wartości wszystkich tensorów.

[Aktualizacja] Oto w jaki sposób to zrobić:

import numpy as np 
import tensorflow as tf 

x = tf.placeholder(shape=[None, 5], dtype=tf.float32, name='x') 
W = tf.Variable(np.zeros([5, 5]), dtype=tf.float32, name='W') 
b = tf.Variable(np.zeros([5]), dtype=tf.float32, name='b') 
y = tf.add(tf.matmul(x, W), b) 

with tf.Session() as session: 
    batch = np.ones([2, 5]) 
    session.run(tf.global_variables_initializer()) 
    print session.run(y, feed_dict={x: batch})  # prints [2, 5] zeros 

    # store the current value 
    store = {v.name: v.eval(session) for v in tf.trainable_variables()} 
    print store          # prints [5, 5] and [5] zeros 

    # update 
    new = {'W:0': np.ones([5, 5]), 'b:0': np.ones([5])} 
    session.run(tf.tuple([tf.assign(var, new[var.name]) for var in tf.trainable_variables()])) 
    print session.run(y, feed_dict={x: batch})  # prints [2, 5] sixes 

    # restore 
    session.run(tf.tuple([tf.assign(var, store[var.name]) for var in tf.trainable_variables()])) 
    print session.run(y, feed_dict={x: batch})  # prints [2, 5] zeros again 

Ale naprawdę, że należy ponownie rozważyć swoją decyzję o Saver, ponieważ został zaprojektowany do stosowania wewnątrz pętli szkolenia, jak również . Wewnętrznie, Saver wykonuje całą trudną pracę dla ciebie (w szczególności, to przywracanie wywołań operacyjnych tf.group i tf.control_dependencies w razie potrzeby), które w przeciwnym razie mogą stać się źródłem dość nieprzyjemnych błędów. Poza tym, dysk jest (prawie) zawsze większy niż twój GPU i pamięć główna, więc jeśli możesz pozwolić sobie na przechowywanie modelu w pamięci, powinieneś być w stanie przechowywać również na dysku.

Oto some parameters które pomagają kontrolować proliferację punktów kontrolnych plików na dysku:

  • max_to_keep wskazuje maksymalną liczbę punktów kontrolnych do najnowszych plików twierdzy. W miarę tworzenia nowych plików starsze pliki są usuwane. Jeśli Brak lub 0, wszystkie pliki punktów kontrolnych są zachowywane. Domyślnie 5 (czyli 5 ostatnich plików punktów kontrolnych ).
  • keep_checkpoint_every_n_hours: Oprócz przechowywania najnowszych plików punktów kontrolnych max_to_keep, możesz chcieć zachować jeden plik punktu kontrolnego na każde N godzin szkolenia. Może to być przydatne, jeśli chcesz później analizować postępy modelu podczas długiej sesji treningowej. Na przykład , przekazanie keep_checkpoint_every_n_hours=2 gwarantuje, że będziesz przechowywać jeden plik punktu kontrolnego na każde 2 godziny szkolenia. Domyślna wartość 10.000 godzin skutecznie wyłącza tę funkcję.

[Aktualizacja] Jak wyjaśniono w komentarzach, głównym problemem jest opóźnienie na dysku, które mogą spowolnić szkolenia czy obejrzano zbyt często. Jeśli korzystasz z Linuksa, to często używane są również strony z dyskami,. Ale jeśli chcesz być absolutnie pewny, rozważ użycie opcji tmpfs.

+0

Powinienem wyjaśnić: kiedy powiedziałem, że nie chcę pisać na dysku, to nie dlatego, że martwiłem się przestrzenią. To przechowywanie i przywracanie będzie występować, w najgorszym przypadku, przy każdej iteracji. Jest to kara za czas ucieczki z powrotem na dysk, którego próbuję uniknąć. Czy możesz edytować swoją odpowiedź, aby zamiast tego pokazać trywialne użycie 'tf.group' do przywracania wykresów? (lub po prostu link do takiego przykładu) –