EfficientDetのsingle-machine model parallelを実装して、D8(D7x)を学習させる
はじめに
魚群コンペ記事の第二弾です。
EfficientDetの良さそうなリポジトリを見つけ、このリポジトリをコンペに使おうと思いました。 github.com
しかし、EfficientDetの性質上、高い係数のモデルを学習させようとすると、バックボーンのネットワークにかなり大きなVRAMが必要になります。 12GB VRAM x4の環境で試しに学習させてみたのですが、案の定CUDA out of memoryです。
そこで、以下の記事のように、modelをGPUにスライスして学習させる手法を見つけたので、これを実装してみました。 pytorch.org
実装したリポジトリ
使い方はシンプルに--model_parallel
を引数に追加するだけで行けます。
実装解説
バックボーン
バックボーンがメモリの8割以上を占めているそうなので、それを分割しようと考えました。
MBConvBlockのリストを単純に.to()
して移せば良いかと思いましたが、pytorchの仕様上、nn.Module
を継承したクラスのインスタンスを.to()
したところで、
中の重みに相当するテンソルは移動しないようです。
なので、ぼちぼち中身をいじる羽目になりました…。
NMS
model parallelの実装が終わり、学習が上手く行って喜んでいたのですが、
https://github.com/zylo117/Yet-Another-EfficientDet-Pytorch/issues/225
ここで議論されてる通り、d5以上のモデルだとtorch.visionのmnsだとintがオーバーフローしてしまい、エラーを吐かれてしまいました。
なので、nms実装も上のリポジトリで変更しています。
まとめ
お世辞にもきれいと言える実装ではないですが、とりあえず動くものができたので公開しました。
ただ、batch 1で学習したところで、Normalization系のモジュールが機能せず学習が思ったように進まないのであしからず…。
mAP(mean Average Precision)を手っ取り早く上げるには
はじめに
signateの物体認識コンペ(魚群検知)に参加したので、そのときに得た知見をいくつか共有したいと思います。(複数記事に分ける予定)
新記事公開しました。(21.02.11)
結論
先に結論を言ってしまうと、mAPを上げるには、推論時のconfidenceスコアのフィルターの値を小さくして大量に予測値を出すことです。
このコンペでは、1枚1クラス20まで予測を提出できたので、その上限まで予測値を出すのが良いです。
理由
お恥ずかしながらmAPの計算方法をきちんと把握してなかったのですが、計算式を追えば自明のことでした。
mAPの算出方法
わかりやすいQiita記事 qiita.com
Qiita記事の元記事 jonathan-hui.medium.com
物体認識の場合、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の値が最大の値に置き換えます。
そして、離散値なので、複数の点をサンプリングして積分計算します。 例として、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のコンテナの作り方
はじめに
この記事の亜種です。
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
オプションをつけることでpip
やapt
などを使って外部ライブラリをインストールできる
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を作成する方法は過去記事に書きましたので、そちらを参照してください。
singularityでubuntu20.04+python(+pipenv)環境を構築
はじめに
pythonは仮想環境が豊富なので、わざわざコンテナ化する必要ある?って思っていましたが、 いざGPUクラスタ上で動かすときに環境構築ハマったので、そのとき作成したpythonを動かすコンテナをSingularity Libraryに公開しました。
構成
が入ってます。
使い方
以下のsingularity libraryで公開しました。
実行方法
python_pyenv
というsandboxを作成する例-w
オプションをつけることでpip
やapt
などを使って外部ライブラリをインストールできる
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を作成する方法は過去記事に書きましたので、そちらを参照してください。
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での解決方法が見つかったので、参考にします。
解決方法(非推奨)
.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| +-----------+----------+-----------+----------+-------+---------+---+------------------+
参考文献
- サンプル集(group by詳しい)
- 関数まとめ
スライドの作りに便利なフリー素材サイト
はじめに
twitterでたまに回ってくる,スライド作成向け便利素材サイトをまとめました
画像系
freepik
- 高品質フリー素材画像サイト stories.freepik.com
Unsplash
pixabay
o-dan
図系
isoflow
- きれいなポンチ絵が掛けるサイト
- Really cool looking diagrams isoflow.io
スライド作り注意点
デザイン苦手な人がこれだけは避けるべき6選 pic.twitter.com/XifruFonum
— つだしん (@shin_5_9) 2020年6月24日
ubuntu18.04 noVNC dockerコンテナを公開しました
はじめに
この記事のSingularityコンテナを作成するべく,参照元のdockerコンテナを作成しました.
以下の素晴らしいリポジトリを使おうと思ったのですが,あいにくubuntu18.04に対応しておらず,リポジトリのメンテナンスも終わりそうです.
issueを漁ったところ,Fromをubuntu18.04にすれば動くらしいので,そこだけを変更したDockerfileGitHubに公開しました.
また,DokerHubでもコンテナを公開しました.
CentOSのアップデートバージョンを公開するかは悩み中です.(要望があれば行います.)
公開したもの
DockerHub
- https://hub.docker.com/r/tmyoda/ubuntu18-xfce-vnc
- https://hub.docker.com/r/tmyoda/ubuntu18-icewm-vnc
GitHub
SingularityコンテナでOpenCV+Boostを使ったC++コードをコンパイル
はじめに
研究でC++コードをpybind11を使ってPythonから呼んで強化学習をしています.
強化学習をGPU上で回したくなったのですが,残念ながらC++系ライブラリを導入するためのsudo権限が付与されておらず,サーバ上でC++コードが実行できません.
そこで,Singularityコンテナ上でビルド&実行までできる環境を作成して,そのままGPUを使った強化学習を行えるようにします.
コンテナ作成
作成したビルド&強化学習に必要な環境
実行方法は2つあります
- Singularity Libraryからpull
- .defファイルからローカルでbuild
Singularity Libraryからpull
Singularity Library(SyLabs)にコンテナを公開しました
以下のコードでビルドできると思います
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の詳しい使い方は以下の記事を参考にしてください
.defファイル
注意点
DockerHubで公開されている,
/consol/ubuntu-xfce-vnc
を使用したかったのですが,のubuntuバージョンが16.04までだったので,18.04に対応させたdocker container(tmyoda/ubuntu-xfce-vnc:18.04
)を作成し,DockerHubに上げたものをベースに作成しています.- 以下記事参照 tmyoda.hatenablog.com
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もMoJoCoもGUIです. というか,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の解説記事はこちらから
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のパネルが良く死ぬので初期化コマンド
xfce4-panel --quit pkill xfconfd rm -rf ~/.config/xfce4/panel rm -rf ~/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-panel.xml xfce4-panel