Подтвердить что ты не робот

Keras использует слишком много памяти GPU при вызове train_on_batch, fit и т.д.

Я возился с Keras и так до сих пор. Там одна большая проблема, которую я испытывал при работе с довольно глубокими сетями: при вызове model.train_on_batch или model.fit и т.д. Keras выделяет значительно больше памяти GPU, чем то, что сама модель должна быть. Это не вызвано попыткой тренироваться на некоторых действительно больших изображениях, это сама модель сети, которая, как представляется, требует много памяти GPU. Я создал этот игрушечный пример, чтобы показать, что я имею в виду. Здесь, по существу, происходит:

Сначала создаю довольно глубокую сеть и использую model.summary(), чтобы получить общее количество параметров, необходимых для сети (в данном случае 206538153, что соответствует примерно 826 МБ). Затем я использую nvidia-smi, чтобы узнать, сколько выделяет память GPU Keras, и я вижу, что это имеет смысл (849 МБ).

Затем я компилирую сеть и могу подтвердить, что это не увеличивает использование памяти GPU. И, как мы видим в этом случае, на данный момент у меня есть почти 1 ГБ VRAM.

Затем я пытаюсь подавать в сеть простое изображение 16x16 и 1x1 прав на землю, а затем все взрывается, потому что Keras снова начинает выделять много памяти, без всякой причины, которая очевидна для меня. Что-то об обучении сети, похоже, требует гораздо больше памяти, чем просто наличие модели, что для меня не имеет смысла. Я тренировал значительно более глубокие сети на этом графическом процессоре в других рамках, поэтому я думаю, что я неправильно использую Keras (или что-то не так в моей настройке или в Keras, но, конечно, это трудно понять наверняка).

Здесь код:

from scipy import misc
import numpy as np
from keras.models import Sequential
from keras.layers import Dense, Activation, Convolution2D, MaxPooling2D, Reshape, Flatten, ZeroPadding2D, Dropout
import os

model = Sequential()

