Переназначение переменных в 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, Фрагменты автономны.

Другие вопросы по тегам