IT/AI\ML

[python/Tensorflow] Tensorflow에서 GPU 제한 혹은 무효화하기

개발자 두더지 2022. 5. 30. 21:14
728x90

일본의 한 블로그 글의 번역한 포스트입니다. 오역 및 직역, 의역이 있을 수 있으며 틀린 내용은 지적해주시면 감사하겠습니다. 

 

개요


GPU판 Tensorflow를 기본 설정대로 사용하면 GPU의 모든 메모리가 확보되어버린다.

import tensorflow as tf
import six
# tf.compat.v1.Session를 만들어 키보드 입력을 기다릴뿐인 코드
tf.compat.v1.Session()
six.moves.input()
$ python test_gpu.py

nvidia-smi로 확인하면 다음과 같이 출력된다.

Fri Oct 28 15:21:14 2016
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 367.44                 Driver Version: 367.44                    |
|-------------------------------+----------------------+----------------------+
| 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 TIT...  Off  | 0000:02:00.0     Off |                  N/A |
| 22%   55C    P8    20W / 250W |  11603MiB / 12206MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
|   1  GeForce GTX TIT...  Off  | 0000:03:00.0     Off |                  N/A |
| 22%   57C    P8    20W / 250W |  11603MiB / 12206MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
|   2  GeForce GTX TIT...  Off  | 0000:83:00.0     Off |                  N/A |
| 22%   53C    P8    21W / 250W |  11603MiB / 12206MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
|   3  GeForce GTX TIT...  Off  | 0000:84:00.0     Off |                  N/A |
| 22%   48C    P8    18W / 250W |  11601MiB / 12206MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID  Type  Process name                               Usage      |
|=============================================================================|
|    0     22830    C   python                                       11599MiB |
|    1     22830    C   python                                       11599MiB |
|    2     22830    C   python                                       11599MiB |
|    3     22830    C   python                                       11597MiB |
+-----------------------------------------------------------------------------+

 공유  머신이나 GPU 1대로 충분한 경우에는 GPU를 제한해서 사용하여 메모리 하나의 소스에서 확보하지 않도록 하는 방법을 조사한 내용대로 공유하고자한다.

 

 

디바이스를 제한하기


CUDA를 이용한 제한

CUDA에는 환경 변수 CUDA_​VISIBLE_​DEVICES를 이용해서 GPU를 제한하는 기능이 존재한다. 

# GPU: 0 0번째 GPU만을 사용한다. 
$ CUDA_​VISIBLE_​DEVICES=0 python test_gpu.py
...
I tensorflow/core/common_runtime/gpu/gpu_device.cc:972] DMA: 0
I tensorflow/core/common_runtime/gpu/gpu_device.cc:982] 0:   Y
I tensorflow/core/common_runtime/gpu/gpu_device.cc:1041] Creating TensorFlow device (/gpu:0) -> (device: 0, name: GeForce GTX TITAN X, pci bus id: 0000:02:00.0)
+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID  Type  Process name                               Usage      |
|=============================================================================|
|    0     26601    C   python                                       11599MiB |
+-----------------------------------------------------------------------------+

확인하면 위와 달리 0번째 GPU만 사용되는 것을 알 수 있다. 또한 지정된 복수의 GPU를 사용하도록 설정할 수 있다.

# GPU: 0번과 3번을 사용한다.
$ CUDA_​VISIBLE_​DEVICES=0,3 python test_gpu.py
...
I tensorflow/core/common_runtime/gpu/gpu_device.cc:855] cannot enable peer access from device ordinal 0 to device ordinal 1
I tensorflow/core/common_runtime/gpu/gpu_device.cc:855] cannot enable peer access from device ordinal 1 to device ordinal 0
I tensorflow/core/common_runtime/gpu/gpu_device.cc:972] DMA: 0 1
I tensorflow/core/common_runtime/gpu/gpu_device.cc:982] 0:   Y N
I tensorflow/core/common_runtime/gpu/gpu_device.cc:982] 1:   N Y
I tensorflow/core/common_runtime/gpu/gpu_device.cc:1041] Creating TensorFlow device (/gpu:0) -> (device: 0, name: GeForce GTX TITAN X, pci bus id: 0000:02:00.0)
I tensorflow/core/common_runtime/gpu/gpu_device.cc:1041] Creating TensorFlow device (/gpu:1) -> (device: 1, name: GeForce GTX TITAN X, pci bus id: 0000:84:00.0)

 여러개의 GPU를 사용할 때는 번호를 바꾸면 pci bus i의 순서가 바뀌는 것을 알 수 있다.