model.add(Convolution2D(256, 3, 3, border_mode='same', input_shape=(16,16,1)))
model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2)))
model.add(Convolution2D(512, 3, 3, border_mode='same'))
model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2)))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2)))
model.add(Convolution2D(256, 3, 3, border_mode='same'))
model.add(Convolution2D(32, 3, 3, border_mode='same'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Flatten())
model.add(Dense(4))
model.add(Dense(1))

model.summary()

os.system("nvidia-smi")
raw_input("Press Enter to continue...")    

model.compile(optimizer='sgd',
              loss='mse', 
              metrics=['accuracy'])

os.system("nvidia-smi")              
raw_input("Compiled model. Press Enter to continue...")

n_batches = 1
batch_size = 1
for ibatch in range(n_batches):
    x = np.random.rand(batch_size, 16,16,1)
    y = np.random.rand(batch_size, 1)

    os.system("nvidia-smi")
    raw_input("About to train one iteration. Press Enter to continue...")

    model.train_on_batch(x, y)         
    print("Trained one iteration")

Что дает мне следующий результат:

Using Theano backend.
Using gpu device 0: GeForce GTX 960 (CNMeM is disabled, cuDNN 5103)
/usr/local/lib/python2.7/dist-packages/theano/sandbox/cuda/__init__.py:600: UserWarning: Your cuDNN version is more recent than the one Theano officially supports. If you see any problems, try updating Theano or downgrading cuDNN to version 5.
  warnings.warn(warn)
____________________________________________________________________________________________________
Layer (type)                     Output Shape          Param #     Connected to                     
====================================================================================================
convolution2d_1 (Convolution2D)  (None, 16, 16, 256)   2560        convolution2d_input_1[0][0]      
____________________________________________________________________________________________________
maxpooling2d_1 (MaxPooling2D)    (None, 8, 8, 256)     0           convolution2d_1[0][0]            
____________________________________________________________________________________________________
convolution2d_2 (Convolution2D)  (None, 8, 8, 512)     1180160     maxpooling2d_1[0][0]             
____________________________________________________________________________________________________
maxpooling2d_2 (MaxPooling2D)    (None, 4, 4, 512)     0           convolution2d_2[0][0]            
____________________________________________________________________________________________________
convolution2d_3 (Convolution2D)  (None, 4, 4, 1024)    4719616     maxpooling2d_2[0][0]             
____________________________________________________________________________________________________
convolution2d_4 (Convolution2D)  (None, 4, 4, 1024)    9438208     convolution2d_3[0][0]            
____________________________________________________________________________________________________
convolution2d_5 (Convolution2D)  (None, 4, 4, 1024)    9438208     convolution2d_4[0][0]            
____________________________________________________________________________________________________
convolution2d_6 (Convolution2D)  (None, 4, 4, 1024)    9438208     convolution2d_5[0][0]            
____________________________________________________________________________________________________
convolution2d_7 (Convolution2D)  (None, 4, 4, 1024)    9438208     convolution2d_6[0][0]            
____________________________________________________________________________________________________
convolution2d_8 (Convolution2D)  (None, 4, 4, 1024)    9438208     convolution2d_7[0][0]            
____________________________________________________________________________________________________
convolution2d_9 (Convolution2D)  (None, 4, 4, 1024)    9438208     convolution2d_8[0][0]            
____________________________________________________________________________________________________
convolution2d_10 (Convolution2D) (None, 4, 4, 1024)    9438208     convolution2d_9[0][0]            
____________________________________________________________________________________________________
convolution2d_11 (Convolution2D) (None, 4, 4, 1024)    9438208     convolution2d_10[0][0]           
____________________________________________________________________________________________________
convolution2d_12 (Convolution2D) (None, 4, 4, 1024)    9438208     convolution2d_11[0][0]           
____________________________________________________________________________________________________
convolution2d_13 (Convolution2D) (None, 4, 4, 1024)    9438208     convolution2d_12[0][0]           
____________________________________________________________________________________________________
convolution2d_14 (Convolution2D) (None, 4, 4, 1024)    9438208     convolution2d_13[0][0]           
____________________________________________________________________________________________________
convolution2d_15 (Convolution2D) (None, 4, 4, 1024)    9438208     convolution2d_14[0][0]           
____________________________________________________________________________________________________
convolution2d_16 (Convolution2D) (None, 4, 4, 1024)    9438208     convolution2d_15[0][0]           
____________________________________________________________________________________________________
convolution2d_17 (Convolution2D) (None, 4, 4, 1024)    9438208     convolution2d_16[0][0]           
____________________________________________________________________________________________________
convolution2d_18 (Convolution2D) (None, 4, 4, 1024)    9438208     convolution2d_17[0][0]           
____________________________________________________________________________________________________
convolution2d_19 (Convolution2D) (None, 4, 4, 1024)    9438208     convolution2d_18[0][0]           
____________________________________________________________________________________________________
convolution2d_20 (Convolution2D) (None, 4, 4, 1024)    9438208     convolution2d_19[0][0]           
____________________________________________________________________________________________________
convolution2d_21 (Convolution2D) (None, 4, 4, 1024)    9438208     convolution2d_20[0][0]           
____________________________________________________________________________________________________
convolution2d_22 (Convolution2D) (None, 4, 4, 1024)    9438208     convolution2d_21[0][0]           
____________________________________________________________________________________________________
convolution2d_23 (Convolution2D) (None, 4, 4, 1024)    9438208     convolution2d_22[0][0]           
____________________________________________________________________________________________________
convolution2d_24 (Convolution2D) (None, 4, 4, 1024)    9438208     convolution2d_23[0][0]           
____________________________________________________________________________________________________
maxpooling2d_3 (MaxPooling2D)    (None, 2, 2, 1024)    0           convolution2d_24[0][0]           
____________________________________________________________________________________________________
convolution2d_25 (Convolution2D) (None, 2, 2, 256)     2359552     maxpooling2d_3[0][0]             
____________________________________________________________________________________________________
convolution2d_26 (Convolution2D) (None, 2, 2, 32)      73760       convolution2d_25[0][0]           
____________________________________________________________________________________________________
maxpooling2d_4 (MaxPooling2D)    (None, 1, 1, 32)      0           convolution2d_26[0][0]           
____________________________________________________________________________________________________
flatten_1 (Flatten)              (None, 32)            0           maxpooling2d_4[0][0]             
____________________________________________________________________________________________________
dense_1 (Dense)                  (None, 4)             132         flatten_1[0][0]                  
____________________________________________________________________________________________________
dense_2 (Dense)                  (None, 1)             5           dense_1[0][0]                    
====================================================================================================
Total params: 206538153
____________________________________________________________________________________________________
None
Thu Oct  6 09:05:42 2016       
+------------------------------------------------------+                       
| NVIDIA-SMI 352.63     Driver Version: 352.63         |                       
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce GTX 960     Off  | 0000:01:00.0      On |                  N/A |
| 30%   37C    P2    28W / 120W |   1082MiB /  2044MiB |      9%      Default |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID  Type  Process name                               Usage      |
|=============================================================================|
|    0      1796    G   /usr/bin/X                                     155MiB |
|    0      2597    G   compiz                                          65MiB |
|    0      5966    C   python                                         849MiB |
+-----------------------------------------------------------------------------+
Press Enter to continue...
Thu Oct  6 09:05:44 2016       
+------------------------------------------------------+                       
| NVIDIA-SMI 352.63     Driver Version: 352.63         |                       
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce GTX 960     Off  | 0000:01:00.0      On |                  N/A |
| 30%   38C    P2    28W / 120W |   1082MiB /  2044MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID  Type  Process name                               Usage      |
|=============================================================================|
|    0      1796    G   /usr/bin/X                                     155MiB |
|    0      2597    G   compiz                                          65MiB |
|    0      5966    C   python                                         849MiB |
+-----------------------------------------------------------------------------+
Compiled model. Press Enter to continue...
Thu Oct  6 09:05:44 2016       
+------------------------------------------------------+                       
| NVIDIA-SMI 352.63     Driver Version: 352.63         |                       
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce GTX 960     Off  | 0000:01:00.0      On |                  N/A |
| 30%   38C    P2    28W / 120W |   1082MiB /  2044MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID  Type  Process name                               Usage      |
|=============================================================================|
|    0      1796    G   /usr/bin/X                                     155MiB |
|    0      2597    G   compiz                                          65MiB |
|    0      5966    C   python                                         849MiB |
+-----------------------------------------------------------------------------+
About to train one iteration. Press Enter to continue...
Error allocating 37748736 bytes of device memory (out of memory). Driver report 34205696 bytes free and 2144010240 bytes total 
Traceback (most recent call last):
  File "memtest.py", line 65, in <module>
    model.train_on_batch(x, y)         
  File "/usr/local/lib/python2.7/dist-packages/keras/models.py", line 712, in train_on_batch
    class_weight=class_weight)
  File "/usr/local/lib/python2.7/dist-packages/keras/engine/training.py", line 1221, in train_on_batch
    outputs = self.train_function(ins)
  File "/usr/local/lib/python2.7/dist-packages/keras/backend/theano_backend.py", line 717, in __call__
    return self.function(*inputs)
  File "/usr/local/lib/python2.7/dist-packages/theano/compile/function_module.py", line 871, in __call__
    storage_map=getattr(self.fn, 'storage_map', None))
  File "/usr/local/lib/python2.7/dist-packages/theano/gof/link.py", line 314, in raise_with_op
    reraise(exc_type, exc_value, exc_trace)
  File "/usr/local/lib/python2.7/dist-packages/theano/compile/function_module.py", line 859, in __call__
    outputs = self.fn()
