Tensorflow c: TensorFlow C++ API Reference  |  TensorFlow Core v2.4.1

Содержание

Построение Tensorflow 1.4.0 из источников для C/C++ в Ubuntu 17.10



Я пытаюсь построить Tensorflow 1.4.0 из источников для C/C++ в 64-битном Ubuntu 17.10. Я попытался следовать инструкциям на веб- сайте Tensorflow и другом веб-сайте для C++ с помощью Bazel и суммировать их следующим образом:

cd tensorflow
./configure
(select N for all the options)
bazel build --config=opt --cxxopt="-D_GLIBCXX_USE_CXX11_ABI=0" --local_resources 2048,.5,1.0 //tensorflow:libtensorflow_cc.so //tensorflow:libtensorflow_framework.so //tensorflow/tools/pip_package:build_pip_package
bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg
sudo -H pip3 install /tmp/tensorflow_pkg/tensorflow-1.4.0rc1-cp36-cp36m-linux_x86_64.whl

Когда я попытался построить простую тестовую программу и включить tensorflow/core/public/session.h в Eclipse (с включенным путем, установленным в корневую папку tensorflow, загруженную из git), он пожаловался на несколько вещей:

  1. Отсутствует Google protobuf common. h в
    device_attributes.pb.h
    (я не могу использовать apt-get для установки protobuf, поскольку он будет жаловаться на слишком старую версию-ниже, чем проверка 3.0.0.4 в device_attributes.pb.h). Я загрузил последнюю версию protobuf и следуйте инструкциям, чтобы установить его
  2. Отсутствует тензорный файл Eigen3 в tensor.h, где tensor.h включает тензорный файл в [каталог tensorflow]/third_party/eigen3/unsupported/Eigen/CXX11/Tensor, а [каталог tensorflow]/third_party/eigen3/unsupported/Eigen/CXX11/Tensor включает отсутствующий файл [/usr/include/eigen3/]unsupported/Eigen/CXX11/Tensor , предоставленный libeigen3-dev. I apt-get для установки libeigen3-dev.
  3. После установки libeigen3-dev я добавил /usr/include/eigen3 в путь включения Eclipse, поскольку файл тензора в каталоге tensorflow не может найти файл тензора в каталоге
    /usr/include
    (с дополнительным каталогом eigen3).
  4. Отсутствует файл nsync_cv.h в файле mutex.h . Я добавил папку, приятной в каталоге tensorflow в пути.

Таким образом, я добавил следующие пути к пути включения в Eclipse:

  • [tensorflow каталог]/
  • [Каталог tensorflow] / bazel-genfiles
  • [Каталог tensorflow] / bazel-tensorflow/external/nsync/public
  • /usr/include/eigen3

Я добавил путь к библиотеке [tensorflow directory]/bazel-bin/tensorflow со следующими библиотеками:

  • tensorflow
  • tensorflow_cc
  • tensorflow_framework

Я также добавил -std=c++11 к компилятору GCC C++ и компоновщику GCC C++ в настройках проекта Eclipse. В конце концов он столкнулся с ошибкой компоновщика:

