Электронная библиотека » Нихиль Будума » » онлайн чтение - страница 3


  • Текст добавлен: 27 января 2020, 12:00


Автор книги: Нихиль Будума


Жанр: Управление и подбор персонала, Бизнес-Книги


Возрастные ограничения: +16

сообщить о неприемлемом содержимом

Текущая страница: 3 (всего у книги 18 страниц) [доступный отрывок для чтения: 5 страниц]

Шрифт:
- 100% +
Борьба с переобучением в глубоких нейросетях

Есть несколько методов борьбы с переобучением. Ниже мы подробно их обсудим. Один из них носит название регуляризации. Он изменяет целевую функцию, которую мы минимизируем, добавляя условия, которые препятствуют появлениям больших весов. Иными словами, мы изменяем целевую функцию на Error + λf(θ), где f(θ) увеличивается, когда компоненты θ растут, а λ – показатель регуляризации (еще один гиперпараметр). Значение λ определяет, в какой степени мы хотим защититься от переобучения. Если λ = 0, мы не принимаем никаких мер. Если λ слишком велико, приоритетом модели будет сохранение θ на низком уровне, а не нахождение значений параметров, которые дадут хорошие результаты на обучающем наборе. Выбор λ – очень важная задача, которая может потребовать ряда проб и ошибок.

Самый распространенный тип регуляризации в машинном обучении – так называемая L2-регуляризация[14]14
  Tikhonov A. N., Glasko V. B. Use of the regularization method in nonlinear problems // USSR Computational Mathematics and Mathematical Physics. 1965. Vol. 5. No. 3. Pp. 93–107.


[Закрыть]
. Ее можно провести, дополнив функцию потерь квадратом величины всех весов в нейросети. Иными словами, для каждого веса w в нейросети мы добавляем в функцию потерь. L2-регуляризация интуитивно интерпретируется как препятствующая появлению пиковых векторов весов и предпочитающая равномерные векторы весов.

Это полезное свойство, побуждающее сеть использовать в равной степени все входные данные, а не отдавать предпочтение одним входам в ущерб другим. К тому же в ходе градиентного спуска использование L2-регуляризации в целом означает, что каждый вес линейно уменьшается до 0. Благодаря этому феномену L2-регуляризация получила второе название: сокращение весов.

Мы можем визуализировать эффекты L2-регуляризации с помощью ConvNetJS. Как на рис. 2.10 и рис. 2.11, здесь используется нейросеть с двумя входами, двумя выходами с мягким максимумом и скрытый слой из 20 нейронов. Мы обучаем сети при помощи мини-пакетного градиентного спуска (размер пакета 10) и показателей регуляризации 0,01, 0,1 и 1. Результаты приведены на рис. 2.15.


Рис. 2.15. Визуализация нейросетей, обученных с показателями регуляризации 0,01, 0,1 и 1 (в таком порядке)


Еще один распространенный вариант – L1-регуляризация. Здесь мы добавляем значение λ|w| для каждого веса w в нейросети. L1-регуляризация обладает интригующим свойством: в ходе оптимизации векторы весов становятся очень разреженными (очень близкими к 0). Иными словами, нейроны начинают использовать небольшое количество самых важных входов и становятся устойчивыми к шуму на входе. А векторы весов, полученные при L2-регуляризации, обычно равномерны и невелики. L1-регуляризация очень полезна, когда вы хотите понять, какие именно свойства вносят вклад в принятие решения. Если такой уровень анализа свойств не нужен, мы используем L2-регуляризацию: она на практике работает лучше.

Максимальные ограничения нормы имеют схожую цель: это попытка предотвратить слишком большие значения θ, но более непосредственная[15]15
  Srebro N., Rennie J. D. M., Jaakkola T. S. Maximum-Margin Matrix Factorization // NIPS. 2004. Vol. 17.


[Закрыть]
. Максимальные ограничения нормы задают абсолютную верхнюю границу для входного вектора весов каждого нейрона и при помощи метода проекции градиента устанавливают ограничение. Иными словами, каждый раз, когда шаг градиентного спуска изменяет входящий вектор весов, так что ||w||2 > c, мы проецируем вектор обратно на шар (центр которого расположен в исходной точке) с радиусом c. Типичные значения c – 3 и 4. Примечательно, что вектор параметров не может выйти из-под контроля (даже если нормы обучения слишком высоки), поскольку обновления весов всегда ограничены.