MemoryError: Error allocating 37748736 bytes of device memory (out of memory).
Apply node that caused the error: GpuContiguous(GpuDimShuffle{3,2,0,1}.0)
Toposort index: 338
Inputs types: [CudaNdarrayType(float32, 4D)]
Inputs shapes: [(1024, 1024, 3, 3)]
Inputs strides: [(1, 1024, 3145728, 1048576)]
Inputs values: ['not shown']
Outputs clients: [[GpuDnnConv{algo='small', inplace=True}(GpuContiguous.0, GpuContiguous.0, GpuAllocEmpty.0, GpuDnnConvDesc{border_mode='half', subsample=(1, 1), conv_mode='conv', precision='float32'}.0, Constant{1.0}, Constant{0.0}), GpuDnnConvGradI{algo='none', inplace=True}(GpuContiguous.0, GpuContiguous.0, GpuAllocEmpty.0, GpuDnnConvDesc{border_mode='half', subsample=(1, 1), conv_mode='conv', precision='float32'}.0, Constant{1.0}, Constant{0.0})]]

HINT: Re-running with most Theano optimization disabled could give you a back-trace of when this node was created. This can be done with by setting the Theano flag 'optimizer=fast_compile'. If that does not work, Theano optimizations can be disabled with 'optimizer=None'.
HINT: Use the Theano flag 'exception_verbosity=high' for a debugprint and storage map footprint of this apply node.

