TensorFlow似乎同时修改了类和示例对象

xfb7svmp  于 2022-11-25  发布在  其他
关注(0)|答案(2)|浏览(146)

我观察到TensorFlow方法,如assign_addassign_sub,修改了对象和类的变量(如果存在的话)。下面是一个简单的代码来重现我的观察。有人能澄清一下这个行为吗(assign_subassign_add修改了类和示例属性)?

#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}')

输出量:

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

使用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()}')

输出量:

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
ymzxtsji

ymzxtsji1#

a是类属性。b是示例属性。
然而,像这样的扩充作业

self.a += to_add
self.a -= to_sub

不会修改您认为通过示例访问的类属性。

self.a = self.a.__iadd__(to_add)
self.a = self.a.__isub__(to_sub)

因此第一次使用时,在RHS上访问class属性,但随后创建了一个新的示例属性,该示例属性在所有将来的调用中遮蔽class属性。
如果你想通过一个示例来修改一个类属性,你需要明确地修改它。一个可能的解决方案是:

type(self).a += to_add

您的TensorFlow代码不会进行任何赋值、增强或其他操作。它只是对self.a解析为的任何内容的方法调用,即类属性。不会创建新的示例属性。

6jygbczu

6jygbczu2#

当类使用你创建的变量和init()函数初始化时,你需要理解类和局部变量。assign_add()和assign_sub()被更新并等待值更新,但python类一旦释放或重新赋值就会被擦除。
示例:var1和var2都从10开始,var2以100作为局部变量,在类及其函数中使用。通过为var1分配更多的30作为局部变量。更新可以达到var1为40,var2为10,因为var2从不在函数之外,结果为100。

import os
from os.path import exists
import tensorflow as tf

import matplotlib.pyplot as plt

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""
: Class and Functions
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""
class MyDenseLayer(tf.keras.layers.Layer):
    var1 = tf.Variable([10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0])
    var2 = tf.Variable([10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0])
    
    def __init__(self, num_outputs):
        super(MyDenseLayer, self).__init__()
        self.num_outputs = num_outputs
        self.var2 = self.var1 * 10.0
        
    def build(self, input_shape):
        self.kernel = self.add_weight("kernel",
        shape=[int(input_shape[-1]),
        self.num_outputs])

    def call(self, inputs):
        self.var1.assign_add([30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0])
        
        temp = tf.constant( self.var2 ).numpy()
        return temp

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""
: Variables
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""
start = 3
limit = 33
delta = 3

# Create DATA
sample = tf.range(start, limit, delta)
sample = tf.cast( sample, dtype=tf.float32 )

# Initail, ( 10, 1 )
sample = tf.constant( sample, shape=( 10, 1 ) )
layer = MyDenseLayer(10)
data = layer(sample)

print( tf.constant( MyDenseLayer.var1 ).numpy() )
print( tf.constant( MyDenseLayer.var2 ).numpy() )
print( data )

输出:本地var1、本地var2(无赋值函数)和数据(类更新的结果)

[40. 40. 40. 40. 40. 40. 40. 40. 40. 40.]
[10. 10. 10. 10. 10. 10. 10. 10. 10. 10.]
[100. 100. 100. 100. 100. 100. 100. 100. 100. 100.]

相关问题