TensorFlowを安価でなるべく速く実行するにはどのような環境がよいのかを自分なりに検討してみました.
測定方法
以下のスクリプトを実行して,速度を比較します.環境変数CUDA_VISIBLE_DEVICES
でGPUの利用するかを指定します.環境変数TF_ENABLE_ONEDNN_OPTS
でoneDNNを使用するかを指定します.
requirements.txt
numpy==1.22.4 tensorflow==2.9.1 protobuf==3.19.4
mnist.py
keras.datasets.mnist
を使用した簡単な機械学習のスクリプトです.
import os os.environ["CUDA_VISIBLE_DEVICES"] = "-1" os.environ["TF_ENABLE_ONEDNN_OPTS"] = "1" import numpy as np from tensorflow import keras, config from tensorflow.keras import layers gpus = config.list_physical_devices(device_type = 'GPU') if len(gpus)>0: print(f">> GPU detected. {gpus[0].name}") config.experimental.set_memory_growth(gpus[0], True) # https://keras.io/examples/vision/mnist_convnet/ # Model / data parameters num_classes = 10 input_shape = (28, 28, 1) # the data, split between train and test sets (x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data() # Scale images to the [0, 1] range x_train = x_train.astype("float32") / 255 x_test = x_test.astype("float32") / 255 # Make sure images have shape (28, 28, 1) x_train = np.expand_dims(x_train, -1) x_test = np.expand_dims(x_test, -1) print("x_train shape:", x_train.shape) print(x_train.shape[0], "train samples") print(x_test.shape[0], "test samples") # convert class vectors to binary class matrices y_train = keras.utils.to_categorical(y_train, num_classes) y_test = keras.utils.to_categorical(y_test, num_classes) model = keras.Sequential( [ keras.Input(shape=input_shape), layers.Conv2D(32, kernel_size=(3, 3), activation="relu"), layers.MaxPooling2D(pool_size=(2, 2)), layers.Conv2D(64, kernel_size=(3, 3), activation="relu"), layers.MaxPooling2D(pool_size=(2, 2)), layers.Flatten(), layers.Dropout(0.5), layers.Dense(num_classes, activation="softmax"), ] ) model.summary() batch_size = 1024 epochs = 4 model.compile(loss="categorical_crossentropy", optimizer="adam", metrics=["accuracy"]) model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs, validation_split=0.1) score = model.evaluate(x_test, y_test, verbose=0) print("Test loss:", score[0]) print("Test accuracy:", score[1])
実行結果
所有しているパソコンや,Google Colabを使用して測定しました.
CPU Xeon E5-2673 v4, oneDNN ON (Colab)
lscpu
コマンドで,CPU family: 6, Model: 79, Model name: Intel(R) Xeon(R) CPU @ 2.20GHzと表示されました.1コア2スレッド, 2.2GHzの割当です.
Epoch 1/4 53/53 [==============================] - 38s 712ms/step - loss: 1.0875 - accuracy: 0.6790 - val_loss: 0.2413 - val_accuracy: 0.9358 Epoch 2/4 53/53 [==============================] - 39s 732ms/step - loss: 0.2834 - accuracy: 0.9144 - val_loss: 0.1363 - val_accuracy: 0.9630 Epoch 3/4 53/53 [==============================] - 38s 714ms/step - loss: 0.1865 - accuracy: 0.9437 - val_loss: 0.1003 - val_accuracy: 0.9730 Epoch 4/4 53/53 [==============================] - 37s 702ms/step - loss: 0.1479 - accuracy: 0.9554 - val_loss: 0.0834 - val_accuracy: 0.9775 Test loss: 0.08833741396665573 Test accuracy: 0.9740999937057495
遅いです.
CPU i5-12400, oneDNN ON
CPU i5-12400は,6コア12スレッド,周波数は2.50 GHzです.
Epoch 1/4 53/53 [==============================] - 5s 88ms/step - loss: 1.1321 - accuracy: 0.6795 - val_loss: 0.2417 - val_accuracy: 0.9370 Epoch 2/4 53/53 [==============================] - 5s 89ms/step - loss: 0.2765 - accuracy: 0.9158 - val_loss: 0.1314 - val_accuracy: 0.9645 Epoch 3/4 53/53 [==============================] - 5s 86ms/step - loss: 0.1785 - accuracy: 0.9461 - val_loss: 0.0968 - val_accuracy: 0.9752 Epoch 4/4 53/53 [==============================] - 5s 86ms/step - loss: 0.1406 - accuracy: 0.9575 - val_loss: 0.0807 - val_accuracy: 0.9785 Test loss: 0.08474256843328476 Test accuracy: 0.9753999710083008
コア数が6倍になり,ターボブーストしているため,8.3倍高速になりました.
CPU i5-12400, oneDNN OFF
Epoch 1/4 53/53 [==============================] - 7s 127ms/step - loss: 1.1301 - accuracy: 0.6792 - val_loss: 0.2377 - val_accuracy: 0.9377 Epoch 2/4 53/53 [==============================] - 7s 123ms/step - loss: 0.2693 - accuracy: 0.9194 - val_loss: 0.1267 - val_accuracy: 0.9682 Epoch 3/4 53/53 [==============================] - 7s 123ms/step - loss: 0.1752 - accuracy: 0.9478 - val_loss: 0.0956 - val_accuracy: 0.9740 Epoch 4/4 53/53 [==============================] - 7s 123ms/step - loss: 0.1390 - accuracy: 0.9583 - val_loss: 0.0787 - val_accuracy: 0.9788 Test loss: 0.08312420547008514 Test accuracy: 0.9757000207901001
CPUを使用するならば,oneDNNにより1.4倍ほど高速になりました.
GPU GT1030
GeForce GT 1030のCUDAコアは384個で,周波数は1.4GHzです*1.
Epoch 1/4 53/53 [==============================] - 6s 82ms/step - loss: 1.1407 - accuracy: 0.6659 - val_loss: 0.2556 - val_accuracy: 0.9283 Epoch 2/4 53/53 [==============================] - 4s 71ms/step - loss: 0.2913 - accuracy: 0.9130 - val_loss: 0.1345 - val_accuracy: 0.9645 Epoch 3/4 53/53 [==============================] - 4s 71ms/step - loss: 0.1850 - accuracy: 0.9448 - val_loss: 0.0993 - val_accuracy: 0.9745 Epoch 4/4 53/53 [==============================] - 4s 71ms/step - loss: 0.1468 - accuracy: 0.9561 - val_loss: 0.0825 - val_accuracy: 0.9775 Test loss: 0.0853961631655693 Test accuracy: 0.974399983882904
nvidia-smi
コマンドでGPU使用率は97%,メモリ使用量は1Gbyteでした.
i5-12400の2.5GHz * 6 core = 15, GT 1030の 1.4GHz * 384 core = 537.6 を比較すると36倍高速になりそうな気がしますが,CPUのほうが1クロックでたくさんの処理ができるので,結局はCPUと同じぐらいの速度になるようです.GPUならばとりあえず高速だというイメージだったので,CPUがいい勝負をしているのは意外でした.
GPU Tesla T4 (Colab)
Tesla T4 のCUDAコアは2560個です*2.
Epoch 1/4 53/53 [==============================] - 13s 29ms/step - loss: 1.1104 - accuracy: 0.6804 - val_loss: 0.2412 - val_accuracy: 0.9353 Epoch 2/4 53/53 [==============================] - 1s 20ms/step - loss: 0.2780 - accuracy: 0.9169 - val_loss: 0.1299 - val_accuracy: 0.9667 Epoch 3/4 53/53 [==============================] - 1s 21ms/step - loss: 0.1759 - accuracy: 0.9483 - val_loss: 0.0967 - val_accuracy: 0.9767 Epoch 4/4 53/53 [==============================] - 1s 20ms/step - loss: 0.1415 - accuracy: 0.9579 - val_loss: 0.0813 - val_accuracy: 0.9780 Test loss: 0.08577422052621841 Test accuracy: 0.9743000268936157
nvidia-smi
コマンドでGPU使用率は76%でした.
CUDAコアが6.6倍になると,3.55倍高速になりました.GPU使用率が下がっているので,GPUの能力を十分に使用できていない可能性があります.
考察
最新のCPUならば,oneDNNを有効にするだけで高速になります.i5-12400は3万円,GT1030は1万円ぐらいで購入でき,同じような速度でした.Tesla T4と同じCUDAコアの数を搭載したRTX 3050は5万円ぐらいで購入できます.
しかし,GPUにはデメリットが少なくとも3個あります.まず,ドライバーのインストールなど環境を整えるのが面倒です.次に,GPUで高速に実行できるようにソフトウェアをある程度調整しなければならないことです.最後に,メモリーを自由に増設できないことです.
mnistでもGPUメモリーを1Gbyteほど使用するので,複雑なモデルの機械学習を実行するならば,GPUメモリーが不足する可能性があります.GPUメモリーへの転送はとても時間がかかる処理なので,GPUメモリーが不足するとせっかくのGPUのパワーを活かせないのです.GeForce最強GPUであるRTX 3090 でもGPUメモリーは24Gbyteです.Tesla A100ならば80GBのGPUメモリーを扱えます. CPUならば安価でよりたくさんのメモリを扱えます.i5-12400ならば最大で128 GBです.
ひとまずCPUで実行してみて,とても時間がかかるならば,必要なスペック(特にCUDAコア数とGPUメモリー)のGPUをクラウドで借りるのが現実的な気がしました.