Введение
TensorFlow в настоящее время является бесспорным и самым популярным фреймворком для глубокого обучения.На самом деле, существует множество отличных дизайнов интерфейсов, таких как Swig Python API, который позволяет пользователям не воспринимать базовую реализацию, и настраиваемые операции, которые можно динамически расширять с помощью Python. или C++ (очень удобно. Обслуживание), и формат модели SavedModel, который интегрирует Model Signature.
Конечно, в TensorFlow есть и конструкции, которые сбивают с толку новичков или программистов старшего возраста.Например, обучение на нескольких GPU требует, чтобы пользователи реализовали структуру башни и указали устройство.Для распределенного обучения нужно самому написать PS, хотя есть почти только один строка кода для присоединения (по умолчанию PS выполняет обучение без выхода). Используйте очередь TensorFlow, чтобы решить ее самостоятельно), и рекомендуемый интерфейс набора данных должен использоваться вместе с while(True) + exclude(OutOfRangeError), а также Keras, Estimator, Learn , Slim и другие подобные высокоуровневые API... Конечно, у этих "неразумных" дизайнов интерфейсов есть причина для существования, так как язык моделирования самого низкого уровня, представленный с помощью Интерфейсы устройства и PS/worker позволяют разработчикам реализовать более сложный параллелизм моделей, параллелизм данных, внутриграфовые и межграфовые структуры.
В прошлом месяце мы нашли несколько одинаково «интересных» дизайнов интерфейсов, и есть еще обсуждения проблемы Github, чтобы все могли учиться (tu) и учиться (cao).
1. Когда используются ФЛАГИ, синтаксический анализ печатает только значение по умолчанию.
Те, кто писал сценарии TensorFlow, обычно использовали tf.app.flags для определения параметров командной строки и значений по умолчанию сценария через интерфейс TensorFlow, Использование аналогично официальному Python argparse и configparser. Это «лучшая практика» почти для всего официального кода TensorFlow, и пример кода прост.
import tensorflow as tf
flags = tf.app.flags
flags.DEFINE_integer("image_width", 224, "Width of the image")
flags.DEFINE_integer("image_height", 224, "Height of the image")
flags.DEFINE_integer("channels", 3, "Channel of the image")
FLAGS = flags.FLAGS
# FLAGS.image_width
Как правило, нет проблем с использованием FLAGS таким образом, и вам не нужно заботиться о том, реализован ли базовый уровень на основе argparse или других библиотек, и когда мы пытаемся напечатать значение параметра во время выполнения, «Ошибка» срабатывает, то есть печать содержимого FLAGS в начале получит только значение по умолчанию, но после однократного использования параметра перезаписанное значение появится при повторной печати, см. «Проблема» для получения подробной информации.Значения по умолчанию tf.app.flags выводятся на печать, хотя параметры передаются в первый раз · Проблема № 20680 · tensorflow/tensorflow.
Есть два условия, чтобы вызвать эту проблему.Первое заключается в том, что код является строгим, и я буду печатать параметры переопределения или параметры по умолчанию при запуске сценария.Второе заключается в том, что соглашение, реализованное tf.app.flags на основе absl.flags, является немного мусора. Первое вводится первым.Чтобы избежать передачи неверных параметров при вызове командной строки, мы рекомендуем запустить проверку.Разные модели имеют разные гиперпараметры.Как правило, все пары ключ-значение можно получить через объект FLAGS.Единственный способ получить значение здесь FLAGS.__flags[key].value, код выглядит следующим образом.
FLAGS = flags.FLAGS
parameter_value_map = {}
for key in FLAGS.__flags.keys():
parameter_value_map[key] = FLAGS.__flags[key].value
print("Parameters: {}".format(parameter_value_map))
# Parameters: {'channels': 3, 'image_height': 224, 'image_width': 224}
Полученное здесь значение является значением по умолчанию, определенным в коде Python.Независимо от того, передается ли параметр в командной строке или нет, эффект проверки явно не может быть достигнут, и нам нужно только вызвать FLAGS.channels и FLAGS.image_height по желанию.,FLAGS.Image_width любая строка кода, значение будет обновлено, чтобы покрыть значение, это «разрешение времени использования». В настоящее время мы смотрим на кодовую реализацию FLAGS и обнаруживаем, что TensorFlow использует код синтаксического анализа параметров abseil-py, еще одного проекта с открытым исходным кодом инженеров Google.GitHub.com/абсейл/абсейл…, параметры sys.argv могут быть проанализированы при активном вызове этого объекта класса (то есть функции __call__()). Поэтому и TensorFlow, и abseil получают параметры командной строки, читая sys.argv Python, и есть явный процесс синтаксического анализа.TensorFlow также имеет пакет-обертку для abseil.Выброс исключения, и после инкапсуляции, если нет синтаксического анализа при получении значение, сделать анализ, код лучший анализGitHub.com/tensorflow/….
Большинство людей не смотрят исходный код при использовании tf.app.flags и не знают, что TensorFlow будет проверять, анализируется ли параметр каждый раз, когда считывает значение параметра.Такой дизайн интерфейса и реализация делают его ненужным для обычные пользователи могут понять, когда Параметр синтаксического анализа можно использовать напрямую для получения последнего значения, но это приведет к потере производительности. Это может оставить дыру для вас, чтобы получить значение по умолчанию через FLAGS.__flags[key].value перед вызовом любого ценность. В настоящее время Issue обсуждает, что Pull-request не реализован.
2. Несколько хеш-таблиц, восстановленных из контрольной точки, перезаписываются.
Многие знают, что контрольная точка TensorFlow может сохранять параметры модели.Помимо сохранения веса матрицы нейронной сети, она также может сохранять HashTable пар ключ-значение.TensorFlow предоставляет большое количество операций для tf.contrib.lookup для достижения . Например, мы пытаемся сохранить читаемую метку (строковый тип) и обучающую метку (целочисленный тип) обучающей выборки в Checkpoint и модель в виде MutableHashTable, Для достижения двустороннего преобразования обычно существуют строковые to-int и int-to -string две хеш-таблицы, наши коллеги обнаружили, что восстановление нескольких хэш-таблиц было перезаписано.GitHub.com/tensorflow/….
После определения двух таблиц MutableHashTable, если вы не укажете имя, вы можете напрямую экспортировать переменную в Checkpoint, а затем написать код для ее восстановления из Checkpoint.Пример выглядит следующим образом.
keys = tf.placeholder(dtype=tf.string, shape=[None])
values = tf.placeholder(dtype=tf.int64, shape=[None])
table1 = tf.contrib.lookup.MutableHashTable(tf.string, tf.int64, -1)
table2 = tf.contrib.lookup.MutableHashTable(tf.string, tf.int64, -1)
insert_table1 = table1.insert(keys, values)
insert_table2 = table2.insert(keys, values)
saver = tf.train.Saver()
with tf.Session() as sess:
sess.run(insert_table1, feed_dict={keys: ["a"], values: [1]})
sess.run(insert_table2, feed_dict={keys: ["b"], values: [2]})
print "table1:", sess.run(table1.export())
print "table2:", sess.run(table2.export())
saver.save(sess, "checkpoint/test")
Весь процесс не сообщит об ошибках, но по результату восстановления Checkpoint видно, что значение table1 пустое, а table2 можно нормально восстановить. Это еще одна хорошая возможность заглянуть в исходный код TensorFlow. Давайте посмотрим на реализацию tf.contrib.lookup.MutableHashTable в коде Python. У этого класса есть атрибут имени, и имя будет иметь значение по умолчанию «MutableHashTable». Экспортированная контрольная точка будет идентифицирована на основе входящего имени или имени по умолчанию.GitHub.com/tensorflow/….
Поэтому, как упоминалось ранее, если вы определяете несколько хэш-таблиц без указания имени, возможны непредвиденные действия, которые будут перезаписаны.Если пользователь привык определять уникальное имя для каждой операции, это исключение не будет активировано. Эта сцена мне очень знакома.Как правило, пользователи TensorFlow пишут сценарии, которые обычно не определяют имена операций для каждого tf.add() и tf.muliple(), особенно когда мы используем перегрузку операторов Python, написанную TensorFlow для нас.Но Граф TensorFlow и контрольная точка очень зависят от имени операции, поэтому Python TensorFlow API установит уникальное имя для каждой операции пользователя, даже если вы передадите конфликтующее имя при его определении, оно будет дополнено уникальным именем. Эта логика реализована на стороне TensorFlow Python, то есть, если вы напрямую настраиваете C++ API или API других языков, вам нужно обратить на это внимание.
такая же логика вGitHub.com/tensorflow/…Это также отражено, но все таблицы в настоящее время предоставляют только фиксированное значение по умолчанию.Если несколько таблиц экспортируются одновременно без указания имени, будет вызвано больше логических ошибок из-за проблемы с перезаписью. В настоящее время Issue обсуждает, что запрос на слияние был отправлен (необходимо обсудить, можно ли объединить уникальную схему имени операции с помощью схемы распределения, подобной переменной)GitHub.com/tensorflow/….
3. Набор данных сохраняет прогресс эпохи и конфликтует с Shuffle.
Набор данных в настоящее время является основным интерфейсом чтения данных, который поддерживает богатые функции, включая указание номера эпохи, размера пакета, перемешивание, кеширование и многие другие расширенные функции, а также может взаимодействовать с пользовательскими функциями карты для реализации файлов TFRecord, CSV и других форматов данных. синтаксический анализ и чтение, чтобы избежать хранения слишком большого количества имен файлов в Graph, он также предоставляет такие функции, как заполнитель для динамической загрузки имен файлов. Сказав так много, есть проблема, что пользователь добавит функцию «задержка точки останова» в сценарий TensorFlow, Как правило, ход обучения и параметры хранятся в контрольной точке, а набор данных знает эпоху обучения пользователя. Для индекса и пакетного индекса интерфейс SaveInternal был реализован с учетом этого в начале проектирования набора данных.GitHub.com/tensorflow/….
Проблема в том, что мы запускаем эту проблему, когда используем ее, что напрямую приводит к тому, что модель не может сохранить контрольную точку после добавления параметров набора данных.Подробности см. в разделе Проблема.Не удалось сохранить контрольную точку с сохранением Итератора набора данных при использовании перемешивания · Проблема № 18583 · tensorflow/tensorflow.
После расследования мы обнаружили, что TensorSliceDataset на основе заполнителя действительно может сохранять прогресс в контрольной точке, но если в набор данных добавляется операция перемешивания, экспорт завершается ошибкой. Причину легко понять. Если пользователь присоединяется к перемешиванию, данные обучения будут зашифрованы в буфере размера. Набор данных может гарантировать, что все данные в эпоху используются, но если вы просто сохраните прогресс в контрольной точке, следующий Re -shuffles для каждого запуска может пропустить некоторые данные.
Эта проблема не обязательно является неразрешимой. Одно из решений — реализовать ее в соответствии с текущим API. Если перетасовка не может сохранить переменную итератора набора данных в контрольной точке, пользователи могут заранее подготовить неупорядоченные наборы данных, не используя перетасовку, чтобы избежать этого. Если мне нужно поддерживать API, у меня также есть две идеи: во-первых, итератор набора данных не гарантирует, что каждая эпоха может обработать все данные, поэтому для восстановления контрольной точки нужно только перетасовать, независимо от того, были ли данные обрабатывается или нет,другое это перетасовка результата.Также сохраняется в Checkpoint.При восстановлении можно воспринять результат последней перетасовки и нормально восстановить.Конечно,даже если эти две схемы реализованы,пользователи будут писать статьи, чтобы распылить их. В настоящее время Issue не имеет ни малейшего представления об обсуждении Pull-request.
4. Другое
В дополнение к этим проблемам, которые мы недавно упоминали, есть также некоторые дизайны интерфейсов, которые заставляют людей чувствовать себя «интересными». Например, ранее мы упоминали в сообществе, может ли распределенный сервер параметров TensorFlow автоматически выходить после обучения, ответ сообщества отрицательный, но вы можете добиться этого. Как этого добиться? Как правило, когда мы реализуем PS распределенного TensorFlow, включая введение официальных документов, мы также будем вызывать server.join(), Просто взглянув на имя, мы знаем, что эта функция блокирует, поэтому, даже если все рабочие закончили обучение , PS продолжит блокировать и не выйдет. . Итак, у некоторых людей в сообществе есть новые идеи, функция блокировки — это не просто join(), мы можем использовать TensorFlow. Очередь, предоставляемая API, PS может получить достаточно данных из очереди (это число является количеством воркеров), а затем воркеры вставят данные в ту же очередь после обучения, поэтому PS будет продолжать блокировать очередь до тех пор, пока все воркеры завершены, чтобы получить достаточно элементов из очереди и выйти из процесса Python. Код такой, если интересно, можете глянутьGitHub.com/to beg IT3 Хубэй….
# If is PS
queue = worker_done_queues[task_index]
dequeue_op = queue.dequeue()
for i in range(master_worker_number):
sess.run(dequeue_op)
logging.info("{} workers are already done".format(i + 1))
# If is Worker
enqueue_ops = []
for queue in worker_done_queues:
enqueue_op = queue.enqueue(1)
enqueue_ops.append(enqueue_op)
for enqueue_op in enqueue_ops:
sess.run(enqueue_op)
Еще одна вещь, на которую стоит пожаловаться в распределенном интерфейсе TensorFlow, заключается в том, что он может использовать самые разные пакеты сеансов, такие как Supervisor и MonitoredTrainingSession. Использование Supervisor в случае сетевого дрожания может привести к сбою с PS или Worker и не может использовать Session, а объект Session, полученный с помощью MonitoredTrainingSession, по сути, не может напрямую использовать официальный save_model_builder для экспорта модели SavedModel из-за несоответствия типов. Пользователи сети с новыми мозгами подумали об экспорте параметров модели в локальную контрольную точку в MonitoredTrainingSession, а затем новые tf.Session() для загрузки модели экспорта Checkpoint. Конечно, мы использовали другую идею для решения этой проблемы: мы добавили SavedModelHook в MonitoredTrainingSession, заметьте, что он был добавлен в Chief_only_hooks вместо обычных хуков (чтобы все воркеры не уходили на экспорт), а затем унаследовал SessionRunHook API в конце ( Пришло время получить объект Session для сохранения модели, поэтому, когда вы видите приведенный ниже код, вам не нужен опыт, который воплощает в себе мудрость дизайнера TensorFlow API.
class SavedModelHook(tf.train.SessionRunHook):
def end(self, session):
saved_model(session, model_path, FLAGS.model_version,
model_signature, legacy_init_op)
chief_hooks = [SavedModelHook()]
with tf.train.MonitoredTrainingSession(
master=server.target,
is_chief=(task_type == "master"),
chief_only_hooks=chief_hooks) as mon_sess:
Суммировать
Некоторые API-интерфейсы TensorFlow вызывают насмешки.Конечно, как разработчики, мы также хорошо осведомлены о присущих им дефектах и трудностях реализации. Как «всесторонняя» среда глубокого обучения, TensorFlow реализует управление DAG и поток управления в дополнение к базовой функции автоградации.Существует также общая очередь очереди для реализации управления именами файлов и управления данными в случайном порядке (включая предоставление пользователям возможности реализовать автоматическое на основе в очередях) ps exit) и общий API файловой системы для поддержки локальных, hdfs, s3 и других файловых систем, а также большое количество абстракций операторов и уровней, которые могут унифицировать интерфейсы на ЦП, ГП и ТПУ, и вышеперечисленное. все должно быть реализовано на op, может быть гарантировано на C++ запустить в tensorflow::ClientSession.
Таким образом, все дизайны интерфейсов трудно быть совершенными с точки зрения простоты использования и масштабируемости.Например, соглашение о том, что FLAGS проверяет и анализирует в __getattr__, описанное выше, может привести к тому, что другие API не смогут воспринимать, и многие интерфейсы хорошо масштабируются. , Он также немного сложнее в использовании, например, Distributed TensorFlow действительно сложен и может быть представлен отдельно позже. В настоящее время мы можем отправить больше проблем и запросов на включение в сообщество TensorFlow. Процесс изучения исходного кода TensorFlow — лучший способ использовать TensorFlow. Мы с нетерпением ждем присоединения других участников TensorFlow (помогите нам решить вышеуказанные проблемы) .