Python 如何编写类,使神经网络能够访问Tensorflow中的层

Python 如何编写类,使神经网络能够访问Tensorflow中的层,python,tensorflow,oop,Python,Tensorflow,Oop,我一直在训练一个用Tensorflow编写的网络,一切都很好,但现在我需要可视化与每层过滤器权重相关的一些指标。所以我需要能够访问层,我知道使用Keras的模型非常简单,但我相信有更好的方法使用Tensorflow定义类,以便可以访问层 我的代码: import tensorflow as tf from tensorflow.keras.layers import (Activation, Conv2D, BatchNormalization) from tensorflow.keras.op

我一直在训练一个用Tensorflow编写的网络,一切都很好,但现在我需要可视化与每层过滤器权重相关的一些指标。所以我需要能够访问层,我知道使用Keras的模型非常简单,但我相信有更好的方法使用Tensorflow定义类,以便可以访问层

我的代码:

import tensorflow as tf
from tensorflow.keras.layers import (Activation, Conv2D, BatchNormalization)
from tensorflow.keras.optimizers import Adam

class neural_net():

    def __init__(self, x):

        self.x = x
        self.layers = self.predictor(self.x)
        self.loss = tf.reduce_mean(tf.squared_difference(self.layers[3], self.x), name = 'mse_loss')
    
    def predictor(self, x):
        layer0 = Conv2D(64, kernel_size=(3, 3), input_shape=(512,512,3), padding='same', name = 'conv1')(x)
        layer1 = Activation('relu')(layer0)
        layer2 = BatchNormalization()(layer1)
        pred = Conv2D(3, (3,3), activation='sigmoid', padding='same',name = 'decoded')(layer2)
        return [layer0,layer1,layer2,pred]

x = tf.compat.v1.placeholder(tf.float32, shape=(None,512,512,3),name = 'x')
net = neural_net(x)
loss = net.loss
layers = net.layers
train_op = tf.train.AdamOptimizer(1e-4).minimize(loss)

w=[]
for layer in net.layers():
    w.append(layer.get_weights())
这会产生以下错误:

AttributeError:“Tensor”对象没有属性“get\u weights”


我还看到了一些示例,其中显示了使用
build
call
方法的类,但我不知道如何在我的案例中使用它们(oop知识有限)。

我会按照您的建议创建一个列表,并将层放入其中。然后,您可以修改
predictor
方法来迭代层并按正确的顺序调用它们。例如:

import tensorflow as tf
from tensorflow.keras.layers import (Activation, Conv2D, BatchNormalization)
from tensorflow.keras.optimizers import Adam

class neural_net():

    def __init__(self, x, y):

        self.x = x
        self.layers = [Conv2D(64, kernel_size=(3, 3), input_shape=(512,512,3), padding='same', name = 'conv1'), 
                       Activation('relu'), 
                       BatchNormalization(), 
                       Conv2D(3, (3,3), activation='sigmoid', padding='same',name = 'decoded')]
        self.pred = self.predictor(self.x)
        self.loss = tf.reduce_mean(tf.squared_difference(self.pred, self.x), name = 'mse_loss')
    
    def predictor(self, x):
        for layer in self.layers:
            x = layer(x)
        return x

x = tf.compat.v1.placeholder(tf.float32, shape=(None,512,512,3),name = 'x')
net = neural_net(x)
loss = net.loss
pred = net.pred
train_op = tf.train.AdamOptimizer(1e-4).minimize(loss)

虽然我认为这就是你的意思,但我怀疑这会像你期望的那样起作用。您不想使用Keras提供的api的确切原因是什么?你可以像你说的那样,通过迭代层来获得权重。

我会像你建议的那样创建一个列表,并将层放入其中。然后,您可以修改
predictor
方法来迭代层并按正确的顺序调用它们。例如:

import tensorflow as tf
from tensorflow.keras.layers import (Activation, Conv2D, BatchNormalization)
from tensorflow.keras.optimizers import Adam

class neural_net():

    def __init__(self, x, y):

        self.x = x
        self.layers = [Conv2D(64, kernel_size=(3, 3), input_shape=(512,512,3), padding='same', name = 'conv1'), 
                       Activation('relu'), 
                       BatchNormalization(), 
                       Conv2D(3, (3,3), activation='sigmoid', padding='same',name = 'decoded')]
        self.pred = self.predictor(self.x)
        self.loss = tf.reduce_mean(tf.squared_difference(self.pred, self.x), name = 'mse_loss')
    
    def predictor(self, x):
        for layer in self.layers:
            x = layer(x)
        return x

x = tf.compat.v1.placeholder(tf.float32, shape=(None,512,512,3),name = 'x')
net = neural_net(x)
loss = net.loss
pred = net.pred
train_op = tf.train.AdamOptimizer(1e-4).minimize(loss)

