2017-01-26 7 views
2

Ich habe einen sliding Window-Algorithmus mit numpy erstellt, der über eine wav-Audiodatei gleitet und Slices davon an meine NN im Tensorflow liefert, der Features in den Audio-Slices erkennt. Sobald tensorflow seine Sache tut, gibt er seinen Ausgang auf numpy Land, wo ich die Scheiben in einer Reihe von Vorhersagen wieder zusammenzusetzen, die jede Probenposition der Originaldatei entsprechen:Wie wird ein Gleitfenster im Tensorflow implementiert?

import tensorflow as tf 
import numpy as np 
import nn 

def slide_predict(layers, X, modelPath): 
    output = None 

    graph = tf.Graph() 
    with graph.as_default(): 
     input_layer_size, hidden_layer_size, num_labels = layers 

     X_placeholder = tf.placeholder(tf.float32, shape=(None, input_layer_size), name='X') 
     Theta1 = tf.Variable(nn.randInitializeWeights(input_layer_size, hidden_layer_size), name='Theta1') 
     bias1 = tf.Variable(nn.randInitializeWeights(hidden_layer_size, 1), name='bias1') 
     Theta2 = tf.Variable(nn.randInitializeWeights(hidden_layer_size, num_labels), name='Theta2') 
     bias2 = tf.Variable(nn.randInitializeWeights(num_labels, 1), name='bias2') 
     hypothesis = nn.forward_prop(X_placeholder, Theta1, bias1, Theta2, bias2) 

     sess = tf.Session(graph=graph) 
     saver = tf.train.Saver() 
     init = tf.global_variables_initializer() 
     sess.run(init) 

     saver.restore(sess, modelPath) 

     window_size = layers[0] 

     pad_amount = (window_size * 2) - (X.shape[0] % window_size) 
     X = np.pad(X, (pad_amount, 0), 'constant') 

     for w in range(window_size): 
      start = w 
      end = -window_size + w 
      X_shifted = X[start:end] 
      X_matrix = X_shifted.reshape((-1, window_size)) 

      prediction = sess.run(hypothesis, feed_dict={X_placeholder: X_matrix}) 

      output = prediction if (output is None) else np.hstack((output, prediction)) 

     sess.close() 

    output.shape = (X.size, -1) 

    return output 

Leider ist dieser Algorithmus ist ziemlich langsam. Ich habe ein paar Logs auf den Weg gelegt und bei weitem ist der langsamste Teil der Teil, wo ich tatsächlich meinen Tensorflow-Graphen laufen lasse. Dies könnte daran liegen, dass die tatsächlichen Tensorflow-Berechnungen langsam sind (wenn das der Fall ist, bin ich wahrscheinlich nur SOL), aber ich frage mich, ob ein großer Teil der Langsamkeit nicht darin liegt, dass ich große Audiodateien wiederholt hin und her übertrage aus Tensorflow. Also meine Fragen sind:

1) Füttert ein Platzhalter wiederholt so deutlich langsamer als einmal füttern und die Werte für X innerhalb Tensorflow berechnen?

2) Wenn ja, was ist der beste Weg, um einen Sliding-Window-Algorithmus im Tensorflow zu implementieren, um diese Berechnung durchzuführen?

Antwort

5

Das erste Problem ist, dass Ihr Algorithmus hat die Komplexität quadratische Zeit in window_size, wegen np.hstack() in jeder Iteration Aufruf den output Array zu bauen, die Kopien sowohl die aktuellen Werte von output und prediction in ein neues Array:

for w in range(window_size): 
    # ... 
    output = prediction if (output is None) else np.hstack((output, prediction)) 

Statt np.hstack() in jeder Iteration des Aufrufs, wäre es effizienter sein, eine Python-Liste des prediction Arrays zu bauen, und rufe np.hstack() auf sie einmal, nachdem die Schleife beendet:

output_list = [] 
for w in range(window_size): 
    # ... 
    prediction = sess.run(...) 
    output_list.append(prediction) 
output = np.hstack(output_list) 

Das zweite Problem ist, dass das Einspeisen großer Werte in TensorFlow ineffizient sein kann, wenn der Berechnungsaufwand im Aufruf sess.run() klein ist, weil diese Werte (momentan) in C++ kopiert werden (und die Ergebnisse kopiert werden). Eine nützliche Strategie hierfür ist es, zu versuchen, die Gleitfensterschleife in das TensorFlow-Diagramm zu verschieben, wobei das tf.map_fn()-Konstrukt verwendet wird. Beispielsweise könnten Sie Ihr Programm wie folgt umstrukturieren:

# NOTE: If you call this function often, you may want to (i) move the `np.pad()` 
# into the graph as `tf.pad()`, and (ii) replace `X_t` with a placeholder. 
X = np.pad(X, (pad_amount, 0), 'constant') 
X_t = tf.convert_to_tensor(X) 

def window_func(w): 
    start = w 
    end = w - window_size 
    X_matrix = tf.reshape(X_t[start:end], (-1, window_size)) 
    return nn.forward_prop(X_matrix, Theta1, bias1, Theta2, bias2) 

output_t = tf.map_fn(window_func, tf.range(window_size)) 
# ... 
output = sess.run(output_t) 
+0

Hat tf.map_fn eine GPU-Implementierung? Vorausgesetzt, das CNN ist auf der GPU mit map_fn wird nur wirksam, wenn es einen GPU-Kern rechts registriert hat? – Priyatham

+0

Ja, 'tf.map_fn()' funktioniert mit einer Funktion, die die GPU verwendet. (Das 'tf.range()' und der Kontrollfluss werden wahrscheinlich auf der CPU ausgeführt, aber es wird das CNN an die GPU schicken.) – mrry

+0

Doh, danke! Diese Stapelmethode von mir war dumm. Wissen Sie zufällig, ob das Schneiden eines Tensors ('X_t [start: end]') Werte kopiert oder nur die Ansicht über diese verschiebt? Das könnte eine andere Quelle der Langsamkeit sein, wenn ich jedes Mal Dinge kopiere. Es wäre großartig, wenn es einen Weg geben würde, nur einen Zeiger über dieses Array zu setzen –

Verwandte Themen