GPU 搭載＋Python＋VS Code の開発環境を作ってみた

# はじめに

生成 AI プログラミングを試してみています。

[生成 AI プログラムを試してみた #LLM - Qiita](https://qiita.com/tinymouse/items/ed64a452bcddf4b8af7d)

プログラムの実行環境は、Google Colab を使ってきました。このサービスは、スクリプトを一時的に実行して結果を確認するには便利です。ただし、一定時間が経過するとプログラムの実行が中断されたり実行環境がリセットされるので、実行するたびにライブラリをインストールし直さないといけなかったり、チューニングなど時間の掛かる処理するには適していません。
Google Colab Enterprise や Vertex AI Workbench なども検討しましたが、GPU 搭載＋Python の実行環境を自分で用意してみようと思いました。併せて IDE（統合開発環境）も導入しておきたいと思います。

# GPU 搭載＋Python＋VS Code の開発環境を検討する

GPU を搭載したマシンを物理機で用意すると高価になります。クラウドサービスで仮想マシンを用意しようと思います。
実行環境に、Python を導入します。
IDE（統合開発環境）は、Visual Stduio code（VS Code）を使うことにします。
どのように構築できるか検討してみました。

## Python＋VS Code の導入パターン

Python 環境と VS Code を導入するパターンを検討します。

![構築イメージ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114460/1bee3302-8f88-a3d6-8822-d9d97e46d84c.png)

### 構築イメージ①

実機に Python 環境と VS Code を導入します。
VS Code はデスクトップ環境がないと使えません。クラウドサービスの仮想マシンで用意できる Linux 機は、基本的にコマンドラインシェルだけのイメージなので、これが使えません。Windows 、Mac OS 、Linux デスクトップ環境なら問題ありません。

### 構築イメージ②

デスクトップ環境のあるクライアント機に VS Code を入れて、Python 実行環境にリモート接続できます。VS Code の `Remote SSH` 拡張機能を使います。
これならリモート機がコマンドラインシェルだけの環境で使えます。
クライアント機とリモート機は SSH 通信します。設定が少々面倒です。

参考：[VSCodeでSSH接続 | SRIA BLOG](https://www.sria.co.jp/blog/2021/06/5316/) 

### 構築イメージ③

VS Code の `Remote Tunnel` 機能を使います。リモート機の VS Code は `--tunnel` を指定して起動します。Microsoft の中継サーバを経由して、クライアント機の VS Code で接続して操作できます。
接続の設定もウィザード形式で難しくありません。クライアント機の VS Code はクラウドサービス（vscode.dev）をウェブブラウザで使えて便利です。

参考：[VSCode の Remote Tunnels で「いつもの開発環境へ」お手軽リモート接続](https://zenn.dev/hankei6km/articles/connect-my-machine-via-vscode-remote-tunne)

### 構築イメージ④

Python 実行環境は Docker を使って用意するといいかも知れません。
VS Code の `Remote Containers` 拡張機能を使うと、Docker で用意した実行環境に接続して操作できます。

参考：[【Visual Studio Code】Dockerコンテナに接続しよう（Dev Containersの使い方） | ひろぴよのDX日記](https://it-dxblog.com/vscode-remote-containers/)


### 構築イメージ⑤

VS Code の `Remote Tunnel` を使って操作するリモート機に、Dokcer で Python 実行環境を用意して、そこに接続して操作できるとよさそうです。
試してみたのですが、できませんでした。残念です。

### 構築イメージ⑥

Docker で用意した実行環境に、VS Code をインストールして `Remote Tunnel` するのはどうでしょうか。
試してみたところ、可能でした。ただし、問題もありました。コンテナを作成し直すと、接続の設定がなくなってしまい、設定の作業し直さないといけませんでした。

## GPU＋Python 環境の構築パターン

用意する実機は、GPU を搭載していて、Python 環境で利用できないといけません。

そのために、GPU を搭載したマシンを用意します。NVIDIA 製の GPU を選ぶことが一般的です。

> 例えば Google Compute Engine サービスで利用できる NVIDIA の GPU は、以下のものがあるようです。
> * NVIDIA P4・・コストパフォーマンスに優れ、レコメンドシステム、画像分類、自然言語処理などの推論タスクに適しています。
> * NVIDIA T4・・P4 より高性能で、機械学習の推論や、リアルタイムの画像処理など、幅広い処理に適しています。
> * NVIDIA L4・・コストパフォーマンスに優れ、T4 より低性能だがメモリが大きい。推論や画像処理など、比較的軽い処理に適しています。
> * NVIDIA P100・・V100 と同様に高性能ですが、V100 より少し古いモデルです。コストパフォーマンスは V100 より劣ります。
> * NVIDIA V100・・T4 よりも高い演算性能を持っていて、大規模な深層学習モデルの学習や、高解像度の画像処理などに適しています。
> * NVIDIA A100・・最新で、非常に高い性能を持っています。大規模な言語モデルや自然言語処理など、最先端の AI 処理に適しています。
> * NVIDIA H100・・A100 の後継モデルで、さらに高い性能と効率性を備えています。大規模言語モデルや生成 AI など、最先端の AI  処理に最適です。

OS に `NVIDIA ドライバ` と `CUDA ツールキット` を導入します。

> CUDA（Compute Unified Device Architecture）とは、コンピュータのグラフィックスプロセッサ（GPU）を利用して汎用の並列計算を行うためのソフトウェア開発・実行環境の一つ。NVIDIA 社が自社製 GPU 向けに開発・提供している。専用のプログラミング言語やコンパイラ、ライブラリ、API などで構成される。標準では C 言語、C++言語をベースにした「CUDA C」「CUDA C++」でコードを記述するが、Fortran 、Java 、Microsoft .NET 、Python 、Perl 、Ruby など他の言語で開発するためのソフトウェアも提供されている。

さらに `Python` エンジンおよび `PyTorch` など必要なライブラリを導入します。

> Python 環境から CUDA を利用するために、`PyCuda` ライブラリが用意されている。これと別に、AI プログラミングで利用されることの多い `PyTorch` ライブラリは、CUDA を利用できるよう対応している。

以上の環境をどのように構築できるか検討してみました。

![構築パターン.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114460/958291f6-c2ab-a38e-7a99-830fe456f070.png)

### 構築パターン①

GPU を搭載したマシンを用意します。ここに NVIDIA ドライバ、CUDA 、Python をインストールします。Windows 、Mac OS 、Linux OS のいずれも同様に準備できます。
搭載されている GPU や利用したい PyTorch のバージョンに合わせて、適切なバージョンのドライバと CUDA を選んでインストールしないと、不整合エラーになります。慣れないと面倒です。

参考：[UbuntuでCUDA，NVIDIAドライバ，cudnnをインストールし，PyTorchでGPU環境を使えるようにするまで #Python - Qiita](https://qiita.com/tf63/items/0c6da72fe749319423b4)

### 構築パターン②

前述の構築イメージ④ないし⑥の通り、Python 環境を Docker で用意するパターンです。

参考：[UbuntuにDockerをインストール！GPUをコンテナから使う方法 | EdgeHUB](https://highreso.jp/edgehub/machinelearning/ubuntudocker.html)

### 構築パターン③

Google Compute Engine サービスで仮想マシンを作るとき、予め用意されたブートディスクイメージから使用したいものを選ぶだけで、GPU 搭載＋Linux OS＋NVIDIA ドライバ＋CUDA＋Python の仮想マシンを容易に作成できます。

参考：[爆速でGCPにリモートAI開発環境を構築する方法🔥 | TC3株式会社｜GIG INNOVATED.](https://www.tc3.co.jp/how-to-build-ai-environment-on-gcp/)

## 結論

適切なイメージを選んで容易に実行環境を作成できる（構築パターン③）なら、Docker で適切なイメージを選んでコンテナ環境を作成するのと同じようなものです。これでいいでしょう。
このとき、作成される Linux OS はデスクトップ環境がありません。VS Code を使用するのに、`Remote Tunnel` 機能を使う（構築イメージ③）がいいように思います。

### 構築イメージ⑦

仮想マシンを容易に作成し直せるのはいいのですが、そこに保存したデータを誤って失うおそれがあります。ソースコードなどの永続化したいデータを保存するフォルダは、仮想マシンと別に用意しておいて参照するのがいいですね。

参考：[RcloneでGoogleドライブをローカルPCにマウント | DevelopersIO](https://dev.classmethod.jp/articles/mounted-google-drive-using-rclone/)

この構築イメージで、開発環境を作ってみました。

# GPU 搭載＋Python＋VS Code の開発環境を作ってみた

## Google Compute Engine で仮想マシンを用意する	

Google Compute Engine で仮想マシンを用意します。

[Google Compute Engine に Ubuntu デスクトップ環境を作ってリモート接続してみた #GoogleCloud - Qiita](https://qiita.com/tinymouse/items/ac1b26a985b82e44465f)

VS Code の `Remote Tunnel` 機能を使うとき（構築イメージ③）は、デスクトップ環境とリモートデスクトップ接続を設定する必要ありません。
> 実機に VS Code を導入する（構築イメージ①）ときは、デスクトップ環境まで構築してリモートデスクトップ接続できるようにします。

### GPU を搭載したマシンを作り、ドライバ＋CUDA＋Python が用意されたイメージを使う

[爆速でGCPにリモートAI開発環境を構築する方法🔥 | TC3株式会社｜GIG INNOVATED.](https://www.tc3.co.jp/how-to-build-ai-environment-on-gcp/)

上記の作業のうち「マシンの構成を設定する」とき、GPU を搭載したマシンを選びます。

* マシンファミリー：GPU
* GPU のタイプ：NVIDIA T4 ←必要に応じて選択
* GPU の数：1　←必要に応じて選択
* マシンタイプ：n1-standard-8　←必要に応じて選択
　シリーズ：N1
　CPU の数：8
　メモリ：30GB

上記の作業のうち「ブートディスクの設定する」とき、OS に「Deep Learning on Linux」を選びます。

* OS：Deep Learning on Linux
* バージョン：Deep Learning VM with CUDA 12.3 M124
Debian 11＋Python 3.10＋Cuda 12.3

## 仮想マシンを起動して接続する

仮想マシンを起動してクライアント機から接続します。コマンドラインシェルに SSH 接続、あるいはデスクトップ環境にリモートデスクトップ接続します。

## 仮想マシンに VS Code を導入する	

仮想マシンに VS Code を導入してクライアント機のウェブブラウザで操作します。
 
[VSCode CLIを利用したVSCode Tunnelのセットアップ](https://gist.github.com/so298/0dbd9211c4a791e25b3870b35250caa2)

> リモートデスクトップ接続したデスクトップ環境に VS Code を導入しても構いません。
>
> [UbuntuでVSCode（日本語版にもできるよ）を使う | BLOGs win](https://blog.winproject.jp/ubuntu-vscode-japanese-language.html)
 
## ソースコードのフォルダを開発環境の外部に置く	

ソースコードなどのデータを保存するフォルダは、開発環境と別に用意しておいて参照するようにしたいと思います。

`Rclone` を使って Google ドライブにあるフォルダを Linux 環境でアクセスできるようにします。

[RcloneでGoogleドライブをローカルPCにマウント | DevelopersIO](https://dev.classmethod.jp/articles/mounted-google-drive-using-rclone/)

### Rclone を設定する

①Rclone をインストールします

```console
$ sudo apt install rclone
```

②設定を実行します

```console
$ rclone config
```

③新規設定するので「n) New remote」を選択します。
④`name` を指定します。例えば「gdrive」にします。
⑤`Type of storage` は「drive」を指定します。
⑥`client_id` と `client_secret` を指定します。以下参照
⑦`scope` は「1. Full access」を指定します。
⑧`root_folder_id` は空で構いません。
⑨`service_account_file` も空で構いません。
⑩`advanced config` は「No (default)」で構いません。
⑪`Use web browser to automatically authenticate rclone with remote?` に対応します。以下参照
⑫設定内容を確認して「y) Yes」を指定します。

#### client_id を指定するための準備

面倒なのは、独自の `clinet_id` を使うために予め Google Cloud で準備することでしょうか。

[RCLONE > Googleドライブ > 自分だけのclient_idを作る](https://rclone-org.translate.goog/drive/?_x_tr_sl=en&_x_tr_tl=ja&_x_tr_hl=ja&_x_tr_pto=wapp#making-your-own-client-id)

①ウェブブラウザで Google Cloud サービスのコンソールにログインします。使用する Google アカウントは、アクセスする Google ドライブと同じアカウントでなくて構いません。
②Google Cloud のプロジェクトを選択します。仮想マシンを作成しているプロジェクトで構いません。
③「API とサービス」→「有効な API とサービス」→「API とサービスを有効にする」で「Google Drive API」を有効にします。
④「API とサービス」→「OAuth 同意画面」
⑤上記の画面で、ユーザタイプ「外部」を指定して「作成」します。「アプリ名」「ユーザサポートメール」「デベロッパの連絡先」を入力して「保存」します。以下の「スコープ」を追加します。
・https://www.googleapis.com/auth/docs
・https://www.googleapis.com/auth/drive
・https://www.googleapis.com/auth/drive.metadata.readonly
⑥上記を「保存」して「テストユーザ」に自分を追加します。そして「保存」します。
⑤「API とサービス」→「認証情報」で「認証情報を作成」の「OAuth クライアント ID」を選択します。
⑧アプリケーションの種類「デスクトップアプリ」を指定して「名前」を入力して「作成」します。
⑨「クライアント ID」と「クライアントシークレット」が作成されるので記録します。

#### デスクトップ環境がないとき

さらに困ったのは、デスクトップ環境がないリモート機のコマンドラインシェルに接続していと、途中のウェブブラウザで認証を求められるときです。

```
Use web browser to automatically authenticate rclone with remote?
 * Say Y if the machine running rclone has a web browser you can use
 * Say N if running rclone on a (remote) machine without web browser access
If not sure try Y. If Y failed, try N.

y) Yes (default)
n) No
y/n> 
```

上記まで進んだとき、通常は [Y] を選択します。するとウェブブラウザが起動して Google の認証画面が開きます。ところがコマンドラインシェルに接続しているので、ウェブブラウザは起動できません。そこで [N] を選択することになります。

```
Option config_token.
For this to work, you will need rclone available on a machine that has
a web browser available.
For more help and alternate methods see: https://rclone.org/remote_setup/
Execute the following on the machine with the web browser (same rclone
version recommended):
        rclone authorize "drive" "eyJjbGllbn (以下略)"
Then paste the result.
Enter a value.
config_token> 
```

ここで、以下の手順が必要になります。
①ウェブブラウザが使える別のマシンを用意する。接続しているクライアント機でいいでしょう。
②そのマシンに `rclone` をインストールします。
③コマンドプロンプトで上記の画面に表示された `rclone authorize "drive" "eyJjbGllbn (以下略)"` を実行します。
④ウェブブラウザで Google の認証画面が開きます。認証を許可します。`Success! All done. Please go back to rclone.` が表示されます。
⑤上記③のコマンドプロンプトに以下のような表示されます。

```
2024/08/11 00:00:00 NOTICE: If your browser doesn't open automatically go to the following link: http://127.0.0.1:53682/auth?state=(以下略)
2024/08/11 00:00:00 NOTICE: Log in and authorize rclone for access
2024/08/11 00:00:00 NOTICE: Waiting for code...
2024/08/11 00:00:00 NOTICE: Got code
Paste the following into your remote machine --->
(中略)
<---End paste
```

上記の `--->` と `<---` の間の文字列を、rclone の設定している画面の `config_token>` に貼付けます。

```
Configure this as a Shared Drive (Team Drive)?

y) Yes
n) No (default)
y/n> 
```

この画面までくれば、通常の手順に戻ります。

### マウントする

Google ドライブにあるフォルダを Linux 環境でマウントしてアクセスできるようにします。

Linux 環境でマウントポイントを作成しておきます。例えば

```
mkdir ~/gdrive
```

ここに Google ドライブの「マイドライブ」をマウントします。

```console
rclone mount gdrive: ~/gdrive --daemon
```

ここで再起動するとマウントが解除されてしまいます。起動時に自動でマウントするようにしたいと思います。

参考：[Ubuntu 18.04でOneDrive を使う！ --- 導入からデスクトップ上への起動時の自動マウントまで --- - 初学者による初学者のためのPython](https://gen-todoroki.hatenablog.com/entry/ubuntu-onedrive)

`crontab` に設定を追加します。

```console
$ crontab -e
```

以下の内容を追記します。

```
@reboot rclone mount gdrive: ~/gdrive &
```

#### rclone mount に失敗した

ここｄ困ったのが、`rclone mount` が失敗したことです。以下のエラーになりました。

```
2024/08/11 00:00:00 Fatal error: failed to mount FUSE fs: fusermount: exec: "fusermount3": executable file not found in $PATH
```

以下の記事を見つけました。

[Rclone 1.62.2 Fatal error: failed to mount FUSE fs: - Help and Support - rclone forum](https://forum.rclone.org/t/rclone-1-62-2-fatal-error-failed-to-mount-fuse-fs/37073/8)

以下のコマンドを実行します。

```shell
$ ln -s /bin/fusermount /bin/fusermount3
```