クラウドエンジニアのノート

情報技術系全般,自分用メモを公開してます。

EfficientDetのsingle-machine model parallelを実装して、D8(D7x)を学習させる

はじめに

魚群コンペ記事の第二弾です。

tmyoda.hatenablog.com

EfficientDetの良さそうなリポジトリを見つけ、このリポジトリをコンペに使おうと思いました。 github.com

しかし、EfficientDetの性質上、高い係数のモデルを学習させようとすると、バックボーンのネットワークにかなり大きなVRAMが必要になります。 12GB VRAM x4の環境で試しに学習させてみたのですが、案の定CUDA out of memoryです。

そこで、以下の記事のように、modelをGPUにスライスして学習させる手法を見つけたので、これを実装してみました。 pytorch.org

実装したリポジトリ

github.com

使い方はシンプルに--model_parallelを引数に追加するだけで行けます。

実装解説

バックボーン

バックボーンがメモリの8割以上を占めているそうなので、それを分割しようと考えました。

MBConvBlockのリストを単純に.to()して移せば良いかと思いましたが、pytorchの仕様上、nn.Moduleを継承したクラスのインスタンス.to()したところで、 中の重みに相当するテンソルは移動しないようです。

なので、ぼちぼち中身をいじる羽目になりました…。

NMS

model parallelの実装が終わり、学習が上手く行って喜んでいたのですが、

https://github.com/zylo117/Yet-Another-EfficientDet-Pytorch/issues/225

ここで議論されてる通り、d5以上のモデルだとtorch.visionmnsだとintがオーバーフローしてしまい、エラーを吐かれてしまいました。

なので、nms実装も上のリポジトリで変更しています。

まとめ

お世辞にもきれいと言える実装ではないですが、とりあえず動くものができたので公開しました。

ただ、batch 1で学習したところで、Normalization系のモジュールが機能せず学習が思ったように進まないのであしからず…。

mAP(mean Average Precision)を手っ取り早く上げるには

はじめに

signateの物体認識コンペ(魚群検知)に参加したので、そのときに得た知見をいくつか共有したいと思います。(複数記事に分ける予定)

signate.jp

新記事公開しました。(21.02.11)

tmyoda.hatenablog.com

結論

先に結論を言ってしまうと、mAPを上げるには、推論時のconfidenceスコアのフィルターの値を小さくして大量に予測値を出すことです。
このコンペでは、1枚1クラス20まで予測を提出できたので、その上限まで予測値を出すのが良いです。

理由

お恥ずかしながらmAPの計算方法をきちんと把握してなかったのですが、計算式を追えば自明のことでした。

mAPの算出方法

物体認識の場合、TN(True Negative)は特に考えません。また、PrecisionとRecallの算出方法も少し違います。

mAPなので名前の通り、AP(Average Precision)の平均です。クラスごとにAPを計算してその平均がmAPになります。

APの算出方法

クラスごとにAPを算出します。 まず、この記事の通り、APはprecision-recall曲線の下側の面積です。

precisionとrecallの算出方法は、通常のクラス分類と同じです。

  • Precisionの算出方法

$$ Precision = \frac{正しく予測できた数}{予測の数} $$

  • Recallの算出方法

$$ Recall = \frac{正しく予測できた数}{すべての正解の数} $$

物体検出の場合は、予測1つ1つに対してこのprecisionとrecallを算出し、recall値0から1まででprecisionを積分します。

りんごが3つ写っている画像に対する予測が以下の7つだったとします。

このときの、りんごクラスのAPを求めてみます。ここでCorrect?とは、iouしきい値を満たし正解ラベルと予測ラベルが一致している場合はTrue、それ以外はFalseです。

Confidence score (Sorted) Correct? Precision Recall
0.99 True 1/1 (1.0) 1/3 (0.3)
0.97 False 1/2 (0.5) 1/3 (0.3)
0.84 False 1/3 (0.3) 1/3 (0.3)
0.74 True 2/4 (0.5) 2/3 (0.7)
0.32 False 2/5 (0.4) 2/3 (0.7)
0.21 False 2/6 (0.3) 2/3 (0.7)
0.01 True 3/7 (0.4) 3/3 (1.0)

次にrecall値0から1までで積分を行います。グラフを滑らかにするために、各Recallの値で横に見た時に、Precisionの値が最大の値に置き換えます。

f:id:tontainoti:20210210002654p:plain
りんごAP

そして、離散値なので、複数の点をサンプリングして積分計算します。 例として、recallを0.1刻みずつ(0.0, 0.1, 0.2, ..., 1.0)の合計11点で計算する場合は、以下の式になります。(COCOの場合は101点で補間するらしい) $$ AP = \frac{1}{11} \times (1.0 + 1.0 + 1.0 + 1.0 + 0.5 + 0.5 + 0.5 + \frac{3}{7} + \frac{3}{7} + \frac{3}{7} + \frac{3}{7}) = 0.655... $$

あとは、クラスごとのAPの平均を取ればmAPが算出できます。
また、COCOやPascal VOCでもmAPの算出方法は若干異なるようです。

mAPを上げるには

もう一度言いますが、予測を増やせばAPが上がるのでmAPも上がります。

上の例のように、たとえconfidence scoreが0.01でも、それが正解ならば、APは上がるのは見ての通りだと思います。