[tensorflow directory]/tensorflow/core/platform/default/logging.h:187: undefined reference to `tensorflow::internal::CheckOpMessageBuilder::NewString[abi::cxx11]()'

Я видел поток , обсуждающий подобную проблему, но я установил -D_GLIBCXX_USE_CXX11_ABI=0 и Ubuntu 17. 10 использует gcc5 или выше.

Пожалуйста, любезно предложите, как исправить ошибку компоновщика. Большое спасибо!

c++ eclipse c++11 ubuntu tensorflow
Поделиться Источник chesschi     15 ноября 2017 в 02:37

2 ответа


  • Установка CouchDB на ubuntu 17.10

    Я пытался установить couchdb в моем недавно обновленном ubuntu 17.10, но безрезультатно. Я использовал много ресурсов в том числе https://www.digitalocean.com/community/tutorials/how-to-install-couchdb-and-futon-on-ubuntu-14-04 но не смог заставить его работать

  • Установите ошибку tensorflow для Go под ubuntu 17.10

    Я установил tensorflow для Go с помощью следующих шагов, сообщение об ошибке не отображается. TF_TYPE=cpu # Change to gpu for GPU support TARGET_DIRECTORY=’/usr/local’ curl -L \ https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-${TF_TYPE}-$(go env GOOS)-x86_64-1. 4.0.tar.gz |…


Поделиться ptphucbk

    15 ноября 2017 в 14:12



1

Если вы не хотите слишком много возиться со своей средой, есть две неофициальные альтернативы. Один из них-скомпилировать C++ API с проектом tensorflow_cc Floop и установить на вашей системе. Другая возможность-установить один из выпусков моего упаковочного проекта для C и C++ API Tensorflow. Оба проекта используют CMake (вместо Bazel)для поддержки компиляции исходных файлов C++.

С точки зрения Tensorflow, преимущество tensorflow_cc в том, что вы можете построить поддержку GPU, если хотите, в то время как мой проект может использовать только CPU для вывода.

Поделиться kecsap     09 августа 2018 в 13:37


Похожие вопросы:


Не удалось установить tensorflow на Ubuntu 17.
10

При попытке установить tensorflow на ubuntu 17.10 (python 3.6) я получил эту ошибку: Collecting tensorflow==1.7.0 from…


Tensorflow C библиотека «available» для Windows?

В примечаниях к выпуску для tensorflow 1.2 говорится, что Библиотека TensorFlow C теперь доступна для Windows. Ницца. Однако страница, посвященная C API на веб-сайте tensorflow, дает инструкции…


tensorflow ошибка установки в Ubuntu 16.04 LTS

У меня есть виртуальная машина с 32-разрядной операционной системой Ubuntu 16.04LTS, и я пытаюсь установить (cpu-только python3.5) tensorflow с virtualenv, используя шаги в:…


Установка CouchDB на ubuntu 17.10

Я пытался установить couchdb в моем недавно обновленном ubuntu 17.10, но безрезультатно. Я использовал много ресурсов в том числе…


Установите ошибку tensorflow для Go под ubuntu 17.10

Я установил tensorflow для Go с помощью следующих шагов, сообщение об ошибке не отображается. TF_TYPE=cpu # Change to gpu for GPU support TARGET_DIRECTORY=’/usr/local’ curl -L \…


Компиляция TensorFlow 1.4.0 GPU на Windows 10 x64

Кажется, нет никакой подробной документации о том, как скомпилировать TensorFlow 1.4.0 GPU на Windows 10 x64. Мне нужно перекомпилировать TF, чтобы добавить недостающие функции для производственной…


Полностью удалить Java 9 из Ubuntu 17.10

Я сделал новую установку Ubuntu 17.10 некоторое время назад и должен был установить Java для создания приложений react-native на моем PC. Таким образом, я смог установить Java 9 вручную, загрузив…


выпуск gRPC на Ubuntu 17.10

При выполнении теста TensorFlow, связанного с gRPC( //tensorflow/core/debug:grpc_session_debug_test ) Я получаю следующую ошибку: self.server =…


tensorflow на ubuntu 17.10 «artful» терпит неудачу

tensorflow работал над версией 1.6, хотя нетерпеливое выполнение не сработало, затем я размонтировал tensorflow через pip uninstall tensorflow , затем установил через pip install tensorflow , я. ..


RPI3 Ubuntu 16.04 ncsdk install error.No соответствующий дистрибутив найден для tensorflow==1.4.0

Попробовал следующее на raspberrypi3, чтобы получить полную установку NCSDK Установлено ubunuMate. Результат релиз: 16.04.4 LTS код: xenial установлен без жалоб запустил скрипт на git clone…

Как создать и использовать API Google TensorFlow C ++

Я использую хак / обходной путь, чтобы избежать необходимости собирать всю библиотеку TF самостоятельно (что экономит время (настраивается за 3 минуты), дисковое пространство, установку зависимостей dev и размер получаемого двоичного файла). Это официально не поддерживается, но работает хорошо, если вы просто хотите быстро подключиться.

Установите TF через пипс ( pip install tensorflowили pip install tensorflow-gpu). Затем найдите его библиотеку _pywrap_tensorflow.so(TF 0. * — 1.0) или _pywrap_tensorflow_internal.so(TF 1. 1+). В моем случае (Ubuntu) он находится по адресу

/usr/local/lib/python2.7/dist-packages/tensorflow/python/_pywrap_tensorflow.so. Затем создайте символическую ссылку на эту библиотеку, которая называется lib_pywrap_tensorflow.soгде-нибудь, где ваша система сборки найдет ее (например /usr/lib/local). Префикс libважен! Вы также можете дать ему другое lib*.soимя — если вы называете этоlibtensorflow.so , вы можете получить лучшую совместимость с другими программами, написанными для работы с TF.

Затем создайте проект C ++, как вы привыкли (CMake, Make, Bazel, все, что вам нравится).

И тогда вы готовы просто сделать ссылку на эту библиотеку, чтобы TF был доступен для ваших проектов (и вам также нужно сделать ссылку на python2.7библиотеки)! В CMake вы, например, просто добавляете target_link_libraries(target _pywrap_tensorflow python2.7)

.

Заголовочные файлы C ++ расположены вокруг этой библиотеки, например, в /usr/local/lib/python2. 7/dist-packages/tensorflow/include/ .

Еще раз: этот способ официально не поддерживается, и вы можете столкнуться с различными проблемами. Библиотека выглядит статически связанной, например, с protobuf, поэтому вы можете работать в нечетных проблемах во время соединения или во время выполнения. Но я могу загрузить сохраненный график, восстановить веса и выполнить вывод, который является IMO наиболее востребованным функционалом в C ++.

Установка Tensorflow

Итак, как я уже писал в статье «Jupyter Notebook — прототипирование облачной автоматизации на Python», использовать Jupyter Notebook-и в процессе разработки очень удобно, т.к. каждый блок кода можно повторить в произвольном порядке столько раз, сколько нужно. Более того, всегда есть возможность наглядно посмотреть на типы данных или построить нужный график для визуализации вычислений или зависимостей между обрабатываемыми объектами.

Установка Jupyter очень проста, делать мы это будем в CentOS 7


sudo yum -y install python-pip
sudo yum -y groupinstall 'Development Tools'
sudo pip install virtualenv

sudo pip install jupyter

cd ~/
mkdir analysis # директория для хранения Notebook-ов

После того, как установка закончится, необходимо настроить на постоянный запуск Jupyter сервер. Для этого вам необходимо сгенерировать хеш пароля для доступа к серверу. Это особенно актуально, если вы устанавливаете Jupyter в виртуальной машине в облаке Google или Amazon. Для этого выполните:

python

Далее необходимо сгенерировать сам пароль:

from notebook.auth import passwd
passwd()

Введите нужный вам пароль и сохраните строку вида ’sha1:’ куда-нибудь в текстовый файл.

Далее сгенерируем конфигурационный файл для Jupyter сервера:

jupyter notebook --generate-config

Вывод команды покажет вам, куда именно записался конфигурационный файл по-умолчанию. Отредактируйте его, изменив следующие опции:

c.NotebookApp.password = 'sha1:'
c.NotebookApp.port = 8888
c.NotebookApp.ip = '*'
c.NotebookApp.open_browser = False

Далее, необходимо прописать старт Jupyter в качестве сервиса. Создайте файл /etc/systemd/system/multi-user.target.wants/jupyter.service следующего содержания:

[Unit]
Description=Jupyter Notebook

[Service]
Type=simple
PIDFile=/run/jupyter.pid
ExecStart=/usr/bin/jupyter notebook --config=/home/centos/.jupyter/jupyter_notebook_config.py
User=centos
Group=centos
WorkingDirectory=/home/centos/analysis
Restart=always
RestartSec=10
#KillMode=mixed

[Install]
WantedBy=multi-user.target

Убедитесь, что в строчке, начинающейся с ExecStart, указан правильный путь до Jupyter и правильный путь до сгенерированного вами конфигурационного файла, в качестве пользователя и группы прописаны пользователь и группа, с которыми вы получаете доступ к виртуальной машине, а в качестве рабочей директории (WorkingDirectory) указана существующая директория, в которой будут храниться ваши Notebook-и.

Обновите конфигурацию systemd

systemctl daemon-reload

Запустите Jupyter:

systemctl status jupyter

Проверьте, что запуск прошел успешно, выполнив команду:

systemctl status jupyter

Подключитесь к серверу Jupyter, используя IP-адрес вашей виртуальной машины, порт 8888 и сгенерированный вами пароль.

Neargye / hello_tf_c_api: API нейронной сети TensorFlow C

Филиал Linux / OSX Windows Лицензия Кодекс
главный

Пример запуска TensorFlow lib C API в Windows, Linux и macOS (Дарвин).

Пример сборки

Окна

  git clone --depth 1 https: // github.ru / Neargye / hello_tf_c_api
cd hello_tf_c_api
mkdir build
cd build
cmake -G "Visual Studio 15 2017" -A x64 ..
cmake --build. --config Отладка
  

Linux

  git clone - глубина 1 https://github.com/Neargye/hello_tf_c_api
cd hello_tf_c_api
mkdir build
cd build
cmake -G "Makefiles Unix" ..
cmake --build.
  

macOS (Дарвин)

  git clone - глубина 1 https://github.com/Neargye/hello_tf_c_api
cd hello_tf_c_api
mkdir build
cd build
cmake -G "XCode". .
cmake --build.
  

Замечания

  • После сборки вы можете найти библиотеку TensorFlow в папке hello_tf_c_api / tensorflow / lib и заголовок в hello_tf_c_api / tensorflow / include.
  • Тензорный поток в репозитории компилируется в режиме x64. Убедитесь, что проект нацелен на 64-битные платформы.
  • Убедитесь, что библиотека tenorflow находится в каталоге вывода или в каталоге, содержащемся в переменной среды% PATH%.

Получить библиотеку тензорного потока

Для процессора x64 вы можете скачать файл tensorflow.Итак, tensorflow.dll и tensorflow.lib из https://github.com/neargye-forks/tensorflow/releases.

Или создайте библиотеку нужной вам версии из исходников с поддержкой CPU или GPU.

Ссылка tenorflow lib

CMakeLists.txt
  link_directories (yourpath / to / tensorflow) # путь к tenorflow lib
... # Другой
target_link_libraries (  тензорный поток)
  
Visual Studio

«Проект» -> «Свойства» -> Свойства конфигурации »->« Компоновщик »->« Дополнительные зависимости »и добавьте путь к вашему тензорному потоку. lib в следующей строке.

Убедитесь, что файл tensorflow.dll находится в каталоге вывода (по умолчанию это Debug \ Release в папке вашего проекта) или в каталоге, содержащемся в переменной среды% PATH%.

Вот пример, как подготовить модели

Для создания файла graph.pb необходимо взять определение графика и набор контрольных точек и заморозить их вместе в один файл.

Вот пример того, как создать файл tensorflow.lib из tensorflow.dll для windows

Несколько статей с подробностями

Развертывание Tensorflow 2.1 как исполняемого файла C / C ++ | Амирул Абдулла | Analytics Vidhya

Насколько я знаю, есть 2 способа получить заголовок C API.

  • Загрузите предварительно скомпилированный API Tensorflow C с веб-сайта (как правило, это устаревшие двоичные файлы) ИЛИ
  • Клонирование и компиляция из исходного кода (длительный процесс, но если что-то не работает, мы можем отлаживать и посмотрите на API)

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

Шаг A: клонируйте свои проекты

Создайте папку и клонируйте проект

 $ git clone https://github.com/tensorflow/tensorflow.git 

Шаг B: Установите необходимые инструменты (Bazel, Numpy)

Вам понадобится Bazel для компиляции. Установите его в своей среде

Ubuntu:

 $ sudo apt update && sudo apt install bazel-1.2.1 

OpenSuse:

 $ sudo zypper install bazel 

Какую бы платформу вы ни использовали, убедитесь, что версия bazel — 1.2.1, так как это то, что сейчас использует Tensorflow 2.1. Может измениться в будущем.

Затем нам нужно будет установить пакет Python Numpy (зачем нам пакет Python для создания C API ??). Вы можете установить его, как хотите, при условии, что на него можно будет ссылаться во время компиляции. Но я предпочитаю устанавливать его через Miniconda и иметь отдельную виртуальную среду для сборки. Вот как это сделать:

Установите Miniconda:

 $ wget https: //repo. anaconda.com / miniconda / Miniconda3-latest-Linux-x86_64.sh 
$ sudo chmod 777 Miniconda3-latest-Linux-x86_64.sh
$ ./Miniconda3-latest-Linux-x86_64.sh

Создать новую среду + Numpy с именем tf -build:

 $ conda create -n tf-build python = 3.7 numpy 

мы используем эту среду позже на шаге D.

Шаг C: Примените патч к исходному коду (ВАЖНО!)

Исходный код Tensorflow 2.1 есть ошибка, из-за которой сборка не удалась. Обратитесь к этому вопросу. Исправление заключается в применении патча здесь.Я включил в это репо файл, который можно использовать в качестве патча.

 $ git apply p.patch 

В будущем это может быть исправлено и не актуально.

Шаг D. Скомпилируйте код

Ссылаясь на документацию Tensorflow и Readme на Github. Вот как мы его компилируем. Нам нужно сначала активировать наш conda env, поскольку он относится к Numpy

 $ conda activate tf-build 
$ bazel test -c opt tensorflow / tools / lib_package: libtensorflow_test
$ bazel build -c opt tensorflow / tools / lib_package: libtensorflow_test

Позвольте мне ПРЕДУПРЕДИТЬ вас еще раз. Для компиляции на виртуальной машине с Ubuntu с конфигурацией из 6 ядер требуется 2 часа. Мой друг с двухъядерным ноутбуком практически завис, пытаясь скомпилировать это. Вот небольшой совет. Запустите какой-нибудь сервер с хорошим ЦП / ОЗУ.

скопируйте файл по адресу bazel-bin / tensorflow / tools / lib_package / libtensorflow.tar.gz и вставьте в нужную папку. разверните его, как показано ниже:

 $ tar -C / usr / local -xzf libtensorflow.tar.gz 

Я распаковываю его в своей домашней папке вместо / usr / local , поскольку я только пробовал.

ПОЗДРАВЛЯЕМ !! ТЫ СДЕЛАЛ ЭТО. компиляция TensorFlow как минимум.

На этом шаге мы создадим модель с использованием класса tf.keras.layers и сохраним модель для загрузки позже с помощью C API. Для этого нам понадобится Python TensorFlow для создания модели. См. Полный код на model.py в репо.

Шаг A: Установите TensorFlow в conda

, нам нужно будет установить отдельную среду conda для этого шага

 $ conda create -n tf python = 3. 7 tensorflow 

Шаг B: Напишите модель

, вот простая модель, в которой есть пользовательский tf.keras.layers.Model с одним плотным слоем . Которая инициализируется . Следовательно, на выходе этой модели (из вызова def () ) будет получен результат, аналогичный входному.

Простая модель с тензорным потоком

Начиная с Tensorflow 2.0, нетерпеливое выполнение позволяет нам запускать модель без черчения графика и проходить через сеанс .Но для того, чтобы сохранить модель (см. Эту строку module.save ('model', save_format = 'tf') ), перед сохранением необходимо построить график. следовательно, нам нужно будет вызвать модель хотя бы один раз, чтобы она создала граф. Вызов print (module (input_data)) заставит его создать график.

Затем запустите код:

 $ conda activate tf 
$ python model.py

Вы должны получить следующий результат:

 tf. Tensor ([[10.]], Shape = (1, 1) , dtype = float32) 

Вы также должны увидеть созданную папку с именем model created.

Шаг C: Проверка сохраненной модели

Когда мы сохраняем модель, она создает папку и набор файлов внутри нее. Он в основном хранит веса и графики модели. У Tensorflow есть инструмент для погружения в эти файлы, чтобы мы могли сопоставить входной тензор и выходной тензор. Он называется saved_model_cli . Это инструмент командной строки, который собирается вместе при установке Tensorflow.

Нам нужно будет извлечь имя графика для входного тензора и выходного тензора и использовать эту информацию позже при вызове C API.Вот как это сделать:

 $ saved_model_cli show --dir  

запустив это и заменив соответствующий путь, вы должны получить вывод, как показано ниже:

 Данная SavedModel содержит следующие наборы тегов: 
serve

используйте это tag-set для дальнейшего углубления в тензорный график, вот как:

 $ saved_model_cli show --dir  --tag_set serve 

и вы должны получить результат, как показано ниже:

 Данный SavedModel MetaGraphDef содержит SignatureDefs с следующие ключи: 
ключ SignatureDef: "__saved_model_init_op"
ключ SignatureDef: "serve_default"

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

 $ saved_model_cli show --dir  

, и вы должны получить результат, как показано ниже:

 Данный SavedModel SignatureDef c содержит следующие входные данные: 
входов ['input_1'] tensor_info:
dtype: DT_INT64
shape: (-1, 1)
name: serve_default_input_1: 0
Данный SavedModel SignatureDef содержит следующие выходные данные:
output ['output_1'] tensor_info:
dtype: DT_FLOAT
shape: (-1, 1)
name: StatefulPartitionedCall: 0
Имя метода: tensorflow / serving / pred

Нам понадобится имя serve_default_input_1 и StatefulPartitioned позже для использования в C API.

Третья часть - написать код C, который использует Tensorflow C API, и импортировать сохраненную модель Python. Полный код можно найти здесь.

Нет надлежащей документации C API, поэтому, если что-то пошло не так, лучше всего взглянуть на их заголовок C в исходном коде (вы также можете отлаживать с помощью GDB и шаг за шагом узнать, как работает заголовок C)

Шаг A: Напишите код C

В пустой файл cpp импортируйте API TensorFlow C следующим образом:

Пустой базовый код C

Обратите внимание, что вы объявили пустую функцию NoOpDeallocator , мы будем использовать ее позже

Затем необходимо загрузить savemodel и сеанс с использованием TF_LoadSessionFromSavedModel API.

Загрузка сохраненной модели с помощью примера кода cpp

Затем мы берем тензорный узел из графа по их имени. Помните, ранее мы искали имя тензора с помощью saved_model_cli ? Здесь мы используем его, когда вызываем TF_GraphOperationByName () . В этом примере serve_default_input_1 - наш входной тензор, а StatefulPartitionedCall - выходной тензор.

Чтение входного тензора

Далее нам нужно будет выделить новый тензор локально с помощью TF_NewTensor , установить входное значение, а позже мы перейдем к запуску сеанса. ЗАМЕТЬТЕ, что ndata - это общий размер байта ваших данных, а не длина массива

Здесь мы устанавливаем входной тензор со значением 20., и мы должны видеть выходное значение как 20.

Тензор выделенного входа

Затем мы можем запустить модель, вызвав TF_SessionRun API. Вот как:

Запуск сеанса

Наконец, мы получаем обратно выходное значение из выходного тензора, используя TF_TensorData , который извлекает данные из тензорного объекта.Поскольку нам известен размер вывода, равный 1, я могу напрямую его распечатать. В противном случае используйте TF_GraphGetTensorNumDims или другой API, доступный в c_api. h или tf_tensor.h

Прочтите результат сеанса

Шаг B: Скомпилируйте код

Скомпилируйте его, как показано ниже:

 gcc -I  / include / -L  / lib main.c -ltensorflow -o main.out 

Шаг C: Запустите его

Перед запуском. Вам нужно будет убедиться, что библиотека C экспортирована в вашу среду

 export LD_LIBRARY_PATH = $ LD_LIBRARY_PATH:  / lib 

RUN IT

./main.out 

Вы должны получить результат, как показано ниже. Обратите внимание, что выходное значение равно 20, как и наш вход. вы можете изменить модель и инициализировать ядро ​​с весом, равным 2, и посмотреть, отражает ли оно другое значение.

 TF_LoadSessionFromSavedModel OK 
TF_GraphOperationByName serve_default_input_1 в порядке
TF_GraphOperationByName StatefulPartitionedCall в порядке
TF_NewTensor в норме
Session000 на языках

00 9137 или 9137 Tensflow 9137

[TOC]

Фон

Этот документ предназначен в качестве руководства для тех, кто заинтересован в создании или разработка функциональности TensorFlow на других языках программирования. Это описывает особенности TensorFlow и рекомендуемые шаги для их создания. доступны на других языках программирования.

Python был первым клиентским языком, поддерживаемым TensorFlow и в настоящее время поддерживает большинство функций. Все больше и больше этой функциональности перемещается в ядро ​​TensorFlow (реализовано на C ++) и предоставляется через C API. Клиентские языки должны использовать интерфейс внешних функций языка (FFI) позвонить в этот C API для обеспечения функциональности TensorFlow.

Обзор

Обеспечение функциональности TensorFlow на языке программирования может быть разбито в широкие категории:

  • Запустить предопределенный график : Учитывая GraphDef (или MetaGraphDef ) сообщение протокола, иметь возможность создавать сеанс, выполнять запросы, и получить тензорные результаты. Этого достаточно для мобильного приложения или сервера, хочет выполнить вывод на предварительно обученной модели.
  • Построение графика : По крайней мере, одна функция для каждой определенной Операция TensorFlow, которая добавляет операцию к графу.В идеале эти функции будут автоматически сгенерированы, чтобы они оставались синхронизированными в соответствии с определениями операций изменены.
  • Градиенты (также известное как автоматическое дифференцирование) : Дан график и список операций ввода и вывода, добавьте к графу операции, вычисляющие частные производные (градиенты) входов по выходам. Позволяет настроить функцию градиента для конкретной операции в графике.
  • Функции : Определите подграф, который может вызываться в нескольких местах в основной GraphDef .Определяет FunctionDef в FunctionDefLibrary включен в GraphDef .
  • Поток управления : Создайте «Если» и «Пока» с указанными пользователем подграфами. В идеале они работают с градиентами (см. Выше).
  • Библиотека нейронной сети : ряд компонентов, которые вместе поддерживают создание моделей нейронных сетей и их обучение (возможно, в распределенная установка). Хотя было бы удобно иметь это в другие языки, в настоящее время нет планов поддерживать это на языках кроме Python.Эти библиотеки обычно являются оболочками для функций описано выше.

Как минимум, языковая привязка должна поддерживать выполнение предопределенного графа, но большинство из них также должны поддерживать построение графов. API-интерфейс TensorFlow Python предоставляет все эти особенности.

Текущее состояние

Поддержка нового языка должна быть построена на основе C API. Однако, как вы можете см. в таблице ниже, еще не все функции доступны в C. Предоставление расширение функциональности в C API - текущий проект.

Характеристика Python С
Запустить предопределенный график tf.import_graph_def , tf.Session TF_GraphImportGraphDef , TF_NewSessionWithGraph
Построение графа с генерируемыми операционными функциями Есть Есть 1
Градиенты тс градиенты
Функции тс. python.framework.function.Defun
Поток управления тс.векунда , тс.время_цикла
Библиотека нейронных сетей tf.train , tf.nn , tf.contrib.layers , tf.contrib.slim

Рекомендуемый подход

Запустить предопределенный график

Предполагается, что языковая привязка определяет следующие классы:

  • График : график, представляющий вычисление TensorFlow.Состоит из операции (представлены на клиентском языке как Operation s) и соответствует TF_Graph в C API. В основном используется как аргумент, когда создание новых объектов Operation и при запуске Session . Также поддерживает итерацию операций в графе ( TF_GraphNextOperation ), поиск операций по имени ( TF_GraphOperationByName ), а также преобразование в GraphDef и обратно сообщение протокола ( TF_GraphToGraphDef и TF_GraphImportGraphDef в C API).
  • Операция : представляет вычислительный узел на графике. Соответствует TF_Operation в C API.
  • Выходные данные : представляет один из выходных данных операции на графике. Имеет DataType (и в конечном итоге форма). Может передаваться как входной аргумент в функция для добавления операций к графику или к сеансу Run () для получения этого вывода в виде тензора. Соответствует TF_Port в C API.
  • Сеанс : представляет клиента конкретному экземпляру TensorFlow время выполнения. Его основная работа должна быть построена с использованием Graph и некоторых опций. а затем полевые вызовы Run () графика. Соответствует TF_SessionWithGraph в C API. (Примечание: TF_SessionWithGraph будет в конечном итоге будет переименован в TF_Session , как только устаревший TF_Session станет удалено. )
  • Тензор : представляет N-мерный (прямоугольный) массив со всеми элементами тот же DataType .Получает данные в вызове Session ' Run () . Соответствует TF_Tensor в C API.
  • DataType : перечислитель со всеми возможными типами тензора, поддерживаемыми TensorFlow. Соответствует TF_DataType в C API и часто упоминается как dtype в Python API.

Построение графика

TensorFlow имеет много операций, и список не является статическим, поэтому мы рекомендуем сгенерировать функции для добавления операций в граф вместо того, чтобы писать их индивидуально от руки (хотя написание нескольких от руки - хороший способ понять, что генератор должен сгенерировать).Информация, необходимая для создания функции: содержится в сообщении протокола OpDef .

Есть несколько способов получить список OpDef s для зарегистрированных операций:

  • TF_GetAllOpList в C API извлекает весь зарегистрированный протокол OpDef Сообщения. Это можно использовать для написания генератора на клиентском языке. Для этого требуется, чтобы на клиентском языке была поддержка буфера протокола, чтобы для интерпретации сообщений OpDef .
  • Функция C ++ OpRegistry :: Global () -> GetRegisteredOps () возвращает то же самое. список всех зарегистрированных OpDef s (определенных в tensorflow / core / framework / op.h ). Это можно использовать для записи генератора в C ++ (особенно полезно для языков, у которых нет буфера протокола поддержка).
  • Сериализованная в формате ASCII версия этого списка периодически проверяется в tensorflow / core / ops / ops.pbtxt с помощью автоматизированного процесса.

OpDef определяет следующее:

  • Название операции в CamelCase.Для сгенерированных функций следуйте соглашениям языка. Например, если в языке используется snake_case, используйте это вместо CamelCase для имени функции операции.
  • Список входов и выходов. Типы для них могут быть полиморфными по ссылки на атрибуты, как описано в разделе входов и выходов Добавление op.
  • Список атрибутов с их значениями по умолчанию (если есть). Обратите внимание, что некоторые из них будут выведены (если они определены входными данными), некоторые будут необязательными (если они имеют значение по умолчанию), а некоторые из них потребуются (нет по умолчанию).
  • Документация по операционной деятельности в целом, а также входам, выходам и не предполагаемые атрибуты.
  • Некоторые другие поля, которые используются средой выполнения и могут игнорироваться генераторы кода.

OpDef можно преобразовать в текст функции, которая добавляет эту операцию к график с использованием TF_OperationDescription C API (завернутый в FFI языка):

  • Начните с TF_NewOperation () , чтобы создать TF_OperationDescription * .
  • Вызов TF_AddInput () или TF_AddInputList () один раз на ввод (в зависимости от имеет ли вход тип списка).
  • Вызов функции TF_SetAttr * () для установки невыявленных атрибутов. Может пропустить атрибуты со значениями по умолчанию, если вы не хотите переопределять значение по умолчанию.
  • Задайте дополнительные поля, если необходимо:
    • TF_SetDevice () : принудительно выполнить операцию на определенном устройстве.
    • TF_AddControlInput () : добавить требования для завершения другой операции перед этой операцией запускается
    • TF_SetAttrString ("_ kernel") для установки метки ядра (редко используется)
    • TF_ColocateWith () для размещения одной операции с другой
  • По завершении вызовите TF_FinishOperation () .Это добавляет операцию к графику, после чего его нельзя изменить.

Существующие примеры запускают генератор кода как часть процесса сборки (используя базельское правило). В качестве альтернативы генератор кода может запускаться автоматизированным cron, возможно, проверяя результат. Это создает риск расхождения между сгенерированным кодом и OpDef , зарегистрированными в репозитории, но полезно для языков, где ожидается, что код будет сгенерирован заранее, например go get для Go и cargo ops для Rust.На другом конце спектра для на некоторых языках код может быть сгенерирован динамически из тензор потока / ядро ​​/ ops / ops.pbtxt .

Константы обработки

Код вызова будет намного более лаконичным, если пользователи могут предоставлять константы для ввода аргументы. Сгенерированный код должен преобразовать эти константы в операции, которые добавляются к графу и используются в качестве входных данных для создаваемой операции.

Дополнительные параметры

Если язык допускает дополнительные параметры функции (например, ключевое слово аргументы со значениями по умолчанию в Python), используйте их для дополнительных атрибутов, операции имена, устройства, входы управления и т. д. На некоторых языках эти необязательные параметры может быть установлен с использованием динамических областей видимости (например, блоков with в Python). Без этих функции, библиотека может прибегнуть к «шаблону построителя», как это сделано в C ++ версия TensorFlow API.

Область действия имени

Хорошая идея - иметь поддержку именования операций с графами с использованием иерархия области видимости, особенно учитывая тот факт, что TensorBoard полагается на нее для разумного отображения больших графиков. Существующие API Python и C ++ использовать разные подходы: в Python часть имени "каталог" (все до последнего "/") происходит от с блоками.По сути, есть стек локального потока с областями действия, определяющими иерархию имен. Последний компонент имени либо предоставляется явно пользователем (с использованием необязательный аргумент ключевого слова name ) или по умолчанию имя типа операции добавляется. В C ++ часть имени "каталог" хранится в явном Область видимости объекта. Метод NewSubScope () добавляется к этой части имени и возвращает новый Scope . Последний компонент имени устанавливается с помощью WithOpName () , и, как и в Python, по умолчанию используется имя типа операции. добавляется. Scope Объекты явно передаются, чтобы указать имя контекст.

Упаковщики

Может иметь смысл сохранить сгенерированные функции закрытыми для некоторых операций, чтобы Вместо этого можно использовать функции-оболочки, которые выполняют небольшую дополнительную работу. Это также дает аварийный выход для вспомогательных функций, выходящих за рамки сгенерированный код.

Обертка используется для поддержки ввода и вывода SparseTensor . А SparseTensor - это кортеж из трех плотных тензоров: индексов, значений и формы.ценности - размер вектора [n], shape - размер вектора [rank], а index - матрица размер [n, ранг]. Есть несколько редких операций, которые используют эту тройку для представления одиночный разреженный тензор.

Еще одна причина использовать обертки - для операций, которые удерживают состояние. Есть несколько таких операторы (например, переменная), у которых есть несколько сопутствующих операций для работы с этим штат. В API Python есть классы для этих операций, в которых конструктор создает op и методы этого класса добавляют операции к графу, которые работают с штат.

Прочие соображения
  • Хорошо иметь список ключевых слов, используемых для переименования операционных функций и аргументы, которые противоречат ключевым словам языка (или другим символам, которые вызвать проблемы, например, имена библиотечных функций или переменных, на которые есть ссылки в сгенерированном коде).
  • Функция для добавления операции Const к графику обычно представляет собой оболочка, поскольку сгенерированная функция обычно имеет избыточный DataType входов.

Градиенты, функции и поток управления

В настоящее время поддержка градиентов, функций и операций потока управления («если» и «пока») недоступен на других языках, кроме Python. Это будет обновляется, когда C API предоставляет необходимую поддержку.

1 . C API поддерживает клиентские языки, которые хотели бы сделать это ↩

Установите TensorFlow 2.3.1 на Jetson Nano

У вас установлен bazel 3.1.0- (@ non-git).

Укажите местонахождение python. [По умолчанию / usr / bin / python3]:

Найдены возможные пути к библиотекам Python:

/ usr / local / lib / python3.6 / dist-packages

/usr/lib/python3.6/dist-packages

/ usr / lib / python3 / dist-packages

Введите путь к желаемой библиотеке Python для использования. По умолчанию это [/usr/local/lib/python3.6/dist-packages]

/ usr / lib / python3 / dist-packages

Хотите ли вы собрать TensorFlow с поддержкой OpenCL SYCL? [y / N]: n

Для TensorFlow не будет включена поддержка OpenCL SYCL.

Хотите собрать TensorFlow с поддержкой ROCm? [y / N]: n

Для TensorFlow не будет включена поддержка ROCm.

Хотите собрать TensorFlow с поддержкой CUDA? [y / N]: y

Поддержка CUDA будет включена для TensorFlow.

Хотите создать TensorFlow с поддержкой TensorRT? [y / N]: y

Поддержка TensorRT будет включена для TensorFlow.

Найдено CUDA 10.2 в:

/usr/local/cuda-10.2/targets/aarch64-linux/lib

/usr/local/cuda-10.2/targets/aarch64-linux/include

Найдено cuDNN 8 в:

/ usr / lib / aarch64-linux-gnu

/ usr / include

Найдено TensorRT 7 в:

/ usr / lib / aarch64-linux-gnu

/ usr / include / aarch64-linux-gnu

Укажите список вычислительных возможностей CUDA, разделенных запятыми, которые вы хотите использовать.

Вы можете узнать о вычислительных возможностях вашего устройства по адресу: https://developer.nvidia.com/cuda-gpus. Каждая возможность может быть указана как «x.y» или «compute_xy», чтобы включать как виртуальный, так и двоичный код GPU, или как «sm_xy», чтобы включать только двоичный код.

Обратите внимание, что каждая дополнительная вычислительная способность значительно увеличивает время сборки и размер двоичного файла, и что TensorFlow поддерживает только вычислительные возможности> = 3,5 [по умолчанию: 3,5,7,0]: 5,3

Вы хотите использовать clang в качестве компилятора CUDA? [y / N]: n

nvcc будет использоваться в качестве компилятора CUDA.

Укажите, какой gcc должен использоваться nvcc в качестве хост-компилятора. [По умолчанию / usr / bin / gcc]:

Укажите флаги оптимизации, которые будут использоваться во время компиляции, если указан параметр bazel "--config = opt" [по умолчанию -march = native -Wno-sign-compare] :

Хотите интерактивно настроить ./WORKSPACE для сборок Android? [y / N]: n

Не настраивается WORKSPACE для сборок Android.

Предварительно сконфигурированные конфигурации сборки Bazel.Вы можете использовать любое из перечисленных ниже, добавив «--config = <>» в свою команду сборки. См. .Bazelrc для более подробной информации.

--config = mkl # Сборка с поддержкой MKL.

--config = monolithic # Конфигурация в основном для статической монолитной сборки.

--config = ngraph # Сборка с поддержкой Intel nGraph.

--config = numa # Сборка с поддержкой NUMA.

--config = dynamic_kernels # (Экспериментальная) Объединение ядер в отдельные общие объекты.

--config = v2 # Сборка TensorFlow 2.x вместо 1.x.

Предварительно настроенные конфигурации сборки Bazel по умолчанию отключены для функций:

--config = noaws # Отключить поддержку файловой системы AWS S3.

--config = nogcp # Отключить поддержку GCP.

--config = nohdfs # Отключить поддержку HDFS.

--config = nonccl # Отключить поддержку NVIDIA NCCL.

Конфигурация завершена

@ tenorflow / tfjs-node - npm

Этот репозиторий обеспечивает собственное выполнение TensorFlow в бэкэнд-приложениях JavaScript под управлением Node. js runtime, ускоряется двоичным файлом TensorFlow C. Он предоставляет тот же API, что и TensorFlow.js.

Этот пакет будет работать на платформах Linux, Windows и Mac, где поддерживается TensorFlow.

Установка

TensorFlow.js для Node в настоящее время поддерживает следующие платформы:

Для поддержки графического процессора [email protected] или более поздней версии требуется следующее программное обеспечение NVIDIA®, установленное в вашей системе:

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

Установка CPU TensorFlow.js для Node:
 npm установить @ tenorflow / tfjs-node
(или)
пряжа добавить @ tenorflow / tfjs-node 
Установка Linux / Windows GPU TensorFlow.js для Node:
 npm установить @ tenorflow / tfjs-node-gpu
(или)
пряжа добавить @ tenorflow / tfjs-node-gpu 
Windows / Mac OS X требует Python 2.7

Поддержка сборки Windows и OSX для node-gyp требует Python 2. 7. Обязательно установите эту версию перед установкой @ tenorflow / tfjs-node или @ tensorflow / tfjs-node-gpu .Машины с Python 3.x не будут правильно устанавливать привязки.

Для получения дополнительных сведений об устранении неполадок в Windows посетите WINDOWS_TROUBLESHOOTING.md.

Mac OS X требует Xcode

Если на вашем компьютере не установлен Xcode, выполните следующие команды:

Для Mac OS Catalina следуйте этому руководству по установке node-gyp.

После завершения этой операции повторно запустите yarn add или npm install для пакета @ tenorflow / tfjs-node .

Вам нужно только включить @ tenorflow / tfjs-node или @ tensorflow / tfjs-node-gpu в файл package.json, поскольку эти пакеты уже поставляются с @ tensorflow / tfjs .

Восстановите пакет на Raspberry Pi

Чтобы использовать этот пакет на Raspberry Pi, вам необходимо перестроить собственный аддон узла с помощью следующей команды после установки пакета:

 $ npm перестроить @ tenorflow / tfjs-node --build-from-source 

Использование привязки

Перед выполнением любого TensorFlow. js, импортируйте пакет узла:

 // Загружаем привязку
const tf = require ('@ tensorflow / tfjs-node');

// Или, если работает с GPU:
const tf = require ('@ tensorflow / tfjs-node-gpu'); 

Примечание: вам не нужно добавлять пакет @ tensorflow / tfjs в свои зависимости или импортировать его напрямую.

Разработка

 # Загрузите и установите зависимости JS, включая libtensorflow 1.8.
пряжа

# Запустить тесты TFJS для серверной части Node.js:
пряжа 
 # Переключиться на GPU для локальной разработки:
пряжа enable-gpu 

Демонстрация MNIST для Node.js

См. Репозиторий tfjs-examples для обучения набора данных MNIST с использованием привязок Node.js.

Необязательно: построить оптимальный TensorFlow из исходного кода

Чтобы получить наиболее оптимальную сборку TensorFlow, которая может использовать преимущества вашего конкретного оборудования (AVX512, MKL-DNN), вы можете собрать библиотеку libtensorflow из источника:

 . /configure
bazel build --config = opt --config = monolithic // тензорный поток / инструменты / lib_package: libtensorflow 

Сборка может занять некоторое время и приведет к созданию bazel-bin / tensorflow / tools / lib_package / libtensorflow.tar.gz файл, который необходимо распаковать и заменить файлы в папке deps tfjs-node repo:

 cp bazel-bin / tensorflow / tools / lib_package / libtensorflow.tar.gz ~ / myproject / node_modules / @ tenorflow / tfjs-node / deps
cd путь к моему проекту / node_modules / @ tenorflow / tfjs-node / deps
tar -xf libtensorflow.tar.gz 

Если вы хотите опубликовать дополнительную библиотеку со своим собственным двоичным файлом libtensorflow, вы можете разместить настраиваемый двоичный файл libtensorflow и дополнительный предварительно скомпилированный модуль надстройки узла в выбранной вами облачной службе и добавить настраиваемый двоичный файл .json в папке scripts со следующей информацией:

 {
  "tf-lib": "URL-адрес для загрузки-настраиваемый-двоичный",
  "добавить": {
    "host": "host-of-pre-compiled-addon",
    "удаленный_путь": "удаленный-путь-предварительно скомпилированного-дополнения",
    "имя_пакета": "имя-файла-дополнения-предварительной компиляции"
  }
} 

Сценарии установки автоматически перехватят этот файл и будут использовать специальный двоичный файл libtensorflow и надстройку. Если надстройка не предоставлена, сценарий установки скомпилирует надстройку из исходников.

Пример запуска TensorFlow lib C API

Пример TensorFlow C API

Пример запуска API TensorFlow lib C в Windows, Linux и macOS (Дарвин).

Пример сборки

Окна

  git clone - глубина 1 https://github.com/Neargye/hello_tf_c_api
cd hello_tf_c_api
mkdir build
cd build
cmake -G "Visual Studio 15 2017" -A x64 ..
cmake --build. --config Отладка
  

Linux и macOS (Дарвин)

  git clone --depth 1 https: // github.ru / Neargye / hello_tf_c_api
cd hello_tf_c_api
mkdir build
cd build
cmake -G "Makefiles Unix" ..
cmake --build.
  
  • После сборки вы можете найти библиотеку TensorFlow в папке hello_tf_c_api / tensorflow / lib и заголовок в hello_tf_c_api / tensorflow / include.
  • Тензорный поток в репозитории компилируется в режиме x64. Убедитесь, что проект нацелен на 64-битные платформы.
  • Убедитесь, что библиотека tenorflow находится в каталоге вывода или в каталоге, содержащемся в переменной среды% PATH%.

Получить библиотеку тензорного потока

Для ЦП x64 вы можете скачать tenorflow.so, tensorflow.dll и tensorflow.lib с https://github.com/Neargye/tensorflow/releases.

Или создайте библиотеку нужной вам версии из исходников с поддержкой CPU или GPU.

Создать файл .lib из .dll для Windows

Откройте командную строку Visual Studio, вы найдете ее ярлык в «Пуск» -> «Программы» -> «Microsoft Visual Studio» -> «Инструменты». Теперь запустите команду dumpbin, чтобы получить список всех экспортированных функций вашей dll:

  dumpbin / экспортирует ваш путь / тензорный поток.dll
  

Это выведет на консоль довольно много текста. Однако нас интересуют только функции:

  порядковая подсказка Имя RVA

          1 0 028D4AB8 [адрес электронной почты защищен] @@ 3QEBDEB
          2 1 028D4AC0 [адрес электронной почты защищен] @@ 3QEBDEB
          3 2 028D4AC8 [адрес электронной почты защищен] @@ 3QEBDEB
          4 3 028E1380 [защита электронной почты] @ [защита электронной почты] @ 2QBDB
          5 4 028E1390 [защита электронной почты] @ [защита электронной почты] @ 2QBDB
          6 5 03242488 [защита электронной почты] @ [защита электронной почты] @@ [защита электронной почты] @ [защита электронной почты] @ [защита электронной почты] @@ [защита электронной почты] @A
          7 6 001996C0 TFE_ContextAddFunction
          8 7 00199710 TFE_ContextAddFunctionDef
          9 8 001997D0 TFE_ContextAsyncClearError
         10 9 001997E0 TFE_ContextAsyncWait
         11 A 00199830 TFE_ContextClearCaches
. ..
  

Теперь скопируйте все эти имена функций (только имена!) И вставьте их в новый текстовый файл. Назовите следующий файл tensorflow.def и поместите строку «EXPORTS» вверху. Мой файл tensorflow.def выглядит так:

  ЭКСПОРТ
[адрес электронной почты защищен] @@ 3QEBDEB
[адрес электронной почты защищен] @@ 3QEBDEB
[адрес электронной почты защищен] @@ 3QEBDEB
[защита электронной почты] @ [защита электронной почты] @ 2QBDB
[защита электронной почты] @ [защита электронной почты] @ 2QBDB
[защита электронной почты] @ [защита электронной почты] @@ [защита электронной почты] @ [защита электронной почты] @ [защита электронной почты] @@ [защита электронной почты] @A
TFE_ContextAddFunction
TFE_ContextAddFunctionDef
TFE_ContextAsyncClearError
TFE_ContextAsyncWait
TFE_ContextClearCaches
...
  

Теперь из этого файла определения мы, наконец, можем создать файл .lib. Для этого мы используем инструмент «lib», поэтому запустите эту команду в командной строке Visual Studio:

  lib /def:yourpath/tensorflow. def /OUT:yourpath/tensorflow.lib / МАШИНА: X64
  

/ MACHINE: X64 - для сборки x64 и / MACHINE: X86 для сборки x32.

Ссылка tenorflow lib

CMakeLists.txt
  link_directories (yourpath / to / tensorflow) # путь к tenorflow lib
... # Другой
target_link_libraries (  тензорный поток)
  
Visual Studio

«Проект» -> «Свойства» -> Свойства конфигурации »->« Компоновщик »->« Дополнительные зависимости »и добавьте путь к вашему tenorflow.lib в качестве следующей строки.

Убедитесь, что файл tensorflow.dll находится в каталоге вывода (по умолчанию это Debug \ Release в папке вашего проекта) или в каталоге, содержащемся в переменной среды% PATH%.

GitHub

Все устарело, что теперь! - Уильям Дж. Шипман

Обновление 2019-11-11: Часть 2 была опубликована здесь, описывая решение, которое работает для меня, которое заключается в использовании формата Open Neural Network eXchange (ONNX) и среды выполнения ONNX с открытым исходным кодом.

Предыстория (или жизнерадостная история)

Несколько месяцев назад я работал над сложной задачей компиляции интерфейса TensorFlow на C ++ и написания приложения, которое будет использовать обученную нейронную сеть для вывода.Это было еще во времена TensorFlow 1.8. Теперь TensorFlow 2.0 не за горами, и многое изменилось. Поиск в Google, как сохранять модели в Python, показал несколько новых методов, но как тогда загрузить эти модели в C ++? Итак, я собрал воедино процесс, используя устаревшие API и исправив некоторые ранее сделанные ошибки, и двинулся дальше. Теперь я вернусь, чтобы выяснить, какое решение является правильным для последней версии TensorFlow, версии 1.13, и это также будет работать с TensorFlow 2.0, который в настоящее время находится в стадии бета-тестирования.

Это часть 1, в которой суммируется мое разочарование из-за изменений API между TensorFlow 1.x и 2.0. Я собирался рассказать, как использовать TensorFlow C API, доступный по адресу https://www. tensorflow.org/install/lang_c, для загрузки сохраненной нейронной сети, но этот пост уже становится довольно длинным, а C API выглядит как чрезмерно сложный способ решения проблемы, плюс я не уверен, какие части C API будут поддерживаться в TensorFlow 2.0. Вторая часть посвящена загрузке модели.Мой новый план - попытаться преобразовать нейронную сеть в формат ONNX и загрузить ее с помощью среды выполнения ONNX. У этой среды выполнения есть C API с примером здесь.

Проблема с использованием TensorFlow C ++ API заключается в том, что вам нужно либо принудительно поместить свой проект в систему сборки TensorFlow, либо попробовать собрать TensorFlow с помощью Cmake. Всем разработчикам TensorFlow, читающим это, предоставьте C ++ API в красивой небольшой библиотеке, которая не заставляет меня строить мой проект с помощью bazel и не оставляет зависимости разбросанными, как в процессе Cmake (который официально не поддерживается).

Старый способ решения проблемы сохранения графика TensorFlow в один файл * . pb заключался в использовании функции tf.graph_util.convert_variables_to_constants для преобразования всех тензоров весов и смещений в константы с последующим использованием tf.gfile. GFile для записи определения графа в файл. Пример этого показан здесь. Проблема в том, что convert_variables_to_constants устарел и будет удален в TensorFlow 2.0.

TL; DR

Если вы хотите обслуживать свою обученную модель с веб-сервера, TensorFlow обслуживает и сохраняет модель с помощью tf.saved_model - хорошая ставка. TF Serving будет поддерживать TensorFlow 2.0, поэтому единственное изменение будет внесено в ваш код, который сохраняет модель, потому что API в tf.saved_model изменяется с TensorFlow 2.0.

Если, как и я, вы ищете метод C / C ++ и думаете, что обслуживание TF - это излишне, я не смогу найти абсолютно гарантированного пути к успеху. Однако, кажется, лучше всего преобразовать в формат ONNX и использовать среду выполнения ONNX для использования модели для вывода. Во второй части этой серии статей я расскажу о моих попытках создать руководство о том, как это сделать.

Множество способов сохранить (скин?) Модель TensorFlow (кот?)

Есть несколько способов сохранить и загрузить / обслужить модели TensorFlow. Для каждого из них я расскажу о сохранении и загрузке в Python, а затем буду стонать, в основном потому, что какая-то часть процесса устарела или метод не соответствует моим потребностям.

Я писал код для использования некоторых методов, пока не понял, что все это устарело. Вы можете найти код этой части, а затем и части 2, на BitBucket.По крайней мере, часть кода, использующего tf.saved_model , будет повторно использована для части 2.

тф.saved_model

Самый простой способ использовать этот модуль - использовать функцию tf.saved_model.simple_save . Ой, этот тоже устарел. Более сложный способ - создать экземпляр класса tf.saved_model.Builder . Только после того, как я пробовал код для использования этого класса, я увидел примечание «Эта функция будет доступна только через библиотеку совместимости v1 как tf.compat.v1.saved_model.builder.SavedModelBuilder или tf.compat.v1.saved_model.Builder. Tensorflow 2.0 представит новый объектно-ориентированный метод создания SavedModels ». Это означает, что буфер протокола SavedModel и tf.saved_model будут по-прежнему использоваться, но в TensorFlow v1.x, а также в 2.0 нет кода для их использования. Ниже приведен код, показывающий, как использовать tf.saved_model.Builder , чего это стоит.

def use_tf_saved_model (X, y, сессия):
строитель = тф.сохраненная_модель.builder.SavedModelBuilder ('./ data / save_model')
builder. add_meta_graph_and_variables (
сессия,
[tf.saved_model.tag_constants.SERVING],
signature_def_map = {
tf.saved_model.signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY: tf.сохраненная_модель.predict_signature_def (
входы = {'X': X},
output = {'y': y}
)
},
strip_default_attrs = True)
builder.save ()
def load_tf_saved_model (sessions, in_name, out_name):
тс. сохраненная_модель.load (сессия, [tf.saved_model.tag_constants.SERVING], './data/save_model')
график = tf.get_default_graph ()
X = graph.get_tensor_by_name (in_name)
y = graph.get_tensor_by_name (out_name)
возврат X, y
Использование tf.saved_model.Builder в TensorFlow 1.13.

Одна вещь, которую я не сделал, - это реализовать правильный метод для получения входных данных непосредственно из SavedModel . Я считаю, что это возможно, но оставлю это для части 2.

В TensorFlow 2.0 есть две полезные функции: tf.saved_model.save и tf.saved_model.load для работы с буферами протокола SavedModel . Примеры в документации TensorFlow 2. 0 показывают, что tf.Модели keras будет легко сохранить, а пользовательские модели потребуют немного больше усилий, так как вам придется обернуть их в класс. С другой стороны, инструмент для преобразования моделей TensorFlow в ONNX поддерживает и даже рекомендует использовать SavedModel . Этот инструмент tf2onnx находится здесь. В настоящее время tf2onnx поддерживает только TensorFlow до 1.13, но не 2.0.

tf.io

Этот модуль предоставляет tf.io.gfile.GFile , упомянутый выше, и функцию tf.io.write_graph .Оба достигают одного и того же результата, они записывают буфер протокола GraphDef в файл. Проще использовать write_graph , который также предоставляет опцию as_text для управления хранением GraphDef в обычном текстовом или двоичном формате. Есть одна проблема, такой подход сохраняет только структуру нейронной сети, но не веса. Бибху Пала предоставляет учебное пособие, показывающее, как использовать tf. train.Saver и tensorflow.python.tools.freeze_graph для сохранения весов и объединения их со структурой сети в единое целое.pb файл. К сожалению, копание в коде freeze_graph показывает, что устаревший convert_variables_to_constants дает нежелательный возврат! Таким образом, косвенно этот подход также устарел.

Есть дополнительная сложность, которую я не мог обойти. Загрузка GraphDef с последующим вызовом tf.import_graph_def должна, насколько я понимаю в документации, создать переменные. Это не так! Попытка создать новый tf.Объект train.Saver для использования его метода restore приводит к ошибке об отсутствии переменных. Кажется, что, хотя GraphDef куда-то импортирован, его нельзя использовать.

тс. Поезда

Этот метод также устарел в Python, YAY. Это также кажется хрупким, поскольку зависит от именования узлов операции восстановления на графе. Вы увидите почему в следующем абзаце. Сохранить MetaGraphDef и веса так же просто, как построить tf.train.Saver и вызов метода save с текущим сеансом и путем к файлу контрольной точки. Это создает файл * .meta , который содержит MetaGraphDef , файл * .data , содержащий переменные, и файл * .index . Перезагрузить эту модель в Python почти так же просто, как сохранить ее. Сначала вызовите tf.train.import_meta_graph , указав путь к файлу * .meta , указанному выше. Это импортирует MetaGraphDef и оставляет один со всеми хорошо определенными переменными.Теперь создание нового объекта tf.train.Saver работает, поэтому последний шаг - вызвать его метод restore с тем же путем, который использовался при вызове save . Это загружает все переменные, и все снова работает. Однако есть одно ограничение. Открытие метафайла в Netron не показывает веса, вероятно, потому, что Netron не знает, что это контрольная точка. Пропуск вызова tf.train.import_meta_graph приведет к тому, что конструктор tf.train.Saver выдаст ошибку об отсутствии переменных, определенных в текущем сеансе.Похоже, должен был быть класс Loader, но не будем зацикливаться на странных API. В приведенном ниже коде показано, как сделать все, что я описал выше.

def save_weights (сессия):
saver = tf.train.Saver ()
saver.save (сессия, './data/tf_io.ckpt')
def load_weights (сессия, имя_входа, имя_выхода):
тс.train.import_meta_graph ('./ data / tf_io. ckpt.meta')
saver = tf.train.Saver ()
saver.restore (сессия, './data/tf_io.ckpt')
X = tf.get_default_graph (). Get_tensor_by_name (in_name)
y = tf.get_default_graph (). Get_tensor_by_name (out_name)
возврат X, y
Используя тс.train.Saver в TensorFlow 1.13.

Здесь есть демонстрация, показывающая, как использовать TensorFlow C API. Граф для сохраненной модели содержит дополнительные узлы для сохранения и восстановления графа. Существует строковый тензор с именем save / Const , в который вы указываете путь к контрольной точке. Выходной тензор называется save \ RestoreV2 в современных версиях и save \ restore_all в старых версиях, отсюда и мой комментарий о хрупкости этого метода. Теперь восстановление сохраненной модели выполняется путем выполнения операций на графике путем выполнения связанных операций, как и для любых других операций в TensorFlow.

Обслуживание TensorFlow

Я собирался исследовать это дальше, потому что думал, насколько плохим может быть веб-сервер, обслуживающий SavedModel . Затем я увидел, что рекомендуемый способ установки - использовать Docker. Итак, в Windows мне понадобится целая виртуальная машина только для запуска моей модели TensorFlow! Хотя в коде это выглядит довольно просто, и сторона C ++ может использовать C ++ REST SDK для вызова API, это, вероятно, наименее эффективное решение, когда ваша модель будет находиться на одном компьютере, обслуживающем только несколько запросов.Это определенно решение, ориентированное на веб-серверы. С положительной стороны, файлы SavedModel можно легко обслуживать с помощью tensorflow_model_server , как показано здесь. Это описано в руководствах v1. x и v2.0, так что это единственный метод, который гарантированно работает в TensorFlow 2.0. Также кажется, что поддержка TensorFlow 2.0 появилась в TensorFlow Serving, и, согласно этому закрытому вопросу, TensorFlow 2.0 SavedModel должен был в основном работать в TF Serving, потому что формат не сильно изменился.

Заключение

Только формат SavedModel и tf.saved_model кажутся относительно надежными методами сохранения ваших моделей. Во второй части я попытаюсь собрать код, который можно переносить между TensorFlow 1.x и 2.0 (не уверен, насколько хорошо это будет работать, но я попробую). С точки зрения создания кода на стороне вывода на C или C ++, который будет работать как с TensorFlow 1.x, так и с 2.0, лучшим вариантом, по-видимому, будет преобразование в ONNX. Инструмент для этого - tf2onnx, который может работать с контрольными точками, созданными с помощью tf.train.Saver , а также SavedModel .

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Theme: Overlay by Kaira Extra Text
Cape Town, South Africa