jupyterHub セットアップ (venv 利用)

環境構築

プロジェクトの作成.

$ mkdir /home/adm01/jupyter
$ cd /home/adm01/jupyter
$ python -m venv venv

アクティベート

$ source venv/bin/activate
(venv) $ 

(venv) $ python -V
  Python 3.7.3

pip でパッケージをインストール.

(venv) $ pip install -U setuptools pip
(venv) $ pip install wheel
(venv) $ pip install tensorflow
(venv) $ pip install keras
(venv) $ pip install matplotlib
(venv) $ pip install scipy
(venv) $ pip install scikit-image scikit-learn pandas
(venv) $ pip install Optuna
(venv) $ pip install cmake 
(venv) $ pip install dlib
(venv) $ pip install numba
(venv) $ pip install opencv-python
(venv) $ pip install torch torchvision
(venv) $ pip install jupyterhub notebook wheel ipywidgets jupyterlab
(venv) $ pip install jupyterthemes
(venv) $ jt -f ubuntu

npm で configurable-http-proxy をインストール

(venv) $ sudo npm install npm@latest -g
(venv) $ sudo npm install -g configurable-http-proxy

jupyter hub の起動

(venv) $ jupyterhub

別のターミナルで起動を確認する. 起動確認できたら jupyterhub を一旦閉じる.

$ w3m http://localhost:8000

設定ファイルを作る.

(venv) $ mkdir jupyterhub
(venv) $ cd jupyterhub
(venv) $ jupyterhub --generate-config  

(venv) $ vi jupyterhub_config.py 

  # デフォルトでjupyter labを用いたいため以下を修正
  c.Spawner.default_url = '/lab' 

   # アクセスしたら各ユーザーディレクトリを参照するように設定
  c.Spawner.notebook_dir = '~'

  # 環境変数を引き継ぐ. 
  # NFS しているディスク上では SQLite がうまく動かないらしく,Failed to open SQLite history となる. 
  c.Spawner.env_keep = ['PATH', 'PYTHONPATH', 'CONDA_ROOT', 'CONDA_DEFAULT_ENV', 'VIRTUAL_ENV', 'LANG', 'LC_ALL', 'JUPYTERHUB_SINGLEUSER_APP', 'IPYTHONDIR']

  #IPYTHONDIRの設定
  c.Spawner.environment = {'IPYTHONDIR': '~/.deep-learning-mct', 'PATH': '/home/adm01/jupyter/venv/bin:/usr/local/cuda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'}
Multiple userで使うには、rootユーザでの起動が必要なので,改めて起動する.

  (venv) $ sudo -s
  (venv) # jupyterhub -f jupyterhub_config.py 

SSL 化

(venv) # mkdir /home/adm01/jupyter/ssl 
(venv) # cd /home/adm01/jupyter/ssl 
(venv) # openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout mykey.key -out mycert.pem

(venv) $ vi jupyterhub_config.py 

    c.JupyterHub.ssl_cert = '/home/adm01/jupyter/ssl/mycert.pem'
    c.JupyterHub.ssl_key = '/home/adm01/jupyter/ssl/mykey.key'

設定追加

  • /etc/profile

    if [ "`id -u`" -eq 0 ]; then
      PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
    else
      PATH="/usr/local/cuda/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games"
    fi
  • /etc/skel/

    # CUDA
    export PATH="/usr/local/cuda/bin:$PATH"
    export LD_LIBRARY_PATH="/usr/local/cuda/lib64:$LD_LIBRARY_PATH"

動作確認

Jupyter で notebook を開く.

GPU の使用状態の確認

!nvidia-smi

利用する GPU の ID を指定 (以下では, ID=2 を使う)

import os
os.environ["CUDA_VISIBLE_DEVICES"]="2"

計算を実行する.以下のようなコードが動くことを確認した.

import tensorflow as tf
import tensorflow.keras.backend as K
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)
])
predictions = model(x_train[:1]).numpy()
predictions
tf.nn.softmax(predictions).numpy()
loss_fn = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
loss_fn(y_train[:1], predictions).numpy()
model.compile(optimizer='adam',
              loss=loss_fn,
              metrics=['accuracy'])
model.fit(x_train, y_train, epochs=100)
model.evaluate(x_test,  y_test, verbose=2)
probability_model = tf.keras.Sequential([
  model,
  tf.keras.layers.Softmax()
])
probability_model(x_test[:5])
K.clear_session()

GPGPU メモリ管理

Jupyter Notebook は計算が終わっても GPU を握りつづけてしまう. そのため,適当なタイミングで sleep していて GPU を使っているジョブを KILL することにする.

以下のようなスクリプトを実行しておく.

#!/usr/bin/env ruby
# coding: utf-8

#ハッシュ (保管用) の初期化
check3 = Hash.new
check2 = Hash.new
check1 = Hash.new

loop do
   #ハッシュの初期化
  check0 = Hash.new

  # GPU を使っているプロセスの pid の取得
  pids = Array.new
  output = `nvidia-smi --query-compute-apps=pid --format=csv,noheader`
  output.each_line do |pid|
    pids.push( pid.chomp )
  end
  pids.uniq!   #重複を切る

  #該当するプロセスの状態の調査・実行
  #  TIME->プロセスが実際にCPUを使った時間
  #  STATUS->プロセスの状態. R (Run) か S (Sleep) を判断. 
  pids.each do |pid|
    status = `ps h -p #{pid} -o stat `   #STATUS 取得
    time   = `ps h -p #{pid} -o bsdtime `#TIME 取得. フォーマットは mm:ss
    times = time.chomp.split(':') 
    unless /^R/ =~ status.chomp
      check0[pid] = times[0].to_i * 60 + times[1].to_i
      if check3[pid] && ( check0[pid] <= check3[pid] + 60 ) #値が存在 & マージン 60 秒 
        puts "STOP"
        system("kill -KILL #{pid}")
      end
    end
  end

  p check0

  sleep 100

  #ハッシュを回す
  check3 = check2
  check2 = check1
  check1 = check0
end

root の cront に登録

# crontab -e

  MAILTO=""
  @reboot ruby /home/adm01/jupyter/check.rb  

作業ディレクトリ作成 (mkdir.rb)

NFS の領域に sqlite や json などがおけないようだ.それを置くディレクトリのみをローカルに置く.

# coding: utf-8

require "fileutils"

Dir.glob("/work/[a-z]*").sort.each do |path|

  next if File.exist?( "#{path}/.deep-learning-mct" ) 
  p path

  user = File.basename( path )

  uid = File.stat(path).uid
  gid = File.stat(path).gid

  dir = "/lwork/JUPYTER/#{user}"
  FileUtils.mkdir( dir )
  FileUtils.chown( uid, gid, dir )

  FileUtils.mkdir( "#{dir}/.deep-learning-mct" )
  FileUtils.chown( uid, gid, "#{dir}/.deep-learning-mct" )
  FileUtils.ln_s( "#{dir}/.deep-learning-mct", "#{path}/.deep-learning-mct")

  if File.exist?( "#{path}/.local" ) 
    FileUtils.mv( "#{path}/.local", "#{dir}/.local" )
  else
    FileUtils.mkdir( "#{dir}/.local" )
    FileUtils.chown( uid, gid, "#{dir}/.local" )
  end
  FileUtils.ln_s( "#{dir}/.local", "#{path}/.local")

end