From a1b64cf2a6a995ffaaf384cf8643221f1c27db48 Mon Sep 17 00:00:00 2001 From: Alexandre Passos Date: Wed, 19 Sep 2018 10:49:11 -0700 Subject: Force-place embedding variables on CPUs ein eager mode. This avoids problems which happen because most optimizers do not have sparse updating gpu kernels implemented. Fixes #22042 PiperOrigin-RevId: 213654354 --- tensorflow/python/keras/BUILD | 5 ++-- tensorflow/python/keras/layers/embeddings.py | 29 ++++++++++++++++++----- tensorflow/python/keras/layers/embeddings_test.py | 13 ++++++++++ 3 files changed, 38 insertions(+), 9 deletions(-) (limited to 'tensorflow/python/keras') diff --git a/tensorflow/python/keras/BUILD b/tensorflow/python/keras/BUILD index b521b1430d..4a72c4b3f3 100755 --- a/tensorflow/python/keras/BUILD +++ b/tensorflow/python/keras/BUILD @@ -381,12 +381,11 @@ py_test( ], ) -py_test( +cuda_py_test( name = "embeddings_test", size = "medium", srcs = ["layers/embeddings_test.py"], - srcs_version = "PY2AND3", - deps = [ + additional_deps = [ ":keras", "//tensorflow/python:client_testlib", ], diff --git a/tensorflow/python/keras/layers/embeddings.py b/tensorflow/python/keras/layers/embeddings.py index 629a9ec9a1..c6df5f2e26 100644 --- a/tensorflow/python/keras/layers/embeddings.py +++ b/tensorflow/python/keras/layers/embeddings.py @@ -18,6 +18,8 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +from tensorflow.python.eager import context +from tensorflow.python.framework import ops from tensorflow.python.keras import backend as K from tensorflow.python.keras import constraints from tensorflow.python.keras import initializers @@ -117,12 +119,27 @@ class Embedding(Layer): @tf_utils.shape_type_conversion def build(self, input_shape): - self.embeddings = self.add_weight( - shape=(self.input_dim, self.output_dim), - initializer=self.embeddings_initializer, - name='embeddings', - regularizer=self.embeddings_regularizer, - constraint=self.embeddings_constraint) + # Note: most sparse optimizers do not have GPU kernels defined. When + # building graphs, the placement algorithm is able to place variables on CPU + # since it knows all kernels using the variable only exist on CPU. + # When eager execution is enabled, the placement decision has to be made + # right now. Checking for the presence of GPUs to avoid complicating the + # TPU codepaths which can handle sparse optimizers. + if context.executing_eagerly() and context.context().num_gpus(): + with ops.device('cpu:0'): + self.embeddings = self.add_weight( + shape=(self.input_dim, self.output_dim), + initializer=self.embeddings_initializer, + name='embeddings', + regularizer=self.embeddings_regularizer, + constraint=self.embeddings_constraint) + else: + self.embeddings = self.add_weight( + shape=(self.input_dim, self.output_dim), + initializer=self.embeddings_initializer, + name='embeddings', + regularizer=self.embeddings_regularizer, + constraint=self.embeddings_constraint) self.built = True def compute_mask(self, inputs, mask=None): diff --git a/tensorflow/python/keras/layers/embeddings_test.py b/tensorflow/python/keras/layers/embeddings_test.py index cab176ee34..2e42e403aa 100644 --- a/tensorflow/python/keras/layers/embeddings_test.py +++ b/tensorflow/python/keras/layers/embeddings_test.py @@ -21,9 +21,11 @@ from __future__ import print_function import numpy as np from tensorflow.python import keras +from tensorflow.python.eager import backprop from tensorflow.python.framework import test_util as tf_test_util from tensorflow.python.keras import testing_utils from tensorflow.python.platform import test +from tensorflow.python.training import adagrad class EmbeddingTest(test.TestCase): @@ -78,6 +80,17 @@ class EmbeddingTest(test.TestCase): outputs = keras.backend.eval(layer(inputs)) self.assertAllClose(outputs, [[[1, 1], [2, 2], [1, 1]]]) + @tf_test_util.run_in_graph_and_eager_modes() + def test_eager_gpu_cpu(self): + l = keras.layers.Embedding(output_dim=2, input_dim=2) + l.build((None, 2)) + inputs = keras.backend.constant([[0, 1, 0]], dtype='int32') + with backprop.GradientTape() as tape: + output = l(inputs) + gs = tape.gradient(output, l.weights) + opt = adagrad.AdagradOptimizer(0.1) + opt.apply_gradients(zip(gs, l.weights)) + self.assertAllEqual(len(gs), 1) if __name__ == '__main__': test.main() -- cgit v1.2.3