0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

自宅サーバ(PowerEdge R720)で機械学習環境を作成する

Last updated at Posted at 2023-11-12

背景

自宅サーバとして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本しかないのでやりくりします。

  1. iDRACはサーバのフロントパネルからIPを192.168.137.254に設定
  2. ノートPCとiDRACのポートを接続
  3. 仮想コンソールからサーバにログイン
    1. nmcliを使ってポートを設定
      1. nmcli con eno1 edit
      2. set ipv4.addresses 192.168.137.254/24
      3. set ipv4.gateway 192.168.137.1
      4. set ipv4.dns 8.8.8.8
      5. set ipv4.method manual
      6. save
      7. activate
    2. SSHでrootにパスワードログイン設定
      1. vim /etc/ssh/sshd_config
      2. PermitRootLogin yes
      3. PasswordAuthentication yes
      4. systemctl restart sshd
  4. ノートPCとサーバのポートを接続
  5. TeraTermを使ってID/PASSでSSH接続

Jupyter環境の構築

今回はDockerを使ってJupyter環境を立ち上げます。

Dockerインストール

  1. dnf config-manager --add-repo=https://download.docker.com/linux/centos/docker-ce.repo
  2. dnf install docker-ce docker-ce-cli containerd.io
  3. systemctl start docker
  4. systemctl enable docker

Jupyterイメージの起動

  1. docker pull jupyter/base-notebook
  2. docker run -p 8888:8888 -v /path/to/your/notebooks:/home/jovyan/work jupyter/base-notebook

コンテナ起動時に表示されるTokenを使ってブラウザからアクセスするとJupyterが使えます。

ベンチマーク

機械学習を試す前に、参考情報としてサーバのベンチマークを試します。

sysbenchのインストール

  1. dnf install epel-release
  2. dnf update
  3. 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を利用した方がよさそうです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?