2016-03-09 21 views
30

Recentemente ho implementato un modello e quando ho eseguito Ho ricevuto questo avvertimento:Spiegazione del gradiente denso di Tensorflow?

UserWarning: Converting sparse IndexedSlices to a dense Tensor of unknown shape. 
This may consume a large amount of memory. 
"Converting sparse IndexedSlices to a dense Tensor of unknown shape. " 

Con alcune impostazioni dei parametri simili (dimensionalità Embedding) improvvisamente il modello è incredibilmente lento.

  1. Che cosa implica questo avviso? Sembra che qualcosa che ho fatto ha causato tutti i gradienti di essere denso e così backprop sta facendo matrice densa calcoli
  2. Se è che ci sia un problema con il modello che sta causando questo, come posso identificare e risolvere il problema ?

risposta

10

Un denso tensore può essere pensato come un array python standard. Uno scarso può essere pensato come una raccolta di indici e valori, ad es.

# dense 
array = ['a', None, None, 'c'] 

# sparse 
array = [(0, 'a'), (3, 'c')] 

Quindi, come si può vedere se si dispone di un sacco di voci vuote un array sparso sarà molto più efficiente di un denso. Ma se tutte le voci sono compilate, la densità è molto più efficiente. Nel tuo caso, da qualche parte nel grafico del flusso del tensore, un array sparse viene convertito in uno denso di dimensioni indeterminate. L'avvertenza sta solo dicendo che è possibile che si possa sprecare molta memoria in questo modo. Ma potrebbe non essere affatto un problema se l'array sparse non è troppo grande/già abbastanza denso.

Se si desidera diagnosticare, si consiglia di denominare i vari oggetti tensori, quindi stamperà esattamente quali sono utilizzati in questa conversione e si può calcolare ciò che si potrebbe essere in grado di regolare per rimuoverlo.

29

Questo avviso viene stampato quando un oggetto sparse tf.IndexedSlices viene convertito implicitamente in un denso tf.Tensor. Questo accade tipicamente quando un op (solitamente tf.gather()) backpropagates un gradiente sparse, ma l'op che lo riceve non ha una funzione di sfumatura specializzata che può gestire gradienti sparse. Di conseguenza, TensorFlow densifica automaticamente lo tf.IndexedSlices, che può avere un effetto devastante sulle prestazioni se il tensore è grande.

Per risolvere questo problema, si dovrebbe cercare di garantire che il params ingresso tf.gather() (o le params ingressi tf.nn.embedding_lookup()) è un tf.Variable. Le variabili possono ricevere direttamente gli aggiornamenti sparsi, quindi non è necessaria alcuna conversione. Sebbene tf.gather() (e tf.nn.embedding_lookup()) accetti i tensori arbitrari come input, questo può portare a un grafico di backpropagation più complesso, con conseguente conversione implicita.

+1

Grazie per i chiarimenti. Come posso identificare quale op sta causando questo? – Taaam

+2

Il modo più semplice è di guardare attraverso il tuo codice per 'tf.gather()' o 'tf.nn.invocazioni di embedding_lookup(), trova il tensore 't' che è l'argomento' params' (primo) su uno di questi op e stampa 't.op'. Generalmente, otterrai le migliori prestazioni se 't' è un' tf.Variable', ma alcune operazioni come 'tf.concat()' hanno specializzazioni che rendono i gradienti efficienti. – mrry

+2

Sembra che sia un 'boolean_mask' alimentato con' reshape'. Questo è usato in un calcolo delle perdite molto nel grafico dopo 'reshape's di mulitple,' pack's, 'tile's,' expand_dim's, 'squeeze's,' batch_matmul's, ecc. C'è un modo per identificare quale op (s) non può accettare gradienti sparsi? – Taaam

5

totalmente d'accordo con la risposta di mrry.

In realtà Io posto un'altra soluzione per questo problema.

Si potrebbe utilizzare tf.dynamic_partition() invece di tf.gather() per eliminare l'avviso.

Il codice di esempio è qui sotto:

# Create the cells for the RNN network 
lstm = tf.nn.rnn_cell.BasicLSTMCell(128) 

# Get the output and state from dynamic rnn 
output, state = tf.nn.dynamic_rnn(lstm, sequence, dtype=tf.float32, sequence_length = seqlen) 

# Convert output to a tessor and reshape it 
outputs = tf.reshape(tf.pack(output), [-1, lstm.output_size]) 

# Set partions to 2 
num_partitions = 2 

# The partitions argument is a tensor which is already fed to a placeholder. 
# It is a 1-D tensor with the length of batch_size * max_sequence_length. 
# In this partitions tensor, you need to set the last output idx for each seq to 1 and 
# others remain 0, so that the result could be separated to two parts, 
# one is the last outputs and the other one is the non-last outputs. 
res_out = tf.dynamic_partition(outputs, partitions, num_partitions) 

# prediction 
preds = tf.matmul(res_out[1], weights) + bias 

Spero che questo potrebbe aiutare.

Problemi correlati