TF 2.2: недопустимый аргумент: ожидается, что arg [0] будет ресурсом, но предоставляется float - PullRequest
1 голос
/ 21 июня 2020

Я пытаюсь выполнить классификацию изображений с помощью API TensorFlow 2.2.0 C ++. Я обучил простой con vnet, используя пакет tenorflow 2.2 pip, установленный с помощью pip. Я сохраняю свою модель, используя функцию model.save(save_format='tf', filepath='../../graphs/test0', include_optimizer=True) python, а затем пытаюсь загрузить и выполнить классификацию с помощью следующего кода:

#include <stdlib.h>

#include <fstream>
#include <iostream>
#include <string>
#include <vector>

#include "class_name.h"
#include "tensorflow/cc/ops/const_op.h"
#include "tensorflow/cc/ops/standard_ops.h"
#include "tensorflow/cc/saved_model/loader.h"
#include "tensorflow/cc/saved_model/tag_constants.h"
#include "tensorflow/core/framework/tensor.h"
#include "tensorflow/core/graph/default_device.h"
#include "tensorflow/core/graph/graph_def_builder.h"
#include "tensorflow/core/lib/core/errors.h"
#include "tensorflow/core/lib/core/stringpiece.h"
#include "tensorflow/core/lib/core/threadpool.h"
#include "tensorflow/core/lib/io/path.h"
#include "tensorflow/core/lib/strings/stringprintf.h"
#include "tensorflow/core/platform/env.h"
#include "tensorflow/core/platform/init_main.h"
#include "tensorflow/core/platform/logging.h"
#include "tensorflow/core/platform/types.h"
#include "tensorflow/core/public/session.h"
#include "tensorflow/core/util/command_line_flags.h"

using namespace tensorflow;
using tensorflow::Flag;
using tensorflow::Status;
using tensorflow::string;
using tensorflow::Tensor;

static Status ReadEntireFile(tensorflow::Env* env, const string& filename,
                             Tensor* output) {
  tensorflow::uint64 file_size = 0;
  TF_RETURN_IF_ERROR(env->GetFileSize(filename, &file_size));

  string contents;
  contents.resize(file_size);

  std::unique_ptr<tensorflow::RandomAccessFile> file;
  TF_RETURN_IF_ERROR(env->NewRandomAccessFile(filename, &file));

  tensorflow::StringPiece data;
  TF_RETURN_IF_ERROR(file->Read(0, file_size, &data, &(contents)[0]));
  if (data.size() != file_size) {
    return tensorflow::errors::DataLoss("Truncated read of '", filename,
                                        "' expected ", file_size, " got ",
                                        data.size());
  }
  output->scalar<tstring>()() = tstring(data);
  return Status::OK();
}

