我试图将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
。怎样才能使训练循环正确?
答案 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)