Issue
I have observed that the TensorFlow
methods like assign_add
and assign_sub
modify the variables of both object and class (if exist). Here is a simple code to reproduce my observation. Can anyone please clarify about this behavior (assign_sub
and assign_add
modifying both class and instance attributes)?
#a python class
class myc_base():
a=1.
def __init__(self, b=1.):
self.b=b
def add(self, to_add=1.):
self.a+=to_add
self.b+=to_add
def sub(self, to_sub=1.):
self.a-=to_sub
self.b-=to_sub
obj_base=myc_base()
print(f'Init. -- class.a: {myc_base.a} | obj.a: {obj_base.a}, obj.b: {obj_base.b}')
obj_base.add(5.)
print(f'after add -- class.a: {myc_base.a} | obj.a: {obj_base.a}, obj.b: {obj_base.b}')
obj_base.sub(2.)
print(f'after sub -- class.a: {myc_base.a} | obj.a: {obj_base.a}, obj.b: {obj_base.b}')
Output:
Init. -- class.a: 1.0 | obj.a: 1.0, obj.b: 1.0
after add -- class.a: 1.0 | obj.a: 6.0, obj.b: 6.0
after sub -- class.a: 1.0 | obj.a: 4.0, obj.b: 4.0
With TensorFlow:
import tensorflow as tf
#a class for tf operations
class myc_tf():
a=tf.Variable(1.)
def __init__(self, b=tf.Variable(1.)):
self.b=b
def add(self, to_add=1.):
self.a.assign_add(to_add)
self.b.assign_add(to_add)
def sub(self, to_sub=1.):
self.a.assign_sub(to_sub)
self.b.assign_sub(to_sub)
obj_tf=myc_tf()
print(f'Init. -- class.a: {myc_tf.a.numpy()} | obj.a: {obj_tf.a.numpy()}, obj.b: {obj_tf.b.numpy()}')
obj_tf.add(5.)
print(f'after add -- class.a: {myc_tf.a.numpy()} | obj.a: {obj_tf.a.numpy()}, obj.b: {obj_tf.b.numpy()}')
obj_tf.sub(2.)
print(f'after sub -- class.a: {myc_tf.a.numpy()} | obj.a: {obj_tf.a.numpy()}, obj.b: {obj_tf.b.numpy()}')
Output:
Init. -- class.a: 1.0 | obj.a: 1.0, obj.b: 1.0
after add -- class.a: 6.0 | obj.a: 6.0, obj.b: 6.0
after sub -- class.a: 4.0 | obj.a: 4.0, obj.b: 4.0
Solution
a
is a class attribute. b
is an instance attribute.
However, augmented assignments like
self.a += to_add
self.a -= to_sub
are not modifying the class attribute you think you are accessing via the instance. They are really equivalent to
self.a = self.a.__iadd__(to_add)
self.a = self.a.__isub__(to_sub)
so the first time one is used, the class attribute is accessed on the RHS, but a new instance attribute is then created, and that instance attribute shadows the class attribute in all future calls.
If you want to modify a class attribute via an instance, you need to be explicit about it. One possible solution:
type(self).a += to_add
Your TensorFlow code doesn't make any assignments, augmented or otherwise. It's simply a method call on whatever self.a
resolves to, which is the class attribute. No new instance attribute is ever created.
Answered By - chepner
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.