Совсем иной метод борьбы с переобучением – прореживание (Dropout), который особенно популярен у специалистов по глубоким нейросетям[16]16
  Srivastava N. et al. Dropout: A Simple Way to Prevent Neural Networks from Overfitting // Journal of Machine Learning Research. 2014. Vol. 15. No. 1. Pp. 1929–1958.


[Закрыть]
. При обучении он используется так: нейрон становится активным только с некой вероятностью p (гиперпараметр), иначе его значение приравнивается к 0. На интуитивном уровне можно решить, что это заставляет нейросеть оставаться точной даже в условиях недостатка информации. Сеть перестает быть слишком зависимой от отдельного нейрона или их небольшого сочетания. С точки зрения математики прореживание препятствует переобучению, давая возможность приблизительно сочетать экспоненциально большое количество архитектур нейросетей, причем эффективно. Процесс прореживания показан на рис. 2.16.


Рис. 2.16. Прореживание помечает каждый нейрон сети как неактивный с некой случайной вероятностью на каждом этапе обучения


Прореживание – понятный процесс, но стоит учесть несколько важных моментов. Во-первых, нужно, чтобы выходные значения нейронов во время тестирования были эквивалентны ожидаемым выходным значениям в процессе обучения. Мы можем добиться этого наивным способом, масштабировав параметры в тесте. Например, если p = 0,5, нейроны должны вдвое уменьшить выходные значения в тесте, чтобы обеспечить те же (ожидаемые) параметры в ходе обучения. Ведь выходное значение нейрона равно 0 с вероятностью (1 − p). И если до прореживания оно равнялось x, после прореживания ожидаемое значение будет E[output] = px + (1 − p) 0 = px. Но такое применение операции нежелательно, поскольку предполагает масштабирование выходных значений нейрона во время тестирования. Результаты тестов очень важны для оценки модели, и предпочтительнее использовать обратное прореживание, при котором масштабирование происходит в процессе обучения, а не тестирования. Выходное значение любого нейрона, активность которого не заглушена, делится на p перед передачей его на следующий уровень. Теперь



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

Резюме

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

Глава 3. Нейросети в TensorFlow

Что такое TensorFlow?

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

Основной инструмент, который нам нужен, называется TensorFlow[17]17
  https://www.tensorflow.org/.


[Закрыть]
. Это открытая программная библиотека, выпущенная в 2015 году Google, чтобы облегчить создание, разработку и обучение моделей. TensorFlow изначально была внутренней библиотекой для разработчиков Google, и мы думаем, что в открытую версию будут добавляться новые функции по мере их тестирования и проверки в Google. TensorFlow – лишь один из вариантов, доступных разработчикам, и мы выбрали эту библиотеку за продуманный дизайн и простоту использования. Краткое ее сопоставление с альтернативами будет дано в следующем разделе.

TensorFlow – библиотека Python, которая дает пользователям возможность выражать произвольные вычисления в виде графа потоков данных. Узлы графа соответствуют математическим операциям, а ребра – данным, которые передаются из одного узла в другой. Данные в TensorFlow представлены в виде тензоров – многомерных массивов (векторы – одномерные тензоры, матрицы – двумерные и т. д.).

Такой способ представления полезен во многих областях, но TensorFlow в основном используется для глубокого обучения в практике и исследованиях. Представление нейросетей в виде тензоров, и наоборот, – не тривиальная задача, а скорее навык, который нужно развить при работе с этой книгой. Это позволит применить варианты ускорения, которые обеспечивают современные компьютеры (например, для параллельных тензорных операций на графических процессорах) и даст четкий и выразительный способ внедрения моделей. Мы поговорим об основах использования TensorFlow и рассмотрим два простых примера (логистическую регрессию и многослойные сети с прямым распространением сигнала). Но, прежде чем погрузиться в предмет, сопоставим в общих чертах TensorFlow с альтернативами для моделей глубокого обучения.

Сравнение TensorFlow с альтернативами

