2016-10-24 6 views
2

Мне удалось выполнить все шаги of the online tutorial for google cloud ml.Приступайте к запуску google-cloud-ml с моим собственным набором данных

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

Затем я попытался создать свой TFRecord, используя this a little bit modified code compared to the official convert_to_records.py. Я понимаю, что мы можем преобразовать примитивные переменные в TFRecord, и поэтому используется трюк для преобразования списка float в байты. Тогда я должен где-то преобразовать мою строку в список поплавков. Таким образом, я попытался выполнить эту задачу либо с линией 97, либо с линией 98 in my modified script model.py.

К сожалению, ни одна из этих попыток не работает. Я всегда получаю следующее сообщение об ошибке:

ValueError: rank of shape must be at least 2 not: 1 

Это потому, что форма моих переменных особенностей является (batch_size,), а не (batch_size, IMAGE_PIXELS). Но я не понимаю, почему.

Я пытаюсь запустить google-cloud-ml неправильным способом или есть еще несколько параметров для настройки?

+1

Сторона примечания: TFRecord формат файла tf.Example не требуется Google Cloud ML. Любой действительный способ чтения данных в TensorFlow будет работать. См. Https://www.tensorflow.org/versions/r0.11/how_tos/reading_data/index.html. Тем не менее, чтение файлов (по сравнению с подачей, см. Ссылку) может быть более эффективным. И кодирование файлов TFRecord tf.Example - это хорошо поддерживаемый и удобный способ кодирования нескольких полей/функций на запись (например, изображение + метка) на диске. – rhaertel80

ответ

3

Ошибка указывает, что ранг 2 (матрица) ожидается, но значение действительно является ранг 1 (вектор). Я подозреваю, что это потому, что np.tostring() возвращает одну строку, а не список строк.

Я думаю, что это несколько тангенциально, поскольку я не думаю, что ваши преобразования с плавающей запятой и строкой в ​​плавать согласованы. Вы конвертируете float-to-string с помощью встроенного метода tostring() numpy. Это возвращает представление байтов данных: т. Е.

import numpy as np 
x = np.array([1.0, 2.0]) 
print x.tostring() 

Возвращает

[email protected] 

И не

['1.0', '2.0'] 

Последнее, что tf.string_to_number ожидает.

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

def _int64_feature(value): 
    return tf.train.Feature(int64_list=tf.train.Int64List(value=value)) 

def _float_feature(value): 
    return tf.train.Feature(float_list=tf.train.FloatList(value=value)) 

e = tf.train.Example(features=tf.train.Features(feature={ 
      'labels': _int64_feature([10]), 
      'features': _float_feature([100.0, 200, ....])})) 

feature_map = { 
     'labels': tf.FixedLenFeature(
      shape=[1], dtype=tf.int64, default_value=[-1]), 
     'features': tf.FixedLenFeature(
      shape=[NUM_PIXELS], dtype=tf.float32), 
} 
result = tf.parse_example([e.SerializeToString()], features=feature_map) 

Feature proto позволяет float32, чтобы хранить внутри float_list. Вам нужно только преобразовать float в байты, если вы используете float64. Ваши данные - float32, поэтому это необязательно.

+0

