Как инициализировать слой встраивания в Estimator API

Я пытаюсь использовать существующие вложения в модели тензорного потока, размер встраивания превышает 2 ГБ, и это делает мою первоначальную попытку сделать это неудачной:

embedding_var = tf.get_variable(
        "embeddings", 
        shape=GLOVE_MATRIX.shape, 
        initializer=tf.constant_initializer(np.array(GLOVE_MATRIX))
)

Что дало мне эту ошибку:

 Cannot create a tensor proto whose content is larger than 2GB.

Я использую AWS SageMaker, который основан на Estimator API, и фактическое выполнение графика в сеансе происходит за сценой, поэтому я не уверен, как инициализировать некоторые заполнители для встраивания, учитывая это. Было бы полезно, если бы кто-нибудь смог поделиться способом такой инициализации с точки зрения EstimatorAPI.


person Stanislav Levental    schedule 11.01.2018    source источник


Ответы (2)


Если вы укажете аргумент initializer для tf.get_variable(), начальное значение GLOVE_MATRIX будет сохранено в графе и превысит 2 Гб. Хороший ответ объясняет, как вообще загружать вложения.


Вот первый пример, где мы используем инициализатор, а определение графа составляет около 4 МБ, поскольку в нем хранится матрица (1000, 1000).

size = 1000
initial_value = np.random.randn(size, size)
x = tf.get_variable("x", [size, size], initializer=tf.constant_initializer(initial_value))

sess = tf.Session()
sess.run(x.initializer)

assert np.allclose(sess.run(x), initial_value)

graph = tf.get_default_graph()
print(graph.as_graph_def().ByteSize())  # should be 4000394

Вот лучшая версия, где мы ее не храним:

size = 1000
initial_value = np.random.randn(size, size)
x = tf.get_variable("x", [size, size])

sess = tf.Session()
sess.run(x.initializer, {x.initial_value: initial_value})

assert np.allclose(sess.run(x), initial_value)

graph = tf.get_default_graph()
print(graph.as_graph_def().ByteSize())  # should be 1203

В оценщиках

Для оценщиков у нас нет прямого доступа к сеансу. Способом инициализации встраивания может быть использование tf.train.Scaffold. Вы можете передать ему аргумент init_fn, в котором вы инициализируете встраиваемую переменную, не сохраняя фактическое значение в графе def.

def model_fn(features, labels, mode):
    size = 10
    initial_value = np.random.randn(size, size).astype(np.float32)
    x = tf.get_variable("x", [size, size])

    def init_fn(scaffold, sess):
        sess.run(x.initializer, {x.initial_value: initial_value})
    scaffold = tf.train.Scaffold(init_fn=init_fn)

    loss = ...
    train_op = ...

    return tf.estimator.EstimatorSpec(mode, loss=loss, train_op=train_op, scaffold=scaffold)

Хорошим моментом использования встроенного Scaffold является то, что он инициализирует встраивание только при первом вызове train_input_fn. Для будущих вызовов он больше не будет запускаться init_fn.

person Olivier Moindrot    schedule 13.01.2018

Оливье Муандро уже дал хорошие подходы, я просто добавлю еще один подход, который я нашел. Чтобы избежать ошибки ограничения 2 ГБ, вы должны действительно заботиться об операциях, которые вы использовали. График в тензорном потоке сериализуется в protobuf (формат обмена, разработанный Google). Ошибка 2 ГБ возникает, когда создается операция, когда проверяется, что значение attr_value превышает 2 ГБ, поэтому нам следует избегать упаковки больших значений в это поле операции attr_value. Я просто предоставляю другую функцию tf.variable.load, и эта функция не добавит дополнительных вещей в пример кода Graph:

graph2 = tf.Graph()
size = 1000
toy_embedding = np.random.randn(size, size)  # you can create your own np.ndarray

with graph2.as_default() as g2:
    emb2 = tf.Variable(initial_value=tf.ones(shape=(size,size)), name='emb2')
    sess = tf.Session()
    init_op = tf.global_variables_initializer()
    sess.run(init_op)
    emb2.load(toy_embedding, session = sess)
    out = sess.run(emb2)
    print (out)

graph2.as_graph_def().ByteSize()
person Philip Zhou    schedule 18.07.2018