虽然我认为这就是你的意思,但我怀疑这会像你期望的那样起作用。您不想使用Keras提供的api的确切原因是什么?您可以像您所说的那样通过迭代层来获得权重。

我认为您应该使用Keras(如果您可以将其称为API的话)。本质上,它是从Keras
模型继承而来的(有点像顺序API),因此您可以同样使用它。它将使您的模型能够模拟Keras模型的行为,例如,您可以调用
model.fit()
model.summary()

然后,您应该在构造函数中定义层(
\uuuu init\uuu
部分),该部分将层设置为实例变量,并允许您访问层,如
model.layer1
。调用模型时,需要定义的
call()
方法将确定其行为(张量将通过层)。除此之外,所有操作都将自动完成,因为行为已由
模型
类预定义

下面是一个关于如何做到这一点的示例:

import tensorflow as tf
from tensorflow.keras import Model

inputs = tf.random.uniform(shape=(8, 512, 512, 3), minval=0, maxval=1)


class MyModel(Model):
    def __init__(self):
        super(MyModel, self).__init__()
        self.layer0 = tf.keras.layers.Conv2D(64, kernel_size=(3, 3), 
            padding='same', name='conv1')
        self.layer1 = tf.keras.layers.Activation('relu')
        self.layer2 = tf.keras.layers.BatchNormalization()

    def call(self, x, **kwargs):
        x = self.layer0(x)
        x = self.layer1(x)
        x = self.layer2(x)
        return x


model = MyModel()

model.build(input_shape=(1, 512, 512, 3))

model(inputs)
您还可以访问各个层,就像您习惯于:

model.layers
[,,
,
]
如果您想将loss和predict功能集成到模型本身,恐怕需要一些面向对象的技能


如果我的答案遗漏了什么,请告诉我。你可以在我的一本书中找到玩具数据集的类似子类API示例,即MNIST和Iris数据集。

我认为你应该使用Keras(如果你可以称之为API的话)。本质上,它是从Keras
模型继承而来的(有点像顺序API),因此您可以同样使用它。它将使您的模型能够模拟Keras模型的行为,例如,您可以调用
model.fit()
model.summary()

然后,您应该在构造函数中定义层(
\uuuu init\uuu
部分),该部分将层设置为实例变量,并允许您访问层,如
model.layer1
。调用模型时,需要定义的
call()
方法将确定其行为(张量将通过层)。除此之外,所有操作都将自动完成,因为行为已由
模型
类预定义

下面是一个关于如何做到这一点的示例:

import tensorflow as tf
from tensorflow.keras import Model

inputs = tf.random.uniform(shape=(8, 512, 512, 3), minval=0, maxval=1)


class MyModel(Model):
    def __init__(self):
        super(MyModel, self).__init__()
        self.layer0 = tf.keras.layers.Conv2D(64, kernel_size=(3, 3), 
            padding='same', name='conv1')
        self.layer1 = tf.keras.layers.Activation('relu')
        self.layer2 = tf.keras.layers.BatchNormalization()

    def call(self, x, **kwargs):
        x = self.layer0(x)
        x = self.layer1(x)
        x = self.layer2(x)
        return x


model = MyModel()

model.build(input_shape=(1, 512, 512, 3))

model(inputs)
您还可以访问各个层,就像您习惯于:

model.layers
[,,
,
]
如果您想将loss和predict功能集成到模型本身,恐怕需要一些面向对象的技能


如果我的答案遗漏了什么,请告诉我。您可以在我的一本书中找到玩具数据集的类似子类API示例,即MNIST和Iris数据集。

您好,非常感谢!这似乎奏效了。为什么你认为这不是个好主意?如果更好的话,我可以尝试使用Keras的
Model
API,但Tensorflow本身似乎提供了更多的控制,所以我习惯了,我在尝试转换代码时遇到了麻烦。我对损失值是否会得到更新有些怀疑。但是我想如果你使用的是tensorflow,那么计算图应该会使它成为可能,并且不会发生错误。如果我的建议适用于你的用例,考虑接受我的回答。我看到你编辑了你的问题。更新代码的问题在于,您将层的输出放入列表中,而不是层本身。使用我提供的代码,其中层在列表中,self.predictor调用这些层。我认为当问题是最新的,并且有其他高质量的答案时,让用户接受答案是不合适的。如果OP给出的反馈是你的答案是他所需要的一切,或者问题提出后已经过了很长时间,或者没有其他答案,那将是另一回事。但是,当有其他答案和其他答案刚刚公布,我会说这不是好的做法。OP说,我的答案似乎工作,并在此基础上,我要求他们考虑接受我的答案,如果它真的解决了他们的问题。我不认为这是不合适的,我也不想让你接受我的答案,而不是你的答案。我很抱歉,如果你觉得这是什么样子。嗨,非常感谢!这似乎奏效了。为什么你认为这不是个好主意?我可以尝试使用Keras的
模型