Перейти к содержимому
Compvision.ru
Pechkin80

Определение размерности входного и выходного узла графа.

Recommended Posts

Когда у меня была незамароженная модель я без труда определял размерность входного и выходного узла графа загруженной модели вот таким образом:

    using namespace std;
    using namespace tensorflow;
    using namespace tensorflow::ops;
    cout << "Step1" << endl;
    GraphDef graph_def(true);
    Session* session;
    SessionOptions sopt;
    Status status = NewSession(sopt, &session);
    if (!status.ok()) {
        std::cerr << "tf error: " << status.ToString() << "\n";
    }
   const string export_dir = "/home/user/MyBuild/build_tftest2/models";
    SavedModelBundle bundle;
    RunOptions run_options;
    status = LoadSavedModel(sopt, run_options, export_dir,
                   {kSavedModelTagServe},
                   &bundle);
    if (!status.ok()) {
        std::cerr << "tf error: " << status.ToString() << "\n";
    }
    else
    {
        GraphDef graph = bundle.meta_graph_def.graph_def();
        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;
        }
        int node_count = graph.node_size();
        for (int i = 0; i < node_count; i++)
        {
                auto n = graph.node(i);
                //graph.node(i).PrintDebugString();
                cout<<"Names : "<< n.name() <<endl;

        }
    }

А потом я захотел модель оптимизировать и для этого её заморозил и теперь код загрузки модели уже другой,

    using namespace std;
    using namespace tensorflow;
    using namespace tensorflow::ops;
    cout << "Step1" << endl;
    GraphDef graph_def(true);
    Session* session;
    SessionOptions sopt;
    Status status = NewSession(sopt, &session);
    if (!status.ok()) {
        std::cerr << "tf error: " << status.ToString() << "\n";
    }
    cout << "Step2" << endl;

    // Читаем граф
    //status = ReadBinaryProto(Env::Default(), "/home/user/MyBuild/build_tftest2/models/saved_model.pb", &graph_def);
    status = ReadBinaryProto(Env::Default(), "/home/user/MySoftware/foreign code/netology_JN/Diplom/Models/optimized/optim_model.pb", &graph_def);
    //status = ReadBinaryProto(Env::Default(), "/home/user/MySoftware/foreign code/netology_JN/Diplom/Models/Raw/frozen_model.pb", &graph_def);
    if (!status.ok()) {
        std::cerr << "tf error: " << status.ToString() << "\n";
    }
    else
    {       
        int node_count = graph_def.node_size();
        for (int i = 0; i < node_count; i++)
        {
                auto n = graph_def.node(i);
                //graph.node(i).PrintDebugString();
                cout<<"Names : "<< n.name() <<endl;
        }
        auto shape = graph_def.node().Get(0).attr().at("shape").shape();
        for (int i = 0; i < shape.dim_size(); i++) {
            std::cout << shape.dim(0).size()<<std::endl;
        }
    }

Список узлов я по прежнему получаю, но при попытки получить размерность имею большой облом.

Цитата

 

Names : conv2d_18_2/Relu

Names : conv2d_19_2/kernel

Names : conv2d_19_2/bias

Names : conv2d_19_2/convolution

Names : conv2d_19_2/BiasAdd

Names : conv2d_19_2/Sigmoid

[libprotobuf FATAL /usr/local/include/google/protobuf/map.h:1064] CHECK failed: it != end(): key not found: shape

terminate called after throwing an instance of 'google::protobuf::FatalException'

what(): CHECK failed: it != end(): key not found: shape

14:21:36: The program has unexpectedly finished.

 

Подскажите пожалуйста как получить размерность хотябы входного и выходного узла. Я же должен знать тензоры каких размерностей надо создавать для интеграции модели  в приложение.

Документации по теме нет и я буду рад любым рассуждениям, которые могут навести на путь истинный.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Замарозку делал вот так:

