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

Tensorflow: восстановление графика и модели, а затем выполнение оценки на одном изображении

Я думаю, что было бы очень полезно сообществу Tensorflow, если бы было хорошо документированное решение решающей задачи тестирования одного нового изображения против модели, созданной convnet в учебнике CIFAR-10.

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

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

Tensorflow: как сохранить/восстановить модель?

Восстановление модели TensorFlow

Невозможно восстановить модели в tensorflow v0.8

https://gist.github.com/nikitakit/6ef3b72be67b86cb7868

Самый популярный ответ - первый, в котором @RyanSepassi и @YaroslavBulatov описывают проблему и подход: нужно "вручную построить график с идентичными именами node и использовать Saver для загрузки в него весов", Хотя оба ответа полезны, неясно, как можно было бы подключить его к проекту CIFAR-10.

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

Надеюсь, мы сможем сблизиться с рабочим script, который каждый мог бы использовать.

Ниже script еще не функционирует, и я был бы рад услышать от вас, как это можно улучшить, чтобы обеспечить решение для классификации одного изображения с использованием обучаемой модели учебника CIFAR-10 TF.

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

Новый файл: cifar10_eval_single.py

import cv2
import tensorflow as tf

FLAGS = tf.app.flags.FLAGS

tf.app.flags.DEFINE_string('eval_dir', './input/eval',
                           """Directory where to write event logs.""")
tf.app.flags.DEFINE_string('checkpoint_dir', './input/train',
                           """Directory where to read model checkpoints.""")

def get_single_img():
    file_path = './input/data/single/test_image.tif'
    pixels = cv2.imread(file_path, 0)
    return pixels

def eval_single_img():

    # below code adapted from @RyanSepassi, however not functional
    # among other errors, saver throws an error that there are no
    # variables to save
    with tf.Graph().as_default():

        # Get image.
        image = get_single_img()

        # Build a Graph.
        # TODO

        # Create dummy variables.
        x = tf.placeholder(tf.float32)
        w = tf.Variable(tf.zeros([1, 1], dtype=tf.float32))
        b = tf.Variable(tf.ones([1, 1], dtype=tf.float32))
        y_hat = tf.add(b, tf.matmul(x, w))

        saver = tf.train.Saver()

        with tf.Session() as sess:
            sess.run(tf.initialize_all_variables())
            ckpt = tf.train.get_checkpoint_state(FLAGS.checkpoint_dir)

            if ckpt and ckpt.model_checkpoint_path:
                saver.restore(sess, ckpt.model_checkpoint_path)
                print('Checkpoint found')
            else:
                print('No checkpoint found')

            # Run the model to get predictions
            predictions = sess.run(y_hat, feed_dict={x: image})
            print(predictions)

def main(argv=None):
    if tf.gfile.Exists(FLAGS.eval_dir):
        tf.gfile.DeleteRecursively(FLAGS.eval_dir)
    tf.gfile.MakeDirs(FLAGS.eval_dir)
    eval_single_img()

if __name__ == '__main__':
    tf.app.run()
4b9b3361

Ответ 1

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

Это вспомогательная функция

def restore_vars(saver, sess, chkpt_dir):
    """ Restore saved net, global score and step, and epsilons OR
    create checkpoint directory for later storage. """
    sess.run(tf.initialize_all_variables())

    checkpoint_dir = chkpt_dir

    if not os.path.exists(checkpoint_dir):
        try:
            os.makedirs(checkpoint_dir)
        except OSError:
            pass

    path = tf.train.get_checkpoint_state(checkpoint_dir)
    #print("path1 = ",path)
    #path = tf.train.latest_checkpoint(checkpoint_dir)
    print(checkpoint_dir,"path = ",path)
    if path is None:
        return False
    else:
        saver.restore(sess, path.model_checkpoint_path)
        return True

Вот основная часть кода, который запускает одно изображение за раз в цикле for.

