Keras GPU 사용하기

쿠버네티스(kubernetes) 위에서 Jupyter를 사용하고 있다. Jupyter Notebook 에서 텐서플로-케라스를 사용하고 있고, GPU 4개를 할당하였다. 주피터에서 노트북을 1개 더 생성해서 작업 할 경우 OOM 에러가 발생하였다.

ResourceExhaustedError (see above for traceback): OOM when allocating tensor with shape[3,3,128,128] and type float on /job:localhost/replica:0/task:0/device:GPU:0 by allocator GPU_0_bfc
	 [[node conv2d_3/kernel/Initializer/random_uniform/RandomUniform (defined at <ipython-input-2-355421ac90ac>:1) ]]
Hint: If you want to see a list of allocated tensors when OOM happens, add report_tensor_allocations_upon_oom to RunOptions for current allocation info.

양쪽 노트북에서 모드 GPU:0을 사용해서 생긴 문제인거 같다. 첫번째 노트북에서 GPU:0의 메모리를 거의 풀로 사용해버린 상태에서, 두번째 노트북에서 GPU:0을 사용하려니 메모리가 부족한 상태가 발생한것이다

서버에서 nvidia-smi을 실행해보면, 프로세스는 생성되었지만, 할당된 메모리가 작다는것을 알 수 있다.

Every 2.0s: nvidia-smi                                                                                         Thu Aug  8 10:09:46 2019

Thu Aug  8 08:09:46 2019
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 418.67       Driver Version: 418.67       CUDA Version: 10.1     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  Tesla M40           Off  | 00000000:02:00.0 Off |                    0 |
| N/A   35C    P0    63W / 250W |  11302MiB / 11448MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
|   1  Tesla M40           Off  | 00000000:82:00.0 Off |                    0 |
| N/A   37C    P0    62W / 250W |    212MiB / 11448MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
|   2  Tesla M40           Off  | 00000000:85:00.0 Off |                    0 |
| N/A   35C    P0    62W / 250W |    212MiB / 11448MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
|   3  Tesla M40           Off  | 00000000:86:00.0 Off |                    0 |
| N/A   37C    P0    62W / 250W |    212MiB / 11448MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
|    0     81475      C   /opt/conda/bin/python                      11060MiB |
|    0     93847      C   /opt/conda/bin/python                        229MiB |
|    1     81475      C   /opt/conda/bin/python                         99MiB |
|    1     93847      C   /opt/conda/bin/python                         99MiB |
|    2     81475      C   /opt/conda/bin/python                         99MiB |
|    2     93847      C   /opt/conda/bin/python                         99MiB |
|    3     81475      C   /opt/conda/bin/python                         99MiB |
|    3     93847      C   /opt/conda/bin/python                         99MiB |
+-----------------------------------------------------------------------------+

알아서 노는 GPU를 사용하면 좋으련만… 어쩔수 없이 GPU 디바이스를 직접 지정하여서 사용핬다.

디바이스 목록 보기

from tensorflow.python.client import device_lib
print(device_lib.list_local_devices())

특정 디바이스를 지정해서 모델 처리하기

텐서플로우에서는 tf.device('/gpu:0') 구문으로 특정 GPU 디바이스를 지정해서 모델을 처리할 수 있다.

import tensorflow as tf

with tf.device('/gpu:0'):
    model = keras.models.Sequential()
    model.add(keras.layers.Conv2D(32, (3, 3), activation='relu', input_shape=(150, 150, 3)))
    model.add(keras.layers.MaxPool2D((2, 2)))
    model.add(keras.layers.Conv2D(64, (3, 3), activation='relu'))
    model.add(keras.layers.MaxPool2D((2, 2)))
    model.add(keras.layers.Conv2D(128, (3, 3), activation='relu'))
    model.add(keras.layers.MaxPool2D((2, 2)))
    model.add(keras.layers.Conv2D(128, (3, 3), activation='relu'))
    model.add(keras.layers.MaxPool2D((2, 2)))
    model.add(keras.layers.Flatten())
    model.add(keras.layers.Dense(512, activation='relu'))
    model.add(keras.layers.Dense(1, activation='sigmoid'))
    
    model.compile(loss='binary_crossentropy', optimizer=keras.optimizers.RMSprop(lr=1e-4), metrics=['acc'])
    
    
    train_datagen = keras.preprocessing.image.ImageDataGenerator(rescale=1./255)
    validation_datagen = keras.preprocessing.image.ImageDataGenerator(rescale=1./255)
    
    train_generator = train_datagen.flow_from_directory(train_dir, target_size=(150, 150), batch_size=20, class_mode='binary')
    validation_generator = validation_datagen.flow_from_directory(validation_dir, target_size=(150, 150), batch_size=20, class_mode='binary')
    
    
    history = model.fit_generator(train_generator, steps_per_epoch=100, epochs=30, validation_data=validation_generator, validation_steps=50)

기타 : 멀티 GPU 사용하기

keras.utils을 사용하면, 모델을 처리할 때 GPU를 사용할 수 있게 지정할 수 있다.

model = ...
model = keras.utils.multi_gpu_model(model, gpus=4)
model.compile(loss='binary_crossentropy', optimizer=keras.optimizers.RMSprop(lr=1e-4), metrics=['acc'])
...