Переназначение переменных в Tensorflow и области видимости
Я пытаюсь понять разницу между тем, почему одна из этих реализаций работает, а другая нет. Я пытаюсь представить некоторую геометрию в тензорном потоке.
Во-первых, вспомогательный файл, d_math.py
! / usr / bin / env python3
импортировать numpy как np импортировать тензор потока как tf
dtype = tf.float64
def skew_symmetric(vector):
#Creates a tensorflow matrix which is a skew-symmetric version of the input vector
return tf.stack([(0., -vector[2], vector[1]), (vector[2], 0., -vector[0]), (-vector[1], vector[0], 0.)], axis=0)
Вот реализация 1:
#!/usr/bin/env python3
import numpy as np
import tensorflow as tf
import d_math as d
import math
import time
class Joint():
def __init__(self, axis, pos): #TODO: right now only revolute:
axis_ = tf.Variable(axis, dtype=d.dtype)
axis_ /= tf.linalg.norm(axis)
theta_ = tf.Variable(0.0, dtype=d.dtype) #Always at the 0 angle config
self.theta_ = theta_
self.R_ = tf.cos(theta_) * tf.eye(3, dtype=d.dtype) + d.skew_symmetric(axis_) + (1. - tf.cos(theta_)) * tf.einsum('i,j->ij', axis_, axis_)
joint = Joint(np.array([1.0, 1.0, 1.0]), 0.0)
init = tf.global_variables_initializer()
with tf.Session() as session:
session.run(init)
print(joint.R_)
print(joint.R_.eval())
joint.theta_ = joint.theta_.assign(math.pi/4.)
session.run(joint.theta_)
print(joint.R_.eval())
Вышеприведенная версия обновляет тета, и затем я получаю оценку двух матриц вращения, одна для тета = 0 и одна для тета = пи /4.
Затем я попытался немного реорганизовать свой код, добавив глобальную переменную сеанса, созданную в отдельном файле, и скрыл в API столько тензорного потока, сколько мог на данный момент:
версия 2:
#!/usr/bin/env python3
import numpy as np
import tensorflow as tf
import d_math as d
import math
import time
import session as s
class Joint():
def __init__(self, axis, pos): #TODO: right now only revolute:
axis_ = tf.Variable(axis, dtype=d.dtype)
axis_ = axis_ / tf.linalg.norm(axis)
theta_ = tf.Variable(0.0, dtype=d.dtype) #Always at the 0 angle config
self.theta_ = theta_
self.R_ = tf.cos(theta_) * tf.eye(3, dtype=d.dtype) + d.skew_symmetric(axis_) + (1. - tf.cos(theta_)) * tf.einsum('i,j->ij', axis_, axis_)
def set_theta(self, theta):
self.theta_.assign(theta)
s.session.run(self.theta_)
joint = Joint(np.array([1.0, 1.0, 1.0]), 0.0)
init = tf.global_variables_initializer()
with s.session as session:
session.run(init)
print(joint.R_)
print(joint.R_.eval())
#joint.theta_ = joint.theta_.assign(math.pi/4.)
joint.set_theta(math.pi/4.)
print(joint.R_.eval())
session.py можно увидеть здесь:
#!/usr/bin/env python3
import tensorflow as tf
session = tf.Session()
Это дает матрицу R с тета = 0 для обеих оценок.
Может кто-нибудь объяснить мне, почему реализация 2 не работает?
1 ответ
tf.assign
возвращает ссылку на обновленную переменную. Согласно документам: Returns: A Tensor that will hold the new value of 'ref' after the assignment has completed.
В первом примере вы на самом деле используете обновленную ссылку:
joint.theta_ = joint.theta_.assign(math.pi/4.)
session.run(joint.theta_)
print(joint.R_.eval())
Во втором примере вы не используете обновленную ссылку:
def set_theta(self, theta):
not_used = self.theta_.assign(theta)
s.session.run(self.theta_)
Я думаю, что если вы используете обновленную ссылку, она должна работать:
def set_theta(self, theta):
self.theta_ = self.theta_.assign(theta)
s.session.run(self.theta_)
Также было бы целесообразно не перезаписывать исходные ссылки на тензор, поэтому я бы создал новый атрибут для обновленной переменной var:
def set_theta(self, theta):
self.theta_updated_ = self.theta_.assign(theta)
s.session.run(self.theta_updated_)
# ...
print(self.theta_updated_.eval()) # <<< This should give you updated value
Важно: Однако работает print(joint.R_.eval())
НЕ МОЖЕТ дать вам обновленное значение еще, потому что операция self.R_
не принуждается зависеть от обновленной ссылки self.theta_updated_
и вам, возможно, придется использовать tf.control_dependencies
для принудительного исполнения self.R_
операция только после обновления. Например:
with tf.control_dependencies([self.theta_updated_]):
self.R_ = tf.cos(theta_) * # ...
Заключительное примечание: назначение значений переменным не говорит автоматически другим операциям, что им нужно ждать, пока это назначение не будет выполнено. Я обнаружил, что это трудный путь. Вот несколько отрывков, которые я написал, которые отслеживают поведение переменных при использовании tf.assign. Я рекомендую внимательно изучить фрагмент: Optimizing original variables that have been updated using tf.assign
, Фрагменты автономны.