В этом руководстве я покажу, как я преобразовал предварительно подготовленную сеть, написанную на TF 2.0, с немного продвинутой архитектурой, в оптимизированную сеть, подходящую для вывода. Моей целью было запустить предтренированную модель в выводе, используя C ++ и модуль Dnn OpenCV . Однако это руководство поможет вам создать оптимизированную модель, которая может использоваться на многих платформах, включая Python и TensorRT.
После обучения модели в TF 2.0 я искал простой способ оптимизировать модель для вывода. Однако я не нашел ни одного места, которое помогло бы мне сделать это в TF 2.0, поскольку TF удалила их поддержку в замороженных оптимизированных графиках, как видно из всех жалоб, собранных в StackOverflow (например, 1 , 2 ).
Есть много решений, написанных на разных интернет-форумах. Я пишу руководство по самому простому способу, который я нашел для этого.
Технические характеристики системы
Anaconda3 4.4+,
Tensorflow 2.0,
OpenCV 4.1.2+,
Вам также может понравиться:
Введение в TensorFlow .
Начиная
В моей сетевой реализации я использовал:
- Набор данных и итераторы (
tf.data.dataset
). - Заполнители (
tf.placeholder
). - Свертки (
tf.layers.conv2d
). - Глубинные свертки (
tf.nn.depthwise_conv2d
иtd.nn.bias_add
). - Relu6 (
tf.nn.relu6
). - Пакетная нормализация (
tf.layers.batch_normalization
). - Свести (
tf.layers.flatten
). - Softmax (
tf.nn.softmax
). - Глобальное среднее (
tf.layers.average_pooling2d
).
После обучения мы хотели бы экспортировать нашу модель в файл .pb, чтобы запустить его на логическом этапе. Tensorflow имеет простой API кода для публикации модели:
tf.saved_model.simple_save(sess,path,inputs,outputs)
Однако это приведет к экспорту полной модели во многие файлы, включая определение графика, переменные, и не удалит сводки, которые не нужны во время вывода. Это ограничивает производительность использования графического процессора, поскольку ненужные сетевые компоненты часто работают на процессоре.
До TF 2.0 наилучшей практикой было:
- Заморозить модель (взять график def в сочетании с контрольной точкой и преобразовать все переменные в константы только в одном файле pb)
- Оптимизируйте замороженный график для вывода, в том числе:
- Удалить неиспользуемые узлы.
- Сложите арифметику и выражения для констант.
- Удалить личность и никаких операций.
- Сложите пакетную нормализацию в простые умножения.
- Сортировать по порядку выполнения, который необходим для запуска в OpenCV.
Этот код в основном поддерживался Graph Transform Tool и был интегрирован в библиотеку инструментов TensorFlow. Это было до TF2.0, где TF удалил свою поддержку и свой граф использует код, поскольку tf.compact1.graph_util
в основном он пуст. Вместо этого они ожидают, что разработчики будут использовать API SavedModels . Однако другие библиотеки и модули логического вывода не поддерживают его, и пользователям TF нужно сломать голову, чтобы найти способ оптимизировать свою модель.
Я подробно опишу, что я сделал, чтобы заморозить мою модель:
Напишите свой код заранее, чтобы соответствовать выводу
Используйте флаг с именем Inference
.
Для итераторов используйте:
питон
xxxxxxxxxx
1
if not inference:
2
X,y=iterator.get_next()
3
is_training=tf.placeholder(tf.bool, name=”is_training”)
4
else:
5
X=tf.placeholder(tf.float32,shape=…)
6
y=tf.placeholder(tf.float32,shape=…)
7
is_training=tf.constant(tf.bool, name=”is_training”)
8
Я рекомендую этот метод вместо пост-редактирования графика. Это помогает рассмотреть вывод с самого начала разработки. Например, я изменил свою реализацию среднего пула во время обучения, от использования average_pooling2d
к reduce_sum
простому использованию , что проще и будет работать на большем количестве платформ.
Вы также можете добавить обработку под этим флагом для сводок и автора файлов. Вместо того, чтобы убирать их на пост-тренинге, просто не добавляйте их 🙂
Тренируй модель в TF 2.0
Сохранить контрольную точку модели, используя:
tf.train.Saver(tf.all_varibles()). save(sess,path)
Сохраните графическое определение модели, используя:
Tf.train.write_graph(sess.graph,path)
Создайте новую среду с tenorflow 1.15 и запустите следующий код:
питон
xxxxxxxxxx
1
From tf.python,tools import freeze_graph,optimize_for_inference_lib
2
freeze_graph.freeze_graph(input_graph_path,input_saver_def_path=””,
4
input binary =False,checkpoint_path=checkpoint_path,
5
output_nodes=[“predictions”],restore_op_name = “”,
6
filename tensor_ name=””, clear_devices=False,””)
7
inputGraph = tf.GraphDef()
9
with tf.gfile.Open(frozen graph path, “rb”) as f:
10
data2read = f.read()
11
inputGraph.ParseFromString(data2read)
12
outputGraph = optimize_for_inference_lib.
14
optimize_for_inference(inputGraph, [input node name],
15
[output node names],
16
tf.float32.as datatype enum)
17
with tf.gfile.FastGFile(optimized graph path, ‘w’) as f :
18
f.write(outputGraph.SerializeToString())
Этот код должен работать отлично, но не работал на моей конкретной модели. Я получил исключение:
“Didn’t find expected Conv2D input to bn”
Это было странно, и я начал исследовать свой код и выяснить, была ли проблема в моей сети или изменилась среда.
Наконец, я обнаружил, что это не было моим предположением. Я обнаружил, что код TF1.15 не обновляется последним кодом инструмента преобразования графов inference_lib
. Проблема с кодом заключалась в том, что при пакетной нормализации в качестве входных данных принималась операция Conv2D. Но в моей сети я использовал смещение, используя результирующую BiasAdd
операцию перед применением нормализации партии
Прежде чем пытаться исправить ошибку, я искал в Интернете и увидел, что об этом уже позаботились в GitHub, но он не обновлялся в TF и не будет, так как он был удален в TF2.0.
Я изменил код TF и исправил файл в:
%installation python folder%/tensorflow/python/tools/optimjzed_for_inference_
lib.py
с прикрепленным кодом . После этих исправлений мой код не возвращал никаких ошибок.
Я надеюсь, что это руководство поможет кому-то конвертировать модель, написанную на TF2.0, для запуска на выводе.
Удачи 🙂
В следующем посте я покажу, как запустить оптимизированный граф при выводе на OpenCV в C ++ и на TF в Python. Я сравню их (подсказка: на процессоре они довольно равны).