細かすぎて伝わらない機械学習するときの環境構築Tips集



## この記事は

機械学習のプロジェクトを進める際に遭遇する
環境構築にまつわるtips集


プロジェクトのたびに忘れては検索しているので個人用にまとめていたものの一部を公開してみます

Tipsなので、このようなTipsがあると知っている場合は、検索すればわかりますが。

知らないことを知らないと調べることもできないので。
だれかの参考になればいいなと思い公開してみます。
初学者向けです


主にクラウドやIDEなどなど環境に関わることなので、
Pandasやグラフなどのトピックは省きました。



## シェルスクリプト

Bashの書き方。
急に忘れる、設定・変数・環境変数のsnippets


[シェルスクリプトを書くときはset -euしておく - Qiita](https://qiita.com/youcune/items/fcfb4ad3d7c1edf9dc96)

```bash
#!/bin/bash
set -eu # e: errorで止まる, u: 未知変数エラーで止まる

# 変数
DATA=/home/nohara/data/

# 第一引数
DEBU=$1

# Pythonの自作モジュールをパスに追加
export PYTHONPATH='../src'

# ディレクトリの中身削除するなら
rm -rf ${DATA}/02_interim/*

# 何かを実行
pipenv run python 001_pre_process.py \
							    -i ${DATA}/01_raw/data.csv \
							    -o ${DATA}/02_interim/data.pkl \
							    -d ${DEBUG}

# 何かを実行
pipenv run python 002_train.py \
							    -i ${DATA}/02_interim/data.pkl \
							    -o ${DATA}/03_outputs/model.pkl \
							    -d ${DEBUG}


```

`set -eu`を入れておきましょう。
これがないと、前後関係を無視してコードが走ってしまいエラーやバグの原因になります.




## Makefile

Makefileの書き方

変数・事前動作などなど.

よく使うスクリプトを登録しておくと便利です


```Makefile
SHELL=/bin/bash

nb:
	pipenv run jupyter notebook --port 8888 --no-browser

mlflow:
	pipenv run mlflow ui --host=0.0.0.0:5000

pep:
	pipenv run autopep8 --in-place --aggressive --aggressive  -r .
	pipenv run yapf -i -r  .
	pipenv run isort .

backup:
	gsutil -m rsync -r ./ gs://hogehoge/backup

```

以下の用に使えます.

```bash
# jupyter notebook を起動
$make nb
# mlflow ui を起動
$make mlflow
# pep でコード整形を実行
$make pep
# 例えばGCSへコードをバックアップ
$make backup
```

## SSH

キーの作り方。作り方はこの記事の通り.
[お前らのSSH Keysの作り方は間違っている - Qiita](https://qiita.com/suthio/items/2760e4cff0e185fe2db9)

```bash
ssh-keygen -t rsa -b 4096 -C "your.name@mail.com"
```

`./.ssh/config`を書くだけで、`ssh ts_proj_1`といったように接続が楽になります。

```bash
Host ts_proj_1
    HostName 32.184.123.21
    User tomoyuki.nohara

Host image_proj_1
    HostName 32.184.123.12
    User tomoyuki.nohara
```

私は、複数のインスタンスを使っていますが、機械学習用途の場合だとどのインスタンスでも、
jupyter notebookやmlflowを使うので、特定のポートは共通設定として登録しています。
便利です。

```s

Host ts_proj_1
    HostName 32.184.123.21
    User tomoyuki.nohara

Host image_proj_1
    HostName 32.184.123.12
    User tomoyuki.nohara

# アスタリスクを使って共通設定を追加可能
Host *
    LocalForward 8888 localhost:8888
    LocalForward 5000 localhost:5000
    LocalForward 5001 localhost:5001
    LocalForward 23750 /var/run/docker.sock	# Dockerへアクセス
    AddKeysToAgent yes		# パスフレーズを聞かれる頻度が減る
    UseKeychain yes			# パスフレーズを聞かれる頻度が減る
    ServerAliveInterval 60	# 再接続の設定

```


## fish

あまりシェルにこだわりなければ、とりあえずaptでfish入れておけば
入力がすごく楽になります。


```s
# ubuntu
$ sudo apt install fish

# mac
$ brew install fish
```

使い方 `fish` と打つだけ. 
すると補完が効くようになるのでとても便利です。



```s
$ fish

```


![スクリーンショット 2020-12-12 20.59.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62413/dde326eb-0853-0ac1-0d52-a85429bc1c60.png)

便利



## Git

何はともあれgitのセットアップ.

```bash
$ git config --global user.name "nopara"
$ git config --global user.email "nopara@mail.com"
```

あと、毎回パスワードを入れるのが面倒な場合、一定期間パスワードをキャッシュするオプションも地味に便利です

```bash
# gitのパスワードを一定期間だけ聞いてこなくなる.
$ git config --global credential.helper 'cache --timeout=3600'
```

基本形.

```bash
# 基本件
git add .
git commit -m ":)"
git push origin master
```

タグを切った際の挙動

```bash
# タグを追加
git tag -a v1.0 -m "model v1"
# タグもpush
git push origin --tags
```

## VSCode - Remote SSH の除外ファイル設定


![スクリーンショット 2020-12-12 21.25.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62413/9119e98c-0ad8-545d-88a4-bb327a327a79.png)



これ、プロジェクトの後半でよくハマって焦るやつ。VSCodeの`Remote SSH`プラグインを使って、クラウドインスタンスで作業するのですが、その際、`Remote SSH`は、指定したディレクトリの中身全てを「同期」しようと頑張ってしまいます。そのため、作業ディレクトリに`data`などが含まれたり、分析の最中に出力した大きなファイルがあると、同期に時間がかかってしまい、最悪の場合は全く動かなくなってしまいます。

そのため、初めの段階で除外するファイルやディレクトリを事前に指定しておくことをお勧めします。

リモート接続時に無視するディレクトリの指定
[Running Visual Studio Code on Linux](https://code.visualstudio.com/docs/setup/linux#_visual-studio-code-is-unable-to-watch-for-file-changes-in-this-large-workspace-error-enospc)



## hyperdash

hyperdashio/hyperdash-sdk-py: Official Python SDK for Hyperdash

```bash
# install
pipenv install hyperdash
# Login (アカウントがある場合)
pipenv run hyperdash login --email
# 実行
pipenv run hd run -n "Long Preprocess" bash download.sh 
```


## Slack 通知

slackへの通知は意外と簡単にできます


[Python3でslackに投稿する - Qiita](https://qiita.com/shtnkgm/items/4f0e4dcbb9eb52fdf316)

```Python
!pipenv install slackweb

import sys
import slackweb

slack = slackweb.Slack(url="https://hooks.slack.com/services/T02D36VHP/asfda")


if len(sys.argv) >= 2:
	msg = sys.argv[1]
	slack.notify(text=msg)
else:
	slack.notify(text="finish")

```


## GCP 関連

[よく使うgcloudコマンドたち - Qiita](https://qiita.com/masaaania/items/7a83c5e44e351b4a3a2c)


auth

```bash
# ログイン
gcloud auth login

# プロジェクト一覧
gcloud projects list

# プロジェクトの設定
gcloud config set project your_proj_id

```

GCE インスタンスの操作

```bash
# インスタンスの起動・停止
gcloud compute instances list
gcloud compute instances start <your-instance-name>
gcloud compute instances stop <your-instance-name>

```


SSH Configの作成.
`~/.ssh/config`にoptionが作成される.

```bash
# SSH Configを自動作成
gcloud compute config-ssh

```

GCSへの同期

```bash
# ローカル -> GCS 転送
gsutil cp ./dataset.csv gs://your-gucket-name/datas/

# -r は再帰処理。ディレクトリ送るときに使う。
gsutil cp -r gs://your-gucket-name/datas/ ./data
```


```bash
# 大量に送る
# -r : recursive
# -d : ローカルにないファイルをリモートから削除
# -m : 並列
gsutil -m rsync -r -d ./datalake gs://abeja_datalake/1702719765261
```



GCEファイヤーウォールの自動更新 
おまけですが結構便利です。
セキュリティの都合でインスタンスに ipアドレス制限をかけている場合、インターネット環境が変わるたびにコンソールからグローバルIPを登録するのが辛いなと思っていました。
以下のスクリプトで、グローバルIPを取得して、指定のファイヤーウォールを更新してくれます。

```bash
#/bin/bash
FIREWALL_NAME=ssh-access # <-------- 自分のファイヤーウォール名に書き換える


# Get Global IP .. 
GIP=$(curl https://httpbin.org/ip | jq -r ".origin")

# 一覧取得 / アップデート
gcloud compute firewall-rules list
gcloud compute firewall-rules update $FIREWALL_NAME --source-ranges=$GIP
gcloud compute firewall-rules describe $FIREWALL_NAME

```




## Jupyter Notebook

横幅を広げる。
どんなエクステンションよりも気に入っているハックです。
横広になりテーブルなどがとてもみやすくなります。

```python
from IPython.core.display import display, HTML
display(HTML("<style>.container { width:90% !important; }</style>"))
```





## tqdm
いつも使わせてもらっております。

引数や、その他の便利な使い方


[tqdm/tqdm: A Fast, Extensible Progress Bar for Python and CLI](https://github.com/tqdm/tqdm)

```py
class tqdm():

  def __init__(self, iterable=None, desc=None, total=None, leave=True,
               file=None, ncols=None, mininterval=0.1,
               maxinterval=10.0, miniters=None, ascii=None, disable=False,
               unit='it', unit_scale=False, dynamic_ncols=False,
               smoothing=0.3, bar_format=None, initial=0, position=None,
               postfix=None, unit_divisor=1000):
```

よく使うのは、descとdisableの二つ

```py
from tqdm.auto import tqdm

# desc: ログ出力用のdescribe
# disable: 表示/非表示
for target in tqdm(tqrgets, desc="Download hoge", disable=False):
    ...

```



pandasのapplyの処理がが長い場合に、tqdmを使ってプログレスバーを出すことができます.
[pandasのapplyの進捗をtqdmで表示 - iMind Developers Blog](https://blog.imind.jp/entry/2019/03/06/111152)


```python
tqdm.pandas(desc="my bar!")

df.progress_apply(lambda x: x**2)
df.progress_map(lambda x: x**2)
```



## warningを非表示


```py

import warnings
warnings.filterwarnings('ignore')
```

## timer

kaggle知見のコード。いつも使わせてもらっています。

[Kaggleコード遺産 - Qiita](https://qiita.com/kaggle_master-arai-san/items/d59b2fb7142ec7e270a5)

```py
import time
from contextlib import contextmanager

@contextmanager
def timer(name):
    t0 = time.time()
    yield
    print(f'[{name}] done in {time.time() - t0:.0f} s')
```







## ABEJAでは

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62413/de94773e-0530-2f45-0034-ac0d8ef83768.png)

[ABEJAでは一緒に仕事をする仲間を募集しています!!](https://hrmos.co/pages/abeja/jobs)
興味がある方がいましたら、カジュアル面談からでも、気軽にご連絡ください!!