복붙노트

[PYTHON] Tensorflow C ++에서 그래프를 내보내고 실행하는 다양한 방법

PYTHON

Tensorflow C ++에서 그래프를 내보내고 실행하는 다양한 방법

훈련 된 네트워크를 C ++로 가져 오려면 네트워크를 내보낼 수 있어야합니다. 많은 것을 검색하고 그것에 대한 정보를 거의 찾지 못한 후에는 freeze_graph ()를 사용하여이를 수행 할 수 있어야한다는 것을 분명히했습니다.

Tensorflow의 새로운 0.7 버전 덕분에, 그들은 그것의 문서를 추가했습니다.

문서를 조사한 결과 유사한 방법이 거의 없다는 것을 알았습니다. freeze_graph ()와 다음과 같은 점을 구분할 수 있습니까?  tf.train.export_meta_graph 그것은 비슷한 매개 변수를 가지고 있지만 C ++로 모델을 임포트하는 데에도 사용될 수 있습니다. (차이점은이 메소드로 파일 출력을 사용하면 import_graph_def () 만 사용할 수 있다는 것입니다. 그밖에?)

또한 write_graph ()를 사용하는 방법에 대한 하나의 질문 : 문서화에서 graph_def는 sess.graph_def로 주어 지지만 freeze_graph ()의 예제에서는 sess.graph.as_graph_def ()입니다. 이 둘의 차이점은 무엇입니까?

이 질문은이 문제와 관련이 있습니다.

고맙습니다!

해결법

  1. ==============================

    1.여기에 TF 0.12에서 도입 된 V2 체크 포인트를 활용하는 내 솔루션이 있습니다.

    여기에 TF 0.12에서 도입 된 V2 체크 포인트를 활용하는 내 솔루션이 있습니다.

    모든 변수를 상수로 변환하거나 그래프를 고정 할 필요가 없습니다.

    명확성을 위해 V2 검사 점은 내 디렉토리 모델에서 다음과 같이 보입니다.

    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)
    

    파이썬 파트 (저장)

    with tf.Session() as sess:
        tf.train.Saver(tf.trainable_variables()).save(sess, 'models/my-model')
    

    tf.trainable_variables ()를 사용하여 Saver를 생성하면 두통과 저장 공간을 절약 할 수 있습니다. 그러나 좀 더 복잡한 모델의 경우 모든 데이터를 저장해야하는 경우이 인수를 Saver로 제거하고 그래프를 만든 후에 Saver를 만들도록하십시오. 또한 모든 변수 / 레이어에 고유 한 이름을 지정하는 것이 좋습니다. 그렇지 않으면 다른 문제로 실행할 수 있습니다.

    파이썬 부분 (추론)

    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 ++ 부분 (추론)

    checkpointPath는 기존 파일에 대한 경로가 아니며 공통 접두어 만 사용합니다. 실수로 .index 파일에 경로를 넣으면 TF가 잘못되었다는 사실을 알려주지 않지만 초기화되지 않은 변수로 인해 추측 중에 죽을 것입니다.

    #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);
    
  2. ==============================

    2.예측 (그리고 다른 모든 작업)에 대해 다음과 같이 할 수 있습니다.

    예측 (그리고 다른 모든 작업)에 대해 다음과 같이 할 수 있습니다.

    우선 파이썬에서 미래의 사용을 위해 변수 또는 연산의 이름을 지정해야합니다.

    self.init = tf.initialize_variables(tf.all_variables(), name="nInit")
    

    교육을 마친 후 계산이 너무 많아서 할당 된 변수가있을 때 그래프를 통해 상수로 저장됩니다. (거의 같은 동결 도구를 사용하여 수행 할 수 있습니다,하지만 난 보통 자신에 의해 그것을 확인, "이름 = nWeights"py와 아래 cpp에서 확인)

    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)
    

    이제 C ++로 가서 저장된 상수로부터 그래프와로드 변수를로드하십시오.

    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);
    

    이제 모든 신경 회로망 무게 또는 다른 변수가로드되었습니다.

    마찬가지로 다른 작업을 수행 할 수 있습니다 (이름은 기억하고 있습니까?). 적절한 크기의 입력 및 출력 텐서를 만들고, 데이터로 텐서를 입력하고 세션을 다음과 같이 실행하십시오 :

    auto operationStatus = session->Run(input, {"put_your_operation_here"}, {}, &out);
    
  3. from https://stackoverflow.com/questions/35508866/tensorflow-different-ways-to-export-and-run-graph-in-c by cc-by-sa and MIT license