Помимо TensorFlow, есть и ряд других библиотек для создания глубоких нейросетей. Это Theano, Torch, Caffe, Neon и Keras[18]18
  http://deeplearning.net/software/theano/ (http://bit.ly/2jtjGea); http://torch.ch/; http://caffe.berkeleyvision.org/; https://www.nervanasys.com/technology/neon/ (http://bit.ly/2r9XugB); https://keras.io/.


[Закрыть]
. На основании двух простых критериев (выразительность и наличие активного сообщества разработчиков) мы в итоге сократили поле выбора до TensorFlow, Theano (создана в LISA Lab Монреальского университета) и Torch (в основном поддерживается командой Facebook AI Research).

Все три библиотеки могут похвастать солидным сообществом разработчиков, позволяют манипулировать тензорами с незначительными ограничениями и обеспечивают возможность автоматического дифференцирования (что позволяет пользователям обучать модели глубокого обучения без необходимости адаптировать алгоритм обратного распространения ошибок для различных архитектур нейросетей, как мы делали в предыдущей главе). Один из недостатков Torch, однако, в том, что эта среда написана на Lua. Это скриптовый язык, который напоминает Python, но мало используется за пределами собственного глубокого обучения. Мы решили не заставлять новичков осваивать новый язык ради создания моделей, так что вариантов теперь два: TensorFlow и Theano.

Из этих двух кандидатов выбрать было труднее (первый вариант главы написан с использованием Theano), но в конце концов мы остановились на TensorFlow по ряду незначительных причин. Во-первых, в Theano нужен дополнительный шаг – «компиляция графа», который занимает много времени при разработке определенных видов архитектур глубокого обучения. Хотя фаза компиляции невелика по сравнению со временем обучения, при написании и отладке нового кода она кажется неприятной. Во-вторых, у TensorFlow гораздо более понятный интерфейс. Многие классы моделей можно выразить значительно меньшим числом строк, не жертвуя общей выразительностью структуры. Наконец, TensorFlow создавалась для использования в продуктивных системах, а Theano разрабатывали ученые почти исключительно для исследовательских целей. Поэтому у TensorFlow много полезных функций и свойств, которые делают эту библиотеку лучшим вариантом для реальных систем (способность работать в мобильной среде, легко создавать модели для запуска на нескольких графических процессорах на одной машине и обучать масштабные сети распределенным методом). Знакомство с Theano и Torch полезно при изучении примеров из открытых источников, но анализ этих библиотек выходит за рамки этой книги[19]19
  В сентябре 2017 года объявлено, что разработка Theano будет прекращена после выпуска версии 1.0 (см. https://groups.google.com/forum/#!msg/theano-users/7Poq8BZutbY/rNCIfvAEAwAJ). Для Torch создали реализацию на Python, названную PyTorch. Эта новая библиотека стремительно набирает популярность. Прим. науч. ред.


[Закрыть]
.

Установка TensorFlow

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

# Ubuntu/Linux 64-bit

$ sudo apt-get install python-pip python-dev

# Mac OS X

$ sudo easy_install pip

Установив Pip (версия 8.1 или новее), примените следующие команды для установки TensorFlow. Отметим разницу в именовании пакетов Pip, если мы хотим загрузить версию TensorFlow для графических процессоров (настоятельно советуем так и поступить):

$ pip install – upgrade tensorflow # for Python 2.7

$ pip3 install – upgrade tensorflow # for Python 3.n

$ pip install – upgrade tensorflow-gpu # for Python 2.7

# and GPU

$ pip3 install – upgrade tensorflow-gpu # for Python 3.n

# and GPU

Дополненные обновленные инструкции и подробности по поводу установки приложения можно найти на сайте TensorFlow[20]20
  https://www.tensorflow.org/install/.


[Закрыть]
.

Создание переменных TensorFlow и работа с ними

Создавая модель глубокого обучения в TensorFlow, мы используем переменные для представления параметров модели. Переменные TensorFlow – буферы в оперативной памяти, содержащие тензоры. Однако, в отличие от нормальных тензоров, которые создаются только при запуске графа и затем тут же стираются из памяти, переменные переживают несколько выполнений графа. Поэтому они обладают следующими тремя свойствами.

• Переменные должны быть явно инициализированы до того, как граф будет использован впервые.

• Можно использовать градиентные методы модификации переменных после каждой итерации, ведь мы ищем оптимальные параметры модели.

• Значения, хранимые в переменных, можно скопировать на диск и восстанавливать для дальнейшего использования.

Эти три свойства делают TensorFlow особенно полезным инструментом в разработке моделей машинного обучения.

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

weights = tf.Variable(tf.random_normal([300, 200], stddev=0.5), name="weights")

Здесь мы сообщаем tf.Variable два аргумента[21]21
  https://www.tensorflow.org/api_docs/python/tf/Variable.


[Закрыть]
. Первый – tf.random_normal – операция, которая создает тензор, инициализированный при помощи нормального распределения со стандартным отклонением 0,5[22]22
  https://www.tensorflow.org/api_docs/python/tf/random_normal.


[Закрыть]
. Мы указали размер тензора – 300×200, подразумевая, что веса соединяют слой из 300 нейронов со слоем из 200 нейронов. Мы задали имя обращения к tf.Variable. Это уникальный идентификатор, который позволяет обращаться к соответствующему узлу в графе вычислений. В этом случае веса считаются обучаемыми; мы будем автоматически вычислять градиенты и применять их к весам. Если они не должны быть обучаемыми, мы можем установить дополнительный флаг при обращении к tf.Variable:

weights = tf.Variable(tf.random_normal([300, 200], stddev=0.5), name="weights", trainable=False)

Помимо tf.random_normal, есть еще несколько методов инициализации переменной TensorFlow:

# Common tensors from the TensorFlow API docs

tf.zeros(shape, dtype=tf.float32, name=None)

tf.ones(shape, dtype=tf.float32, name=None)

tf.random_normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None)