to_restore = True
with tf.Session() as sess:

    for i in test_img_idx_set:

            # Gets the image
            images = get_image(i)
            images = np.asarray(images,dtype=np.float32)
            images = tf.convert_to_tensor(images/255.0)
            # resize image to whatever you're model takes in
            images = tf.image.resize_images(images,256,256)
            images = tf.reshape(images,(1,256,256,3))
            images = tf.cast(images, tf.float32)

            saver = tf.train.Saver(max_to_keep=5, keep_checkpoint_every_n_hours=1)

            #print("infer")
            with tf.variable_scope(tf.get_variable_scope()) as scope:
                if to_restore:
                    logits = inference(images)
                else:
                    scope.reuse_variables()
                    logits = inference(images)


            if to_restore:
                restored = restore_vars(saver, sess,FLAGS.train_dir)
                print("restored ",restored)
                to_restore = False

            logit_val = sess.run(logits)
            print(logit_val)

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

imgs_place = tf.placeholder(tf.float32, shape=[my_img_shape_put_here])
images = tf.reshape(imgs_place,(1,256,256,3))

saver = tf.train.Saver(max_to_keep=5, keep_checkpoint_every_n_hours=1)

#print("infer")
logits = inference(images)

restored = restore_vars(saver, sess,FLAGS.train_dir)
print("restored ",restored)

with tf.Session() as sess:
    for i in test_img_idx_set:
        logit_val = sess.run(logits,feed_dict={imgs_place=i})
        print(logit_val)

Ответ 2

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

Код для первого подхода выглядит следующим образом:

import tensorflow as tf
import numpy as np
import cv2

sess = tf.Session('', tf.Graph())
with sess.graph.as_default():
    # Read meta graph and checkpoint to restore tf session
    saver = tf.train.import_meta_graph("/tmp/cifar10_train/model.ckpt-200.meta")
    saver.restore(sess, "/tmp/cifar10_train/model.ckpt-200")

    # Read a single image from a file.
    img = cv2.imread('tmp.png')
    img = np.expand_dims(img, axis=0)

    # Start the queue runners. If they are not started the program will hang
    # see e.g. https://www.tensorflow.org/programmers_guide/reading_data
    coord = tf.train.Coordinator()
    threads = []
    for qr in sess.graph.get_collection(tf.GraphKeys.QUEUE_RUNNERS):
        threads.extend(qr.create_threads(sess, coord=coord, daemon=True,
                                         start=True))

    # In the graph created above, feed "is_training" and "imgs" placeholders.
    # Feeding them will disconnect the path from queue runners to the graph 
    # and enable a path from the placeholder instead. The "img" placeholder will be 
    # fed with the image that was read above.
    logits = sess.run('softmax_linear/softmax_linear:0', 
                     feed_dict={'is_training:0': False, 'imgs:0': img})

    #Print classifiction results.
    print(logits) 

script требует, чтобы пользователь создал два заполнителя и условный оператор выполнения, чтобы он работал.

Заполнители и оператор условного выполнения добавляются в cifar10_train.py, как показано ниже:

def train():   
"""Train CIFAR-10 for a number of steps."""   
    with tf.Graph().as_default():
        global_step = tf.contrib.framework.get_or_create_global_step()

    with tf.device('/cpu:0'):
        images, labels = cifar10.distorted_inputs()

    is_training = tf.placeholder(dtype=bool,shape=(),name='is_training')
    imgs = tf.placeholder(tf.float32, (1, 32, 32, 3), name='imgs')
    images = tf.cond(is_training, lambda:images, lambda:imgs)
    logits = cifar10.inference(images)

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