Несколько замечаний:

  • Я попробовал оба Theano и TensorFlow. Оба имеют те же проблемы, и заканчиваются на одной и той же строке. В TensorFlow кажется, что Keras предопределяет много памяти (около 1,5 ГБ), поэтому nvidia-smi не помогает нам отслеживать, что происходит там, но я получаю такие же исключения из памяти. Опять же, это указывает на ошибку (мое использование) Keras (хотя трудно быть уверенным в таких вещах, это может быть что-то с моей настройкой).
  • Я пробовал использовать CNMEM в Theano, который ведет себя как TensorFlow: он предопределяет большой объем памяти (около 1,5 ГБ), но сбой в одном и том же месте.
  • Есть некоторые предупреждения о версии CudNN. Я попробовал запустить теано-бэкэнд с CUDA, но не CudNN, и я получил те же ошибки, что и не является источником проблемы.
  • Если вы хотите протестировать это на своем собственном графическом процессоре, вы можете сделать сеть более глубокой/более мелкой в ​​зависимости от того, сколько памяти GPU вам нужно протестировать.
  • Моя конфигурация выглядит следующим образом: Ubuntu 14.04, GeForce GTX 960, CUDA 7.5.18, CudNN 5.1.3, Python 2.7, Keras 1.1.0 (устанавливается через pip)
  • Я попытался изменить компиляцию модели для использования разных оптимизаторов и потерь, но это ничего не меняет.
  • Я попытался изменить функцию train_on_batch, чтобы использовать ее, но у нее такая же проблема.
  • Я видел один похожий вопрос здесь, на StackOverflow - Почему эта модель Keras требует более 6 ГБ памяти? - но насколько я могу судить, я не имеют эти проблемы в моей конфигурации. У меня никогда не было нескольких версий CUDA, и я дважды проверял переменные PATH, LD_LIBRARY_PATH и CUDA_ROOT больше, чем могу считать.
  • Юлий предположил, что сами параметры активации занимают память GPU. Если это правда, может кто-нибудь объяснить это более четко? Я попытался изменить функцию активации моих сверточных слоев на функции, которые явно жестко закодированы, без каких-либо обучаемых параметров, насколько я могу судить, и это ничего не меняет. Кроме того, маловероятно, что эти параметры занимают почти столько же памяти, сколько и остальная часть самой сети.
  • После тщательного тестирования самая большая сеть, которую я могу обучить, составляет около 453 МБ параметров, из моего ~ 2 ГБ ОЗУ GPU. Это нормально?
  • После тестирования Keras на некоторых более мелких CNN, которые соответствуют моему графическому процессору, я вижу, что в использовании GPU очень резкие скачки. Если я запускаю сеть со 100 МБ параметров, то в 99% случаев во время тренировки будет использоваться менее 200 МБ ОЗУ GPU. Но время от времени использование памяти увеличивается примерно до 1,3 ГБ. Кажется безопасным предположить, что это эти шипы, которые вызывают мои проблемы. Я никогда не видел этих шипов в других рамках, но они могут быть там по уважительной причине? Если кто-нибудь знает, что их вызывает, и если есть способ избежать их, пожалуйста, звоните!
4b9b3361

Ответ 1

Очень часто приходится забывать, что активация и градиенты также принимают vram, а не только параметры, что увеличивает использование памяти. Расчеты заднего пролета делают это так, что тренировочная фаза почти вдвое превосходит VRAM для использования нейронной сети в прямом/умозаключении.

Итак, в начале, когда сеть создана, выделяются только параметры. Однако, когда начинается обучение, активация (раз каждый мини-пуск) распределяется, давая поведение, которое вы наблюдаете.

Ответ 2

Оба Theano и Tensorflow дополняют созданный символический граф, хотя и по-разному.

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

Вот фрагмент кода для увеличения batch_size на основе исходного кода:

