python - started - tensorflow tutorial pdf
Tensorflow Diferentes maneras de exportar y ejecutar el gráfico en C++ (2)
Para importar su red entrenada a C ++, necesita exportar su red para poder hacerlo. Después de buscar mucho y no encontrar casi información al respecto, se aclaró que deberíamos usar freeze_graph() para poder hacerlo.
Gracias a la nueva versión 0.7 de Tensorflow, agregaron documentation de la misma.
Después de buscar en las documentaciones, descubrí que hay pocos métodos similares, ¿puedes decir cuál es la diferencia entre freeze_graph()
y: tf.train.export_meta_graph
ya que tiene parámetros similares, pero parece que también se puede usar para importar modelos a C ++ (supongo que la diferencia es que para usar la salida de archivo con este método, solo puede usar import_graph_def()
o es otra cosa)
También una pregunta sobre cómo usar write_graph()
: en documentaciones, graph_def
viene dada por sess.graph_def
pero en ejemplos en freeze_graph()
es sess.graph.as_graph_def()
. ¿Cuál es la diferencia entre estos dos?
Esta pregunta está relacionada con este problema.
¡Gracias!
Aquí está mi solución utilizando los puntos de control V2 introducidos en TF 0.12.
No es necesario convertir todas las variables en constantes o congelar el gráfico .
Solo por claridad, un punto de control V2 se ve así en mis models
directorio:
checkpoint # some information on the name of the files in the checkpoint
my-model.data-00000-of-00001 # the saved weights
my-model.index # probably definition of data layout in the previous file
my-model.meta # protobuf of the graph (nodes and topology info)
Parte de Python (guardando)
with tf.Session() as sess:
tf.train.Saver(tf.trainable_variables()).save(sess, ''models/my-model'')
Si crea el Saver
con tf.trainable_variables()
, puede ahorrarse un poco de dolor de cabeza y espacio de almacenamiento. Pero tal vez algunos modelos más complicados necesitan que todos los datos se guarden, luego elimine este argumento a Saver
, solo asegúrese de que está creando Saver
después de crear su gráfico. También es muy sabio dar nombres únicos a todas las variables / capas, de lo contrario puede ejecutar diferentes problemas .
Parte de Python (inferencia)
with tf.Session() as sess:
saver = tf.train.import_meta_graph(''models/my-model.meta'')
saver.restore(sess, tf.train.latest_checkpoint(''models/''))
outputTensors = sess.run(outputOps, feed_dict=feedDict)
C ++ parte (inferencia)
Tenga en cuenta que checkpointPath
no es una ruta de acceso a ninguno de los archivos existentes, solo su prefijo común. Si colocó por error la ruta al archivo .index
, TF no le dirá que estaba equivocado, pero morirá durante la inferencia debido a variables no inicializadas.
#include <tensorflow/core/public/session.h>
#include <tensorflow/core/protobuf/meta_graph.pb.h>
using namespace std;
using namespace tensorflow;
...
// set up your input paths
const string pathToGraph = "models/my-model.meta"
const string checkpointPath = "models/my-model";
...
auto session = NewSession(SessionOptions());
if (session == nullptr) {
throw runtime_error("Could not create Tensorflow session.");
}
Status status;
// Read in the protobuf graph we exported
MetaGraphDef graph_def;
status = ReadBinaryProto(Env::Default(), pathToGraph, &graph_def);
if (!status.ok()) {
throw runtime_error("Error reading graph definition from " + pathToGraph + ": " + status.ToString());
}
// Add the graph to the session
status = session->Create(graph_def.graph_def());
if (!status.ok()) {
throw runtime_error("Error creating graph: " + status.ToString());
}
// Read weights from the saved checkpoint
Tensor checkpointPathTensor(DT_STRING, TensorShape());
checkpointPathTensor.scalar<std::string>()() = checkpointPath;
status = session->Run(
{{ graph_def.saver_def().filename_tensor_name(), checkpointPathTensor },},
{},
{graph_def.saver_def().restore_op_name()},
nullptr);
if (!status.ok()) {
throw runtime_error("Error loading checkpoint from " + checkpointPath + ": " + status.ToString());
}
// and run the inference to your liking
auto feedDict = ...
auto outputOps = ...
std::vector<tensorflow::Tensor> outputTensors;
status = session->Run(feedDict, outputOps, {}, &outputTensors);
Para predecir (y cualquier otra operación) puedes hacer algo como esto:
En primer lugar, en Python, debe asignar un nombre a sus variables u operación para su uso futuro
self.init = tf.initialize_variables(tf.all_variables(), name="nInit")
Después del entrenamiento, los cálculos de modo ... cuando tenga asignadas las variables, repáselas todas y guárdelas como constantes en su gráfica. (casi lo mismo se puede hacer con esa herramienta de congelación, pero normalmente lo hago por mí mismo, verifique "nombre = nWeights" en py y cpp a continuación)
def save(self, filename):
for variable in tf.trainable_variables():
tensor = tf.constant(variable.eval())
tf.assign(variable, tensor, name="nWeights")
tf.train.write_graph(self.sess.graph_def, ''graph/'', ''my_graph.pb'', as_text=False)
Ahora vaya c ++ y cargue nuestro gráfico y cargue las variables de las constantes guardadas:
void load(std::string my_model) {
auto load_graph_status =
ReadBinaryProto(tensorflow::Env::Default(), my_model, &graph_def);
auto session_status = session->Create(graph_def);
std::vector<tensorflow::Tensor> out;
std::vector<string> vNames;
int node_count = graph_def.node_size();
for (int i = 0; i < node_count; i++) {
auto n = graph_def.node(i);
if (n.name().find("nWeights") != std::string::npos) {
vNames.push_back(n.name());
}
}
session->Run({}, vNames, {}, &out);
Ahora tienes todos tus pesos netos neuronales u otras variables cargadas.
Del mismo modo, puedes realizar otras operaciones (¿recuerdas los nombres?); haga tensores de entrada y salida del tamaño adecuado, llene el tensor de entrada con datos y ejecute la sesión de la siguiente manera:
auto operationStatus = session->Run(input, {"put_your_operation_here"}, {}, &out);