tf.truncated_normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None name=None)

tf.random_uniform(shape, minval=0, maxval=None, dtype=tf.float32, seed=None, name=None)

При обращении к tf.Variable к графу вычислений добавляются три операции:

• операция, создающая тензор для инициализации переменной;

• операция tf.assign, которая наполняет переменную инициализирующим тензором до ее использования;

• операция переменной, которая содержит ее текущее значение.

Визуализация приведена на рис. 3.1.


Рис. 3.1. Три операции добавляются при реализации переменной TensorFlow. Здесь мы инициализируем переменные веса при помощи нормального распределения


Как мы уже говорили, прежде чем использовать переменную TensorFlow, нужно запустить операцию tf.assign[23]23
  https://www.tensorflow.org/api_docs/python/tf/assign.


[Закрыть]
, чтобы переменной было присвоено желаемое начальное значение. Для этого можно запустить tf.initialize_all_variables()[24]24
  http://bit.ly/2rtqoIA.


[Закрыть]
, что приведет к выполнению всех операций tf.assign в нашем графе. Мы можем также выборочно инициализировать некоторые переменные графа вычислений командой tf.initialize_variables(var1, var2, …)[25]25
  https://www.tensorflow.org/api_docs/python/tf/initialize_variables.


[Закрыть]
. Подробнее обо всем этом мы поговорим при обсуждении сессий TensorFlow.

Операции в TensorFlow

Мы уже упомянули о некоторых операциях в контексте инициализации переменных, но в TensorFlow доступны и многие другие. Они выражают абстрактные трансформации, которые применяются к тензорам в графе вычислений. Операции могут иметь атрибуты, которые либо заданы изначально, либо вводятся в процессе работы. Например, атрибут может описывать ожидаемые типы входных данных (добавление тензоров типа float32 или int32). Операциям, как и переменным, может присваиваться имя для простоты обращения на графе вычислений. Они состоят из одного или более ядер, которые содержат специфичные для устройств реализации.

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

Общий обзор типов доступных операций приведен в таблице 3.1, взятой из оригинальной технической документации TensorFlow[26]26
  Abadi M. et al. TensorFlow: Large-Scale Machine Learning on Heterogeneous Distributed Systems // arXiv preprint arXiv: 1603.04467 (2016).


[Закрыть]
.


Таблица 3.1. Общая таблица операций в TensorFlow

Тензоры-заполнители

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

TensorFlow решает эту проблему при помощи так называемого заполнителя[27]27
  https://www.tensorflow.org/api_docs/python/tf/placeholder.


