Предварительная обработка изображений с помощью tf.data.experimental.make_csv_dataset или с параметром read_csv - PullRequest
0 голосов
/ 20 декабря 2018

Я добавляю это обобщение моей проблемы, чтобы ее было легче понять: я хочу сделать именно то, что делается в следующем примере с тензорным потоком: https://www.tensorflow.org/guide/datasets

# Reads an image from a file, decodes it into a dense tensor, and resizes it
# to a fixed shape.
def _parse_function(filename, label):
  image_string = tf.read_file(filename)
  image_decoded = tf.image.decode_jpeg(image_string)
  image_resized = tf.image.resize_images(image_decoded, [28, 28])
  return image_resized, label

# A vector of filenames.
filenames = tf.constant(["/var/data/image1.jpg", "/var/data/image2.jpg", ...])

# `labels[i]` is the label for the image in `filenames[i].
labels = tf.constant([0, 37, ...])

dataset = tf.data.Dataset.from_tensor_slices((filenames, labels))
dataset = dataset.map(_parse_function)

Единственные различияявляются: Я читаю данные из CSV, который имеет гораздо больше функций, а затем вызываю метод map:

dataset = tf.data.experimental.make_csv_dataset(file_pattern=CSV_PATH_TRAIN,
                                                    batch_size=2,
                                                    header=True,
                                                    label_name = 'label').map(_parse_function) 

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

спасибо, eilalan

================== Вот мой код пытается: ==================

Мой код читает CSV со столбцами функций и меткой.Одна из особенностей - это путь к изображению, остальные - строки.Путь изображения должен быть обработан в матрицу номеров изображений.Я попытался сделать это со следующими параметрами.В обоих случаях tf.read_file завершается с ошибкой входного размера.У меня вопрос, как передать одно изображение за раз в методы карты

def read_image_png_option_1(image_path, depth=3, scale=False):
  """Reads the image from image_path (tf.string tensor) [jpg image].
  Cast the result to float32 and if scale=True scale it in [-1,1]
  using scale_image. Otherwise the values are in [0,1]
  Reuturn:
      the decoded jpeg image, casted to float32
  """
  image = tf.image.convert_image_dtype(
      tf.image.decode_png(tf.read_file(image_path), channels=depth),
      dtype=tf.float32)
  if scale:
      image = scale_image(image)
  return image

def read_image_png_option_2(features, depth=3, scale=False):
  """Reads the image from image_path (tf.string tensor) [jpg image].
  Cast the result to float32 and if scale=True scale it in [-1,1]
  using scale_image. Otherwise the values are in [0,1]
  Reuturn:
      the decoded jpeg image, casted to float32
  """
  image = tf.image.convert_image_dtype(
      tf.image.decode_png(tf.read_file(features['image']), channels=depth),
      dtype=tf.float32)
  if scale:
      image = scale_image(image)
  features['image'] = image
  return features

def make_input_fn(fileName,batch_size=8, perform_shuffle=True):
  """An input function for training """
  def _input_fn():
    def  decode_csv(line):
      print('line is ',line)
      filename_col,label_col,gender_col,ethinicity = tf.decode_csv(line, 
                                                                   [[""]]*amount_of_columns_csv, 
                                                                   field_delim=",",
                                                                   na_value='NA',
                                                                   select_cols=None)
      image_col = read_image_png_option_1(filename_col)
      d = dict(zip(['image','label','gender','ethinicity'], [image_col,label_col,gender_col,ethinicity])), label
      return d

    ## OPTION 1:
#     filenames could be more than one
#    dataset = tf.data.TextLineDataset(filenames=fileName).skip(1).batch(batch_size).map(decode_csv)

    ## OPTION 2: 
    dataset = tf.data.experimental.make_csv_dataset(file_pattern=CSV_PATH_TRAIN,
                                                    batch_size=2,
                                                    header=True,
                                                    label_name = 'label').map(read_image_png_option_2)
                                                    #select_columns=[0,1]) #[tf.string,tf.string,tf.string,tf.string])

    if perform_shuffle:
        dataset = dataset.shuffle(buffer_size=256)
    return dataset
  return _input_fn()

train_input_fn = lambda: make_input_fn(CSV_PATH_TRAIN)
train_spec = tf.estimator.TrainSpec(input_fn=train_input_fn, max_steps=50)