//Read the image file, apply appropriate decoding depending on type of image
int TensorFromFile(string file_name, const int input_height, const int input_width, std::vector<Tensor>* out_tensors) {
  Status status;
  const float input_mean = 0.;
  const float input_std = 255.;

  auto root = tensorflow::Scope::NewRootScope();
  using namespace ::tensorflow::ops;  // NOLINT(build/namespaces)

  string input_name = "file_reader";
  string output_name = "normalized";

  // read file_name into a tensor named input
  Tensor input(tensorflow::DT_STRING, tensorflow::TensorShape());
  status = (ReadEntireFile(tensorflow::Env::Default(), file_name, &input));
  LOG(INFO) << status.ToString();

  // use a placeholder to read input data
  auto file_reader =
      Placeholder(root.WithOpName("input"), tensorflow::DataType::DT_STRING);

  std::vector<std::pair<string, tensorflow::Tensor>> inputs = {
      {"input", input},
  };

  // Now try to figure out what kind of file it is and decode it.
  const int wanted_channels = 3;
  tensorflow::Output image_reader;
  if (tensorflow::str_util::EndsWith(file_name, ".png")) {
    image_reader = DecodePng(root.WithOpName("png_reader"), file_reader,
                             DecodePng::Channels(wanted_channels));
  } else if (tensorflow::str_util::EndsWith(file_name, ".gif")) {
    // gif decoder returns 4-D tensor, remove the first dim
    image_reader =
        Squeeze(root.WithOpName("squeeze_first_dim"),
                DecodeGif(root.WithOpName("gif_reader"), file_reader));
  } else if (tensorflow::str_util::EndsWith(file_name, ".bmp")) {
    image_reader = DecodeBmp(root.WithOpName("bmp_reader"), file_reader);
  } else {
    // Assume if it's neither a PNG nor a GIF then it must be a JPEG.
    image_reader = DecodeJpeg(root.WithOpName("jpeg_reader"), file_reader,
                              DecodeJpeg::Channels(wanted_channels));
  }
  // Now cast the image data to float so we can do normal math on it.
  auto float_caster =
      Cast(root.WithOpName("float_caster"), image_reader, tensorflow::DT_FLOAT);
  // The convention for image ops in TensorFlow is that all images are expected
  // to be in batches, so that they're four-dimensional arrays with indices of
  // [batch, height, width, channel]. Because we only have a single image, we
  // have to add a batch dimension of 1 to the start with ExpandDims().
  auto dims_expander = ExpandDims(root, float_caster, 0);
  // Bilinearly resize the image to fit the required dimensions.
  auto resized = ResizeBilinear(
      root, dims_expander,
      Const(root.WithOpName("size"), {input_height, input_width}));
  // Subtract the mean and divide by the scale.
  Div(root.WithOpName(output_name), Sub(root, resized, {input_mean}),
      {input_std});

  // This runs the GraphDef network definition that we've just constructed, and
  // returns the results in the output tensor.
  tensorflow::GraphDef graph;
  status = (root.ToGraphDef(&graph));

  std::unique_ptr<tensorflow::Session> session(
      tensorflow::NewSession(tensorflow::SessionOptions()));
  status = (session->Create(graph));
  LOG(INFO) << status.ToString();
  status = (session->Run({inputs}, {output_name}, {}, out_tensors));
  LOG(INFO) << status.ToString();

  return 0;
}

int main(int argc, char* argv[]) {
  using namespace ::tensorflow::ops;
  tensorflow::Status status;

  std::string delimiter = ".";
  std::string ofilename;
  std::vector<Tensor> inputs;
  std::vector<Tensor> outputs;

  std::string graph_path = "../../graphs/test1/";
  std::string image_path = "../../graphs/test0.png";

  std::string mdlpath(graph_path);
  std::string imgpath(image_path);
  int32 inputdim = 32;

  //std::unique_ptr<tensorflow::Session> session(tensorflow::NewSession({}));
  tensorflow::GraphDef graph;

  LOG(INFO) << "OK";

  tensorflow::SavedModelBundle model;

  Status load_status = tensorflow::LoadSavedModel(tensorflow::SessionOptions(), tensorflow::RunOptions(), graph_path, {tensorflow::kSavedModelTagServe}, &model);
  LOG(INFO) << model.meta_graph_def.has_graph_def();
  LOG(INFO) << load_status.ToString() << std::endl;

  graph = model.meta_graph_def.graph_def();

  //add graph to scope
  //status = session->Create(graph);
  //if (!status.ok()) {
  //  std::cout << status.ToString() << "\n";
  //  return -1;
  //}

  LOG(INFO) << "OK";

  //Read input image, assuming to be a sqaure image
  if (TensorFromFile(imgpath, inputdim, inputdim, &inputs)) {
    LOG(ERROR) << "Image reading failed"
               << "\n";
    return -1;
  }

  LOG(INFO) << "OK L1";

  LOG(INFO) << typeid(inputs).name();
  std::cout << "input dimension of the image: " << inputs[0].DebugString() << std::endl;
  auto shape = graph.node().Get(0).attr().at("shape").shape();
  for (int i = 0; i < shape.dim_size(); i++) {
    std::cout << shape.dim(i).size() << std::endl;
  }

  LOG(INFO) << "";
  for (int i = 0; i < graph.node_size(); i++) {
    LOG(INFO) << graph.node(i).name();
  }
  LOG(INFO) << "";

  //get the appropriate input and out layer names from the graph/mode to execute
  auto inputlayer = graph.node(0).name();
  LOG(INFO) << "OK A1";
  LOG(INFO) << inputlayer;
  auto outputlayer = graph.node(graph.node_size() - 1).name();
  LOG(INFO) << "OK A2";
  LOG(INFO) << outputlayer;

  const Tensor& resized_tensor = inputs[0];

  std::vector<std::pair<string, tensorflow::Tensor>> inputsPair = {
      {inputlayer, inputs[0]},
  };

  status = model.GetSession()->Run({{inputlayer, resized_tensor}}, {outputlayer}, {}, &outputs);
  if (!status.ok()) {
    LOG(ERROR) << status.ToString();
    return -1;
  }

  std::cout << "Output dimension of the image" << outputs[0].DebugString() << std::endl;

  //create filename
  ofilename.append(imgpath.substr(0, imgpath.find(delimiter)));
  ofilename.append("_mask.png");

  std::cout << "output filename: " << ofilename << std::endl;

  //Now write this to a image file
  //if (TensorToFile(ofilename, outputs, threshold)) return -1;

  model.GetSession()->Close();

  return 0;
}

