Тензорный поток: нехватка памяти (OOM) с использованием train_op.compute_gradients (потеря) в глубокой нейронной сети с прямой связью - PullRequest
0 голосов
/ 28 сентября 2018

Здравствуйте, уважаемое сообщество Stackoverflow!

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

Обзор

Я пытаюсь воспроизвести некоторые выводы из статьи 80-х годов:

Видроу, Бернард и Деррик Нгуен: Сторонник грузовиков-Вверх: пример самообучения в нейронных сетях.Технический отчет, 1989.

Это что-то вроде помощи при парковке, которая способна рассчитать эталонные траектории для нелинейной системы.Интересно, что авторы предлагают применять этот метод и к другим нелинейным динамическим системам.

Основная идея в терминах тензорного потока состоит в том, чтобы создать подграф, который содержит контроллер мультиперцептрона и другой мультиперцепт, эмулирующий системудинамика.Цель состоит в том, чтобы рассчитать траекторию, соединив несколько копий этого подграфа последовательно и применив алгоритм обучения на основе градиентного спуска, чтобы найти подходящие веса для мультиперцептрона контроллера.Общий ввод представляет начальное состояние, а общий вывод представляет конечное состояние.Ошибка возникает из конечного состояния и контрольного конечного состояния.Количество используемых копий определяет временной горизонт или «временные шаги», за которые система оценивается.Кроме того, важно, чтобы все копии подграфа или «временного шага» были идентичны между «временными шагами».Только для каждого шага оптимизации / обучения параметры NN контроллера адаптируются к сумме всех градиентов для каждого «временного шага». Можно сказать, что они делят значения своих весов по временным шагам.

Настройка вTensorflow

Мой вопрос касается операции train_op.compute_gradients () и возможности повторного использования переменных, а также градиентов в нескольких областях.

Я хочу соединить несколько подграфов, каждый из которых содержит мелкую нейронную областьnet (NN) и некоторые другие tf-ops, с идентичными параметрами и структурой в серии.Таким образом, построение этой серии вывод одного подграфа становится входом его преемника.Это приводит к графу вычислений, подобному показанному в Визуализация графика вычислений с использованием графического интерфейса тензорной доски .На изображении каждый step_ представляет такой вышеупомянутый подграф.

Важная часть состоит в том, чтобы затем вычислить градиенты функции стоимости из выходных данных последнего «слоя» по параметрамNN в каждом step_ .

Следующий код предоставляет то, что я в настоящее время построил с tenorflow.

import tensorflow as tf
import numpy as np    
sess = tf.InteractiveSession()

Установите некоторые значения конфигурации:

K = 3 # number of timesteps
nodes_controller_nn = 25 # number of neurons in hidden layer
deflayer = [4, nodes_controller_nn, 1] # specifies number of inputs, hidden
                                       # layer neurons and outputs in this order

Создать случайные начальные значения для FNN.Они будут использоваться для каждого шага k в следующем цикле for.Операции определяются вне цикла, потому что они будут переоцениваться в каждом цикле k цикла for, генерирующего разные псевдослучайные значения.

W0random = tf.random_normal([4, nodes_controller_nn], 
                            mean=0.0, 
                            stddev= np.sqrt(nodes_controller_nn)**-1)
W1random = tf.random_normal([nodes_controller_nn,1], 
                            mean=0.0, 
                            stddev= np.sqrt(nodes_controller_nn)**-1)
b0random = tf.random_normal([nodes_controller_nn], 
                            mean=0.0, 
                            stddev= np.sqrt(nodes_controller_nn)**-1)
b1random = tf.random_normal([1], 
                            mean=0.0, 
                            stddev= np.sqrt(2)**-1)

Теперь нужно настроить последовательную структуру (WithingGUI тензорной доски визуализация выглядит следующим образом: Граф вычислений в графическом интерфейсе Tensorboard с расширенным подграфом 'step_0'. ):