В то время как бегуны в очереди эффективны в предварительной выборке большого набора данных для обучения, они являются излишним для вывода или тестирования, где нужно классифицировать только один файл, а также они немного участвуют в изменении/обслуживании. По этой причине я добавил местозаполнитель "is_training", для которого установлено значение False при тренировке, как показано ниже:

 import numpy as np
 tmp_img = np.ndarray(shape=(1,32,32,3), dtype=float)
 with tf.train.MonitoredTrainingSession(
     checkpoint_dir=FLAGS.train_dir,
     hooks=[tf.train.StopAtStepHook(last_step=FLAGS.max_steps),
            tf.train.NanTensorHook(loss),
            _LoggerHook()],
     config=tf.ConfigProto(
         log_device_placement=FLAGS.log_device_placement)) as mon_sess:
   while not mon_sess.should_stop():
     mon_sess.run(train_op, feed_dict={is_training: True, imgs: tmp_img})

Другой placeholder "imgs" содержит тензор формы (1,32,32,3) для изображения, которое будет подаваться во время вывода - первое измерение представляет собой размер партии, который является одним в этом случае. Я изменил модель cifar, чтобы принимать 32x32 изображения вместо 24x24, поскольку исходные изображения cifar10 - 32x32.

Наконец, условный оператор подает вывод на столбец или счетчик очереди. Заполнитель "is_training" установлен на False во время вывода, а "img" заполнитель получает массив numpy - массив numpy преобразуется из 3-х мерного вектора в соответствие входному тензору с функцией вывода в модели.

Вот и все. Любая модель может быть выведена с помощью отдельных/пользовательских тестовых данных, как показано в script выше. По существу читайте график, подавайте данные в узлы графа и запускайте график, чтобы получить окончательный результат.

Теперь второй метод. Другой подход - взломать cifar10.py и cifar10_eval.py, чтобы изменить размер партии на один и заменить данные, поступающие из очереди, с одной, прочитанной из файла.

Установите размер партии в 1:

tf.app.flags.DEFINE_integer('batch_size', 1,
                             """Number of images to process in a batch.""")

Вывод вызова с файлом изображения.

def evaluate():   with tf.Graph().as_default() as g:
    # Get images and labels for CIFAR-10.
    eval_data = FLAGS.eval_data == 'test'
    images, labels = cifar10.inputs(eval_data=eval_data)
    import cv2
    img = cv2.imread('tmp.png')
    img = np.expand_dims(img, axis=0)
    img = tf.cast(img, tf.float32)

    logits = cifar10.inference(img)

Затем передайте логины в eval_once и измените eval один раз, чтобы оценить логиты:

def eval_once(saver, summary_writer, top_k_op, logits, summary_op): 
    ...
    while step < num_iter and not coord.should_stop():
        predictions = sess.run([top_k_op])
        print(sess.run(logits))

Для запуска этого метода вывода нет отдельного script, просто запустите cifar10_eval.py, который теперь будет читать файл из пользовательского местоположения с размером партии в один.

Ответ 3

получил работу с этим

softmax = gn.inference(image)
saver = tf.train.Saver()
ckpt = tf.train.get_checkpoint_state(FLAGS.checkpoint_dir)
with tf.Session() as sess:
  saver.restore(sess, ckpt.model_checkpoint_path)
  softmaxval = sess.run(softmax)
  print(softmaxval)

Выход

[[  6.73550041e-03   4.44930716e-04   9.92570221e-01   1.00681427e-06
    3.05406687e-08   2.38927707e-04   1.89839399e-12   9.36238484e-06
    1.51646684e-09   3.38977535e-09]]

Ответ 4

У меня нет рабочего кода для вас, я боюсь, но здесь, как мы часто решаем эту проблему в производстве:

  • Сохраните GraphDef на диск, используя что-то вроде write_graph.

  • Используйте freeze_graph для загрузки GraphDef и контрольных точек и сохраните GraphDef с переменными, преобразованными в константы.

  • Загрузите GraphDef в нечто вроде label_image или classify_image.

Для вашего примера это слишком много, но я бы хотя бы предложил сериализовать график в исходном примере как GraphDef, а затем загрузить его в ваш script (так что вам не нужно дублировать код, генерирующий график). С тем же графиком, который вы создали, вы сможете заполнить его из SaverDef, а в качестве примера может помочь файл freeze_graph script.