Я следил за вашим советом и переписывал свой код, чтобы создать TFRecords [как вы можете видеть его здесь] (http://pastebin.com/xJYQWp4P). Таким образом, я адаптирую [script model.py] (http://pastebin.com/gwH9gYJK), чтобы соответствовать новой типизации. Но я все равно получаю ту же ошибку, и печатная строка 97 все еще возвращает форму (batch_size,), а не (batch_size, IMAGE_PIXELS). –

+1

Я думаю, вам нужно указать shape = NUM_PIXELS для функций. Если вы посмотрите на документ для [parse_example] (https://www.tensorflow.org/versions/r0.11/api_docs/python/io_ops.html#parse_example), то получившийся тензор имеет форму (serialized.size(),) + df.shape –

+0

Я пробовал то, что вы только что предложили. Это приводит к тому, что тезисы скриптов [скрипт для создания TFRecord с поплавками] (http://pastebin.com/HYdx4u13) и [сценарий модели для поплавков] (http://pastebin.com/smXkN333). Все работает, но [результат] (http://hpics.li/3a1da05) позволяет мне думать, что мне не удается правильно декодировать мой TFRecord и в итоге получить очень маленькие значения в качестве входных данных. Я не могу проверить эту гипотезу, поскольку, насколько я знаю, я не могу распечатать свои данные. –

3

Это может помочь проанализировать как выход read_data_sets.py и выход операции parse_example в вашем model.py

Что read_data_sets производит

read_data_sets, как Вы отмечаете, создает Numpy массивы для каждого изображения. Они имеют форму [28, 28, 1] для каналов с шириной x ширины (изображения монохромные), а в вашем первоначальном вызове read_data_sets вы указываете, что вам нужны данные изображения в виде массивов uint8. Когда вы вызываете tostring в массив uint8 numpy, информация о форме отбрасывается, и поскольку каждый uint8 является одиночным байтом, вы заканчиваете байтовой строкой длиной 784 с одной записью для каждого пикселя в исходном массиве 28x28x1 numpy в ряду строк заказ. Затем он сохраняется как bytes_list в результате tf.train.Example.

Для отображения каждой записи на карте функций под ключом features имеется список байтов с ровно одной записью. Эта запись представляет собой строку длиной 784, где каждый «символ» в строке представляет собой значение между 0-255, представляющим значение монохромного пикселя для точки в исходном изображении 28x28. Ниже приведен пример экземпляра tf.train.Example как напечатано на Python:

features { 
    feature { 
    key: "features" 
    value { 
     bytes_list { 
     value: "\000\000\257..." 
     } 
    } 
    } 
    feature { 
    key: "labels" 
    value { 
     int64_list { 
     value: 10 
     } 
    } 
    } 
} 

Что parse_example ожидает и возвращает

tf.parse_example принимает вектор tf.string объектов в качестве входных данных. Эти объекты сериализуются tf.train.Example объектов. В вашем коде util.read_examples производит именно это.

Другой аргумент tf.parse_example - это схема примеров. Как упоминалось ранее, запись features в вашем примере представляет собой tf.string, как определено выше. Для справки ваш код имеет:

def parse_examples(examples): 
    feature_map = { 
     'labels': tf.FixedLenFeature(
      shape=[], dtype=tf.int64, default_value=[-1]), 
     'features': tf.FixedLenFeature(
      shape=[], dtype=tf.string), 
    } 
    return tf.parse_example(examples, features=feature_map) 

Интересующая вещь, связанная с полученным вами сообщением об ошибке, является параметром формы.Этот параметр формы указывает форму одного экземпляра, в этом случае, указав, что shape=[] вы говорите, что каждое изображение является строкой ранга 0, то есть простой-старой строкой (т. Е. Не вектором , а не матрица и т. д.). Это требует, чтобы bytes_list имели ровно один элемент. Это именно то, что вы храните в каждом поле features вашего tf.train.Example.

Несмотря на то, shape свойства относится к форме одного экземпляра, выход tf.parse_example для features поля будет вся партии примеров. Это может быть немного запутанным. Поэтому, в то время как каждый отдельный пример имеет одну строку (shape=[]), партия представляет собой вектор строк (shape=[batch_size]).

Используя изображение

Имея данные изображения в строке не очень полезно; нам нужно преобразовать его в числовые данные. Оп TensorFlow сделать это tf.decode_raw (Джереми Lewi explained почему tf.string_to_number не будет работать здесь):

image_bytes = tf.decode_raw(parsed['features'], out_type=tf.uint8) 
image_data = tf.cast(image_bytes, tf.float32) 

(не забудьте установить out_type=tf.uint8 поскольку это тип данных, который был выход в read_data_sets). Как правило, вы хотите, чтобы результат был равен tf.float32. Иногда это даже полезно, чтобы изменить тензор, чтобы восстановить исходные формы, например,

# New shape is [batch_size, height, width, channels]. We use 
# -1 as the first dimension in case batches are variable size. 
image_data = tf.reshape(image_data, [-1, 28, 28, 1]) 

(NB: Вы, вероятно, не нужно, чтобы в вашем коде).

В качестве альтернативы, вы можете сохранить данные как tf.float32, вызвав read_data_sets с dtype=tf.float32 (по умолчанию). Затем вы можете построить свой tf.train.Example как explained Джереми Льюи, который также дал код для анализа таких примеров. Однако в этом случае формы будут разными. Форма каждого экземпляра (как указано в форме в FixedLenFeature) теперь равна IMAGE_PIXELS, а форма записи features на выходе tf.parsed_example равна [batch_size, IMAGE_PIXELS].

Компромисс между uint8 и float32, конечно же, заключается в том, что данные на диске будут в четыре раза больше для последнего, но вы избегаете дополнительного броска, необходимого для первого. В случае MNIST, где данных не так много, добавленная ясность непосредственного использования данных с плавающей точкой, вероятно, стоит дополнительного места.

+0

Я пробовал то, что вы только что предложили. Это приводит к тому, что в сценариях [скрипт создается TFRecord с байтами] (http://pastebin.com/mzW8mXBG) и [сценарий модели для байтов] (http://pastebin.com/vc09XKab). Все работает, но [результат] (http://hpics.li/e18d9b2) позволяет мне думать, что мне не удается правильно декодировать мой TFRecord и в итоге получить очень маленькие значения в качестве входных данных. Я не могу проверить эту гипотезу, поскольку, насколько я знаю, я не могу распечатать свои данные. Кроме того, я не понимаю, откуда происходит вектор длиной 768 с 28 * 28 = 784. –

+1

Вы можете начать с печати примеров в 'convert_to'. Вы также можете печатать тензоры в TensorFlow с помощью image_bytes = tf.Print (image_bytes, [image_bytes], summary = 1000). Я не думаю, что вам нужно изменить форму (image_data); если вы его сохраните, я бы использовал [-1, IMAGE_PIXELS], чтобы быть в безопасности. И в 'convert_to' я бы удалял преобразование, которое вы делаете, в массив numpy - это в основном no-op после tostring(). – rhaertel80

+0

Спасибо большое, я смог проверить шаг за шагом мои переменные и заметить, что все было так, как я ожидал. Проблема заключалась в том, что я не уверен в конечном итоге для всех нейронов в последнем слое с отрицательными значениями. В сочетании с функцией активации relu это привело к градиенту 0 и 0,1 вероятности для всех классов. Поскольку моя конечная цель - не оптимизировать mnist, я просто изменил функцию активации на сигмоид и получил приемлемые результаты. –