2016-03-09 27 views
30

Niedawno wdrożył model i kiedy prowadził ją dostałam to ostrzeżenie:Tensorflow - gęste wyjaśnienie gradientu?

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. " 

Z niektórych podobnych ustawień parametrów (zatapiania wymiarowości) nagle modelu jest śmiesznie powolna.

  1. Co oznacza to ostrzeżenie? Wygląda na to, że coś, co zrobiłem, spowodowało, że wszystkie gradienty są gęste, a więc backprop wykonuje gęstą matrycę.
  2. Jeśli jest problem z modelem, który to powoduje, jak mogę go zidentyfikować i naprawić ?

Odpowiedz

10

Gęsty Tensor może być uważany za standardową tablicę Pythona. Rzadki może być uważany za zbiór indeksów i wartości, np.

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

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

Tak więc, jak widać, jeśli masz dużo pustych wpisów, rzadka tablica będzie znacznie bardziej wydajna niż gęsta. Ale jeśli wszystkie wpisy są wypełnione, gęstość jest znacznie bardziej efektywna. W twoim przypadku gdzieś na wykresie przepływu tensora przekształcana jest rzadka tablica na gęsty o nieokreślonej wielkości. Ostrzeżenie mówi tylko, że możliwe jest zmarnowanie dużej ilości pamięci w ten sposób. Ale może to nie być problemem, jeśli rzadka tablica nie jest zbyt duża/już dość gęsta.

Jeśli chcesz ją zdiagnozować, zaleciłbym nazewnictwo twoich różnych obiektów tensorowych, a następnie wydrukuje dokładnie te, które są używane w tej konwersji i możesz ustalić, co możesz poprawić, aby ją usunąć.

29

To ostrzeżenie jest drukowane, gdy rzadki obiekt tf.IndexedSlices jest niejawnie przekonwertowany na gęsty . Zdarza się to zazwyczaj, gdy jedna operacja (zwykle tf.gather()) odrzuca gradient rzadki, ale operacja, która go otrzymuje, nie ma specjalistycznej funkcji gradientu, która poradzi sobie z niewielkimi gradientami. W rezultacie TensorFlow automatycznie densyfikuje tf.IndexedSlices, co może mieć niszczący wpływ na wydajność, jeśli tensor jest duży.

Aby rozwiązać ten problem, należy starać się zapewnić, że wejście params do tf.gather() (lub params wejścia do tf.nn.embedding_lookup()) jest tf.Variable. Zmienne mogą bezpośrednio otrzymywać rzadkie aktualizacje, więc konwersja nie jest potrzebna. Chociaż tf.gather() (i tf.nn.embedding_lookup()) akceptują dowolne tensory jako dane wejściowe, może to prowadzić do bardziej skomplikowanego wykresu propagacji wstecznej, powodującego niejawną konwersję.

+1

Dziękuję za wyjaśnienia. Jak mogę określić, które op powoduje to? – Taaam

+2

Najprostszym sposobem jest przejrzenie twojego kodu dla 'tf.gather()' lub 'tf.nn.embedding_lookup() 'wywołania, znajdź tensor' t', który jest argumentem 'params' (pierwszy) dla każdego z tych opów i wypisz' t.op'. Ogólnie rzecz biorąc, uzyskasz najlepszą wydajność, jeśli 't' jest' tf.Variable', ale niektóre operacje, takie jak 'tf.concat()' mają specjalizacje, które sprawiają, że gradienty są wydajne. – mrry

+2

Wygląda na to, że 'boolean_mask' jest karmione' reshape'. Jest to używane w obliczeniach strat daleko na wykresie po mulitple 'reshape's,' pack's, 'tile's,' expand_dim's, 'squeeze's,' batch_matmul's, itd. Czy istnieje sposób określić, które op (s) nie mogą zaakceptować rzadkich gradientów? – Taaam

5

Całkowicie zgadzam się z odpowiedzią mrry.

Właściwie opublikuję inne rozwiązanie tego problemu.

Możesz użyć tf.dynamic_partition() zamiast tf.gather(), aby wyeliminować ostrzeżenie.

Przykładowy kod jest poniżej:

# 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 

Nadzieja to może pomóc.