[Закрыть]
. Его можно использовать в операциях так же, как и все обычные переменные и тензоры TensorFlow, и он реализуется следующим образом:

x = tf.placeholder(tf.float32, name="x", shape=[None, 784])

W = tf.Variable(tf.random_uniform([784,10], -1, 1), name="W")

multiply = tf.matmul(x, W)

Здесь мы определяем заполнитель, где x – мини-пакет данных, сохраненных как float32. Можно отметить, что в x 784 столбца, то есть каждый образец данных имеет 784 измерения. Для x не определено число строк. Это значит, что он может быть инициализирован произвольным количеством образцов данных. Можно и отдельно умножать каждый из них на W, но представление всего мини-пакета в виде тензора позволяет вычислить результаты для всех образцов данных параллельно. В результате i-я строка тензора multiply соответствует W, умноженному на i-й образец данных.

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

Сессии в TensorFlow

Программа TensorFlow взаимодействует с графом вычислений в рамках сессии[28]28
  https://www.tensorflow.org/api_docs/python/tf/Session.


[Закрыть]
. В ходе сессии TensorFlow происходит создание изначального графа, а также инициализация всех переменных и запуск графа вычислений. Для анализа этих элементов рассмотрим простой скрипт на Python:

import tensorflow as tf

from read_data import get_minibatch()

x = tf.placeholder(tf.float32, name="x", shape=[None, 784])

W = tf.Variable(tf.random_uniform([784, 10], -1, 1), name="W")

b = tf.Variable(tf.zeros([10]), name="biases")

output = tf.matmul(x, W) + b

init_op = tf.initialize_all_variables()

sess = tf.Session()

sess.run(init_op)

feed_dict = {"x": get_minibatch()}

sess.run(output, feed_dict=feed_dict)

Первые четыре строчки после оператора импорта описывают граф вычислений, который строится в ходе сессии, когда она будет создана. Этот граф (без операций инициализации переменных) изображен на рис. 3.2. Затем мы инициализируем переменные, используя сессию для запуска соответствующей операции – sess.run(init_op). Наконец, мы можем запустить подграф, вновь обратившись к sess.run, но уже передав на вход тензор или список тензоров, которые мы хотим вычислить, и feed_dict, который вводит необходимые данные в заполнители.


Рис. 3.2. Пример простого графа вычислений в TensorFlow


Наконец, интерфейс sess.run можно использовать для обучения сетей. Мы рассмотрим это подробнее, когда при помощи TensorFlow будем обучать нашу первую модель на MNIST. Но как именно единственная строка кода (sess.run) выполняет так много функций? Все дело в выразительности лежащего в ее основе графа вычислений. Его функции представлены в виде операций TensorFlow, которые передаются в sess.run в качестве аргументов. Ей остается обратиться к графу вычислений и определить все зависимости, которые образуют соответствующий подграф; убедиться, что все переменные-заполнители, принадлежащие к выявленному подграфу, заданы при помощи feed_dict, и пройти по подграфу (выполнив промежуточные операции), чтобы вычислить исходные аргументы.

Теперь мы обратимся к еще двум важнейшим понятиям из области создания графов вычислений и управления ими.

Области видимости переменной и совместное использование переменных

Мы пока не встречались с этой задачей. Создание сложных моделей часто требует повторного и совместного использования больших наборов переменных, которые желательно создавать в одном месте. К сожалению, попытки обеспечить модульность и читабельность порой приводят к неожиданным проблемам, если мы неосторожны. Рассмотрим пример:

def my_network(input):

W_1 = tf.Variable(tf.random_uniform([784, 100], -1, 1), name="W_1")

b_1 = tf.Variable(tf.zeros([100]), name="biases_1")

output_1 = tf.matmul(input, W_1) + b_1

W_2 = tf.Variable(tf.random_uniform([100, 50], -1, 1), name="W_2")

b_2 = tf.Variable(tf.zeros([50]), name="biases_2")

output_2 = tf.matmul(output_1, W_2) + b_2

W_3 = tf.Variable(tf.random_uniform([50, 10], -1, 1), name="W_3")

b_3 = tf.Variable(tf.zeros([10]), name="biases_3")

output_3 = tf.matmul(output_2, W_3) + b_3

# printing names

