2

我正在尝试在 tensorflow 模型中使用现有的嵌入,嵌入的大小大于 2Gb,这使得我最初尝试这样做不成功:

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.

我正在使用基于 Estimator API 的 AWS SageMaker,并且会话中图形的实际运行发生在幕后,因此我不确定如何初始化一些占位符以进行嵌入。如果有人能够分享如何根据 EstimatorAPI 进行此类初始化,那将很有帮助。

4

2 回答 2

14

如果将initializer参数指定为tf.get_variable(),则初始值GLOVE_MATRIX将存储在图形中并超过 2Gb。一个好的答案解释了如何加载嵌入。


这是我们使用初始化程序的第一个示例,并且图形 def 大约为 4Mb,因为它将(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

在估算器中

对于 Estimators,我们无法直接访问 Session。初始化嵌入的一种方法是使用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

于 2018-01-13T18:38:21.533 回答
0

Olivier Moindrot 已经给出了很好的方法,我只是添加了另一种我发现的方法。为了避免 2GB 限制错误,您应该真正关心您使用的操作。tensorflow中的Graph可以序列化成protobuf(google设计的一种交换格式)。2GB 错误是在创建操作时检查它的 attr_value 超过 2GB 时触发的,因此我们必须避免将大值打包到该操作的 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()
于 2018-07-18T16:02:01.717 回答