Это дает этот журнал:

2020-06-21 00:26:13.628887: I main.cpp:149] OK
2020-06-21 00:26:13.629011: I tensorflow/cc/saved_model/reader.cc:31] Reading SavedModel from: ../../graphs/test1/
2020-06-21 00:26:13.635410: I tensorflow/cc/saved_model/reader.cc:54] Reading meta graph with tags { serve }
2020-06-21 00:26:13.635458: I tensorflow/cc/saved_model/loader.cc:295] Reading SavedModel debug info (if present) from: ../../graphs/test1/
2020-06-21 00:26:13.674455: I tensorflow/core/platform/profile_utils/cpu_utils.cc:102] CPU Frequency: 1995615000 Hz
2020-06-21 00:26:13.674913: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x5559c0d43e20 initialized for platform Host (this does not guarantee that XLA will be used). Devices:
2020-06-21 00:26:13.674942: I tensorflow/compiler/xla/service/service.cc:176]   StreamExecutor device (0): Host, Default Version
2020-06-21 00:26:13.709421: I tensorflow/cc/saved_model/loader.cc:234] Restoring SavedModel bundle.
2020-06-21 00:26:13.770175: I tensorflow/cc/saved_model/loader.cc:183] Running initialization op on SavedModel bundle at path: ../../graphs/test1/
2020-06-21 00:26:13.790109: I tensorflow/cc/saved_model/loader.cc:364] SavedModel load for tags { serve }; Status: success: OK. Took 161100 microseconds.
2020-06-21 00:26:13.790167: I main.cpp:154] 1
2020-06-21 00:26:13.790187: I main.cpp:155] OK

