Я проследовал вместе со связанными постами и, наконец, сумел загрузить график + веса моей обученной модели тензорного потока в C ++, не вызывая при этом ошибок, но, похоже, неправильно загружает веса. Возможно, я пропустил шаг, скорее всего, в разделе логического вывода.
Я включил полностью функциональный минимальный рабочий пример ниже. Для его запуска вам (вероятно) понадобится Python + 1.4.0 < Tensorflow <= 1.7.0, Tensorflow для C ++ и keras. Любое понимание проблемы, с которой я столкнулся, было бы очень радостно получено, я был в тяжелой битве с тф уже две недели.
Код Python, который «обучит» модель и сохранит ее + веса, как показано Вот:
from __future__ import absolute_import, division, print_function
import os
import tensorflow as tf
import numpy as np
import random
import keras
from keras import backend as K
# Set it manually so C++ interface can use mem growth
config = tf.ConfigProto()
config.gpu_options.allow_growth = True
sess = tf.Session(config=config)
K.set_session(sess)
model = tf.keras.Sequential([
tf.keras.layers.Convolution2D(64, (5, 5), input_shape=(7, 19, 19), data_format='channels_first', name='Input'),
tf.keras.layers.ZeroPadding2D(padding =(4, 4), data_format='channels_first', name='Pad0'),
tf.keras.layers.BatchNormalization(axis=1, momentum=0.99, name='Norm0'),
tf.keras.layers.Dropout(0.25, name='Drop0'),
tf.keras.layers.Flatten(name='Flatten0'),
tf.keras.layers.Dense(361, activation='softmax', name='Output'),
])
X = np.ones((25, 7, 19, 19))
Y = np.zeros((25, 361))
optimizer = tf.train.AdamOptimizer(learning_rate=0.0018)
model.compile(optimizer=optimizer, loss='categorical_crossentropy', metrics=['accuracy'])
x = np.zeros((1, 7, 19, 19))
print(model.predict(x))
model.fit(X, Y, 1, 5, 2)
print(model.predict(x)) # Just to verify output is different after training
K.set_learning_phase(0)
sess.run(tf.global_variables_initializer())
saver = tf.train.Saver(tf.global_variables())
saver.save(sess, save_path='./models/myModel')
// Just used to look at graph structure
tf.train.write_graph(sess.graph, '.', './models/graph.pb', as_text=True)
И код C ++, в настоящее время использующий tf 1.5.0:
Код для загрузки модели, как показано Вот
#define _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS
#define COMPILER_MSVC
#define NOMINMAX
#include <iomanip>
#include <tensorflow\core\public\session.h>
#include <tensorflow\core\protobuf\meta_graph.pb.h>
#include <tensorflow\core\framework\tensor.h>
#include <tensorflow\cc\ops\standard_ops.h>
namespace tf = tensorflow;
tf::Status status;
tf::Session* session;
tf::SessionOptions options;
tf::MetaGraphDef graphDef;
std::string pathToGraph = "models/myModel.meta";
std::string pathToCheckpoint = "models/myModel";
int main()
{
options.config.mutable_gpu_options()->set_allow_growth(true);
options.config.mutable_gpu_options()->set_per_process_gpu_memory_fraction(1.0);
session = tf::NewSession(options);
if (!session)
throw std::runtime_error("Could no create Tensorflow Session!");
// Read in the protobuf
status = tf::ReadBinaryProto(tf::Env::Default(), pathToGraph, &graphDef);
if (!status.ok())
throw std::runtime_error("Error reading graph: " + status.ToString());
status = session->Create(graphDef.graph_def());
if (!status.ok())
throw std::runtime_error("Error creating graph: " + status.ToString());
// Read the weights
tf::Tensor checkpointPathTensor(tf::DT_STRING, tf::TensorShape());
checkpointPathTensor.scalar<std::string>()() = pathToCheckpoint;
const auto fileTensorName = graphDef.saver_def().filename_tensor_name();
const auto restoreOpName = graphDef.saver_def().restore_op_name();
status = session->Run(
{ { fileTensorName, checkpointPathTensor }, },
{},
{ restoreOpName },
nullptr
);
if (!status.ok())
throw std::runtime_error("Error loading checkpoint from " + pathToCheckpoint + ": " + status.ToString());
...
Затем следует код для запуска вывода с загруженной / обученной моделью.
float inData[2527] = { 0.f };
static const std::string inputName = "Input_input";
static const std::string outputName = "Output/Softmax";
static const auto shape = tf::TensorShape({ 1, 7, 19, 19});
tf::Tensor input(tf::DT_FLOAT, shape);
std::copy_n(inData, 2527, input.flat<float>().data());
std::vector<tf::Tensor> outputs;
status = session->Run({ { inputName, input } }, { outputName }, {}, &outputs);
tf::TTypes<float>::Flat flatOut = outputs[0].flat<float>();
for (int i = 0; i < 361; ++i)
{
if (i % 19 == 0)
std::cout << '\n';
std::cout << std::setw(8) << std::fixed << std::setprecision(8) << flatOut(i) << ", ";
}
std::cout << '\n';
}
Для меня, когда я запускаю это, все работает как должно в разделе Python, но молча не удается загрузить обученный граф (или делает что-то похожее) в разделе C ++. При запуске раздела C ++ модель выводит точно такой же вывод, что и необученная модель Python. Есть ли какой-то шаг, который я здесь пропускаю?
Пример вывода Python перед обучением модели:
[[0.00277008 0.00277008 0.00277008 0.00277008 0.00277008 0.00277008
0.00277008 0.00277008 0.00277008 0.00277008 0.00277008 ...etc ]]
Пример вывода после обучения в Python:
.00387822 0.00228055 0.0018196 0.0014322 0.00266262 0.00234695
0.0026182 0.00322318 0.00252047 0.00353322 0.00342526 ...etc ]]
Пример вывода после загрузки модели и запуска в C ++ с одинаковыми входными данными:
0.00277008, 0.00277008, 0.00277008, 0.00277008, ... etc
В идеале я хотел бы видеть вывод C ++, идентичный выводу Python после обучения!
Вы можете изменить main.cc из проекта tf_label_image_example.
Тем не менее, я установил tenorflow_BUILD_CC_EXAMPLE = ON, когда я построил тензорный поток с использованием CMake.
Вы можете сослаться на это http://www.stefanseibert.com/2017/10/tensorflow-as-dll-into-your-windows-c-project-with-gpu-support-and-cmake-v1-3/.
Кроме того, я создал один проект Visual Studio (VS 2015 x64 Release), который похож на tf_label_image_example_project.
На самом деле я открыл tf_label_image_example_project с помощью Visual Studio и скопировал многие конфигурации в свой проект. Самое главное, библиотеки объектов в * .vcxproj и * .vcxproj.filters.
Других решений пока нет …