“No Operation named [input] in the Graph” 在Java中

huangapple go评论81阅读模式
英文:

"No Operation named [input] in the Graph" in Java

问题

在你的Java程序中,出现了"No Operation named [input] in the Graph"的错误,尽管你的输入层已经有这个名称。这可能是因为在模型保存和加载过程中,名称可能会发生变化或丢失。你可以尝试以下解决方法:

  1. 确保保存模型时的输入层名称与加载模型时的名称匹配。你可以在Python代码中添加一个明确的名称:
model.add(tf.keras.Input(shape=(28, 28), name='input'))

然后在Java代码中使用相同的名称:

.feed("input", x)
  1. 确保TensorFlow的版本兼容性。有时,不同版本的TensorFlow在模型保存和加载时可能存在兼容性问题。尽量确保你的Python和Java TensorFlow版本匹配。

如果以上方法没有解决问题,你可能需要检查模型的结构和操作名称,以确保它们在加载时匹配。也可以尝试查看TensorFlow的官方文档或社区支持,以获取更多关于模型保存和加载的帮助。

英文:

Following this Colab exeercise from Google's ML Crash Course, I generated a model in Python for the MNIST database. The code looks as follows:

import pandas as pd
import tensorflow as tf


def create_model(my_learning_rate):
    model = tf.keras.models.Sequential()
    model.add(tf.keras.Input(shape=(28, 28), name='input'))
    model.add(tf.keras.layers.Flatten(input_shape=(28, 28)))
    model.add(tf.keras.layers.Dense(units=256, activation='relu'))
    model.add(tf.keras.layers.Dense(units=128, activation='relu'))
    model.add(tf.keras.layers.Dropout(rate=0.2))
    model.add(tf.keras.layers.Dense(units=10, activation='softmax', name='output'))
    model.compile(optimizer=tf.keras.optimizers.Adam(lr=my_learning_rate),
                  loss='sparse_categorical_crossentropy',
                  metrics=['accuracy'])
    return model


def train_model(model, train_features, train_label, epochs,
                batch_size=None, validation_split=0.1):
    history = model.fit(x=train_features, y=train_label, batch_size=batch_size,
                        epochs=epochs, shuffle=True,
                        validation_split=validation_split)
    epochs = history.epoch
    hist = pd.DataFrame(history.history)
    return epochs, hist


if __name__ == '__main__':
    (x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data()
    x_train_normalized = x_train / 255.0
    x_test_normalized = x_test / 255.0

    learning_rate = 0.003
    epochs = 50
    batch_size = 4000
    validation_split = 0.2

    my_model = create_model(learning_rate)
    epochs, hist = train_model(my_model, x_train_normalized, y_train,
                               epochs, batch_size, validation_split)

    my_model.save('my_model')

The model is saved to the "my_model" folder, as it should. Now I load it again in my Java program:

public class HelloTensorFlow {
    public static void main(final String[] args) {
        final String filePath = Paths.get("my_model").toAbsolutePath().toString();
        try (final SavedModelBundle b = SavedModelBundle.load(filePath, "serve")) {
            final Session sess = b.session();

            final Tensor<Float> x = Tensor.create(new float[1][28 * 28], Float.class);
            final List<Tensor<?>> run = sess.runner()
                    .feed("input", x)
                    .fetch("output")
                    .run();

            final float[] y = run.get(0).copyTo(new float[1]);
            System.out.println(y[0]);
        }
    }
}

The model is loaded but the runner does not work. When I execute the program, I get "No Operation named [input] in the Graph", even though my Input has this name. What am I doing wrong. I have the newest TensorFlow versions: 2.3.0 (Python) and 1.15.0 (Java).

答案1

得分: 3

我解决了它。TensorFlow 2似乎有奇怪的命名方案,但使用MetaGraphDef,这可以被解密。首先,您需要org.tensorflow.proto依赖项。然后,您可以像这样从元图中提取信息:

final MetaGraphDef metaGraphDef = MetaGraphDef.parseFrom(bundle.metaGraphDef());
final SignatureDef signatureDef = metaGraphDef.getSignatureDefMap().get("serving_default");

final TensorInfo inputTensorInfo = signatureDef.getInputsMap()
    .values()
    .stream()
    .filter(Objects::nonNull)
    .findFirst()
    .orElseThrow(() -> ...);

final TensorInfo outputTensorInfo = signatureDef.getOutputsMap()
    .values()
    .stream()
    .filter(Objects::nonNull)
    .findFirst()
    .orElseThrow(() -> ...);

现在,您可以将您创建的张量输入到inputTensorInfo.getName()中,并从outputTensorInfo.getName()中获取结果。

英文:

I solved it. TensorFlow 2 seems to have odd naming schemes, but using the MetaGraphDef, this can be deciphered. First, you need the org.tensorflow.proto dependency. Then, you can extract the information from the meta graph like so:

final MetaGraphDef metaGraphDef = MetaGraphDef.parseFrom(bundle.metaGraphDef());
final SignatureDef signatureDef = metaGraphDef.getSignatureDefMap().get("serving_default");

final TensorInfo inputTensorInfo = signatureDef.getInputsMap()
    .values()
    .stream()
    .filter(Objects::nonNull)
    .findFirst()
    .orElseThrow(() -> ...);

final TensorInfo outputTensorInfo = signatureDef.getOutputsMap()
    .values()
    .stream()
    .filter(Objects::nonNull)
    .findFirst()
    .orElseThrow(() -> ...);

Now you can feed the tensor you created into the name from inputTensorInfo.getName() and fetch the results from outputTensorInfo.getName().

huangapple
  • 本文由 发表于 2020年7月31日 01:41:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/63178526.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定