TF-Lite: PReLU работает неправильно после преобразования модели pb в tflite - PullRequest
0 голосов
/ 12 сентября 2018

В модели pb у меня есть слой PRelu.Поскольку tflite не имеет PRelu OP, поэтому я преобразую PRelu в Relu следующим образом:

 pos = relu(x)
 neg = - alphas * relu(-x)
 return pos + neg

При преобразовании в модель tflite, PRelu будет замененна relu и отрицательных ОП.Но при конвертации отрицательная часть relu op между двумя отрицательными операциями уменьшается на toco.Преобразованная модель выглядела так:

pos = relu(x)
neg = -alphas * (-x)
return pos + neg

есть проблемы?

Ответы [ 2 ]

0 голосов
/ 29 сентября 2018

Чтобы просто решить эту проблему, измените PRelu на Max (x, 0) + alphas * Min (0, x)

0 голосов
/ 27 сентября 2018

Tensorflow Lite объединяет функцию активации с самой операцией, поэтому Relu ops будут удалены из графика.Цитата из документации (в которой также упоминается tf.nn.relu):

Обратите внимание, что многие из этих операций не имеют эквивалентов TensorFlow Lite и соответствующая модель не будет конвертируемой, еслиони не могут быть исключены или слиты.


Давайте посмотрим, что это значит.Приведенный выше код PReLU в TensorFlow, визуализированный с использованием TensorBoard , выглядит следующим образом (график ORIGINAL ):

conv --> relu ---------------------\
     \-> neg -> relu -> mul -> neg --> add

Однако из-за того, что TfLiteобъединяет операции Relu с предыдущей операцией (подробнее в документы ), TRY создаст что-то вроде этого (обратите внимание, что [A+B] представляет собой сплавленный слой Aи B ops):

[conv+relu] -----------------------------\
            \-> [neg+relu] -> mul -> neg --> add

Но, поскольку операция neg (унарный минус) не имеет функции активации, что ACTUALLY происходит внутри внешнего вида TF-Liteкак следующее (это было проверено мной на версии 1.9.0):

[conv+relu] ----------------------\
            \-> neg -> mul -> neg --> add

Так что, это не имеет смысла!


Моя личная работа заключается в следующем(учитывая, что у вас уже есть обученная модель *.pb и вы не хотите переобучать новую модель только потому, что архитектура изменилась):

def tflite_tolerant_prelu(_x, alpha, name_scope):
    with tf.name_scope(name_scope):
        alpha = tf.constant(alpha, name='alpha')
        return tf.maximum(_x, 0) + alpha * tf.minimum(_x, 0)

def replace_prelu(graph, prelu_block_name, tensor_before, tensor_after):
    alpha = graph.get_tensor_by_name(os.path.join(prelu_block_name, 'alpha:0'))
    with tf.Session() as sess:
        alpha_val = alpha.eval()
    new_prelu = tflite_tolerant_prelu(tensor_before,
            alpha_val, prelu_block_name + '_new')
    tf.contrib.graph_editor.swap_inputs(tensor_after.op, [new_prelu])

before = mtcnn_graph.get_tensor_by_name('pnet/conv1/BiasAdd:0')
after = mtcnn_graph.get_tensor_by_name('pnet/pool1:0')
replace_prelu(mtcnn_graph, 'pnet/PReLU1', before, after)

Этот код использовался для передачи MTCNN от TensorFlow до TensorFlow Lite.Выглядит немного некрасиво (определенно нужно, чтобы он выглядел чище), но он полностью функционален и выполняет свою работу.Обратите внимание, что я использовал инструмент редактора графиков tensorflow.contrib.graph_editor, чтобы изменить график в автономном режиме.

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