Подтвердить что ты не робот

TensorFlow: Есть ли способ конвертировать замороженный график в модель контрольной точки?

Возможна конвертация модели контрольной точки в замороженный график (файл.ckpt в файл.pb). Однако существует ли обратный метод преобразования файла pb в файл контрольной точки еще раз?

Я предполагаю, что это требует преобразования констант обратно в переменную - существует ли способ идентифицировать правильные константы в качестве переменных и вернуть их обратно в контрольную модель?

В настоящее время существует поддержка преобразования переменных в константы: https://www.tensorflow.org/api_docs/python/tf/graph_util/convert_variables_to_constants

но не наоборот.

Здесь был задан аналогичный вопрос: Тензорный поток: преобразовать постоянный тензор из предварительно обученной модели Vgg в переменную

Но решение основано на использовании модели ckpt для восстановления весовых переменных. Есть ли способ восстановить весовые переменные из файлов PB вместо файла контрольной точки? Это может быть полезно для обрезки веса.

4b9b3361

Ответ 1

Если у вас есть исходный код, который создал сеть, это можно сделать относительно легко, потому что имя Convolutions/Fully connected не изменилось методом замораживания графа, поэтому вы можете в основном исследовать график и сопоставить операции констант с их переменными. соответствует и просто загрузить переменные со значением констант.

Если у вас нет кода, который создал сеть, это все еще можно сделать, но это не так просто.

Например, вы можете искать все узлы в вашем графике и искать операции типа Constant, а затем, найдя все операции типа Constant, вы можете увидеть, связана ли операция с Convolution/Fully connected, например.. (Или вы можете просто преобразовать все константы, это зависит от вас).

После того, как вы узнаете, какие константы вы хотите преобразовать в переменные, вы можете добавить переменную в график, которая содержит значение константы, а затем использовать Tensorflow редактор графиков для перемонтирования соединений (используйте reroute_ts метод) между операцией const и переменной.

После того, как вы это сделали, вы можете сохранить свой график, и когда вы загрузите его снова, у вас будут переменные (но помните, что константы все равно останутся в вашем графике, но их можно оптимизировать с помощью graph-transform инструмент например)

Ответ 2

  Если у вас есть исходный код, который создал сеть, это можно сделать относительно легко, поскольку имя Convolutions/Fully connected не изменилось методом замораживания графа, поэтому вы можете в основном исследовать график и сопоставить операции констант с их переменными. совпадает и просто загружает переменные со значением констант. - Альмог Давид

Спасибо @Альмогу Дэвиду за отличный ответ выше; Я столкнулся с точно такой же ситуацией, что и

  • У меня есть frozen_inference_graph.pb, но нет контрольных точек;
  • У меня есть исходный код для создания frozen_inference_graph.pb, но я не знаю параметров.

ниже приведены три шага для решения этой дилеммы.

1. Получить пары имен узлов и значений из frozen_inference_graph.pb

import tensorflow as tf
from tensorflow.python.framework import tensor_util

def get_node_values(old_graph_path):
    old_graph = tf.Graph()
    with old_graph.as_default():
        old_graph_def = tf.GraphDef()
        with tf.gfile.GFile(old_graph_path, "rb") as fid:
            serialized_graph = fid.read()
            old_graph_def.ParseFromString(serialized_graph)
            tf.import_graph_def(old_graph_def, name='')

    old_sess = tf.Session(graph=old_graph)

    # get all the nodes from the graph def
    nodes = old_sess.graph.as_graph_def().node

    value_dict = {}
    for node in nodes:
        value = node.attr['value'].tensor
        try:
            # get name and value (numpy array) from tensor 
            value_dict[node.name] = tensor_util.MakeNdarray(value) 
        except:
            # some tensor does not have value; for example np.squeeze
            # just ignore it 
            pass
    return value_dict

value_dict = get_node_values("frozen_inference_graph.pb")

2. Создать новый график с использованием существующего кода; настраивайте параметры модели, пока все узлы в новом графике не будут присутствовать в value_dict

new_graph = tf.Graph()
with new_graph.as_default():
    tf.create_global_step()
    #existing code 
    # ...
    # ...
    # ...

    model_variables = tf.model_variables()
    unseen_variables = set(model_variable.name[:-2] for model_variable in model_variables) - set(value_dict.keys())
    print  ("\n".join(sorted(list(unseen_variables))))

