【问题标题】:Training while loop in Tensorflow在 Tensorflow 中训练 while 循环
【发布时间】:2019-04-16 20:49:24
【问题描述】:

我尝试将 Python 端的训练循环转换为 Tensorflow,以(假设地)使代码运行得更快——不必不断地将控制权交给 cpu。但是,我无法使用tf.while_loop 进行管理。

这是有效的代码:

import numpy as np
import tensorflow as tf

from tqdm import tqdm
from sklearn.datasets import load_iris
from sklearn.preprocessing import RobustScaler

x, y = load_iris(True)
x = RobustScaler().fit_transform(x)

shape = (10, 10)
max_epochs = 1000


graph = tf.Graph()
sess = tf.Session(graph=graph)

x = x.astype(np.float64)


# Construct graph
with graph.as_default():
    weights = tf.get_variable(
        'weights', shape, initializer=tf.constant_initializer, dtype=tf.float64
    )
    curr_epoch = tf.placeholder(dtype=tf.int64, shape=())

    with tf.name_scope('data'):
        data = tf.data.Dataset.from_tensor_slices(x)
        data = data.shuffle(buffer_size=10000)
        data = data.repeat(max_epochs)
        data = data.batch(1)
        data = data.make_one_shot_iterator().get_next()

    with tf.name_scope('update'):
        update_op = make_update_op(weights)

    init = tf.global_variables_initializer()


sess.run(init)

for i in tqdm(range(max_epochs)):
    for _ in range(x.shape[0]):
        sess.run(update_op, feed_dict={
            curr_epoch: i
        })

np_weights = sess.run(weights)
print(np_weights) # Correctly prints an array of 150's.

现在,如果我创建一个更新函数来传递tf.while_loop,则会引发错误。

def make_update_op(w):
    return w.assign(
        w + 0.001
    )

# In the code above:
update_op = tf.while_loop(lambda _: True, make_update_op, (weights,), maximum_iterations=x.shape[0])

# No inner loop:
for i in tqdm(range(max_epochs)):
    sess.run(update_op, feed_dict={
        curr_epoch: i
    })

第 22 行,在 make_update_op 中 return w.assign( AttributeError:“张量”对象没有属性“分配”

即使阅读了文档,我也不太明白发生了什么。 weights 毕竟是 Variable。可以做些什么来正确地进行训练循环?

【问题讨论】:

    标签: python tensorflow while-loop


    【解决方案1】:

    您尝试在 while 循环中分配新值的张量是多个操作张量序列的结果(操作是图中的节点,而张量是有向边)。特别是,while 循环会产生:

    Variable/Read-->while/Enter-->while/Merge-->while/Switch-->while/Identity

    您要在此处分配的是张量 while/Identity

    tf.while_loop 通常用于迭代张量的维度(也包括 None - 未知维度)。您正在尝试迭代完全定义的变量。您无需为此创建tf.while_loop。只需创建更新每个变量的操作并将这些操作组合在一起:

    update_ops = [w.assign(w + 0.001) for w in weights]
    update_op = tf.group(update_ops)
    

    现在,当您使用tf.Session() 接口执行update_op 时,它将更新所有变量。

    例子:

    import tensorflow as tf
    
    v1 = tf.Variable(tf.ones((1, 2), dtype=tf.float32))
    v2 = tf.Variable(2*tf.ones((1, 3), dtype=tf.float32))
    
    update_ops = [w.assign(w + 0.001) for w in [v1, v2]]
    update_op = tf.group(update_ops)
    
    with tf.Session() as sess:
        sess.run(tf.global_variables_initializer())
        print('before update:')
        print(v1.eval(), v2.eval())
        print('after update:')
        sess.run(update_op) # <-- update your variables
        print(v1.eval(), v2.eval())
    
        # before update:
        # [[1. 1.]] [[2. 2. 2.]]
        # after update:
        # [[1.001 1.001]] [[2.001 2.001 2.001]]
    

    【讨论】:

    • 我特意简化了这个例子。正确的循环包括更多操作。此外,循环要运行数千次。我被警告不要在 Python 循环中构造这样的操作。您是否建议这样做?
    • 我认为你误解了 TF 图形模式的工作原理。在图形模式下,您首先创建操作,然后执行它们。我的 Python 循环创建了这些操作,稍后我将使用 Session 接口执行这些操作。建议您不要使用 Python 循环的人可能意味着尽可能避免执行 Python 代码并改用 TF API。操作的创建与此无关。
    • 任何变量的任何更新都是一个操作。如果不创建执行该操作的操作,您没有任何其他方法可以更新变量。如果您想每次分配不同的值,请使用占位符并向其提供您希望变量递增/分配的值。
    • 我明白创建操作然后执行它们的含义。这正是我提出问题的原因。避免在图上创建数以万计的重复操作不是可取的吗?示例来源:How not to program a tensorflow graph(此评论属于上面,但由于编辑限制,我不得不重做)
    • 是的,但我想有一种更优雅的方式来按顺序执行一组操作,而不是创建每个展开的操作。我想在每次迭代时重复使用当前值,因此称为“训练循环”。
    【解决方案2】:

    事实证明,所缺少的只是不能将循环内的变量赋值为Vlad pointed out。相反,可以返回一个变量的新值。

    def make_update_op(w):
        return w + 0.001
    
    new_w = tf.while_loop(lambda _: True, make_update_op, (weights,), maximum_iterations=x.shape[0])
    update_op = weights.assign(new_w)
    

    要使用更多的变量,需要从函数中返回相同数量的变量并在 Python 中解压,但原理是一样的。

    def make_update_op(w, d):
        return w + 0.001, d
    
    new_w, _ = tf.while_loop(lambda *_: True, make_update_op, (weights, data), maximum_iterations=x.shape[0])
    update_op = weights.assign(new_w)
    

    【讨论】:

    • @Vlad 你是什么意思?这产生了正确的结果,也适用于更复杂的任务。
    • 放两个变量而不是(weights, ),例如(var1, var2)。它不会工作
    • @Vlad 观察什么?我就是这样做的,同时输入权重和训练数据。
    • 当你对TF有更多经验的时候,回到这里承认我是对的!祝你好运,兄弟! (ps 仍然无法同时处理多个变量/数据块!)
    • @Vlad 我能说什么,但完整的算法使用 Iris 数据集产生了一个清晰的解决方案并且没有抛出任何错误:D 也许你是对的,这不是我第一次错了,但仅仅吸引经验也不会飞得很远。
    猜你喜欢
    • 2021-09-13
    • 2020-02-22
    • 2020-06-23
    • 2021-02-24
    • 2020-04-13
    • 1970-01-01
    • 2016-03-09
    • 2019-07-04
    • 1970-01-01
    相关资源
    最近更新 更多