もう少し深く考えてみると、すべて正解数しないとrecall 1のときのprecisionが0になります。 recallが低いところしかprecisionの値がなくて、recallが高くなるとprecisionが0に近くなり、積分計算で大きくロスします。 つまり、とにかく予測しまくって、低confidenceスコアでも正解bboxを予測してたら、高recallでの低precisionを回避できるという訳です。

singularityでcuda+pytorchのコンテナの作り方

はじめに

tmyoda.hatenablog.com

この記事の亜種です。

singularityは--nvを付ければホストのGPUをマウントするので、本来はホストのcudaを使いますが、harmo2とharmo5のcudaバージョンが微妙に違ったりして環境構築に手間取ったので、cudaが入ったsingularityコンテナを作りました。

構成

  • ubuntu18.04.5LTS(元のcuda dockerコンテナのデフォルト)
  • cuda11.0
  • pytorch1.7.1
  • python3.8.5
  • pyenv
  • その他よく使うコマンド(git, vim, wget, curl...)

が入ってます。 pytorchをそのまま使う目的と、一応pipenvを使えるようにpyenvを入れておきました。(不要でしたら、.defからpyenv抜いてbuildしてください)

使い方

以下のsingularity libraryで公開しました。 https://cloud.sylabs.io/library/tmyoda/default/cuda-torch-pyenv

実行方法

  • python_pyenvというsandboxを作成する例
  • -wオプションをつけることでpipaptなどを使って外部ライブラリをインストールできる

sandbox作成

singularity build --sandbox torch_cuda_pyenv library://tmyoda/default/cuda-torch-pyenv

shellに入る

その他run, execも可 (詳細は 過去記事参照)

singularity shell -w --nv torch_cuda_pyenv

.defファイル

man apt によると apt(8) ではなく apt-get(8) をスクリプトで使用するよう推奨されているため、defファイル等のスクリプトでインストールを動かす場合はapt-getを使用した方が良いみたいです。

Bootstrap: docker
From: pytorch/pytorch:1.7.1-cuda11.0-cudnn8-runtime


%environment
    export LC_ALL=C.UTF-8
    export Lang=C.UTF-8
    export PATH="/usr/local/opt/openssl/bin:$PATH"

    # pyenv
    export PYENV_ROOT="/pyenv"
    export PATH="$PYENV_ROOT/bin:$PATH"
    eval "$(pyenv init -)"