3. Присвойте значения переменным и сохраните в контрольную точку (или сохраните в график)

new_graph_path = "model.ckpt"
saver = tf.train.Saver(model_variables)

assign_ops = []
for variable in model_variables:
    print ("Assigning", variable.name[:-2])
    # variable names have ":0" but constant names does not have.
    value = value_dict[variable.name[:-2]]
    assign_ops.append(variable.assign(value))

sess =session.Session(graph = new_graph)
sess.run(tf.global_variables_initializer())
sess.run(assign_ops)
saver.save(sess, new_graph_path+"model.ckpt")

Это единственный способ решить эту проблему. Тем не менее, он все еще имеет некоторые недостатки: если вы перезагрузите контрольные точки модели, вы найдете (наряду со всеми полезными переменными) много нежелательных переменных assign, таких как Assign_700/value. Это неизбежно и выглядит некрасиво. Если у вас есть лучшие предложения, не стесняйтесь комментировать. Благодарю.

Ответ 3

Существует метод для преобразования констант обратно в обучаемые переменные в TensorFlow через редактор графиков. Однако вам нужно будет указать узлы для преобразования, так как я не уверен, есть ли способ автоматически определять это надежным способом.

Вот шаги:

Шаг 1. Загрузите замороженный график

Мы загружаем наш файл .pb в графический объект.

import tensorflow as tf

# Load protobuf as graph, given filepath
def load_pb(path_to_pb):
    with tf.gfile.GFile(path_to_pb, 'rb') as f:
        graph_def = tf.GraphDef()
        graph_def.ParseFromString(f.read())
    with tf.Graph().as_default() as graph:
        tf.import_graph_def(graph_def, name='')
        return graph

tf_graph = load_pb('frozen_graph.pb')

Шаг 2. Найдите константы, которые необходимо преобразовать

Вот два способа перечислить имена узлов на вашем графике:

  • Используйте этот скрипт, чтобы напечатать их
  • print([n.name for n in tf_graph.as_graph_def().node])

Узлы, которые вы хотите преобразовать, скорее всего, названы как-то по принципу "Const". Конечно, это хорошая идея - загрузить свой график в Netron, чтобы увидеть, какие тензоры хранят обучаемые веса. Часто можно предположить, что все константные узлы когда-то были переменными.

После того как вы определили эти узлы, давайте сохраним их имена в списке:

to_convert = [...] # names of tensors to convert

Шаг 3. Преобразование констант в переменные

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

import numpy as np
import tensorflow as tf
import tensorflow.contrib.graph_editor as ge

const_var_name_pairs = []
with tf_graph.as_default() as g:

    for name in to_convert:
        tensor = g.get_tensor_by_name('{}:0'.format(name))
        with tf.Session() as sess:
            tensor_as_numpy_array = sess.run(tensor)
        var_shape = tensor.get_shape()
        # Give each variable a name that does not already exist in the graph
        var_name = '{}_turned_var'.format(name)
        # Create TensorFlow variable initialized by values of original const.
        var = tf.get_variable(name=var_name, dtype='float32', shape=var_shape, \  
                      initializer=tf.constant_initializer(tensor_as_numpy_array))
        # We want to keep track of our variables names for later.
        const_var_name_pairs.append((name, var_name))

    # At this point, we added a bunch of tf.Variables to the graph, but they're
    # not connected to anything.

    # The magic: we use TF Graph Editor to swap the Constant nodes' outputs with
    # the outputs of our newly created Variables.

    for const_name, var_name in const_var_name_pairs:
        const_op = g.get_operation_by_name(const_name)
        var_reader_op = g.get_operation_by_name(var_name + '/read')
        ge.swap_outputs(ge.sgv(const_op), ge.sgv(var_reader_op))

Шаг 4. Сохранить результат как .ckpt

    with tf.Session() as sess:
        sess.run(tf.global_variables_initializer())
        save_path = tf.train.Saver().save(sess, 'model.ckpt')
        print("Model saved in path: %s" % save_path)

И альт! На этом все должно быть сделано :) Я сам смог заставить это работать и проверил, что веса моделей сохраняются - единственное отличие состоит в том, что график теперь обучаем. Пожалуйста, дайте мне знать, если есть какие-либо проблемы.