# 순서를 바꿀 수 있다. pci bus id의 순서가 위와 달라진 것을 확인할 수 있다.
$ CUDA_​VISIBLE_​DEVICES=3,0 python test_gpu.py
...
I tensorflow/core/common_runtime/gpu/gpu_device.cc:855] cannot enable peer access from device ordinal 0 to device ordinal 1
I tensorflow/core/common_runtime/gpu/gpu_device.cc:855] cannot enable peer access from device ordinal 1 to device ordinal 0
I tensorflow/core/common_runtime/gpu/gpu_device.cc:972] DMA: 0 1
I tensorflow/core/common_runtime/gpu/gpu_device.cc:982] 0:   Y N
I tensorflow/core/common_runtime/gpu/gpu_device.cc:982] 1:   N Y
I tensorflow/core/common_runtime/gpu/gpu_device.cc:1041] Creating TensorFlow device (/gpu:0) -> (device: 0, name: GeForce GTX TITAN X, pci bus id: 0000:84:00.0)
I tensorflow/core/common_runtime/gpu/gpu_device.cc:1041] Creating TensorFlow device (/gpu:1) -> (device: 1, name: GeForce GTX TITAN X, pci bus id: 0000:02:00.0)

 GPU를 완전히 사용하지 않고 CPU만으로 작동시키고 싶은 경우에는  -1과 같이 존재하지 않는 GPU번호를 지정하면 된다.

# GPU를 무효화시키고 싶은 경우 값은 빈 공백이나 존재하지 않는 값으로 지정한다.
$ CUDA_VISIBLE_DEVICES= python test_gpu.py
...
E tensorflow/stream_executor/cuda/cuda_driver.cc:491] failed call to cuInit: CUDA_ERROR_NO_DEVICE

 코드 안에 작성하고 싶은 경우 python의 os라이브러리를 이용해서 작성하면 된다.

import os
os.environ['CUDA_VISIBLE_DEVICES'] = '-1' #무효화할 경우 -1, 그 외에는 사용한 GPU 번호를 지정

 

tf.compat.v1.ConfigProto.gpu_options.visible_device_list 를 이용한 방법

tf.compat.v1.Session 초기화시에 전달하는 tf.compat.v1.ConfigProto에 GPU의 설정을 추가하여 제한하는 방법이 존재한다.

tf.compat.v1.ConfigProto.gpu_options.visible_device_list에 CUDA_VISIBLE_DEVICES와 동일하게 사용할 GPU ID를 콤마로 구분하여 지정하여 GPU 사용을 제어할 수 있다.

# test_gpu_gpuopt_0.py 파일 내용

import tensorflow as tf
import six

config = tf.compat.v1.ConfigProto(
    gpu_options=tf.compat.v1.GPUOptions(
        visible_device_list="0"
    )
)
tf.compat.v1.Session(config=config)
six.moves.input()
$ python test_gpu_gpuopt_0.py
...
I tensorflow/core/common_runtime/gpu/gpu_device.cc:972] DMA: 0
I tensorflow/core/common_runtime/gpu/gpu_device.cc:982] 0:   Y
I tensorflow/core/common_runtime/gpu/gpu_device.cc:1041] Creating TensorFlow device (/gpu:0) -> (device: 0, name: GeForce GTX TITAN X, pci bus id: 0000:02:00.0)

 

 tf.compat.v1.ConfigProto.device_count를 사용하는 방법

 tf.compat.v1.ConfigProto의 device_count를 지정하여 제한하는 것도 가능하다. 그러나 이 방법에서는 Tensorflow에 의한 GPU 초기화를 행하는데 100M정도의 GPU 메모리가 사용된다. 이 내용에 대해 알기 쉽도록 메모리 확보가 어떻게 되는지도 살펴보자.

# test_gpu_device_count_0.py에 기재된 내용

import tensorflow as tf
config = tf.compat.v1.ConfigProto(
    device_count={"GPU":0}, # GPU수 번호를 0으로
    log_device_placement=True
)

sess = tf.compat.v1.Session(config=config)

# GPU를 사용하도록
with tf.device("/gpu:0"):
    x = tf.constant(0)

sess.run(x)
$ python test_gpu_device_count_0.py
...
I tensorflow/core/common_runtime/gpu/gpu_device.cc:982] 3:   N N Y Y
I tensorflow/core/common_runtime/gpu/gpu_device.cc:1041] Creating TensorFlow device (/gpu:0) -> (device: 0, name: GeForce GTX TITAN X, pci bus id: 0000:02:00.0)
I tensorflow/core/common_runtime/gpu/gpu_device.cc:1041] Creating TensorFlow device (/gpu:1) -> (device: 1, name: GeForce GTX TITAN X, pci bus id: 0000:03:00.0)
I tensorflow/core/common_runtime/gpu/gpu_device.cc:1041] Creating TensorFlow device (/gpu:2) -> (device: 2, name: GeForce GTX TITAN X, pci bus id: 0000:83:00.0)
I tensorflow/core/common_runtime/gpu/gpu_device.cc:1041] Creating TensorFlow device (/gpu:3) -> (device: 3, name: GeForce GTX TITAN X, pci bus id: 0000:84:00.0)
Device mapping: no known devices.
I tensorflow/core/common_runtime/direct_session.cc:252] Device mapping:
Traceback (most recent call last):
...
InvalidArgumentError (see above for traceback): Cannot assign a device to node 'Const': Could not satisfy explicit device specification '/device:GPU:0' because no devices matching that specification are registered in this process; available devices: /job:localhost/replica:0/task:0/cpu:0
     [[Node: Const = Const[dtype=DT_INT32, value=Tensor<type: int32 shape: [] values: 0>, _device="/device:GPU:0"]()]]

 