from scipy import misc
import numpy as np
from keras.models import Sequential
from keras.layers import Dense, Activation, Convolution2D, MaxPooling2D, Reshape, Flatten, ZeroPadding2D, Dropout
import os
import matplotlib.pyplot as plt


def gpu_memory():
    out = os.popen("nvidia-smi").read()
    ret = '0MiB'
    for item in out.split("\n"):
        if str(os.getpid()) in item and 'python' in item:
            ret = item.strip().split(' ')[-2]
    return float(ret[:-3])

gpu_mem = []
gpu_mem.append(gpu_memory())

model = Sequential()
model.add(Convolution2D(100, 3, 3, border_mode='same', input_shape=(16,16,1)))
model.add(Convolution2D(256, 3, 3, border_mode='same'))
model.add(Convolution2D(32, 3, 3, border_mode='same'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Flatten())
model.add(Dense(4))
model.add(Dense(1))

model.summary()
gpu_mem.append(gpu_memory())

model.compile(optimizer='sgd',
              loss='mse', 
              metrics=['accuracy'])
gpu_mem.append(gpu_memory())


batches = []
n_batches = 20
batch_size = 1
for ibatch in range(n_batches):
    batch_size = (ibatch+1)*10
    batches.append(batch_size)
    x = np.random.rand(batch_size, 16,16,1)
    y = np.random.rand(batch_size, 1)
    print y.shape

    model.train_on_batch(x, y)         
    print("Trained one iteration")

    gpu_mem.append(gpu_memory())

fig = plt.figure()
plt.plot([-100, -50, 0]+batches, gpu_mem)
plt.show()

Кроме того, для скорости Tensorflow запускает всю доступную память GPU. Чтобы остановить это, вам нужно добавить config.gpu_options.allow_growth = True в get_session()

# keras/backend/tensorflow_backend.py
def get_session():
    global _SESSION
    if tf.get_default_session() is not None:
        session = tf.get_default_session()
    else:
        if _SESSION is None:
            if not os.environ.get('OMP_NUM_THREADS'):
                config = tf.ConfigProto(allow_soft_placement=True,
                    )
            else:
                nb_thread = int(os.environ.get('OMP_NUM_THREADS'))
                config = tf.ConfigProto(intra_op_parallelism_threads=nb_thread,
                                        allow_soft_placement=True)
            config.gpu_options.allow_growth = True
            _SESSION = tf.Session(config=config)
        session = _SESSION
    if not _MANUAL_VAR_INIT:
        _initialize_variables()
    return session

Теперь, если вы запустили предыдущий фрагмент, вы получите графики:

Theano: Theano Tensorflow: Tenserflow

Theano: После model.compile() независимо от того, какая память нужна, во время начала тренировки она почти удваивается. Это связано с тем, что Теано увеличивает символический граф для обратного распространения, и каждый тензор нуждается в соответствующем тензоре для достижения обратного потока градиентов. Потребности в памяти, похоже, не растут с batch_size, и это неожиданно для меня, поскольку размер заполнителя должен увеличиваться для обеспечения притока данных из CPU- > GPU.

Tensorflow: память GPU не выделяется даже после model.compile(), поскольку Keras не вызывает get_session() до этого времени, которое фактически вызывает _initialize_variables(). Tensorflow, похоже, загружает память в куски для скорости, и поэтому память не растет линейно с помощью batch_size.

Сказав все, что Tensorflow, похоже, голоден, но для больших графиков он очень быстрый. Theano, с другой стороны, очень эффективен с использованием памяти gpu, но уходит много времени, чтобы инициализировать график в начале обучения. После этого его тоже довольно быстро.

Ответ 3

Параметры 200M для 2 Гб графического процессора много. Кроме того, ваша архитектура неэффективна, используя локальные узкие места, будет более эффективной. Также вы должны перейти от небольшой модели к большой, а не назад, прямо сейчас у вас есть вход 16x16, с этой архитектурой это означает, что в конце большая часть вашей сети будет "нулевым дополнением" и не будет основана на входных функциях. Уровни вашей модели зависят от вашего ввода, поэтому вы не можете просто установить произвольное количество слоев и размеров, вам нужно подсчитать, сколько данных будет передано каждому из них, с пониманием, почему это делается. Я бы рекомендовал вам посмотреть этот бесплатный курс http://cs231n.github.io