※ 일본의 한 블로그 글의 번역한 포스트입니다. 오역 및 직역, 의역이 있을 수 있으며 틀린 내용은 지적해주시면 감사하겠습니다.
개요
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)
참고자료
'IT > AI\ML' 카테고리의 다른 글
labelme 사용법 (0) | 2022.09.06 |
---|---|
[python/Tensorflow2.X] "ValueError: tf.function-decorated function tried to create variables on non-first call" 에러 해결하기 (0) | 2022.08.16 |
Annotation과 Annotation의 툴 비교 (0) | 2022.05.13 |
머신러닝 구현 속도를 올려주는 VSCode 설정 (0) | 2022.04.14 |
[python] AI엔지니어가 주의해야할 python 코드 작성 포인트 (0) | 2022.04.13 |