eval_input_fn = lambda: make_input_fn(CSV_PATH_VAL)
eval_spec = tf.estimator.EvalSpec(eval_input_fn)

feature_columns = [tf.feature_column.numeric_column("image",shape=(224,224)),  # here i need a pyhton method to transform
                   tf.feature_column.categorical_column_with_vocabulary_list("gender", ["ww","ee"]),
                   tf.feature_column.categorical_column_with_vocabulary_list("ethinicity",["xx","yy"])]

estimator = tf.estimator.DNNClassifier(feature_columns=feature_columns,hidden_units=[1024, 512, 256],warm_start_from=ws)

tf.estimator.train_and_evaluate(estimator, train_spec=train_spec, eval_spec=eval_spec)

Ошибка для варианта 2: ValueError: Shape должен иметь ранг 0, но имеет ранг 1 для «ReadFile» (op: «ReadFile») с входными фигурами: [2].

Ошибка для варианта 1: ValueError: Shape должен иметь ранг 0, но является рангом 1 для 'ReadFile' (op: 'ReadFile') с входными фигурами: [?].

Любая помощь приветствуется.Спасибо

1 Ответ

0 голосов
/ 21 декабря 2018

Сначала вам нужно прочитать файл CSV в набор данных.

Затем для каждой строки в вашем CSV вы можете вызвать функцию анализа.

def getInput(fileList):
    # returns a dataset containing list of filenames
    files = tf.data.Dataset.from_tensor_slices(fileList)

    # Returs a dataset containing list of rows taken from all the files in file list.
    # dataset is filled dynamically and not all entries are read at once
    dataset = files.interleave(tf.data.TextLineDataset)

    # call parse function for each row
    # returned dataset will contain list of whatever the parse function is returning for the row
    # we want the image path to be converted to decoded image in parse function
    dataset = dataset.map(_parse_function, num_parallel_calls=8)
    # return an iterator for the dataset which will be used to get elements.
    return dataset.make_one_shot_iterator().get_next()

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

Допустим, у вас есть 3 столбца в CSV, каждый из которых представляет собой строку.

def _parse_function(value):
    columns_default = [[""], [""], [""]]
    # this will be a tensor of columns in the row
    columns = tf.decode_csv(value, record_defaults=columns_default,
            field_delim=',')
    col_names = ["label", "imagepath", "c3"]
    features = dict(zip(col_names, columns))
    for f, tensor in features.items():
        # process imagepath to decoded image
        if f == "imagepath":
            image_string = tf.read_file(tensor)
            image_decoded = tf.image.decode_jpeg(image_string)
            image_resized = tf.image.resize_images(image_decoded, [28, 28])
            features[f] = image_resized
    labels = tf.equal(features.pop('label'), "1")
    labels = tf.expand_dims(labels, 0)
    return features, labels

Редактировать:

Объяснение для комментария:

  1. Объект набора данных просто содержит список элементов.Элементами могут быть тензоры или кортежи тензоров и т. Д. Тензорный объект может содержать что угодно.Он может представлять одну функцию, одну запись или серию записей.Кроме того, API набора данных предоставляют удобные методы для управления элементами внутри.
    Если вы используете набор данных с другим API, таким как оценщик, тогда они ожидают, что элементы набора данных будут в определенном формате, что необходимо для возврата из нашей функции ввода, например.

https://www.tensorflow.org/api_docs/python/tf/estimator/Estimator#train

Я отредактировал мой блок кода выше, чтобы описать, что будет содержать объект набора данных на каждом шаге.

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

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

Это было бы неправильно:

files = tf.data.Dataset.from_tensor_slices(ds['imagepath']) 
dataset = files.interleave(tf.data.TextLineDataset)

Если вы используете функцию make_csv () для чтения вашего csvзатем он преобразует каждую строку вашего CSV в одну запись, где одна запись будет содержать список всех объектов, такой же, как столбцы CSV.

Таким образом, каждый элемент в возвращенном наборе данных должен содержать один тензор, содержащий все ваши функции.

Здесь ваш путь к изображению будет одной из функций.Теперь вы хотите преобразовать этот путь изображения в декодированное изображение.

Я полагаю, что вы можете сделать это, применив функцию разбора к элементам набора данных с помощью функции map (), но это будет немного сложнее, поскольку все ваши функции уже упакованы в один тензор.

...