Pythonおよび機械学習勉強用のRaspberryPiの構築 (RaspberryPi4 & Buster版 (RaspberryPi3も可))

## 【内容】
- **2020/02/19 一部内容を見直し、Raspberry Pi 3 model Bでも動作確認しました。**
- **Node-REDの環境構築を追加しました。**

ついにRaspberry Pi 4 model Bが日本で発売を開始しました。
早速使って見るべく、以前投稿した[【Pythonおよび機械学習勉強用のRaspberryPiの構築】](https://qiita.com/rhene/items/71b92c253d5ac2a4cc52)をラズパイ4版に書き直してみました。
ハードウェア以外にもRaspbianのバージョンを最新(Buster 20200213)にしてあります。
また、**Raspberry Pi 3 model B**でも同じ手順で環境構築できることを確認済みです。

なお、2020年02月19日現在、以下の問題があります。

- pip3でインストールできるTensorFlowの最新版が1.14.0 (2020/02/19時点)
- `import tensorflow` 実行時にエラーが出る (無視できる?)
- ~~Edge TPUが正式には対応していない (← 非公式手順で対応)~~
- ~~pip3でインストールできるOpenCVの最新版4.1.1.26が動かない (← 4.1.0.25 なら動く)~~
- ~~pip3でインストールできるOpenCVでUSBカメラが利用できない。 (← apt installで対応 3.2.0)~~
- ~~MicroHDMIケーブルを持ってないので画面がない^^; (← [Headlessセットアップ](https://qiita.com/rhene/items/828858afae699c5ac0ab)してます)~~


## 【本手順で作ったラズパイでできるようになること】
- Pythonの基礎学習
- データの可視化 (pandas, matplotlib)
- Computer Vision (OpenCV)
- 機械学習 (Scikit-Learn)
- DeepLearning (TensorFlow, Keras)
- Coral Edge TPUを使った推論
- 上記を使ったアプリの実装 (Flask)
- Jupyter Lab
- Node-RED


## 【システム構成】
- Raspberry Pi 3 または 4 Model B
- Raspbian Buster 20200213
- Coral Edge TPU (オプション)


## 【0. OSイメージの準備】
Raspbian Buster 20200213を使うことを想定しています。
2020年02月19日時点では公式サイトからはDLできますが、念の為ミラーサイトを記しておきます。
[【Raspbian Buster 20200213 ミラーサイト (ftp.jaist.ac.jp) 】](http://ftp.jaist.ac.jp/pub/raspberrypi/raspbian/images/raspbian-2020-02-14/2020-02-13-raspbian-buster.zip)


## 【1. OSイメージの書き込み & 起動】
### 1-1. OSイメージの書き込み
上記で準備したOSイメージをSDカードに書き込みます。
SDカードへの書き込み手順は、以下の記事を参考にしてください。

-  [【www.raspberrypi.org - Installing operating system images】](https://www.raspberrypi.org/documentation/installation/installing-images/README.md)

- [【Raspberry PiをHeadlessでセットアップする】](https://qiita.com/rhene/items/828858afae699c5ac0ab)

### 1-2. ssh起動用ファイルの作成
現行バージョンのRaspbianではデフォルトではsshサービスが無効化されています。
これを自動起動できるようにSDカードの「Boot」パティションに`ssh`(拡張子なし)という空のファイルを作ってください。
windowsをご利用の方は、標準では拡張子が非表示になっているので、拡張子が付いていないか確認してください。

なお、`ssh`ファイルはRaspberry Pi起動時に読み込まれて削除されます。


### 1-3. Wifi接続用の設定ファイルの作成
ssh同様、「Boot」パティションにWifi設定用のファイルを置いておくと、自動的に読み込まれて適切な場所に書き込まれます。

具体的には「Boot」パティションに`wpa_supplicant.conf`という名前のファイルを作り、設定を記述します。
Wifiに接続するためには下記の内容を記載してください。
設定内容は接続するアクセスポイントに応じて変更する必要があります。

```wpa_supplicant.conf
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
country=JP

network={
    ssid="<SSID名>"
    psk="<パスワード>"
}
```

ActiveDirectoryと連携したRADIUSサーバとの認証が必要な場合は、下記の記事を参考にしてください。
[【ラズパイからADと連携したRADIUS認証が必要な無線LANに接続する (WPA2-EAP)】- Qiita](https://qiita.com/rhene/items/1fa28208b14639b87bda)

### 1-4. Raspberry Piの起動
上記の準備ができたらPCからSDカードを取り出し、ラズパイ本体に挿入して電源を投入します。


## 【2. システムアップデート & ネットワーク設定】
### 2-1. システムアップデート
ラズパイが起動したらsshで接続するかコンソールのターミナルで以下のコマンドを実行して、システムアップデートを行います。
(数分かかります)

```bash:システムアップデート
sudo apt update
sudo apt upgrade -y
sudo reboot
```

### 2-2. ipv6 無効化 (オプション)
必須ではありませんが、場合によっては邪魔する場合があるので無効化しておきます。
ipv6運用の場合は本設定は必要ありません。

```bash:ipv6無効化設定
sudo vi /etc/sysctl.conf
```

【設定内容】

```/etc/sysctl.conf
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
```

【設定の反映】

```bash:設定反映
sudo sysctl -p

または

sudo reboot
```

### 2-3. IPアドレスの固定 (オプション)
必要に応じてIPアドレスを固定します。
DHCP環境で利用する場合は本設定は必要ありません。
本手順では無線LANでの運用を想定しているため、無線LANアダプタもしくはSSIDに対してIPの固定設定をしています。
具体的には `/etc/dhcpcd.conf` に以下の内容を追加します。
`<IPアドレス>`、`<ルータアドレス>`、`<DNSアドレス>`、`<your_ssid>`は環境に応じて変更してください。

```/etc/dhcpcd.conf
interface wlan0
inform <IPアドレス>
static routers=<ルータアドレス>
static domain_name_servers=<DNSアドレス>
noipv6

または

SSID <your_ssid>
inform <IPアドレス>
static routers=<ルータアドレス>
static domain_name_servers=<DNSアドレス>
noipv6
```
複数の無線AP環境で利用する場合はSSIDで固定するのが便利です。


### 2-4. 無線LANのPowerManagementをOFFにする (オプション)
有線LAN環境で利用する場合は本設定は必要ありません。
デフォルトでは無線LANのPowerManagement機能がONになっていますが、この機能のせいでWifi通信が不安定になる場合があります。
起動時に実行される`rc.local`にPowerManagementをOFFにするコマンドを追加します。

```bash:rc.localの編集
sudo vi /etc/rc.local
```

```rc.local
# exit文の前に以下を追加して保存
sudo iwconfig wlan0 power off
```

```bash:再起動
sudo reboot
```

## 【3. 必要モジュールのインストール】
以下の操作で必要になるモジュールをインストールします。
(主にOpenCVおよびNumpyで利用)

```bash:必要モジュールインストール
sudo apt install -y libhdf5-dev libqtwebkit4 libqt4-test libatlas-base-dev libjasper-dev
```


## 【4. Python3 関連のインストール】
### 4-1. 基本モジュールのインストール
```bash:Python3&pip3インストール
sudo apt install python3 python3-dev -y
```

なお、Busterでは事前にインストール済みのため、本操作は必要ありませんでした。

#### 4-1-1. pip3の最新化 (オプション)
**本手順は特に実行する必要はありません**

過去の手順を踏襲してpip3コマンドを最新化すると、pip3実行時にエラーを吐いて機能しなくなります。

```bash:pip3のアップグレード【失敗】
# 下記コマンドを実行するとpip3が実行できなくなります
sudo pip3 install pip -U
pip3 -V

# 上記コマンドでpip3が動かせなくなったら、下記コマンドでリカバリ
sudo python3 -m pip uninstall pip
sudo apt install python3-pip --reinstall
```

一応、下記の手順でpip3コマンドを最新化することは可能ですが、本手順では特に必要ありませんでした。

```bash:pip3のアップグレード(オプション)
# 既存のpip3コマンドをアンインストール
sudo apt remove python3-pip

# 最新のpip3コマンドをインストール
wget https://bootstrap.pypa.io/get-pip.py
sudo python3 get-pip.py
pip3 -V

# setuptoolsの最新化
sudo pip3 install setuptools -U
```

### 4-2. Python3の各種モジュールインストール
pipコマンドで各種のモジュールをインストールします。
~~numpyおよびpandasのバージョンを指定していますが、環境構築時点で最新のバイナリーパッケージが存在せずビルドが始まってインストールに時間がかかってしまうため、一つ前のバージョンを指定しています。
TensorFlowに関しては、環境構築時点で動作確認が取れている最新のものを指定しています。~~
各モジュールは2020/02/19時点でPython3.7系でパッケージインストールできる最新バージョンを指定しています。
それぞれ必要に応じてバージョンを変更してください。


```bash:Python3用各種モジュールインストール(2020/02/19時点)
# numpy
sudo pip3 install numpy==1.18.1

# scipy
sudo pip3 install scipy==1.4.1

# sklearn
sudo pip3 install scikit-learn==0.22.1

# matplotlib
sudo pip3 install matplotlib==3.1.3

# pandas
sudo pip3 install pandas==1.0.1

# seaborn
sudo pip3 install seaborn==0.10.0


# Tensorflow (2020/02/19時点で最新は1.14.0)
sudo pip3 install tensorflow
# pip3を最新化した場合は `--ignore-installed` オプションを付けて対応
#sudo pip3 install tensorflow --ignore-installed 

# keras (tf.kerasを使うのであれば不要)
# sudo pip3 install keras

# flask
sudo pip3 install flask flask_cors -U

# OpenCV
sudo pip3 install opencv-python==4.1.1.26
# 環境変数の変更と反映 (← これをやらないと `import cv2` 実行時にエラーになる)
echo "export LD_PRELOAD=/usr/lib/arm-linux-gnueabihf/libatomic.so.1" | tee -a ~/.bashrc
source ~/.bashrc

# cv2.VideoCaptureで複数のカメラが上手く使えない場合は apt インストールで暫定対応 (ただし3.2.0)
# sudo pip3 uninstall opencv-python
# sudo apt install python3-opencv
```

なお、最近パッケージを管理している「[https://www.piwheels.org/](https://www.piwheels.org/)」の調子が悪いのか、pipがパッケージをダウンロードしている最中にセッションを切断され、結果インストールに失敗する場合が多々あります。
再実行すれば解決することが多いですが、scipyやtensorflowなどダウンロードサイズが大きいものはなかなか成功しません。
その際にはpip install実行時に表示されるダウンロード中のパッケージのURLをコピーして、`wget`コマンドでそのファイルをローカルフォルダにダウンロードしてください。
`wget`コマンドはダウンロードに失敗してもリジューム機能があるので、自動的にリトライしてなんとか目的のファイルをダウンロードしてくれます。
そのうえで`sudo pip3 install <ダウンロードしたファイル>`を実行するとインストールできます。

ミラーサイトがあればpipの参照先をそちらに向ければよいのですが、本記事を書いている時点ではわかりませんでしたので、ご存じの方がいらっしゃいましたら教えていただけると助かります。


## 【5. Edge TPU のインストール】(オプション)
本項目は必須ではありません。
Edge TPUを使う場合のみ実行してください。


```bash:EdgeTPU用のライブラリのインストール
echo "deb https://packages.cloud.google.com/apt coral-edgetpu-stable main" | sudo tee /etc/apt/sources.list.d/coral-edgetpu.list

curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -

sudo apt update

# 通常版
sudo apt install libedgetpu1-std
# または、最大クロック版
# sudo apt install libedgetpu1-max
```

```bash:TFLiteインストール
sudo pip3 install https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp37-cp37m-linux_armv7l.whl
```

```bash:Edge_TPU_Python_APIインストール
sudo apt install python3-edgetpu
```

## 【6. Jupyter Lab】
強力なNotebook環境が利用できるようになるJupyter Labをインストールします。

### 6-1. 基本インストール
【インストール】
下記のコマンドでインストールします。

```bash:JupyterLabインストール
sudo pip3 install jupyterlab
```

【設定】
インストールが完了したら下記のコマンドで設定ファイルを作成した上で、作成された設定ファイルを編集します。
下記手順ではどの端末からも接続でき、接続時にパスワードを要求するように設定しています。

```bash:設定ファイルの作成
jupyter notebook --generate-config
```
【設定ファイルの編集】

```bash:設定ファイルの編集
vi ~/.jupyter/jupyter_notebook_config.py
```
【設定内容】

```jupyter_notebook_config.py
c.NotebookApp.ip = '*'
c.NotebookApp.open_browser = False
c.NotebookApp.password = 'sha1:<ハッシュ化されたパスワード>'
```

なお、パスワードのハッシュ化は以下のコマンドで取得できます。

```bash:パスワードのハッシュ化
python3 -c 'from notebook.auth import passwd;print(passwd())'
(上記実行後、ハッシュ化したい文字を入力)
```


### 6-2. Jputer Labの起動とサービス化
Jupyter Labの起動は以下のコマンドで実行します。

```bash:JupyterLab起動
jupyter lab
```

サービス化については、まずサービス用の設定ファイルを準備します。

```bash:サービス用ファイル準備
sudo vi /etc/systemd/system/jupyter.service
```

ファイルの内容は以下の通り。

```bash:/etc/systemd/system/jupyter.service
[Unit]
Desctiption = Jupyter Lab
After = syslog.target

[Service]
Type = simple
WorkingDirectory = /home/pi
Restart = always
ExecStart = /usr/local/bin/jupyter lab
User = pi
Group = pi

[Install]
WantedBy = multi-user.target
```

ファイルの準備ができたら下記コマンドでサービスの有効化と開始を行います。

```bash:コマンド
# サービス有効化
sudo systemctl enable jupyter.service 

# サービス開始
sudo systemctl start jupyter.service 
```






### 6-3. ブラウザから接続
上記でJupyter Labを起動した状態で、ブラウザから以下のURLに接続してください。
上記手順では、他のPCからも接続できる設定になっていますので、ぜひご自分のPCからJupyterLabに接続して操作してみてください。

```
http://<ip_address>:8888/lab
```
パスワードを要求されるので、上記で設定したパスワードを入力してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/454012/44ff9dd0-1b2c-5aaf-bc2b-0b400b795301.png)


## 【7. Node-RED】
### 7-1. Node-REDのインストール
以下のコマンドを実行することでNode-REDを実行する環境を作ることができます。

```bash:Node-REDのインストール
bash <(curl -sL https://raw.githubusercontent.com/node-red/linux-installers/master/deb/update-nodejs-and-nodered)
```

下記メッセージが表示されるので、 `y` を押してEnterを押す。
**なお、古いnode.jsがインストールされている場合は新しいものに置き換わりますので、問題がある場合は本手順は実行しないでください。**
本手順ではまっさらな状態からのインストールを想定していますので、そのまま実行します。

```
This script will remove versions of Node.js prior to version 7.x, and Node-RED and
if necessary replace them with Node.js 10.x LTS (dubnium) and the latest Node-RED from Npm.

It also moves any Node-RED nodes that are globally installed into your user
~/.node-red/node_modules directory, and adds them to your package.json, so that
you can manage them with the palette manager.

It also tries to run 'npm rebuild' to refresh any extra nodes you have installed
that may have a native binary component. While this normally works ok, you need
to check that it succeeds for your combination of installed nodes.

To do all this it runs commands as root - please satisfy yourself that this will
not damage your Pi, or otherwise compromise your configuration.
If in doubt please backup your SD card first.

Are you really sure you want to do this ? [y/N] ?
```

引き続き、以下のメッセージが表示されるので同じく `y` を選択して先に進む。

```
Would you like to install the Pi-specific nodes ? [y/N] ?
```
(Pi固有のノードをインストールしますか?)

インストールが進むと、以下のように表示されます。

```
Running Node-RED update for user pi at /home/pi on raspbian


This can take 20-30 minutes on the slower Pi versions - please wait.

  Stop Node-RED                       ?
  Remove old version of Node-RED      ?
  Remove old version of Node.js       ?
  Install Node.js LTS                 ?   Node v12.16.0   Npm 6.13.7
  Clean npm cache                     ?
  Install Node-RED core               ?   1.0.3
  Move global nodes to local          -
  Install extra Pi nodes              -
  Npm rebuild existing nodes          -
  Add shortcut commands               ?
  Update systemd script               ?


Any errors will be logged to   /var/log/nodered-install.log
All done.
  You can now start Node-RED with the command  node-red-start
  or using the icon under   Menu / Programming / Node-RED
  Then point your browser to localhost:1880 or http://{your_pi_ip-address}:1880

Started  2020年  2月 19日 水曜日 15:45:42 JST  -  Finished  2020年  2月 19日 水曜日 15:48:04 JST
```

### 7-2. Node-REDの起動とサービス化
Node-REDの起動は以下のコマンドで行います。

```bash:Node-REDの起動
node-red
```

Node-REDのサービス化には以下のコマンドを使用します。
サービス化することで、ラズパイ起動時に自動的にNode-REDが実行されるようになります。

```bash:Node-REDのサービス有効化
sudo systemctl enable nodered.service
```

```bash:サービス起動(初回のみ、次回以降自動起動)
sudo systemctl start nodered.service
```



### 7-3. ブラウザから接続
上記でNode-REDを起動した状態で、ブラウザから以下のURLに接続してください。

```
http://<ip_address>:1880/
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/454012/d0919ea3-cd16-0e35-754a-6d46925970d2.png)



## 【最後に】
一部課題もありますが、ほぼ過去の手順を踏襲して環境を構築ができました。
まだ細かい動作確認は行っていなので、何かありましたらコメントください。


## 【既知の不具合】
### python3 で `import tensorflow` 実行時にエラーが表示される
TensorFlowを利用しようと `import tensorflow` を実行すると、下記エラーが表示されます。

```
2020-02-19 18:45:02.436414: E tensorflow/core/platform/hadoop/hadoop_file_system.cc:132] HadoopFileSystem load error: libhdfs.so: cannot open shared object file: No such file or directory
```

今のところ影響がないので、現時点では無視しています。


### pip install できる TensorFlow のバージョンが古い (2020/02/19時点)
ラズパイでパッケージインストール可能なTensorFlowの最新バージョンは `1.14.0` と少し古いのです。
tf1系なら最新バージョンの `1.15.0` を使いたいところです。
新しいバージョンを利用したい場合、自力でビルドする必要があります。
[TensorFlowの公式手順](https://www.tensorflow.org/install/source_rpi)には30分程度でビルド出来ると書いてありますが、何度かトライしてみたのですが、3時間以上かかって最終的に失敗します…

TensorFlowのバージョンについては @PINTO 氏がビルド済みのパッケージを公開していますので、そちらを利用すると、とても幸せになれます。
現時点でtf1系ならば `1.15.0`、tf2系ならば `2.1.0` が公開されています。

https://github.com/PINTO0309/Tensorflow-bin
https://github.com/PINTO0309/Tensorflow-bin/#usage

なお、こちらのパッケージを使うと上記のimport時のエラーも解消します。