def freeze_session(session, keep_var_names=None, output_names=None, clear_devices=True):
    """
    Freezes the state of a session into a pruned computation graph.

    Creates a new computation graph where variable nodes are replaced by
    constants taking their current value in the session. The new graph will be
    pruned so subgraphs that are not necessary to compute the requested
    outputs are removed.
    @param session The TensorFlow session to be frozen.
    @param keep_var_names A list of variable names that should not be frozen,
                          or None to freeze all the variables in the graph.
    @param output_names Names of the relevant graph outputs.
    @param clear_devices Remove the device directives from the graph for better portability.
    @return The frozen graph definition.
    """
    graph = session.graph
    with graph.as_default():
        freeze_var_names = list(set(v.op.name for v in tf.global_variables()).difference(keep_var_names or []))
        output_names = output_names or []
        output_names += [v.op.name for v in tf.global_variables()]
        # Graph -> GraphDef ProtoBuf
        input_graph_def = graph.as_graph_def()
        if clear_devices:
            for node in input_graph_def.node:
                node.device = ""
        frozen_graph = convert_variables_to_constants(session, input_graph_def,
                                                      output_names, freeze_var_names)
        return frozen_graph


frozen_graph = freeze_session(K.get_session(),
                              output_names=[out.op.name for out in model.outputs])
tf.train.write_graph(frozen_graph, "model", "tf_model.pb", as_text=False)

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Так там вроде как размеры тензоров при заморозке фиксируются, и надо самому их знать по модели. Вроде как получение размеров тензоров и не поддерживалось. Но тут у меня опыта немного, могу ошибаться.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
4 минуты назад, Smorodov сказал:

Так там вроде как размеры тензоров при заморозке фиксируются, и надо самому их знать по модели. Вроде как получение размеров тензоров и не поддерживалось. Но тут у меня опыта немного, могу ошибаться.

Размер тензора вроде можно узнать, но мне надо конвертировать Node графа в тензор прежде и я без понятия как это сделать.

Да я конечно могу сам забить размер, но както дико ненадёжное реение получается от таких кастылей.

Второй вариант это всёже както сохранять аттрибуты в модели. Функция simple_save это както же делает.

В любом случае спасибо. Мне важно знать как делают другие.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
В 9/12/2019 at 18:30, Smorodov сказал:

Так там вроде как размеры тензоров при заморозке фиксируются, и надо самому их знать по модели. Вроде как получение размеров тензоров и не поддерживалось. Но тут у меня опыта немного, могу ошибаться.

А C API можно миксить с С++ API ?

Вот тут интересные рассуждения.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Не уверен что хуже, задавать размер тензора вручную, или мешать C и C++, но так-то теоретически возможно:

https://www.oracle.com/technetwork/articles/servers-storage-dev/mixingcandcpluspluscode-305840.html

Может оптимально будет просто записывать при заморозке еще один файл, с дополнительной инфой ?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
3 часа назад, Smorodov сказал:

Не уверен что хуже, задавать размер тензора вручную, или мешать C и C++, но так-то теоретически возможно:

https://www.oracle.com/technetwork/articles/servers-storage-dev/mixingcandcpluspluscode-305840.html

Может оптимально будет просто записывать при заморозке еще один файл, с дополнительной инфой ?

 

Пока забил вручную:

 Но я не врублюсь какой размерности тензор создавать. В питоне было [-1, 192, 512, 1], а в плюсах

    const auto size1 = 0;
    const auto size2 = 192;
    const auto size3 = 512;
    const auto size4 = 1;
    Tensor inputTensor1(DT_FLOAT, TensorShape({size1, size2, size3, size4}));

если создать с размерностью (0, 192, 512, 1) то при такой иннициаллизации:

for (int i1 = 0; i1 < size2; i1++) {
        for (int j1 = 0; j1 < size3; j1++) {
            inputTensor1.matrix<float>()(i1, j1) = 128;
        }
    }

я получаю ошибку времени выполнения :

Цитата

2019-09-14 20:26:51.187250: F tensorflow/core/framework/tensor_shape.cc:44] Check failed: NDIMS == dims() (2 vs. 4)Asking for tensor of 2 dimensions from a tensor of 4 dimensions

А при такой иннициаллизации:

    for (int i1 = 0; i1 < size2; i1++) {
        for (int j1 = 0; j1 < size3; j1++) {
            inputTensor1.matrix<float>()(0, i1, j1, 0) = 128;
        }
    }

такую на этапе компиляции:

Цитата

 

required from here

/usr/include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorMap.h:239:7: error: static assertion failed: Number of indices used to access a tensor coefficient must be equal to the rank of the tensor.