+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID  Type  Process name                               Usage      |
|=============================================================================|
|    0     15335    C   python                                         106MiB |
|    1     15335    C   python                                         106MiB |
|    2     15335    C   python                                         106MiB |
|    3     15335    C   python                                         106MiB |
+-----------------------------------------------------------------------------+

 Tensorflow는 GPU 4대를 인식하여 초기화하고 있지만, GPU:0은 사용할 수 없다는 메시지를 출력했다. 추가로 allow_soft_placement=True로 지정한 경우

I tensorflow/core/common_runtime/gpu/gpu_device.cc:1041] Creating TensorFlow device (/gpu:0) -> (device: 0, name: GeForce GTX TITAN X, pci bus id: 0000:02:00.0)
I tensorflow/core/common_runtime/gpu/gpu_device.cc:1041] Creating TensorFlow device (/gpu:1) -> (device: 1, name: GeForce GTX TITAN X, pci bus id: 0000:03:00.0)
I tensorflow/core/common_runtime/gpu/gpu_device.cc:1041] Creating TensorFlow device (/gpu:2) -> (device: 2, name: GeForce GTX TITAN X, pci bus id: 0000:83:00.0)
I tensorflow/core/common_runtime/gpu/gpu_device.cc:1041] Creating TensorFlow device (/gpu:3) -> (device: 3, name: GeForce GTX TITAN X, pci bus id: 0000:84:00.0)
Device mapping: no known devices.
I tensorflow/core/common_runtime/direct_session.cc:252] Device mapping:

Const: /job:localhost/replica:0/task:0/cpu:0
I tensorflow/core/common_runtime/simple_placer.cc:819] Const: /job:localhost/replica:0/task:0/cpu:0

 CPU상에 메모리를 확보했다.

test_gpu_device_count_0.py에서 다음과 같이 GPU 1번째로 지정하도록 device_count={"GPU":1} 으로 수정해서 재 실행하면 다음과 같이 제대로 GPU가 확보되어 있음을 알 수 있다.

$ test_gpu_device_count_1.py
I tensorflow/core/common_runtime/gpu/gpu_device.cc:1041] Creating TensorFlow device (/gpu:0) -> (device: 0, name: GeForce GTX TITAN X, pci bus id: 0000:02:00.0)
I tensorflow/core/common_runtime/gpu/gpu_device.cc:1041] Creating TensorFlow device (/gpu:1) -> (device: 1, name: GeForce GTX TITAN X, pci bus id: 0000:03:00.0)
I tensorflow/core/common_runtime/gpu/gpu_device.cc:1041] Creating TensorFlow device (/gpu:2) -> (device: 2, name: GeForce GTX TITAN X, pci bus id: 0000:83:00.0)
I tensorflow/core/common_runtime/gpu/gpu_device.cc:1041] Creating TensorFlow device (/gpu:3) -> (device: 3, name: GeForce GTX TITAN X, pci bus id: 0000:84:00.0)
Device mapping:
/job:localhost/replica:0/task:0/gpu:0 -> device: 0, name: GeForce GTX TITAN X, pci bus id: 0000:02:00.0
I tensorflow/core/common_runtime/direct_session.cc:252] Device mapping:
/job:localhost/replica:0/task:0/gpu:0 -> device: 0, name: GeForce GTX TITAN X, pci bus id: 0000:02:00.0

Const: /job:localhost/replica:0/task:0/gpu:0
I tensorflow/core/common_runtime/simple_placer.cc:819] Const: /job:localhost/replica:0/task:0/gpu:0

 

 

 

메모리 제한하기


메모리의 최대치를 제한하기

 이것은  tf.compat.v1.ConfigProto.gpu_options.per_process_gpu_memory_fraction를 설정하여 변경할 수 있다.

config = tf.compat.v1.ConfigProto(
    gpu_options=tf.compat.v1.GPUOptions(
        per_process_gpu_memory_fraction=0.5 #최대치의 50%까지
    )
)
sess = sess = tf.compat.v1.Session(config=config)

 

맨처음에는 메모리를 확보하지 않고 필요에 따라 메모리 확보하게 하기

이것은 tf.compat.v1.ConfigProto.gpu_options.allow_growth쪽을 설정하면 된다.

config = tf.compat.v1.ConfigProto(
    gpu_options=tf.compat.v1.GPUOptions(
        allow_growth=True # True->필요에 따라 확보, False->전부 확보
    )
)
sess = sess = tf.compat.v1.Session(config=config)

참고자료

https://qiita.com/kikusumk3/items/907565559739376076b9

728x90