Нихиль Будума - Основы глубокого обучения
- Название:Основы глубокого обучения
- Автор:
- Жанр:
- Издательство:Манн, Иванов и Фербер
- Год:2020
- Город:Москва
- ISBN:9785001464723
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Нихиль Будума - Основы глубокого обучения краткое содержание
Основы глубокого обучения - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
Сессии в TensorFlow
Программа TensorFlow взаимодействует с графом вычислений в рамках сессии [28]. В ходе сессии 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]:
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]:
Если приглядеться, во втором обращении к my_network используются не те переменные, что в первом (имена различны). Мы создали второй набор переменных! Чаще мы хотим не создавать копию, а повторно использовать модель и ее переменные. Оказывается, в этом случае не стоит использовать tf.Variable. Нужно применить более сложную схему именования, которая использует область видимости переменных TensorFlow.
Механизмы области видимости переменных TensorFlow по большей части контролируются двумя функциями.
tf.get_variable(, , )
Проверяет, существует ли переменная с этим именем, выбирает ее, если та существует, или создает ее при помощи формы и функции инициализации, если ее еще не существует [29].
tf.variable_scope()
Управляет пространством имен и определяет область видимости tf.get_variable [30].
Попытаемся четче переписать 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]:
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)
Это позволяет сохранить модульность, не запрещая совместное использование переменных. К тому же схема именования становится проще и гораздо удобнее.
Управление моделями на CPU и GPU
TensorFlow позволяет при необходимости пользоваться несколькими вычислительными устройствами для обучения модели. Поддерживаемые устройства представлены строковыми идентификаторами, что обычно выглядит так:
"/cpu:0"
CPU нашей машины.
"/gpu:0"
Первый GPU нашей машины (если есть).
"/gpu:1"
Второй GPU нашей машины (если есть).
Если у операции есть ядра CPU и GPU и разрешено использование GPU, TensorFlow автоматически будет выбирать вариант для GPU. Чтобы посмотреть, какие устройства использует граф вычислений, мы можем инициализировать сессию TensorFlow, установив параметр log_device_placement в значение True:
sess = tf.Session(config=tf.ConfigProto(log_device_placement=True))
Если мы хотим использовать конкретное устройство, можно его выбрать с помощью конструкции with tf.device [31]. Но если оно недоступно, возникнет ошибка. Нужно, чтобы TensorFlow нашла другое доступное устройство, если выбранное не существует; можно передать флаг allow_soft_placement в переменную сессии таким образом [32]:
Читать дальшеИнтервал:
Закладка: