在Tensorflow中循环训练

时间:2019-04-16 07:48:27

标签: python tensorflow while-loop

我试图将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:“ Tensor”对象没有属性“ assign”

即使阅读文档,我也不太了解发生了什么。 weights毕竟是Variable。怎样才能使训练循环正确?

2 个答案:

答案 0 :(得分:0)

您试图在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)

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

示例:

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]]

答案 1 :(得分:0)

结果是,所缺少的是这样一个事实,即无法将循环内的变量分配为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)