%post
    apt-get update
    DEBIAN_FRONTEND=noninteractive apt-get install -y make build-essential libssl-dev zlib1g-dev libbz2-dev \
    libreadline-dev libsqlite3-dev wget curl llvm \
    xz-utils tk-dev libffi-dev liblzma-dev python3-distutils apt-utils\
    openssl git bzip2 vim  bash-completion

    git clone https://github.com/pyenv/pyenv.git ${PYENV_ROOT}

    export PYENV_ROOT="/pyenv"
    export PATH="$PYENV_ROOT/bin:$PATH"
    eval "$(pyenv init -)"


    # pipenv
    pip install -U pip

    # clean up
    apt-get clean
    rm -rf /var/lib/apt/lists/*

%labels
    Author tmyoda
    Version v1.0.1

ローカルでこの.defから.sifを作成する方法は過去記事に書きましたので、そちらを参照してください。

#6: 研究室機器の使い方/サーバ室/Singularityの使い方 #gpu

singularityでubuntu20.04+python(+pipenv)環境を構築

はじめに

pythonは仮想環境が豊富なので、わざわざコンテナ化する必要ある?って思っていましたが、 いざGPUクラスタ上で動かすときに環境構築ハマったので、そのとき作成したpythonを動かすコンテナをSingularity Libraryに公開しました。

構成

  • ubuntu20.04
  • pyenv
  • pipenv
  • その他よく使うコマンド(git, vim, wget, curl...)

が入ってます。

使い方

以下のsingularity libraryで公開しました。

実行方法

  • python_pyenvというsandboxを作成する例
  • -wオプションをつけることでpipaptなどを使って外部ライブラリをインストールできる

sandbox作成

singularity build --sandbox python_pipenv library://tmyoda/default/ubuntu-pyenv:20.04

shellに入る

その他run, execも可 (過去記事参照)

singularity shell -w --nv python_pipenv

.defファイル

man apt によると apt(8) ではなく apt-get(8) をスクリプトで使用するよう推奨されているため、defファイル等のスクリプトでインストールを動かす場合はapt-getを使用した方が良いみたいです。

Bootstrap: docker
From: ubuntu:20.04


%environment
    export LC_ALL=C.UTF-8
    export Lang=C.UTF-8
    export PIPENV_VENV_IN_PROJECT=1
    export PATH="/usr/local/opt/openssl/bin:$PATH"
    # pipenv property
    # export PIPENV_SKIP_LOCK=1

    # pyenv
    export PYENV_ROOT="/pyenv"
    export PATH="$PYENV_ROOT/bin:$PATH"
    eval "$(pyenv init -)"


%post
    # Change if you want
    INSTALL_PYTHON_VERSION=3.7.9

    apt-get update
    # 依存関係
    DEBIAN_FRONTEND=noninteractive apt-get install -y make build-essential libssl-dev zlib1g-dev libbz2-dev \
    libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev \
    xz-utils tk-dev libffi-dev liblzma-dev python3-distutils \
    openssl git bzip2 vim  bash-completion

    git clone https://github.com/pyenv/pyenv.git ${PYENV_ROOT}

    export PYENV_ROOT="/pyenv"
    export PATH="$PYENV_ROOT/bin:$PATH"
    eval "$(pyenv init -)"

    # python setting
    pyenv install ${INSTALL_PYTHON_VERSION}
    pyenv global ${INSTALL_PYTHON_VERSION}

    # pipenv
    pip install -U pip
    pip install pipenv

    # clean up
    apt-get clean
    rm -rf /var/lib/apt/lists/*

%labels
    Author tmyoda
    Version v1.0.0

ローカルでこの.defから.sifを作成する方法は過去記事に書きましたので、そちらを参照してください。

tmyoda.hatenablog.com

docker, singularityでtzdata等の対話が必要なモジュールのインストールで止まるとき Please select the geographic area in which you live.

singularityをdefからbuildしていたのですが、以下ような画面でインストールが止まってました。

Configuring tzdata
------------------

Please select the geographic area in which you live. Subsequent configuration
questions will narrow this down by presenting a list of cities, representing
the time zones in which they are located.

どうやら、dockerからfromでubuntuを指定して、gitを一緒にインストールするときに発生するようです。

調べたところ、Dockerfileでの解決方法が見つかったので、参考にします。

qiita.com

解決方法(非推奨)

.defファイルの%postに以下の環境変数を追加

export DEBIAN_FRONTEND=noninteractive

なのですが、Docker公式によると、noninteractiveにし続けるのは非推奨みたいです。

解決方法

apt installのときだけ適用されるようにして、他のモジュールへの影響を抑えます。

DEBIAN_FRONTEND=noninteractive apt-get install -y git tzdata

pysparkの使い方に慣れるためにirisデータセットをいじってみる

はじめに

pysparkを触る機会があったので,irisデータセットで色々試してみました. 適当にメモ程度なのであしからず.

環境構築

sparkの環境をローカルに構築するのが大変そうだったので,以下のDockerコンテナをつかいました.

https://hub.docker.com/r/jupyter/pyspark-notebook

サンプル集

読み込み

from pyspark import *
from pyspark.sql import *
from pyspark.sql.types import *
import pyspark.sql.functions as F


conf = SparkConf()
sc = SparkContext.getOrCreate(conf=conf)
sqlContext = SQLContext(sc)


df = sqlContext.read.format('com.databricks.spark.csv') \
    .options(header='true', inferschema='true') \
    .load('/home/jovyan/work/iris.csv') 

df.show()
+-----------+----------+-----------+----------+-------+
|sepalLength|sepalWidth|petalLength|petalWidth|variety|
+-----------+----------+-----------+----------+-------+
|        5.1|       3.5|        1.4|       0.2| Setosa|
|        4.9|       3.0|        1.4|       0.2| Setosa|
|        4.7|       3.2|        1.3|       0.2| Setosa|
|        4.6|       3.1|        1.5|       0.2| Setosa|
|        5.0|       3.6|        1.4|       0.2| Setosa|
|        5.4|       3.9|        1.7|       0.4| Setosa|
|        4.6|       3.4|        1.4|       0.3| Setosa|
|        5.0|       3.4|        1.5|       0.2| Setosa|
|        4.4|       2.9|        1.4|       0.2| Setosa|
|        4.9|       3.1|        1.5|       0.1| Setosa|
|        5.4|       3.7|        1.5|       0.2| Setosa|
|        4.8|       3.4|        1.6|       0.2| Setosa|
|        4.8|       3.0|        1.4|       0.1| Setosa|
|        4.3|       3.0|        1.1|       0.1| Setosa|
|        5.8|       4.0|        1.2|       0.2| Setosa|
|        5.7|       4.4|        1.5|       0.4| Setosa|
|        5.4|       3.9|        1.3|       0.4| Setosa|
|        5.1|       3.5|        1.4|       0.3| Setosa|
|        5.7|       3.8|        1.7|       0.3| Setosa|
|        5.1|       3.8|        1.5|       0.3| Setosa|
+-----------+----------+-----------+----------+-------+

カラム確認

df.columns
['sepalLength', 'sepalWidth', 'petalLength', 'petalWidth', 'variety']

統計量

df.describe().show()
+-------+------------------+-------------------+------------------+------------------+---------+
|summary|       sepalLength|         sepalWidth|       petalLength|        petalWidth|  variety|
+-------+------------------+-------------------+------------------+------------------+---------+
|  count|               150|                150|               150|               150|      150|
|   mean| 5.843333333333335|  3.057333333333334|3.7580000000000027| 1.199333333333334|     null|
| stddev|0.8280661279778637|0.43586628493669793|1.7652982332594662|0.7622376689603467|     null|
|    min|               4.3|                2.0|               1.0|               0.1|   Setosa|
|    max|               7.9|                4.4|               6.9|               2.5|Virginica|
+-------+------------------+-------------------+------------------+------------------+---------+

スライシング

df[['sepalLength', 'sepalWidth']]
DataFrame[sepalLength: double, sepalWidth: double]

ランダムサンプリング

df.sample(False, fraction=0.1).show()
+-----------+----------+-----------+----------+----------+
|sepalLength|sepalWidth|petalLength|petalWidth|   variety|
+-----------+----------+-----------+----------+----------+
|        4.9|       3.0|        1.4|       0.2|    Setosa|
|        5.7|       4.4|        1.5|       0.4|    Setosa|
|        5.2|       3.4|        1.4|       0.2|    Setosa|
|        4.7|       3.2|        1.6|       0.2|    Setosa|
|        6.3|       3.3|        4.7|       1.6|Versicolor|
|        6.0|       2.2|        4.0|       1.0|Versicolor|
|        6.1|       2.9|        4.7|       1.4|Versicolor|
|        5.6|       2.5|        3.9|       1.1|Versicolor|
|        5.5|       2.4|        3.8|       1.1|Versicolor|
|        6.0|       2.7|        5.1|       1.6|Versicolor|
|        6.7|       2.5|        5.8|       1.8| Virginica|
|        6.4|       2.7|        5.3|       1.9| Virginica|
|        7.4|       2.8|        6.1|       1.9| Virginica|
|        7.9|       3.8|        6.4|       2.0| Virginica|
|        6.7|       3.3|        5.7|       2.5| Virginica|
+-----------+----------+-----------+----------+----------+

列の追加

df = df.withColumn('PetalMult', df['petalWidth'] * df['petalLength'])
df.show(5)
+-----------+----------+-----------+----------+-------+-------------------+----+------------------+
|sepalLength|sepalWidth|petalLength|petalWidth|variety|          PetalMult|  ID|        totalWidth|
+-----------+----------+-----------+----------+-------+-------------------+----+------------------+
|        5.1|       3.5|        1.4|       0.2| Setosa|0.27999999999999997|40.0|0.7000000000000001|
|        4.9|       3.0|        1.4|       0.2| Setosa|0.27999999999999997|45.0|0.6000000000000001|
|        4.7|       3.2|        1.3|       0.2| Setosa|               0.26| 9.0|0.6400000000000001|
|        4.6|       3.1|        1.5|       0.2| Setosa|0.30000000000000004|79.0|0.6200000000000001|
|        5.0|       3.6|        1.4|       0.2| Setosa|0.27999999999999997|27.0|0.7200000000000001|
+-----------+----------+-----------+----------+-------+-------------------+----+------------------+

ユーザ定義関数

データ更新毎に呼ばれるので注意!!

my_udf = F.UserDefinedFunction(lambda x: x + 5, DoubleType())
df.withColumn("my_col", my_udf("sepalLength")).show(5)
+-----------+----------+-----------+----------+-------+-------------------+----+------------------+------+
|sepalLength|sepalWidth|petalLength|petalWidth|variety|          PetalMult|  ID|        totalWidth|my_col|
+-----------+----------+-----------+----------+-------+-------------------+----+------------------+------+
|        5.1|       3.5|        1.4|       0.2| Setosa|0.27999999999999997|40.0|0.7000000000000001|  10.1|
|        4.9|       3.0|        1.4|       0.2| Setosa|0.27999999999999997|45.0|0.6000000000000001|   9.9|
|        4.7|       3.2|        1.3|       0.2| Setosa|               0.26| 9.0|0.6400000000000001|   9.7|
|        4.6|       3.1|        1.5|       0.2| Setosa|0.30000000000000004|79.0|0.6200000000000001|   9.6|
|        5.0|       3.6|        1.4|       0.2| Setosa|0.27999999999999997|27.0|0.7200000000000001|  10.0|
+-----------+----------+-----------+----------+-------+-------------------+----+------------------+------+

グルーピング

  • 列の値でグループ分けし、一列の合計を取得する場合:
df.groupBy('variety').sum().show()
+----------+------------------+------------------+------------------+------------------+------------------+
|   variety|  sum(sepalLength)|   sum(sepalWidth)|  sum(petalLength)|   sum(petalWidth)|    sum(PetalMult)|
+----------+------------------+------------------+------------------+------------------+------------------+
| Virginica| 329.3999999999999|             148.7|277.59999999999997|101.29999999999998| 564.8099999999997|
|    Setosa|250.29999999999998|171.40000000000003| 73.10000000000001|12.299999999999995|18.280000000000012|
|Versicolor|             296.8|138.50000000000003|212.99999999999997|              66.3|            286.02|
+----------+------------------+------------------+------------------+------------------+------------------+
  • 列の値でグループ分けし、一列をカウントする場合:
df.groupBy('variety').count().show()
+----------+-----+
|   variety|count|
+----------+-----+
| Virginica|   50|
|    Setosa|   50|
|Versicolor|   50|
+----------+-----+

groupBy→aggで集計

  • filterは行の抽出
  • selectは列の抽出(スライシングで代用可能)
df.groupBy('variety').agg({'petalWidth': 'min', 'sepalWidth': 'min'}).filter('min(sepalWidth) > 2.0').show()
df.groupBy('variety').agg({'petalWidth': 'min', 'sepalWidth': 'min'}).filter('min(sepalWidth) > 2.0').show()
+---------+---------------+---------------+
|  variety|min(petalWidth)|min(sepalWidth)|
+---------+---------------+---------------+
|Virginica|            1.4|            2.2|
|   Setosa|            0.1|            2.3|
+---------+---------------+---------------+
df.groupBy('variety').agg(F.min('petalWidth')).show()
+----------+---------------+
|   variety|min(petalWidth)|
+----------+---------------+
| Virginica|            1.4|
|    Setosa|            0.1|
|Versicolor|            1.0|
+----------+---------------+

groupBy→pivotで縦横変換

# groupBy("縦のままの列").pivot("縦から横へ変換したい列").sum("集計値の列")
df.groupBy('ID').pivot('variety').sum('totalWidth').show()
+--------------------+------+------------------+------------------+
|                  ID|Setosa|        Versicolor|         Virginica|
+--------------------+------+------------------+------------------+
|4c86ce73cf93883ac...|  null|3.6399999999999997|              null|
|1d0123419d79ed9f4...|  null|              null|               5.6|
|9ee6f2276bb903d07...|  0.68|              null|              null|
|feb96d4b9ba61a234...|  0.66|              null|              null|
|9d1bf310e18c3906a...|  null|              null|              6.16|
|083c4bf137c021384...|  null|              null| 7.359999999999999|
|e8249fb5d09a3670e...|  null|              3.75|              null|
|d2a5cfc97fc88bd4a...|  null|              null|6.6000000000000005|
|cff32af7114873f26...|  null|              3.12|              null|
|78c2373ceaeedd5f7...|  null|              null| 5.319999999999999|
|c0299202f49017bf2...|  1.02|              null|              null|
|cf2b784ce8118783c...|  null|              null| 6.510000000000001|
|1b4ac9d118b902964...|  null|              null|              5.13|
|1aeacde745c81b265...|  null|               4.5|              null|
|b6f96e27904f4f6de...|  null|              null|               6.0|
|abed0bc37e718a5e4...|  null|              3.12|              null|
|b89932d736fa67711...|  null|              5.28|              null|
|7d132d0ead06d6ba5...|  null|              3.77|              null|
|cfb737bf348cd3b2c...|  null|3.9199999999999995|              null|
|42209ddc3b698bb94...|  0.68|              null|              null|
+--------------------+------+------------------+------------------+

一意の識別子を付ける

df = df.withColumn("ID", F.monotonically_increasing_id())
df = df.withColumn('totalWidth', df['sepalWidth'] * df['petalWidth'])
df.show(5)
+-----------+----------+-----------+----------+-------+-------------------+---+------------------+
|sepalLength|sepalWidth|petalLength|petalWidth|variety|          PetalMult| ID|        totalWidth|
+-----------+----------+-----------+----------+-------+-------------------+---+------------------+
|        5.1|       3.5|        1.4|       0.2| Setosa|0.27999999999999997|  0|0.7000000000000001|
|        4.9|       3.0|        1.4|       0.2| Setosa|0.27999999999999997|  1|0.6000000000000001|
|        4.7|       3.2|        1.3|       0.2| Setosa|               0.26|  2|0.6400000000000001|
|        4.6|       3.1|        1.5|       0.2| Setosa|0.30000000000000004|  3|0.6200000000000001|
|        5.0|       3.6|        1.4|       0.2| Setosa|0.27999999999999997|  4|0.7200000000000001|
+-----------+----------+-----------+----------+-------+-------------------+---+------------------+

DFのJOIN

df1 = df[['ID', 'totalWidth']].sort('ID')
print(df1.show(3), df1.count())
+---+------------------+
| ID|        totalWidth|
+---+------------------+
|  0|0.7000000000000001|
|  1|0.6000000000000001|
|  2|0.6400000000000001|
+---+------------------+
df2 = df[['ID', 'variety', 'PetalMult']].sort('ID')
print(df2.show(3), df2.count())
+---+-------+-------------------+
| ID|variety|          PetalMult|
+---+-------+-------------------+
|  0| Setosa|0.27999999999999997|
|  1| Setosa|0.27999999999999997|
|  2| Setosa|               0.26|
+---+-------+-------------------+
  • 元のDataframe(こちらがLeftになる)でjoin methodを呼び、joinの相手(Rightになる)とjoinの条件を書くと、SQLのjoinの様にDataframeの結合が可能
df1.join(df2, df1['ID'] == df2['ID'], 'inner').show()
+---+-------------------+---+-------+-------------------+
| ID|         totalWidth| ID|variety|          PetalMult|
+---+-------------------+---+-------+-------------------+
|  0| 0.7000000000000001|  0| Setosa|0.27999999999999997|
|  1| 0.6000000000000001|  1| Setosa|0.27999999999999997|
|  2| 0.6400000000000001|  2| Setosa|               0.26|
|  3| 0.6200000000000001|  3| Setosa|0.30000000000000004|
|  4| 0.7200000000000001|  4| Setosa|0.27999999999999997|
|  5|               1.56|  5| Setosa|               0.68|
|  6|               1.02|  6| Setosa|               0.42|
|  7|               0.68|  7| Setosa|0.30000000000000004|
|  8|               0.58|  8| Setosa|0.27999999999999997|
|  9|0.31000000000000005|  9| Setosa|0.15000000000000002|
| 10| 0.7400000000000001| 10| Setosa|0.30000000000000004|
| 11|               0.68| 11| Setosa|0.32000000000000006|
| 12|0.30000000000000004| 12| Setosa|0.13999999999999999|
| 13|0.30000000000000004| 13| Setosa|0.11000000000000001|
| 14|                0.8| 14| Setosa|               0.24|
| 15| 1.7600000000000002| 15| Setosa| 0.6000000000000001|
| 16|               1.56| 16| Setosa|               0.52|
| 17|               1.05| 17| Setosa|               0.42|
| 18|               1.14| 18| Setosa|               0.51|
| 19|               1.14| 19| Setosa|0.44999999999999996|
+---+-------------------+---+-------+-------------------+

列を取り出す

  • df.selectじゃないと動作しない
  • .rddとは
    • Dataframeの各行がそれぞれRow OjbectなRDDに変換されます。Row ObjectはSpark SQLで一行分のデータを保持する為のObjectです
sorted(df.select('ID').distinct().rdd.map(lambda x: x[0]).collect())[:10]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
df.filter(df['ID'] == 2).show()
+-----------+----------+-----------+----------+-------+---------+---+------------------+
|sepalLength|sepalWidth|petalLength|petalWidth|variety|PetalMult| ID|        totalWidth|
+-----------+----------+-----------+----------+-------+---------+---+------------------+
|        4.7|       3.2|        1.3|       0.2| Setosa|     0.26|  2|0.6400000000000001|
+-----------+----------+-----------+----------+-------+---------+---+------------------+

参考文献

sinhrks.hatenablog.com

  • サンプル集(group by詳しい)

qiita.com

  • 関数まとめ

qiita.com

スライドの作りに便利なフリー素材サイト

はじめに

twitterでたまに回ってくる,スライド作成向け便利素材サイトをまとめました

画像系

freepik

Unsplash

unsplash.com

pixabay

https://pixabay.com/ja/

o-dan

https://o-dan.net/ja/

図系

isoflow

スライド作り注意点

ubuntu18.04 noVNC dockerコンテナを公開しました

はじめに

tmyoda.hatenablog.com

この記事のSingularityコンテナを作成するべく,参照元のdockerコンテナを作成しました.

以下の素晴らしいリポジトリを使おうと思ったのですが,あいにくubuntu18.04に対応しておらず,リポジトリのメンテナンスも終わりそうです.

github.com

issueを漁ったところ,Fromをubuntu18.04にすれば動くらしいので,そこだけを変更したDockerfileGitHubに公開しました.

また,DokerHubでもコンテナを公開しました.

CentOSのアップデートバージョンを公開するかは悩み中です.(要望があれば行います.)

公開したもの

DockerHub

GitHub

SingularityコンテナでOpenCV+Boostを使ったC++コードをコンパイル

はじめに

研究でC++コードをpybind11を使ってPythonから呼んで強化学習をしています.

強化学習GPU上で回したくなったのですが,残念ながらC++系ライブラリを導入するためのsudo権限が付与されておらず,サーバ上でC++コードが実行できません.

そこで,Singularityコンテナ上でビルド&実行までできる環境を作成して,そのままGPUを使った強化学習を行えるようにします.

コンテナ作成

作成したビルド&強化学習に必要な環境

  • Ninja build
  • OpenCV 3.4.6
  • Boost 1.65
  • Pipenv
  • python
  • VLC(動画出力するため)

実行方法は2つあります

  • Singularity Libraryからpull
  • .defファイルからローカルでbuild

Singularity Libraryからpull

Singularity Library(SyLabs)にコンテナを公開しました

cloud.sylabs.io

以下のコードでビルドできると思います

singularity pull library://tmyoda/default/headless-ubuntu-xfce-pipenv-opencv-boost
singularity build --sandbox cpp_vnc headless-ubuntu-xfce-pipenv-opencv-boost.sif

実行方法は以下の通りです

singularity instance start -w cpp_vnc xfce
singularity start -w instance://xfce

Singularityの詳しい使い方は以下の記事を参考にしてください

tmyoda.hatenablog.com

.defファイル

注意点

  • DockerHubで公開されている,/consol/ubuntu-xfce-vnc を使用したかったのですが,のubuntuバージョンが16.04までだったので,18.04に対応させたdocker container(tmyoda/ubuntu-xfce-vnc:18.04)を作成し,DockerHubに上げたものをベースに作成しています.

  • OpenCVは動画生成したかったので,その辺のオプション有効にしてます

Bootstrap: docker
From: tmyoda/ubuntu18-xfce-vnc:latest

%environment
    export LC_ALL=C.UTF-8
    export Lang=C.UTF-8
    export PIPENV_VENV_IN_PROJECT=1
    export PATH="/usr/local/opt/openssl/bin:$PATH"
    # pipenv property
    export PIPENV_VENV_IN_PROJECT=1
    export PIPENV_SKIP_LOCK=1


%post
    apt update
    # for jupyter and pipenv 
    apt install -y bzip2 ca-certificates curl git ffmpeg openssl libssl-dev \
    libsqlite3-dev libreadline6-dev libbz2-dev libssl-dev libsqlite3-dev libncursesw5-dev \
    libffi-dev libdb-dev libexpat1-dev zlib1g-dev liblzma-dev libgdbm-dev libmpdec-dev \
    vim-tiny build-essential inkscape jed libsm6 libxext-dev libxrender1 lmodern netcat tzdata unzip \
    wget build-essential gcc zlib1g-dev python3-distutils vlc bash-completion

    # pip
    curl -kL https://bootstrap.pypa.io/get-pip.py | python3
    # pipenv
    pip3 install virtualenv
    pip3 install pipenv


    apt install -y \
        libboost1.65-all-dev libboost1.65-dev libboost1.65-tools-dev ninja-build ccache \
        libncurses5-dev libavutil-dev libavcodec-dev libavfilter-dev libavformat-dev libavdevice-dev ffmpeg pkg-config \
        cmake libgtk-3-dev libjpeg-dev

    # opencv3.4.6
    wget https://github.com/opencv/opencv/archive/3.4.6.tar.gz
    tar zxvf 3.4.6.tar.gz
    cd opencv-3.4.6

    export SOURCE_DIR="../"
    export BUILD_DIR="/build"
    export GENERATOR_NAME="Unix Makefiles"

    # build opencv
    mkdir build
    cd build
    cmake \
    -G "${GENERATOR_NAME}" \
    --build ${BUILD_DIR} \
    -D BUILD_CUDA_STUBS=OFF \
    -D BUILD_DOCS=OFF \
    -D BUILD_EXAMPLES=OFF \
    -D BUILD_JASPER=OFF \
    -D BUILD_JPEG=ON \
    -D BUILD_OPENEXR=OFF \
    -D BUILD_PACKAGE=ON \
    -D BUILD_PERF_TESTS=OFF \
    -D BUILD_PNG=ON \
    -D BUILD_SHARED_LIBS=ON \
    -D BUILD_TBB=OFF \
    -D BUILD_TESTS=OFF \
    -D BUILD_TIFF=OFF \
    -D BUILD_WITH_DEBUG_INFO=ON \
    -D BUILD_ZLIB=OFF \
    -D BUILD_WEBP=OFF \
    -D BUILD_opencv_apps=ON \
    -D BUILD_opencv_calib3d=ON \
    -D BUILD_opencv_core=ON \
    -D BUILD_opencv_cudaarithm=OFF \
    -D BUILD_opencv_cudabgsegm=OFF \
    -D BUILD_opencv_cudacodec=OFF \
    -D BUILD_opencv_cudafeatures2d=OFF \
    -D BUILD_opencv_cudafilters=OFF \
    -D BUILD_opencv_cudaimgproc=OFF \
    -D BUILD_opencv_cudalegacy=OFF \
    -D BUILD_opencv_cudaobjdetect=OFF \
    -D BUILD_opencv_cudaoptflow=OFF \
    -D BUILD_opencv_cudastereo=OFF \
    -D BUILD_opencv_cudawarping=OFF \
    -D BUILD_opencv_cudev=OFF \
    -D BUILD_opencv_features2d=ON \
    -D BUILD_opencv_flann=ON \
    -D BUILD_opencv_highgui=ON \
    -D BUILD_opencv_imgcodecs=ON \
    -D BUILD_opencv_imgproc=ON \
    -D BUILD_opencv_java=OFF \
    -D BUILD_opencv_ml=ON \
    -D BUILD_opencv_objdetect=ON \
    -D BUILD_opencv_photo=ON \
    -D BUILD_opencv_python2=OFF \
    -D BUILD_opencv_python3=ON \
    -D BUILD_opencv_shape=ON \
    -D BUILD_opencv_stitching=ON \
    -D BUILD_opencv_superres=ON \
    -D BUILD_opencv_ts=ON \
    -D BUILD_opencv_video=ON \
    -D BUILD_opencv_videoio=ON \
    -D BUILD_opencv_videostab=ON \
    -D BUILD_opencv_viz=OFF \
    -D BUILD_opencv_world=OFF \
    -D CMAKE_BUILD_TYPE=RELEASE \
    -D WITH_1394=ON \
    -D WITH_CUBLAS=OFF \
    -D WITH_CUDA=OFF \
    -D WITH_CUFFT=OFF \
    -D WITH_EIGEN=ON \
    -D WITH_FFMPEG=ON \
    -D WITH_GDAL=OFF \
    -D WITH_GPHOTO2=OFF \
    -D WITH_GIGEAPI=ON \
    -D WITH_GSTREAMER=ON \
    -D WITH_GTK=ON \
    -D WITH_INTELPERC=OFF \
    -D WITH_IPP=ON \
    -D WITH_IPP_A=OFF \
    -D WITH_JASPER=ON \
    -D WITH_JPEG=ON \
    -D WITH_LIBV4L=ON \
    -D WITH_OPENCL=ON \
    -D WITH_OPENCLAMDBLAS=OFF \
    -D WITH_OPENCLAMDFFT=OFF \
    -D WITH_OPENCL_SVM=OFF \
    -D WITH_OPENEXR=ON \
    -D WITH_OPENGL=ON \
    -D WITH_OPENMP=OFF \
    -D WITH_OPENNI=OFF \
    -D WITH_PNG=ON \
    -D WITH_PTHREADS_PF=OFF \
    -D WITH_PVAPI=ON \
    -D WITH_QT=OFF \
    -D WITH_TBB=ON \
    -D WITH_TIFF=ON \
    -D WITH_UNICAP=OFF \
    -D WITH_V4L=OFF \
    -D WITH_VTK=OFF \
    -D WITH_WEBP=ON \
    -D WITH_XIMEA=OFF \
    -D WITH_XINE=OFF \
    ${SOURCE_DIR}

    make -j8
    make install
    echo /usr/local/lib > /etc/ld.so.conf.d/opencv.conf
    ldconfig -v

    # clean up
    apt clean
    rm -rf /var/lib/apt/lists/*

%labels
    Author tmyoda
    Version v0.0.3

Singularity + headless VNC + Pipenvを使ってサーバ上で強化学習環境を整える(gym, pybullet)

はじめに

強化学習をしてると何かとGUI問題に直面します. OpenAI GymもPyBulletもMoJoCoGUIです. というか,GUIで動作確認ぐらいしか,学習経過を把握できるものがありません.

ということで,GPUサーバ上でGUIが見れるような環境が欲しくなりました.

追記: Sylabs.ioにcontainerをpushしました.

headless VNCとは

VNCとは離れた環境のGUIを操作するリモートデスクトップのことを指しますが,headlessマシンとはディスプレイを持たない,つまりGUIを持たないマシンのことを指します.

つまり,GUIを持たない共有のGPU付きサーバ上に,xfce環境 (GUI) を作って,しかもブラウザ上からVNCできかつ,pytorchがGPU上で動く環境を作成します.

headless VNCを触ってみる

楽するために,Docker, もしくはSingularityを使って今回は進めます. また,私はxfceの方が好きなのでxfceでの例を示します.(もちろんIceWMでも良いです)

Singularityの解説記事はこちらから

tmyoda.hatenablog.com

https://hub.docker.com/r/consol/ubuntu-xfce-vnc/

docker

docker run -d -p 5901:5901 -p 6901:6901 consol/centos-xfce-vnc:latest

Singularity

# sandbox作成
singularity build --sandbox ubuntu-xfce docker://consol/ubuntu-xfce-vnc:latest

# instance作成 
singularity instance start -w --nv ubuntu-xfce xfce

# vnc実行
singularity run instance://xfce

singularityでそのままrunしても動きますが,プロセス管理が大変なのでinstanceで動かします.

あとはブラウザでlocalhost:6901/vnc.htmlへアクセスすればなんとGUIが見れます.(初期パスワードは vncpassword ) これでgymとかpybulletとかの動作を確認できます.

導入

docker

dockerの導入はかんたんで,先程のコンテナに好きなだけaptでほしいものを入れればokです.

singularity (rootless)

ルート権限サーバへの導入方法は3つあります. - singularity libraryからpull - ローカルPCでbuild - サーバ上でremote build

singularity libraryからpull (おすすめ!)

sylabにuploadしました.

singularity pull library://tmyoda/default/headless-ubuntu-xfce-pipenv

これで.sifファイルが手に入ります.

ローカルPCでbuild

rootlessだとaptコマンドが実行できないため,ローカルPCにsingularityを導入しました. そして,.defファイルを作成しましたので公開します.

Bootstrap: docker
From: consol/ubuntu-xfce-vnc:latest


%environment
    export LC_ALL=C.UTF-8
    export Lang=C.UTF-8
    export PIPENV_VENV_IN_PROJECT=1
    export PATH="/usr/local/opt/openssl/bin:$PATH"


%post
    apt-get -y update 
    # for jupyter and pipenv 
    apt-get install -y bzip2 ca-certificates curl git ffmpeg openssl libssl-dev \
    libsqlite3-dev libreadline6-dev libbz2-dev libssl-dev libsqlite3-dev libncursesw5-dev \
    libffi-dev libdb-dev libexpat1-dev zlib1g-dev liblzma-dev libgdbm-dev libmpdec-dev \
    vim-tiny build-essential inkscape jed libsm6 libxext-dev libxrender1 lmodern netcat tzdata unzip
    
    # pyton3.6 from source
    apt-get install -y wget build-essential gcc zlib1g-dev
    cd /root/
    wget https://www.python.org/ftp/python/3.6.8/Python-3.6.8.tgz
    tar zxf Python-3.6.8.tgz
    cd Python-3.6.8
    ./configure 
    make altinstall
    cd .. && rm -rf Python-3.6.8.tgz Python-3.6.8
    cd $HOME
    rm /usr/bin/python3
    ln -s /usr/local/bin/python3.6 /usr/bin/python3
    # install pip
    export PATH="/usr/local/opt/openssl/bin:$PATH"
    curl -kL https://bootstrap.pypa.io/get-pip.py | python3
    apt-get clean
    rm -rf /var/lib/apt/lists/*
    # pipenv
    pip3 install virtualenv
    pip3 install pipenv

%labels
    Author tmyoda
    Version v0.1.0

root権限付きローカルPCでbuildします.

sudo singularity build --fix-perms ubuntu-xfce-pipenv.sif ubuntu-xfce-pipenv.def

*.defからローカルでbuildするのはroot必須です. しかしsingularityには--remoteというオプションがあり,これを用いると非rootでもbuildできます.

出来上がったxfce-pipenv.sifをscp等でサーバへコピーします.

サーバ上での作業

pullもしくはdefからのbuildでサーバ上に*.sifが手に入っている状態かと思います.

1 サーバ上で--sandboxオプションをつけてビルドします. これしないとvnc動かないです.

singularity build --sandbox ubuntu-xfce ubuntu-xfce-pipenv.sif

2 サーバ上でinstance startしてrunします.

singularity instance start -w --nv  ubuntu-xfce xfce
singularity run -w --nv instance://xfce

あとは先程のようにlocalhost:6901/vnc/htmlにアクセスします.

そして,pipenvが導入されているので,gym, pybullet, jupyterなりを好きに入れ環境を整えます.

xfce4 パネル初期化コマンド

最後にxfce4のパネルが良く死ぬので初期化コマンド

www.achiachi.net

xfce4-panel --quit
pkill xfconfd
rm -rf ~/.config/xfce4/panel
rm -rf ~/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-panel.xml
xfce4-panel