Привет, это вторая часть серии. В этом посте я покажу, как передать формат данных TFRecord и необработанные изображения в вашу модель тензорного потока. Различные преимущества формата TFRecords:

  1. Быстрее читается, чем PNG или другие форматы.
  2. Обеспечивает гибкость конвейерной обработки данных.
  3. Полезно, когда данные не умещаются в памяти.
  4. Меньше файлов для управления (личное мнение)

Ссылка на часть 1 находится здесь, а ссылка на код для преобразования в tfrecords - здесь.

Используемый набор данных - MNIST

Архитектура модели - два скрытых слоя по 100 нейронов каждый и 1 выходной слой из 10 нейронов.

Я предполагаю, что у вас есть данные в формате TFRecords. Приступим.

## import necessary stuff
import tensorflow as tf
import numpy as np
import os,sys
import time
## defining the type of features columns to be used on model.
feature_column = [tf.feature_column.numeric_column(key='image',shape=(784,))]
##defining the model
model = tf.estimator.DNNClassifier([100,100],n_classes=10,feature_columns=feature_column)

Теперь, когда мы создали модель, давайте определим поток данных. Мы будем использовать метод TFRecordDataset из DATASET API.

Сначала нам нужно определить функцию, которая преобразует формат TFRecords обратно в тензор dtype tf.float32 в случае изображения и в tf.int32 в случае метки.

Преобразование будет таким -

TFRecords --> Serialized Example --> Example --> Tensor

Вот функция -

def _parse_(serialized_example):
    feature = {'image_raw':tf.FixedLenFeature([],tf.string),
                'label':tf.FixedLenFeature([],tf.int64)}
    example = tf.parse_single_example(serialized_example,feature)
    image = tf.decode_raw(example['image_raw'],tf.int64) #remember to parse in int64. float will raise error
    label = tf.cast(example['label'],tf.int32)
    return (dict({'image':image}),label)

В приведенном выше коде мы разбираем один пример из сериализованного. Чтобы проанализировать один пример или простыми словами одну точку данных, нам нужно предоставить имя функций и их соответствующий тип в качестве словаря для parse_single_example вместе с сериализованным примером. Я сохранил изображения с ключом image_raw и пометил с помощью ключ 'label' с типами данных как tf.string и tf.int64 соответственно, поэтому я передал те же значения в словарь. Если вы не помните названия функций, есть трюк, чтобы узнать их. Просто сделайте head -n20 /path/to/tfrecords в Linux. Это напечатает название функций в удобочитаемом формате.

Теперь, когда мы знаем, как анализировать tfrecords, давайте напишем функцию, которая будет использовать эту _parse_ функцию и будет возвращать пакеты (features, label) для подачи в модель.

mnist_tfrecord_path = os.path.abspath('./mnist_train.tfrecords')
def tfrecord_train_input_fn(batch_size=32):
    tfrecord_dataset = tf.data.TFRecordDataset(mnist_tfrecord_path)
    tfrecord_dataset = tfrecord_dataset.map(lambda   x:_parse_(x)).shuffle(True).batch(batch_size)
    tfrecord_iterator = tfrecord_dataset.make_one_shot_iterator()
    
    return tfrecord_iterator.get_next()

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

model.train(lambda:tfrecord_train_input_fn(32),steps=200)

  • Что делать, если у меня на диске есть необработанные изображения ???

Код для записи массивов numpy в формат jpg на диске находится здесь.

Приведенный выше код запишет изображение в формате «image [i] _ [class] .jpg», где class - это метка изображения, а i - для количества. Общее количество изображений составляет 60 тыс. Теперь, чтобы прочитать изображения и обработать их, нам нужно снова написать функцию синтаксического анализа, которая будет читать изображение, разделять метку, преобразовывать метку в скаляр tf.int32, а изображение в tf.float и возвращать кортеж.

path = os.path.abspath('./digit-recognizer/train/')
def _ondisk_parse_(filename):
    filename = tf.cast([filename],tf.string)
    
    label = tf.string_split([tf.string_split(filename,'_').values[1]],'.').values[0]
    label = tf.string_to_number([label],tf.int32)
    
    path = os.path.abspath('./digit-recognizer/train//')
    path = tf.cast([path],tf.string)
    
    final_path = tf.string_join((path,tf.cast(['/'],tf.string),filename))
    
    image_string = tf.read_file(final_path[0])
    image = tf.image.decode_jpeg(image_string)
    image = tf.cast(image,tf.int8)
    image = tf.cast(image,tf.float32)
    image_reshaped = tf.reshape(image,(784,))
    return (dict({'image':image}),label)

Здесь я использовал собственные методы тензорного потока string_split, string_to_number и т. Д., Поскольку он был рекомендован авторами тензорного потока, в противном случае мне пришлось бы обернуть мою функцию, которая будет использовать методы python (.split, string () и т. Д.), Вокруг оболочки, заданной tenorflow, и я был не в настроении делать это. Здесь не забудьте вернуть изображение в int8, так как во время сохранения изображения формат был int8. Непосредственное преобразование в другой формат, что int8 вызовет ошибку.

Теперь, когда _ondisk_parse готов, давайте напишем последнюю функцию ввода поезда.

def ondisk_train_input_fn(filenames,batch_size=32):
    dataset  = tf.data.Dataset.from_tensor_slices(filenames)
    dataset = dataset.map(lambda x:_ondisk_parse_(x)).shuffle(True).batch(batch_size)
    ondisk_iterator = dataset.make_one_shot_iterator()
    
    return ondisk_iterator.get_next()

Здесь я снова использовал метод _from_tensor_slices, поскольку вы можете передавать данные в памяти (тензоры или массивы numpy) или имена файлов изображений, которые вам нужно передать этому методу. Остальная часть конвейера такая же, как сначала сопоставление _ondisk_parse_, затем перемешивание, создание пакетов, создание one_shot_iterator и возврат следующего пакета.

Наконец, обучающая часть -

#list of the images in train folder
f = !ls ./digit-recognizer/train/ 
#train the model
model.train(lambda:ondisk_train_input_fn(f,32),steps=200)

КОНЕЦ

Полный код доступен здесь.

Если вам понравился пост, хлопните в ладоши.