print "Printing names of weight parameters"

print W_1.name, W_2.name, W_3.name

print "Printing names of bias parameters"

print b_1.name, b_2.name, b_3.name

return output_3

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

In [1]: i_1 = tf.placeholder(tf.float32, [1000, 784], name="i_1")

In [2]: my_network(i_1)

Printing names of weight parameters

W_1:0 W_2:0 W_3:0

Printing names of bias parameters

biases_1:0 biases_2:0 biases_3:0

Out[2]: <tensorflow.python.framework.ops.Tensor …>

In [1]: i_2 = tf.placeholder(tf.float32, [1000, 784], name="i_2")

In [2]: my_network(i_2)

Printing names of weight parameters

W_1_1:0 W_2_1:0 W_3_1:0

Printing names of bias parameters

biases_1_1:0 biases_2_1:0 biases_3_1:0

Out[2]: <tensorflow.python.framework.ops.Tensor …>

Если приглядеться, во втором обращении к my_network используются не те переменные, что в первом (имена различны). Мы создали второй набор переменных! Чаще мы хотим не создавать копию, а повторно использовать модель и ее переменные. Оказывается, в этом случае не стоит использовать tf.Variable. Нужно применить более сложную схему именования, которая использует область видимости переменных TensorFlow.

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

tf.get_variable(<name>, <shape>, <initializer>)

Проверяет, существует ли переменная с этим именем, выбирает ее, если та существует, или создает ее при помощи формы и функции инициализации, если ее еще не существует[29]29
  https://www.tensorflow.org/api_docs/python/tf/get_variable.


[Закрыть]
.

tf.variable_scope(<scope_name>)

Управляет пространством имен и определяет область видимости tf.get_variable[30]30
  https://www.tensorflow.org/api_docs/python/tf/variable_scope.


[Закрыть]
.

Попытаемся четче переписать my_network при помощи области видимости переменных TensorFlow.

Новые названия переменных включают пространство имен, например layer1/W, layer2/b и т. д.:

def layer(input, weight_shape, bias_shape):

weight_init = tf.random_uniform_initializer(minval=-1, maxval=1)

bias_init = tf.constant_initializer(value=0)

W = tf.get_variable("W", weight_shape initializer=weight_init)

b = tf.get_variable("b", bias_shape initializer=bias_init)

return tf.matmul(input, W) + b

def my_network(input):

with tf.variable_scope("layer_1"):

output_1 = layer(input, [784, 100], [100])

with tf.variable_scope("layer_2"):

output_2 = layer(output_1, [100, 50], [50])

with tf.variable_scope("layer_3"):

output_3 = layer(output_2, [50, 10], [10])

return output_3

Попробуем дважды обратиться к my_network, как мы сделали в предыдущем фрагменте кода:

In [1]: i_1 = tf.placeholder(tf.float32, [1000, 784], name="i_1")

In [2]: my_network(i_1)

Out[2]: <tensorflow.python.framework.ops.Tensor …>

In [1]: i_2 = tf.placeholder(tf.float32, [1000, 784], name="i_2")

In [2]: my_network(i_2)

ValueError: Over-sharing: Variable layer_1/W already exists…

В отличие от tf.Variable, команда tf.get_variable проверяет, что переменная с соответствующим именем еще не создана. По умолчанию совместное использование запрещено (из соображений безопасности!), но если мы хотим его решить в области видимости, то должны прописать это прямо:

with tf.variable_scope(«shared_variables») as scope:

i_1 = tf.placeholder(tf.float32, [1000, 784], name="i_1")

my_network(i_1)

scope.reuse_variables()

i_2 = tf.placeholder(tf.float32, [1000, 784], name="i_2")

my_network(i_2)

Это позволяет сохранить модульность, не запрещая совместное использование переменных. К тому же схема именования становится проще и гораздо удобнее.


Страницы книги >> Предыдущая | 1 2 3 4 5 | Следующая
  • 4 Оценок: 5

Правообладателям!

Данное произведение размещено по согласованию с ООО "ЛитРес" (20% исходного текста). Если размещение книги нарушает чьи-либо права, то сообщите об этом.

Читателям!

Оплатили, но не знаете что делать дальше?


Популярные книги за неделю


Рекомендации