본문 바로가기

프로그램 개발

딥러닝에서 CPU와 GPU 성능 비교; 2. CNN (Conv2D) 모델 학습 측정

딥러닝에서 CPU와 GPU 성능 비교

1. DNN (Dense) 모델 학습 측정

2. CNN (Conv2d) 모델 학습 측정

 

3. CIFA-100 + CNN 모델에서 CPU와 GPU학습 비교

이번에는 CIFA-100을 CNN으로 분류하는 모델을 간단하게 만들어서 학습하면서 CPU와 GPU의 학습 속도를 비교해 보기로 했다. 아래와 같이 Conv2D와 Pooling을 겹쳐서 쌓아 특성값을 추출하고 Dense로 분류하는 간단한 모델이다. 그래도 50 Epoch정도의 학습으로도 82% 정도의 정확도를 가질 수 있다. 물론 Conv2D와 Polling을 한 번 더 반복하면 90%의 정확도까지 올릴 수 있지만 속도 비교의 목적으로는 이 정도 모델로도 충분히 비교를 할 수 있을 것이라 생각된다.

 

이 모델은 975,692 파라미터를 학습해야 하는 모델이고, 특성을 뽑아낼 Conv2d층과 분류에 사용하는 Dense층으로 분리하고 상위 특성값만을 뽑아내는 pooling 층과 분류 학습 성능을 높이기 위해 Dropout층을 추가한 간단하고 전형적인 이미지 인식 CNN모델이다.

 

파이썬 코드는 아래와 같다. CPU학습 속도가 느리기 때문에 Epoch는 20으로 설정하고 모델을 학습하고 성능을 비교했다.

 

import os
os.environ["KERAS_BACKEND"] = "torch"

from keras import datasets, Input, models, layers
from keras.utils import to_categorical

(x_train, y_train), (x_test, y_test) = datasets.cifar100.load_data()

x_train, x_test = x_train / 255.0, x_test / 255.0
y_train, y_test = to_categorical(y_train, 100), to_categorical(y_test, 100)

model = models.Sequential(
    [
        Input(shape=(32, 32, 3)),
        layers.Conv2D(128, kernel_size=(7, 7), activation="relu", kernel_initializer="he_normal"),
        layers.MaxPooling2D(pool_size=(2, 2)),
        layers.Conv2D(256, kernel_size=(3, 3), activation="relu", kernel_initializer="he_normal"),
        layers.Conv2D(256, kernel_size=(3, 3), activation="relu", kernel_initializer="he_normal"),
        layers.GlobalAveragePooling2D(),
        layers.Flatten(),
        layers.Dense(200, activation="relu", kernel_initializer="he_normal"),
        layers.Dropout(0.5),
        layers.Dense(100, activation="softmax"),
    ]
)

model.compile(optimizer="adam",
            loss='categorical_crossentropy',
            metrics=['accuracy'])
            
%%timeit -n1 -r1
history = model.fit(x_train, y_train, epochs = 20, validation_split=0.15)

a. GPU로 모델을 학습한 결과

각 Epoch는 21초 내외가 걸렸고 전체 7분 35초가 소요되었는데, 20 Epoch에서 100 Epoch에 걸쳐 학습한 Dense모델보다 성능이 뛰어나 50% 정도의 정확도를 보였다.

 

Epoch 1/20
1329/1329 ━━━━━━━━━━━━━━━━━━━━ 21s 15ms/step - accuracy: 0.0381 - loss: 4.3761 - val_accuracy: 0.1193 - val_loss: 3.7578
Epoch 2/20
1329/1329 ━━━━━━━━━━━━━━━━━━━━ 20s 15ms/step - accuracy: 0.1148 - loss: 3.7498 - val_accuracy: 0.1745 - val_loss: 3.4458

...