2020-06-21 00:26:13.793408: I main.cpp:166] OK
2020-06-21 00:26:13.793553: I main.cpp:71] OK
2020-06-21 00:26:13.794331: I main.cpp:123] OK
2020-06-21 00:26:13.800549: I main.cpp:125] OK
2020-06-21 00:26:13.800864: I main.cpp:175] OK L1
2020-06-21 00:26:13.800891: I main.cpp:177] St6vectorIN10tensorflow6TensorESaIS1_EE
input dimension of the image: Tensor<type: float shape: [1,32,32,3] values: [[[0.596078455 0.690196097 0.729411781]]]...>
3
3
3
32
2020-06-21 00:26:13.800986: I main.cpp:184] 
2020-06-21 00:26:13.801005: I main.cpp:186] conv2d/kernel
2020-06-21 00:26:13.801022: I main.cpp:186] conv2d/kernel/Read/ReadVariableOp
2020-06-21 00:26:13.801037: I main.cpp:186] conv2d/bias
2020-06-21 00:26:13.801053: I main.cpp:186] conv2d/bias/Read/ReadVariableOp
2020-06-21 00:26:13.801068: I main.cpp:186] conv2d_1/kernel
2020-06-21 00:26:13.801084: I main.cpp:186] conv2d_1/kernel/Read/ReadVariableOp
2020-06-21 00:26:13.801100: I main.cpp:186] conv2d_1/bias
2020-06-21 00:26:13.801116: I main.cpp:186] conv2d_1/bias/Read/ReadVariableOp
2020-06-21 00:26:13.801132: I main.cpp:186] conv2d_2/kernel
2020-06-21 00:26:13.801148: I main.cpp:186] conv2d_2/kernel/Read/ReadVariableOp
2020-06-21 00:26:13.801163: I main.cpp:186] conv2d_2/bias
2020-06-21 00:26:13.801179: I main.cpp:186] conv2d_2/bias/Read/ReadVariableOp
2020-06-21 00:26:13.801195: I main.cpp:186] conv2d_3/kernel
2020-06-21 00:26:13.801210: I main.cpp:186] conv2d_3/kernel/Read/ReadVariableOp
2020-06-21 00:26:13.801224: I main.cpp:186] conv2d_3/bias
2020-06-21 00:26:13.801240: I main.cpp:186] conv2d_3/bias/Read/ReadVariableOp
2020-06-21 00:26:13.801255: I main.cpp:186] dense/kernel
2020-06-21 00:26:13.801271: I main.cpp:186] dense/kernel/Read/ReadVariableOp
2020-06-21 00:26:13.801286: I main.cpp:186] dense/bias
2020-06-21 00:26:13.801302: I main.cpp:186] dense/bias/Read/ReadVariableOp
2020-06-21 00:26:13.801317: I main.cpp:186] dense_1/kernel
2020-06-21 00:26:13.801332: I main.cpp:186] dense_1/kernel/Read/ReadVariableOp
2020-06-21 00:26:13.801348: I main.cpp:186] dense_1/bias
2020-06-21 00:26:13.801363: I main.cpp:186] dense_1/bias/Read/ReadVariableOp
2020-06-21 00:26:13.801378: I main.cpp:186] dense_2/kernel
2020-06-21 00:26:13.801394: I main.cpp:186] dense_2/kernel/Read/ReadVariableOp
2020-06-21 00:26:13.801409: I main.cpp:186] dense_2/bias
2020-06-21 00:26:13.801425: I main.cpp:186] dense_2/bias/Read/ReadVariableOp
2020-06-21 00:26:13.801440: I main.cpp:186] dense_3/kernel
2020-06-21 00:26:13.801455: I main.cpp:186] dense_3/kernel/Read/ReadVariableOp
2020-06-21 00:26:13.801471: I main.cpp:186] dense_3/bias
2020-06-21 00:26:13.801486: I main.cpp:186] dense_3/bias/Read/ReadVariableOp
2020-06-21 00:26:13.801502: I main.cpp:186] NoOp
2020-06-21 00:26:13.801517: I main.cpp:186] Const
2020-06-21 00:26:13.801532: I main.cpp:186] serving_default_input
2020-06-21 00:26:13.801548: I main.cpp:186] StatefulPartitionedCall
2020-06-21 00:26:13.801564: I main.cpp:186] saver_filename
2020-06-21 00:26:13.801580: I main.cpp:186] StatefulPartitionedCall_1
2020-06-21 00:26:13.801596: I main.cpp:186] StatefulPartitionedCall_2
2020-06-21 00:26:13.801611: I main.cpp:188] 
2020-06-21 00:26:13.801625: I main.cpp:192] OK A1
2020-06-21 00:26:13.801640: I main.cpp:193] conv2d/kernel
2020-06-21 00:26:13.801655: I main.cpp:195] OK A2
2020-06-21 00:26:13.801670: I main.cpp:196] StatefulPartitionedCall_2
2020-06-21 00:26:13.813969: E main.cpp:206] Invalid argument: Expects arg[0] to be resource but float is provided

I не очень хорошо понимаю этот код ошибки. Что означает Invalid argument: Expects arg[0] to be resource but float is provided?

...