背景
自宅サーバとしてPowerEdge R720を購入しカスタマイズしました。
- CPU: 16コア32スレッド(8コア16スレッド2.60 GHz×2)
- MEM: 256GiB (DDR3L、16GiB×16)
- SSD: 256GiB (SATA3、256GiB×1、RAID0)
このスペックを活かして何かするには機械学習かk8sだろうということで、まずは機械学習に挑戦してみます。
機械学習といえばGPUも欲しくなりますが、PowerEdge R720で使えるのはNVIDIA Tesla Kシリーズが限界で、GPU本体のほか1100Wの電源や取り付け器具など追加出費が必要です。
また機器自体が古く最新のライブラリの機能が動かない可能性もあります。まずはCPUのみでどれだけ頑張れるか実際にやってみます。
環境構築
今回はJupyterでTensorFlowが実行できる環境を目指します。自宅のNW環境は、マンション備え付けの回線(無線LAN、有線LANポート1)という環境なので工夫しながらやります。
OSインストール
OSはAlmaLinux9.2のminimalを使用します。イメージファイルをダウンロードでは、回線が詰まっていると時間がかかります。日本のミラーサイトを色々試したところ、Nishi Network からのダウンロードがとても速くて助かりました。聞き覚えのない組織名だったので調べてみると個人運用でした。とてもありがたいです。
iDRACから仮想ディスクをマッピングしてサーバを起動しOSインストールを行いました。最初起動に失敗しましたがBISOメニューからUEFIを有効にすると起動できるようになりました。
インターネットへの接続
サーバには無線LANアダプタがないので、ノートPC(Windows10)経由でインターネットに接続させます。
DHCPを使うと毎回IPアドレスを調べないといけなくて不便なので静的に設定しておきます。
L2SWもなくLANケーブルも1本しかないのでやりくりします。
- iDRACはサーバのフロントパネルからIPを192.168.137.254に設定
- ノートPCとiDRACのポートを接続
- 仮想コンソールからサーバにログイン
- nmcliを使ってポートを設定
nmcli con eno1 edit
set ipv4.addresses 192.168.137.254/24
set ipv4.gateway 192.168.137.1
set ipv4.dns 8.8.8.8
set ipv4.method manual
save
activate
- SSHでrootにパスワードログイン設定
vim /etc/ssh/sshd_config
PermitRootLogin yes
PasswordAuthentication yes
systemctl restart sshd
- nmcliを使ってポートを設定
- ノートPCとサーバのポートを接続
- TeraTermを使ってID/PASSでSSH接続
Jupyter環境の構築
今回はDockerを使ってJupyter環境を立ち上げます。
Dockerインストール
dnf config-manager --add-repo=https://download.docker.com/linux/centos/docker-ce.repo
dnf install docker-ce docker-ce-cli containerd.io
systemctl start docker
systemctl enable docker
Jupyterイメージの起動
docker pull jupyter/base-notebook
docker run -p 8888:8888 -v /path/to/your/notebooks:/home/jovyan/work jupyter/base-notebook
コンテナ起動時に表示されるTokenを使ってブラウザからアクセスするとJupyterが使えます。
ベンチマーク
機械学習を試す前に、参考情報としてサーバのベンチマークを試します。
sysbenchのインストール
dnf install epel-release
dnf update
dnf install sysbench
CPU
passmarkでCPUのスコアを調べると9942(Single Thread Rating: 1687)でした。物理CPUを2個並べてますので、単純計算すると2万弱になります。
クロック数が高くないのでシングルスレッドの性能は劣りますが、全体の性能としてはAMD Ryzen 5 5500やIntel Core i5-12400が目安になりそうです。
sysbenchを使って実際に試してみます。比較用に--cpu-max-prime=9999
で試します
threads=1
sysbench cpu --cpu-max-prime=9999 run
CPU speed:
events per second: 1020.73
General statistics:
total time: 10.0003s
total number of events: 10212
threads=2
sysbench cpu --cpu-max-prime=9999 --threads=2 run
CPU speed:
events per second: 2022.73
General statistics:
total time: 10.0011s
total number of events: 20233
threads=4
sysbench cpu --cpu-max-prime=9999 --threads=4 run
CPU speed:
events per second: 3949.42
General statistics:
total time: 10.0011s
total number of events: 39505
threads=8
sysbench cpu --cpu-max-prime=9999 --threads=8 run
CPU speed:
events per second: 7395.63
General statistics:
total time: 10.0010s
total number of events: 73977
threads=16
sysbench cpu --cpu-max-prime=9999 --threads=16 run
CPU speed:
events per second: 14556.50
General statistics:
total time: 10.0011s
total number of events: 145606
threads=32
sysbench cpu --cpu-max-prime=9999 --threads=32 run
CPU speed:
events per second: 20776.00
General statistics:
total time: 10.0017s
total number of events: 207829
評価
threads | CPU speed | threads=1の単純倍との差分[%] |
---|---|---|
1 | 1020.73 | 100 |
2 | 2022.73 | 99.1 |
4 | 3949.42 | 96.7 |
8 | 7395.63 | 90.1 |
16 | 14556.50 | 89.1 |
32 | 20776.00 | 63.6 |
2から4、4から8、16から32でそれぞれパフォーマンスが落ちています。
2から4では、ある程度線形に1%弱落ちています。
4から8では、ある程度線形ですが、落ち幅が大きくなり1%強落ちています。
8から16では、ほぼ差がありませんでした。
16から32では、26%も落ちています。
4コア程度まではターボブーストで特定コアのクロック数が高い状態となり、8コア以上はターボブーストがない状態なのでパフォーマンスの差が無くなったかと考えます。
物理コアを上回りハイパースレッドなどを使う場合、3割減のパフォーマンスになると思ってよさそうです。全体のスコアは上がっているので、同時に多数の処理を行う場合にはとても有効そうです。
以下のサイトの結果と比較すると「Ryzen 7 PRO 4750GE (3.1GHz)」と「Ryzen 7 5800HS」の間になります。
Passmarkでは以下の通りなので、おおむね評価通りかと思います。
- Ryzen 7 PRO 4750GEのは18432(Single Thread Rating: 2688)
- Ryzen 7 5800HSは21166(Single Thread Rating: 3100)
メモリ
比較対象の情報があまりないので結果を張るだけにとどめておきます。DDR3L-1333なので、速くはないはずです。
sysbench memory run
Total operations: 53872491 (5384814.25 per second)
52609.85 MiB transferred (5258.61 MiB/sec)
General statistics:
total time: 10.0002s
total number of events: 53872491
MNIST
MNISTをやってみます。最初に!pip install tensorflow
でTensorFlowをインストールしておきます。
比較用にGoogle Colaboratoryでも同様のプログラムを実行しました。GPUモデルはT4です。
共通のコード
import tensorflow as tf
mnist = tf.keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0
model = tf.keras.models.Sequential([
tf.keras.layers.Flatten(input_shape=(28, 28)),
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.Dense(10, activation='softmax')
])
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
batch_size=32
model.fit(x_train, y_train, epochs=5)
Epoch 1/5
1875/1875 [==============================] - 10s 5ms/step - loss: 0.2986 - accuracy: 0.9134
Epoch 2/5
1875/1875 [==============================] - 9s 5ms/step - loss: 0.1456 - accuracy: 0.9563
Epoch 3/5
1875/1875 [==============================] - 9s 5ms/step - loss: 0.1094 - accuracy: 0.9671
Epoch 4/5
1875/1875 [==============================] - 9s 5ms/step - loss: 0.0898 - accuracy: 0.9727
Epoch 5/5
1875/1875 [==============================] - 9s 5ms/step - loss: 0.0768 - accuracy: 0.9761
batch_size=32 GPU
Epoch 1/5
1875/1875 [==============================] - 11s 3ms/step - loss: 0.2925 - accuracy: 0.9138
Epoch 2/5
1875/1875 [==============================] - 6s 3ms/step - loss: 0.1426 - accuracy: 0.9574
Epoch 3/5
1875/1875 [==============================] - 5s 3ms/step - loss: 0.1075 - accuracy: 0.9674
Epoch 4/5
1875/1875 [==============================] - 5s 3ms/step - loss: 0.0881 - accuracy: 0.9725
Epoch 5/5
1875/1875 [==============================] - 6s 3ms/step - loss: 0.0739 - accuracy: 0.9764
batch_size=1024
model.fit(x_train, y_train, epochs=5, batch_size=1024)
Epoch 1/5
59/59 [==============================] - 1s 7ms/step - loss: 0.0511 - accuracy: 0.9841
Epoch 2/5
59/59 [==============================] - 1s 9ms/step - loss: 0.0454 - accuracy: 0.9863
Epoch 3/5
59/59 [==============================] - 1s 10ms/step - loss: 0.0431 - accuracy: 0.9866
Epoch 4/5
59/59 [==============================] - 1s 10ms/step - loss: 0.0422 - accuracy: 0.9872
Epoch 5/5
59/59 [==============================] - 1s 10ms/step - loss: 0.0400 - accuracy: 0.9876
batch_size=1024 GPU
Epoch 1/5
59/59 [==============================] - 1s 7ms/step - loss: 0.0547 - accuracy: 0.9828
Epoch 2/5
59/59 [==============================] - 0s 6ms/step - loss: 0.0497 - accuracy: 0.9849
Epoch 3/5
59/59 [==============================] - 0s 4ms/step - loss: 0.0472 - accuracy: 0.9857
Epoch 4/5
59/59 [==============================] - 0s 4ms/step - loss: 0.0462 - accuracy: 0.9858
Epoch 5/5
59/59 [==============================] - 0s 4ms/step - loss: 0.0443 - accuracy: 0.9861
評価
Google Colaboratoryの方がbatch_size=32で1.5倍ほど速いです。
batch_size=1024でも5倍ほど速いですが。
ただし元々の学習時間が短いこともあり、15秒未満の違いに留まりました。
batch_size | CPU[s] | GPU[s] | CPU/GPU |
---|---|---|---|
32 | 46 | 33 | 1.4 |
1024 | 5 | 1 | 5.0 |
CIFAR-10
より学習データの入力量が大きな場合を試してみます。
比較用にGoogle Colaboratoryでも同様のプログラムを実行しました。GPUモデルはT4です。
共通のコード
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout
cifar10 = tf.keras.datasets.cifar10
(x_train, y_train), (x_test, y_test) = cifar10.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0
model = Sequential([
Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3)),
MaxPooling2D((2, 2)),
Conv2D(64, (3, 3), activation='relu'),
MaxPooling2D((2, 2)),
Conv2D(64, (3, 3), activation='relu'),
Flatten(),
Dense(64, activation='relu'),
Dense(10, activation='softmax')
])
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
batch_size=32
model.fit(x_train, y_train, epochs=10, validation_data=(x_test, y_test))
Epoch 1/10
1563/1563 [==============================] - 29s 18ms/step - loss: 1.5656 - accuracy: 0.4290 - val_loss: 1.2707 - val_accuracy: 0.5429
Epoch 2/10
1563/1563 [==============================] - 27s 17ms/step - loss: 1.1862 - accuracy: 0.5786 - val_loss: 1.1050 - val_accuracy: 0.6101
Epoch 3/10
1563/1563 [==============================] - 27s 17ms/step - loss: 1.0397 - accuracy: 0.6337 - val_loss: 1.0132 - val_accuracy: 0.6454
Epoch 4/10
1563/1563 [==============================] - 27s 17ms/step - loss: 0.9467 - accuracy: 0.6665 - val_loss: 0.9479 - val_accuracy: 0.6712
Epoch 5/10
1563/1563 [==============================] - 27s 17ms/step - loss: 0.8724 - accuracy: 0.6943 - val_loss: 0.9690 - val_accuracy: 0.6690
Epoch 6/10
1563/1563 [==============================] - 27s 17ms/step - loss: 0.8178 - accuracy: 0.7137 - val_loss: 0.9132 - val_accuracy: 0.6847
Epoch 7/10
1563/1563 [==============================] - 27s 17ms/step - loss: 0.7615 - accuracy: 0.7334 - val_loss: 0.9359 - val_accuracy: 0.6845
Epoch 8/10
1563/1563 [==============================] - 27s 17ms/step - loss: 0.7242 - accuracy: 0.7450 - val_loss: 0.8493 - val_accuracy: 0.7121
Epoch 9/10
1563/1563 [==============================] - 27s 17ms/step - loss: 0.6886 - accuracy: 0.7600 - val_loss: 0.9016 - val_accuracy: 0.6951
Epoch 10/10
1563/1563 [==============================] - 27s 17ms/step - loss: 0.6524 - accuracy: 0.7724 - val_loss: 0.9093 - val_accuracy: 0.6949
batch_size=32 GPU
Epoch 1/10
1563/1563 [==============================] - 18s 5ms/step - loss: 1.5053 - accuracy: 0.4541 - val_loss: 1.3427 - val_accuracy: 0.5255
Epoch 2/10
1563/1563 [==============================] - 9s 6ms/step - loss: 1.1350 - accuracy: 0.5994 - val_loss: 1.0751 - val_accuracy: 0.6107
Epoch 3/10
1563/1563 [==============================] - 9s 6ms/step - loss: 0.9933 - accuracy: 0.6502 - val_loss: 0.9809 - val_accuracy: 0.6568
Epoch 4/10
1563/1563 [==============================] - 8s 5ms/step - loss: 0.8965 - accuracy: 0.6853 - val_loss: 0.9127 - val_accuracy: 0.6857
Epoch 5/10
1563/1563 [==============================] - 9s 6ms/step - loss: 0.8229 - accuracy: 0.7119 - val_loss: 0.8965 - val_accuracy: 0.6845
Epoch 6/10
1563/1563 [==============================] - 8s 5ms/step - loss: 0.7612 - accuracy: 0.7328 - val_loss: 0.8555 - val_accuracy: 0.7043
Epoch 7/10
1563/1563 [==============================] - 8s 5ms/step - loss: 0.7062 - accuracy: 0.7522 - val_loss: 0.8778 - val_accuracy: 0.7011
Epoch 8/10
1563/1563 [==============================] - 8s 5ms/step - loss: 0.6569 - accuracy: 0.7684 - val_loss: 0.9124 - val_accuracy: 0.6982
Epoch 9/10
1563/1563 [==============================] - 8s 5ms/step - loss: 0.6137 - accuracy: 0.7833 - val_loss: 0.8634 - val_accuracy: 0.7139
Epoch 10/10
1563/1563 [==============================] - 8s 5ms/step - loss: 0.5740 - accuracy: 0.7981 - val_loss: 0.9002 - val_accuracy: 0.7071
batch_size=1024
model.fit(x_train, y_train, epochs=10, batch_size=1024, validation_data=(x_test, y_test))
Epoch 1/10
13/13 [==============================] - 9s 678ms/step - loss: 0.4405 - accuracy: 0.8484 - val_loss: 0.8206 - val_accuracy: 0.7357
Epoch 2/10
13/13 [==============================] - 8s 621ms/step - loss: 0.4373 - accuracy: 0.8499 - val_loss: 0.8209 - val_accuracy: 0.7349
Epoch 3/10
13/13 [==============================] - 8s 615ms/step - loss: 0.4355 - accuracy: 0.8506 - val_loss: 0.8206 - val_accuracy: 0.7347
Epoch 4/10
13/13 [==============================] - 8s 612ms/step - loss: 0.4336 - accuracy: 0.8509 - val_loss: 0.8221 - val_accuracy: 0.7351
Epoch 5/10
13/13 [==============================] - 8s 612ms/step - loss: 0.4323 - accuracy: 0.8518 - val_loss: 0.8229 - val_accuracy: 0.7353
Epoch 6/10
13/13 [==============================] - 8s 610ms/step - loss: 0.4311 - accuracy: 0.8517 - val_loss: 0.8242 - val_accuracy: 0.7373
Epoch 7/10
13/13 [==============================] - 8s 619ms/step - loss: 0.4298 - accuracy: 0.8527 - val_loss: 0.8237 - val_accuracy: 0.7373
Epoch 8/10
13/13 [==============================] - 8s 612ms/step - loss: 0.4285 - accuracy: 0.8532 - val_loss: 0.8245 - val_accuracy: 0.7345
Epoch 9/10
13/13 [==============================] - 8s 609ms/step - loss: 0.4275 - accuracy: 0.8536 - val_loss: 0.8254 - val_accuracy: 0.7359
Epoch 10/10
13/13 [==============================] - 8s 620ms/step - loss: 0.4259 - accuracy: 0.8531 - val_loss: 0.8267 - val_accuracy: 0.7355
batch_size=1024 GPU
Epoch 1/10
49/49 [==============================] - 3s 55ms/step - loss: 0.4408 - accuracy: 0.8488 - val_loss: 0.8452 - val_accuracy: 0.7326
Epoch 2/10
49/49 [==============================] - 1s 30ms/step - loss: 0.3924 - accuracy: 0.8664 - val_loss: 0.8475 - val_accuracy: 0.7360
Epoch 3/10
49/49 [==============================] - 1s 28ms/step - loss: 0.3780 - accuracy: 0.8711 - val_loss: 0.8548 - val_accuracy: 0.7345
Epoch 4/10
49/49 [==============================] - 1s 25ms/step - loss: 0.3686 - accuracy: 0.8744 - val_loss: 0.8592 - val_accuracy: 0.7345
Epoch 5/10
49/49 [==============================] - 1s 26ms/step - loss: 0.3609 - accuracy: 0.8778 - val_loss: 0.8642 - val_accuracy: 0.7347
Epoch 6/10
49/49 [==============================] - 1s 26ms/step - loss: 0.3535 - accuracy: 0.8796 - val_loss: 0.8685 - val_accuracy: 0.7363
Epoch 7/10
49/49 [==============================] - 1s 25ms/step - loss: 0.3470 - accuracy: 0.8829 - val_loss: 0.8716 - val_accuracy: 0.7356
Epoch 8/10
49/49 [==============================] - 1s 26ms/step - loss: 0.3401 - accuracy: 0.8857 - val_loss: 0.8788 - val_accuracy: 0.7358
Epoch 9/10
49/49 [==============================] - 1s 26ms/step - loss: 0.3341 - accuracy: 0.8880 - val_loss: 0.8825 - val_accuracy: 0.7355
Epoch 10/10
49/49 [==============================] - 1s 26ms/step - loss: 0.3280 - accuracy: 0.8903 - val_loss: 0.8892 - val_accuracy: 0.7353
評価
比較用にGoogle Colaboratoryで同様のプログラムを実行しました。GPUモデルはT4です。
Google Colaboratoryの方がbatch_size=32で約3倍速いです。
batch_size=1024では約7倍速くなりました。
ただし元々の学習時間が短いこともあり、5分未満の違いに留まりました。
batch_size | CPU[s] | GPU[s] | CPU/GPU |
---|---|---|---|
32 | 272 | 93 | 2.9 |
1024 | 81 | 12 | 6.8 |
また、データのダウンロードについて、自宅サーバは7403秒かかったのに対し、Google Colaboratoryは2秒でした。
自宅サーバ
Downloading data from https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
170498071/170498071 [==============================] - 7403s 43us/step
Google Colaboratory
Downloading data from https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
170498071/170498071 [==============================] - 2s 0us/step
まとめ
入力データのサイズが大きくない、数が少ないなどで元々学習に時間がかからないようなケースでは自宅サーバのCPUでも十分そうです。
しかし実際のケースではデータサイズも数も大きくなり、モデルを何度も調整するため繰り返し学習を行う場合がほとんどだと思います。また、GPUでしか動かない機能やコードもあるかと思いますので、素直にGoogle Colaboratoryを利用した方がよさそうです。