Epoch 19/20
1329/1329 ━━━━━━━━━━━━━━━━━━━━ 22s 17ms/step - accuracy: 0.4981 - loss: 1.8006 - val_accuracy: 0.4328 - val_loss: 2.2090
Epoch 20/20
1329/1329 ━━━━━━━━━━━━━━━━━━━━ 22s 17ms/step - accuracy: 0.5048 - loss: 1.7399 - val_accuracy: 0.4087 - val_loss: 2.3686
7min 35s ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)

 

50 Epoch를 학습했을 때 82% 정도의 정확도를 보여줬다. Conv2D층을 추가하고 Epoch 수를 늘리면 90% 정도의 정확도를 나타내는 적을 확인한 적이 있다.

 

...

Epoch 49/50
1329/1329 ━━━━━━━━━━━━━━━━━━━━ 24s 18ms/step - accuracy: 0.8220 - loss: 0.5471 - val_accuracy: 0.4176 - val_loss: 3.4655
Epoch 50/50
1329/1329 ━━━━━━━━━━━━━━━━━━━━ 24s 18ms/step - accuracy: 0.8169 - loss: 0.5465 - val_accuracy: 0.4153 - val_loss: 3.6471
20min 40s ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)

b. CPU로 모델을 학습한 결과

같은 모델을 CPU로 학습했을 때 2시가 가까운 시간이 소요되었다. 많은 행렬을 병렬로 계산하기에는 CPU의 속도로는 core 수를 따라가지 못하는 것을 확인했다.

 

Epoch 1/20
1329/1329 ━━━━━━━━━━━━━━━━━━━━ 288s 216ms/step - accuracy: 0.0348 - loss: 4.3997 - val_accuracy: 0.1028 - val_loss: 3.8212
Epoch 2/20
1329/1329 ━━━━━━━━━━━━━━━━━━━━ 292s 220ms/step - accuracy: 0.1122 - loss: 3.7529 - val_accuracy: 0.1792 - val_loss: 3.4207

...

Epoch 19/20
1329/1329 ━━━━━━━━━━━━━━━━━━━━ 345s 259ms/step - accuracy: 0.4722 - loss: 1.9025 - val_accuracy: 0.4180 - val_loss: 2.2609
Epoch 20/20
1329/1329 ━━━━━━━━━━━━━━━━━━━━ 360s 271ms/step - accuracy: 0.4834 - loss: 1.8493 - val_accuracy: 0.4184 - val_loss: 2.2923
1h 54min 22s ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)

 

결과적으로 DNN 모델을 학습할 때보다 CNN 모델을 학습할 때 GPU를 사용하면 확실히 빠르다는 것을 확인했다.

4. GPU를 사용하지 못하게 하는 방법 (GPU disable)

딥러닝 프로젝트를 시작하면, 흔히 받는 질문이나 의아해하는 것 중 하나가, CPU가 더 빠른 경우도 있다는 것이다. 흔히 딥러닝 프로젝트는 GPU로 해야 한다고 알고 있지만, Dense만 쌓아도 되는 예측 모델이나, 인자가 복잡하지 않은 RNN, LSTM, GRU로 만드는 시계열 모델을 학습시키는 경우라면 일반 CPU가 더 빠를 수 있기 때문에 GPU를 끄는 방법도 알아두면 좋을 것 같다. 일반적으로 CPU를 강제로 사용하게 하는 방법은 인터넷에 많이 나와 있는 것처럼

 

  • CUDA를 사용하는 프레임워크를 import 하기 전에 환경변수를 통해 설정하거나
os.environ["CUDA_VISIBLE_DEVICES"] = ""

 

  • 프레임워크에서 인식할 수 없게 함수를 override 하거나
torch.cuda.is_available = lambda: False

 

  • 함수를 호출할 때 직접 device를 지정하는 방법 (model의 layer별로도 지정가능)
device = torch.device("cpu")
torch.randn(4, 5).to(device)

 

등이 있는데, 이번 테스트에서는 전체를 CPU로 전환해야 하기 때문에 간단히 is_available함수를 override했다.

 

python - Disable PyTorch GPU Usage - machine learning - deep learning

 

python-code.dev