static_assert(sizeof...(otherIndices) + 2 == NumIndices || NumIndices == Dynamic, "Number of indices used to access a tensor coefficient must be equal to the rank of the tensor.");

Вообщем очень сильно плаваю в ситуации, поэто и хотел задавать размерность на автомате чтоб меньше ошибаться.

UPDATE:

Я на самом деле вроде придумал как определять размерность и если я прав, то всё очень грустно, потомучто тензор в файле записан одномерным.

    auto intensor = graph_def.node(1).attr().at("value");
    Tensor tmp_tensor;
    bool result = tmp_tensor.FromProto(intensor);
    int num_dimensions = tmp_tensor.shape().dims();
    std::cerr << num_dimensions << std::endl;
    for(int ii_dim = 0; ii_dim < num_dimensions; ii_dim++) {
        std::cerr <<  "i" << tmp_tensor.shape().dim_size(ii_dim) << std::endl;
    }

Потомучто я имею на любом узле num_dimensions равное единице.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

А вот так почти сработало, только понять бы в чём разница с предыдущем вариантом.

    const auto size1 = 1;
    const auto size2 = 192;
    const auto size3 = 512;
    const auto size4 = 1;
    Tensor inputTensor1(DT_FLOAT, TensorShape({size1, size2, size3, size4}));
    //заполнение тензоров-входных данных
    for (int i1 = 0; i1 < size2; i1++) {
        for (int j1 = 0; j1 < size3; j1++) {
            inputTensor1.tensor<float, 4>()(0, i1, j1, 0) = 128.;
        }
    }

Теперь с GPU воевать придёться:

Цитата

2019-09-14 22:24:12.077757: W tensorflow/core/common_runtime/bfc_allocator.cc:237] Allocator (GPU_0_bfc) ran out of memory trying to allocate 1.27GiB with freed_by_count=0. The caller indicates that this is not a failure, but may mean that there could be performance gains if more memory were available.

UPDATE:

В предыдущем сообщении была ошибка:

вместо 

 auto intensor = graph_def.node(1).attr().at("shape");

надо:

 

 auto intensor = graph_def.node(1).attr().at("value");

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Нашел тот старый проект TF_EX.RAR посмотрите, может пригодится.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
1 час назад, Smorodov сказал:

Нашел тот старый проект TF_EX.RAR посмотрите, может пригодится.

Да всё, проблема с размерностью решена. :gym:

Щас осталось разобраться как контрлировать процесс с памятью для GPU и перенаправлений логов сессии в файл.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Дык на чем остановились то ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
8 минут назад, Smorodov сказал:

Дык на чем остановились то ?

Не уверен что понял вопрос.

Щас пилю инференс. Там много вещей, которые нужны в любой задаче.

Особенно для меня загадка как аккуратно распределить GPU память между tensorflow, opencv, ffmpeg.

Предпологаеться что каждая либа будет использовать куду. Надо както расчитать сколько нужно памяти для модели.

Ну а прямо щас копаю как перенаправить логи, а то пишет много всего, но в терминал.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Перенаправить вывод в линуксе можно стандартно: 

SomeCommand > SomeFile.txt  

Подробнее тут: https://askubuntu.com/questions/420981/how-do-i-save-terminal-output-to-a-file

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
4 минуты назад, Smorodov сказал:

Перенаправить вывод в линуксе можно стандартно: 


SomeCommand > SomeFile.txt  

Подробнее тут: https://askubuntu.com/questions/420981/how-do-i-save-terminal-output-to-a-file

 

Да эт я знаю, но программа может иметь свои сообщения. Хочеться не на уровне окружения(оболочки) решать вопрос.

есть класс SessionLog, причём как в питоне так и в плюсах. Ну не хочет пока выдавать лог.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Кажеться разобрался как разрулить с логами без перекомпиляции.

Поторопился. Без перекомпиляции кажеться нереально.

Там как я понял создаётся временный объект tensorflow/core/platform/default/logging.h

И по сути никаких логов там не ведётся.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте учётную запись или войдите для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать учётную запись

Зарегистрируйтесь для создания учётной записи. Это просто!

Зарегистрировать учётную запись

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас


  • Сейчас на странице   0 пользователей

    Нет пользователей, просматривающих эту страницу

×