xin = tf.placeholder(tf.float32, [None, 4], name='x_start')
for k in range(0,K):
    with tf.name_scope('step_'+str(k)):
        with tf.name_scope("C"):
            W0 = tf.Variable(W0random, name='W0', trainable=True) 
            b0 = tf.Variable(b0random, name='b0', trainable=True)
            W1 = tf.Variable(W1random, name='W1', trainable=True) 
            b1 = tf.Variable(b1random, name='b1', trainable=True)
            with tf.name_scope('Layer0'):
                Z0 = tf.add(tf.matmul(xin, W0), b1, name='Z0')
                A0 = tf.nn.tanh(Z0, name='A0')
            with tf.name_scope('Layer1'):
                Z1 = tf.add(tf.matmul(A0, W1), b1, name='Z1')
                A1 = tf.identity(Z1, name='A1')
        yC = tf.identity(A1, name = 'u')
        xT = tf.identity(tf.concat([xin, yC], 1), name = 'xT')
        with tf.name_scope('T'):
            # Calculation of the system dynamics (cart-pole system)
            # Args:
            #    xT: contains the state variables x, dxdt, phi, dphidt
            #    fe: control force on cart
            # Params:
            #    m,M,l: mass pendulum, mass cart, length pendulum
            #    g: gravitational acceleration
            with tf.name_scope('state_vars'):
                x1 = tf.slice(xT, [0,0], [1,1])
                x2 = tf.slice(xT, [0,1], [1,1])
                x3 = tf.slice(xT, [0,2], [1,1])
                x4 = tf.slice(xT, [0,3], [1,1])
                fe = tf.slice(xT, [0,4], [1,1])
            with tf.name_scope('constants'):
                m = tf.constant([[0.1]], name='mass_pend')
                M = tf.constant([[0.1]], name='mass_cart')
                l = tf.constant([[1.0]], name='length_pend')
                g = tf.constant([[9.81]], name='gravitation')
                dt = tf.constant([[0.001]], name='time_step')
            with tf.name_scope('rhs'):
                dx1dt = x2
                num = -m*g*tf.sin(x3)*tf.cos(x3)+m*l*x4**2*tf.sin(x3)+fe
                den = M + (1-tf.cos(x3)**2)*m
                dx2dt = num/den
                dx3dt = x4
                num = (M+m)*g*tf.sin(x3)-(l*m*x4**2*tf.sin(x3) + fe)*tf.cos(x3)
                den = M+m*(1-tf.cos(x3)**2)
                dx4dt = num/den/l
                dxdt = tf.concat([dx1dt, dx2dt, dx3dt, dx4dt], axis=1)
                xx = tf.concat([x1, x2, x3, x4], axis=1)
                xx = xx + tf.multiply(dt, dxdt)
            yL = tf.identity(xx, name='yL')
    tensor_name = 'step_'+str(k)+'/T'+'/yL:0'
    xin = tf.get_default_graph().get_tensor_by_name(tensor_name)
yT = tf.identity(yL, name='x_end')
y_ = tf.placeholder(tf.float32, [None, 4], name='x_target')
loss = tf.identity(tf.losses.mean_squared_error(yT, y_), name='loss')
train_op = tf.train.GradientDescentOptimizer(0.01)
train_step = train_op.minimize(loss, name='sgd')

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

Я пытался отслеживать потребности скрипта в памяти, используя psutil , добавив следующее в приведенный выше код:

import os
from time import time
import psutil
process = psutil.Process(os.getpid())
mem1 = process.memory_info().rss*1e-6
tic1 = time()
grads = train_op.compute_gradients(loss)
tic2 = time()
mem2 = process.memory_info().rss*1e-6

Соответственно, изображение Потребление памяти и время оценки по количеству вычисленных шагов K. показывает эти значения (mem1 представляет память без градаций в [Мб], mem2 - общий объем памяти в [Мб] и градов в[Мб] представляет разницу двух.)Это изображение показывает, что для тысячи шагов K мне понадобится примерно 10 ГБ ОЗУ, которого у меня нет.

Буду признателен за идеи и комментарии:

  • Было быМожно ли каким-то образом использовать tf.variable_scopes для повторного использования переменных и градиентов для этой задачи и сохранять их только один раз?
  • Использует ли tf.slice, tf.concat и все назначения в пределах'rhs'-scope генерирует ненужные много операций и тензоров в computation_graph, которые можно было бы предотвратить?
  • Поскольку эти процедуры кажутся похожими на обратное распространение во времени для RNN, можно ли каким-то образом использовать уже существующий метод оптимизации?
  • Было бы более целесообразно попытаться решить эту проблему с помощью RNN или возникнет та же проблема?
  • И, конечно, общие советы по синтаксису, удобочитаемости и т. Д. Приветствуются!

Большое спасибо, что нашли время.

...