M1 MacでPythonの機械学習環境を作る

Appleシリコン搭載のMac（いわゆるM1 Mac）において、機械学習環境の構築にかなり苦戦しましたので、対応方法をまとめておきます。
なお、時間の経過とともに各種ソフトウェアがM1 Macに随時対応していくものと思われますので、記事執筆時点（2021年9月）の情報としてご覧ください。

# PC環境
- macOS BigSur 11.6
- MacBook Air (M1, 2020)
- メモリ16GB

なお、Pythonは3.9を利用する前提で話を進めていきます。

# 今回のゴール
以下の2種類の方法を実施してみます。
1. Pythonの仮想環境を構築する方法
2. Dockerを利用する方法

また、機械学習環境を作るということで、Jupyter Notebookを起動して実装できる状態をゴールとします。

# 1. Pythonの仮想環境を構築する方法
## pipenvによる環境構築は茨の道
もともと私はpipenvを使って機械学習環境を構築してましたが、M1 Macではなかなか大変です。

```python
$ pip install pipenv
$ pipenv --python 3.9
$ pipenv install sklearn

ERROR: Command errored out with exit status 1: ... /Users/***/work/.venv/include/site/python3.9/scipy Check the logs for full command output.
✘ Installation Failed
```
現状、インストールできるパッケージもありますが、エラーになるパッケージも多く、それらは個々にエラーとなる原因を解決していかないといけません。

## 今はminiforgeが最適解
どうやら現時点でM1 Mac上にPythonによる機械学習環境を作るには、miniforgeを使うのが最も導入コストを抑えられそうです。
miniforgeとは、Pythonの必要最小限のパッケージとパッケージ管理システムのcondaを同梱した軽量のPythonディストリビューションです。

### miniforgeをインストール
1. https://github.com/conda-forge/miniforge からarm64 (Apple Silicon) 版をダウンロード
2. インストール

```bash
$ cd [download dir]
$ bash Miniforge3-MacOSX-arm64.sh  ※sh,zshにも対応してます
$ conda config --set auto_activate_base false
```
`auto_activate_base false` はターミナル起動時にbase環境を自動で立ち上げない設定です。

### condaで仮想環境を構築
例として、ml-envという仮想環境を構築し、必要なパッケージをインストールしていきます。

```bash
$ conda create -n ml-env python=3.9
$ conda activate ml-env
(ml-env) $ conda install pandas
(ml-env) $ conda install scikit-learn
(ml-env) $ conda install matplotlib
(ml-env) $ conda install jupyter
```
インストールしたいパッケージがcondaコマンド（conda-forgeリポジトリ）では見つからないケースもあります。その場合は、仮想環境上でpipコマンドでインストールすることも可能です。

```bash
(ml-env) $ pip install slackweb
```
### 主要なcondaコマンド
| コマンド                               | 説明                                    |
|:--------------------------------------|:---------------------------------------|
| conda create -n [env name] python=3.9 | 仮想環境作成（Pythonバージョンを指定）      |
| conda info -e                         | 仮想環境の一覧表示                        |
| conda activate [env name]             | 仮想環境に切り替える                      |
| conda info                            | 現在の仮想環境情報を表示                   | 
| conda install [pkg name]              | パッケージのインストール                   |
| conda uninstall [pkg name]            | パッケージのアンインストール                |
| conda list                            | インストールしたパッケージの表示             |
| conda deactivate                      | 仮想環境を終了する                         |
| conda remove -n [env name] --all      | 仮想環境を削除する                         |
| conda env export > [file name]        | 仮想環境設定をファイルに出力                |
| conda env create -f [file name]       | 設定ファイルをもとに仮想環境を再構築         |

その他コマンドは、[公式サイト](https://conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html)を参照してください。

## Jupyter Notebook起動
Jupyter Notebookを起動するには、仮想環境上で以下のコマンドを実行するだけです。

```bash
(ml-env) $ jupyter notebook
```

# 2. Dockerを利用する方法
## Dockerインストール
### Docker Desktop for Apple silicon をダウンロード
まず、[公式サイト] (https://docs.docker.com/desktop/mac/apple-silicon/) からM1 Mac用のDocker Desktopをダウンロードします。

### Rosetta２をインストール
M1 Mac用のDockerと言いつつも、現状はIntel製CPU上で動作する挙動のようで、Rosetta２を介して実行させる必要があります。

※ Rosetta２については [こちら](https://support.apple.com/ja-jp/HT211861) を参照

```bash
$ softwareupdate --install-rosetta
```
### Docker Desktopをインストール
ダウンロードしたファイルをダブルクリックして、Docker Desktopをインストールします。
![スクリーンショット 2021-09-26 20.12.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35420/a5b5eecc-ebf4-f121-8ebf-19995a28706a.png)

## DockerfileとPipfileを作成
あらかじめPipfileを作成しておいて、必要なパッケージをコンテナにインストールします。

```:Pipfile
[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true

[dev-packages]

[packages]
pandas = "*"
sklearn = "*"
matplotlib = "*"
jupyter = "*"

[requires]
python_version = "3.9"
```

```Dockerfile:Dockerfile
FROM python:3.9.7

WORKDIR /workspace/

ADD Pipfile /tmp/Pipfile

RUN cd /tmp && \
    pip install -U pip && \
    pip install pipenv && \
    pipenv install --system --skip-lock

CMD ["jupyter", "notebook", "--port=8888", "--no-browser", "--ip=0.0.0.0", "--allow-root"]
```
`pipenv install` のオプションは以下の意味になります。

| オプション        | 説明                                                         |
|:----------------|:-------------------------------------------------------------|
| --system        | パッケージを仮想環境ではなく、コンテナに直接インストール              |
| --skip-lock     | lockファイルを無視して、Pipfileのみでインストール                                       |

## イメージ作成とコンテナ起動
例として、ml-envというイメージを作成し、コンテナを起動します。

```bash
$ cd [build context dir]
$ docker build . -t ml-env
$ docker run -p 8888:8888 -it ml-env
```
## Jupyter Notebook起動
ブラウザから http://127.0.0.1:8888/ にアクセスすることで、Jupyter Notebookを利用できます。

# さいごに
現時点では、M1 Macにおける機械学習環境の選択肢は少ないと感じますが、それでもモデル構築作業において、不気味なくらい静かに負荷の高い処理を迅速に実行してくれる様は感動ものです。導入する価値は十分にあると思いました。