GPU付きPCをset upしてVSCodeでdocker環境を作ってみた

# そもそものきっかけ
E資格2025#1に合格しました(これに関しては別の記事で)、その際にdockerをゴリゴリ勉強する必要があり、調べてみるとdockerの環境ではGPUの設定も簡単にできるんだとか。それまではPythonのvenvで仮想環境作っていろいろ遊んでいたのですが、GPUを使ってみたいという願望と、将来的にdocker使えないとだめなんだろうなという焦りから、今回取り組むことに。

## 1. 前準備
GPU付きのPCを買いましょう。会社の後輩にゲーミングPCを持っている子がいて、その子にいろいろ教えてもらいました。その子曰く、ドスパラというゲーミングPC通販サイトがおすすめとのこと。ゲームに適しているハイスペックPCは機械学習にも適しているはず？

↓ドスパラサイト

https://www.dospara.co.jp/

色々見てみましたが、確かに値段も思ったほど高くなく、NVIDIAのGPUがついているPCが売られていました。選定基準は以下のようにしました。

1. 予算20万以下
2. GPU付き、GeForceとやらが人気らしい
3. ~~ゲーミングPC特有のピカピカひかる仕様はいらない~~
4. 家族の他メンバーも使うので、普段使いもできるようにWindows PCに

で、結局以下のPCを購入しました。

**Lightning AV5 通販限定モデル**
- OS : Windows11 Home
- office : 無し
- CPU : AMD Ryzen 5 4500
- GPU： NVIDIA GeForce RTX 4060 8GB
- メモリ：32GB (16GBx2)
- SSD：1TB NVMe SSD

GPUに重きを置いて、それ以外はコストカットした感じです。officeは後から自分でやっすいやつ入れればいいやとなり、設置サービスも不要と思い、値段抑えられるところはなるべく削りました。

これで総額18万くらいです。結局ふたを開けてみれば、思ったほど安くはないのですが、GPU付きPCはもっと高いと思っていましたし、E資格合格のご褒美と思い自己投資しました。普段使いもできますし。

実際、設置はそこまで難しくなく、wifi用のアンテナをつけたり、ほかのPCでも同様に最初のset upをするだけでした。ここまでは特段問題なし（スピーカー内蔵ではないので、音がしなくてもそれは故障ではありません、私は焦ってドスパラに連絡しました。私の頭が故障していました✌✌✌）

## 2. 必要なものをインストール
ここからが本題。GPU付きのPCを用意してもいきなり使えるわけではありません。GPUをPCに認識させる必要があります。事前にいろいろサイトなど調べていたのですが、結局作業はChatGPT（愛称を込めてチャッピーと呼んでいます）にサポートしてもらいました。やはりこいつはすごい、たまに間違ったことをいうのはご愛敬ですが、その辺は人間がカバーしましょう。最近は一番の友達です！！笑

GUIでexeファイルをダウンロードして実行するか、コマンド入力で直接インストールするかの2通り方法があるのですが、今回はGUIでやりました。環境変数のPathを通すのを自動でやってくれたり、初心者には便利なので。

:::note info
これから様々なソフトウェアをダウンロードしていきますが、exeファイルを実行したときに、環境変数のPathを通すというチェックボックスがあったら、基本はチェックしてください。後からPathを通すこともできますが、インストール時に通しておいた方が楽です。
:::

### 2.1 NVIDIAドライバをインストール
まずNVIDIA driverとネットで検索し、NVIDIAのサイトに行きます。そこでドライバなどをダウンロードします。

https://www.nvidia.com/en-us/drivers/

サイトに行くと、このように自分のGPU情報を入力するところがあるので、ここに自分のGPU情報を入力し、適切なドライバを探します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4092284/4fa9e374-243f-43b8-a3ea-18005ed64e57.png)

Findをクリックすると、`NVIDIA Studioドライバー`と`GeForce Game Ready Driver`が出てくるのですが、機械学習などをする場合は前者をダウンロードしてインストールしましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4092284/9764ffd1-8530-4653-b308-d2d56d6e88a6.png)

ダウンロードしたexeファイルを実行すると、このような画面が。ドライバーとアプリ両方入れましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4092284/a9b88ecc-6cf1-4d67-99bd-b2db7f83a562.png)

カスタムを選択し、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4092284/d9d9558d-5356-4637-a443-22ba213f1dee.png)

クリーンインストールの実行にチェックを入れて、次に進むと、インストールが始まります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4092284/b0504cc9-5042-4f85-866f-f94d2fc80001.png)

インストール完了後、タスクバーの検索ボックスで「NVIDIA Control Panel」と検索すると、そやつがヒットします。こいつを開いてみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4092284/06d8ef72-c120-4b58-9eb8-1cce95e3016d.png)

すると、確かにStudioドライバーがインストールされていることがわかります。私の場合、versionは576.52でした。なるべく最新のversionをインストールしたほうが良いとのこと。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4092284/a742f1b6-d3cc-40c2-af89-505542a84519.png)

### 2.2 WSL2のインストール
Powershellを開いて、下記コマンドを打ちましょう。

``` powershell
wsl --install
```

一番最初はパスワードなどを求められます。Docker DesktopはWindowsで動作するので、Linuxはいらないのでは？と思うのですが、チャッピー曰く内部的にWSL2を使うらしい。ちなみに後で作るnotebookなどはLinux上のフォルダに格納する予定なので、Linuxは入れておきます。

### 2.3 Dockerデスクトップをインストール
現在、企業で使う場合は有料らしいですが、商用目的でない個人利用なら無償で使っていいとのこと。Docker DesktopはGUIサポートがあるので、こちらの方が初心者的には使いやすいかも。どうしても気になるならば、Docker Engineを入れるといいみたいです。それではインストールしましょう、公式サイトに行きます。

https://www.docker.com/products/docker-desktop/

Downloadの部分をクリックし、自分のOSに合ったものをダウンロード
私の場合は、`Download for Windows – AMD64`を選びました。自分のPCが64ビットの場合はこちらでいいみたいです。ビットを確認する方法はシステム情報から見ることができます。ダウンロードしたexeファイルを実行し、インストールを始めましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4092284/e93072bd-83ca-42a8-b4ee-f91b155606df.png)

インストールが終わるとdockerが立ち上がります。そして、`設定→WSL integration→Ubuntu`を有効化します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4092284/b2d13dab-6b75-4c8d-ae6c-039179021a92.png)

### 2.4 VSCodeのインストール
次にVSCodeのダウンロードかつインストールです。いろんな開発環境あると思いますが、私はVSCodeが使いやすいと思っています。一番の大きな理由は`Remote-Containers (Dev Containers)`という機能が使えるからです。この機能により、VSCodeがDockerコンテナを自動で作ってくれ、且つ接続まで全部やってくれます。利点をあまりうまく説明できていませんが、コマンド操作をあまりしなくても、コンテナのビルドが簡単にできてしまうので、こちらも初心者としてはありがたい機能です。

それではインストールしましょう。公式サイトに行って、

https://code.visualstudio.com/download

`User Installer`か`System Installer`のどちらかをダウンロードしましょう。赤枠で囲んだところをクリックすると、`User Installer`のダウンロードが始まります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4092284/6e7e78f5-8505-46bd-9910-52c66be3c802.png)

私は`User Installer`の方を入れました。違いは以下の通りです。

- User Installer：管理者権限なしでインストール可能。
- System Installer：全ユーザーで利用可能。管理者権限が必要。

複数UserでVSCodeを使うときやシステム全体にインストールしたい場合は後者の方がいいそうです。そしてインストールが終わったら、次は**拡張機能**を入れていきます。

赤枠で囲んだ**1**のところをクリックすると（なんて汚い字なんだ！）、**2**の検索Boxが出てくるので、そこに`Dev container`と入力すると、対応する拡張機能のリストが表示されます。対応しているのは**3**でこれをインストールしましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4092284/98600674-caa0-4a32-98bb-b141d2d5d7e6.png)

同様にして、
- `Python`
- `Jupyter`
- `Docker`
- `Japanese Language Pack for Visual Studio Code`(日本語表記にしたい場合)

などの拡張機能を入れていきます。もし足りないものがあれば、VSCodeがインストールしろと教えてくれるので、ひとまずこの辺で大丈夫。

## 3. Docker環境構築
### 3.1 プロジェクトフォルダや必要なfileを作る

まず`powershell`を開いて、下記コマンドでwslを起動させます。
```powershell
wsl
```

次に`wsl`上で下記コマンドを入力し、プロジェクトフォルダを作ります。

```bash
mkdir -p ~/docker_projects/gpu_notebook
cd ~/docker_projects/gpu_notebook
```

`docker_projects`というフォルダの中に、`gpu_notebook`というフォルダをさらにつくっています。この辺は任意の名前を付けてください。gpu_notebookというフォルダ作らずに、docker_projectsフォルダのみでもいいです。

そして、`cd`のコマンドにより、gpu_notebookというフォルダに現在いるので、下記コマンドで`VSCode`を立ち上げます。

```bash
code .
```

すると、VSCodeが立ち上がります。このとき、VSCode上で`gpu_notebookフォルダを開いた状態`？になっています。そして以下の階層に示しているフォルダやファイルを作っていきます。

<pre><code>docker_projects/
└── gpu_notebook/
        ├── requirements.txt 
        └── .devcontainer/ 
            ├── devcontainer.json 
            └── Dockerfile </code></pre>

赤枠で囲ったアイコンをクリックすると、新しいファイルやフォルダを作成できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4092284/a1eb575e-d58b-415b-b5ff-a615f270e0a1.png)

まず`.devcontainer`（これはフォルダです）を作成します。

:::note warn
先頭に「.」が必要なので注意です。忘れるとちゃんと認識しません、そういったルールらしい。
:::

そしてその中に、`devcontainer.json`と`Dockerfile`をつくります。どちらもファイルです。後者は拡張子無しです。正しく入力すると、VSCodeが認識してjsonファイルの方は`{ }`が、Dockerfileの方は`クジラ`のアイコンが表示されます。


`json`ファイルは設定ファイルのことで、いろんなツールで使われているみたいです。ここでは、VSCodeが「どんなDockerコンテナをどうやって作ればいいのか」を読み込むための設定を記しています。


jsonファイルの中身は

```json
{
    "name": "ML-Docker-Dev",
    "build": {
        "dockerfile": "Dockerfile", 
        "context": ".."                           
    },
    "settings": {
        "terminal.integrated.shell.linux": "/bin/bash"
    },
    "extensions": [
        "ms-python.python",
        "ms-toolsai.jupyter"
    ],
    "remoteUser": "root",
    "runArgs": ["--gpus", "all"]
}
```

としました。上から順に

**"name"** : Dev Containerの表示名、VSCodeのタブやステータスバーなどに表示される名前。任意に決めていいです。

**"build" : { ... }**
Dockerイメージのビルドに使う情報：
- "dockerfile" : 使用するDockerfileのファイル名（ここではそのままDockerfileにしている）
- "context" : Dockerビルドの「コンテキスト（作業ディレクトリ）」

". ." : 「.devcontainer」の1つ上の階層（=プロジェクトのルート）を使うという意味

**"settings" : { ... }**
VSCode上のユーザー設定（エディタ設定）、ここではコンテナ内のターミナルで使うシェルをbashに固定している。

**"extensions" : [ ... ]**
コンテナ内のVSCodeに自動でインストールされる拡張機能：
- ms-python.python : Python言語のサポート
- ms-toolsai.jupyter : ノートブックファイル(.ipynb)を開くときに必要

**"remoteUser"** : コンテナ内で作業する際のユーザー名、"root"にすると権限の制限がなくなり何でもできる（セキュリティは下がるけど開発は楽）

**"runArgs" : ["--gpus", 'all']**
コンテナ起動時の追加引数をDockerに渡しており、GPUをすべてのコンテナに割り当てるオプション。

となっております。このjsonファイルを .devcontainer/ フォルダに配置すれば、

⇒ `VSCode`が`Dockerfile`からGPU対応の`Docker`コンテナをビルド
⇒ 自動で`Python`と`Jupyter`の拡張が入る
⇒ `Bash`でターミナルが動く
⇒ `root`権限で開発できる

となるわけです。ただし、この辺は目的に合わせていろいろ修正できるので、必ずしもこうしないといけないわけではないです。

そして、次に`Dockerfile`です。


```dockerfile
FROM pytorch/pytorch:2.2.1-cuda12.1-cudnn8-runtime

WORKDIR /workspace

COPY requirements.txt .

RUN pip install --upgrade pip
RUN pip install -r requirements.txt

CMD ["/bin/bash"]
```

**FROM ...**
- このDockerfileイメージのベースとなるOS・環境を指定
- pytorch/pytorch は公式のPyTorch Dockerイメージ
- PyTorch 2.2.1、CUDA 12.1（NVIDIAのGPU計算用ライブラリ)、cuDNN 8（ディープラーニング高速化ライブラリ）、つまりGPUが使えるPyTorch環境の完成版をベースにしている

**WORKDIR /workspace**
- コンテナ内の作業ディレクトリを`/workspace`に設定

**COPY requirements.txt .**
- ホスト側の`requirements.txt`をコンテナ内のカレントディレクトリ(`/workspace`)にコピー

**RUN pip install -r requirements.txt**
- `requirements.txt`に記載されているPythonパッケージを一括インストール

そして、.devcontainerフォルダと同じ階層に「requirements.txt」を作成し、
```
torch
torchvision
ipykernel
matplotlib
seaborn
numpy
pandas
diffusers
transformers
accelerate
scikit-learn
```

と記載します。この辺も使いたいライブラリに合わせて編集してください（筆者はE資格の復習をしたかったのでこれらのライブラリを記載しているだけです）。

### 3.2 コンテナビルド
左下の`><`みたいなアイコンをクリックすると、画面上(コマンドパレット？）に「コンテナで再度開く」というものがあるのでこちらをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4092284/4733f0c4-000f-4e11-8d32-57e1f1cd1915.png)


するとコンテナへの接続が開始され、接続が終わると仮想環境が使用できるようになります。最初のビルドには時間がかかりますが、さっき押した`><`のところにコンテナ名が表示されれば、接続完了です！！ひとまずお疲れさまでした🎉

こんな感じで表示されたらOK
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4092284/6237973b-5c98-447d-b354-197a92e2337f.png)

最後に恒例のGPUチェックからの画像認識をしましょう

### 3.3 Notebookの実行
「.devcontainer」ディレクトリと同じ階層に、「MNIST_CNN_Training.ipynb」という名前のnotebookを作ります。

こんな感じ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4092284/ab82d425-6a53-4f50-b741-dd7f5eb07ec8.png)

notebookを記載していきましょう。まず、ライブラリ読み込みます。

```python
# 必要なライブラリ読み込む
import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms
```

そして、次にGPUのチェックです。以下のコードを実行すると、

```python
# GPU
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

print('使用デバイス：', device)
```

問題なくGPUが認識されていれば、下記出力が返ってきます。
```
使用デバイス： cuda
```
GPUが使えている証拠です！！長かった。。。

それでは、手書き文字認識のデータセットとして基本のMNISTを読み込んで学習させていきましょう。

```python
# データセット
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.5,), (0.5))  # mean=0.5, std=0.5ってこと
])

trainset = torchvision.datasets.MNIST(root='./data', train=True,
                                      download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=64, shuffle=True)

testset = torchvision.datasets.MNIST(root='./data', train=False,
                                      download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=64,
                                         shuffle=False)
```

モデルを定義します。シンプルなCNNにしましょう。損失関数も定義します。
```python
# CNNモデル定義、畳み込み層、プーリング層、全結合層
class SimpleCNN(nn.Module):
    def __init__(self):
        super(SimpleCNN, self).__init__()
        self.conv = nn.Conv2d(1, 8, 3)
        self.pool = nn.MaxPool2d(2, 2)
        self.fc = nn.Linear(8*13*13, 10)

    def forward(self, x):
        x = self.pool(torch.relu(self.conv(x)))
        x = x.view(-1, 8*13*13)
        x = self.fc(x)
        return x
    
model = SimpleCNN().to(device)

# 損失関数
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
```

学習させます、たくさん学習させたければrange(3)のところを増やしましょう。
```python
# 学習、3epochのみ回す
for epoch in range(3):
    running_loss = 0.0
    for inputs, labels in trainloader:
        inputs, labels = inputs.to(device), labels.to(device)

        optimizer.zero_grad()

        outputs = model(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

        running_loss += loss.item()  # 各ミニバッチ毎のlossを足していく

    print(f"Epoch {epoch + 1}, Loss: {running_loss / len(trainloader)}")  # batch数で割り、平均を出す

print('学習終了')
```

出力です、着々とLossが減っており、順調に学習が進んでいる。
```
Epoch 1, Loss: 0.34451929879372817
Epoch 2, Loss: 0.13228549120494965
Epoch 3, Loss: 0.09520191097282556
学習終了
```

最後に汎化性能チェックです。
```python
# テスト
correct = 0
total = 0

with torch.no_grad():
    for inputs, labels in testloader:
        inputs, labels = inputs.to(device), labels.to(device)
        outputs = model(inputs)
        _, predicted = torch.max(outputs.data, 1)
        total += labels.size(0)  # バッチサイズを足していく
        correct += (predicted==labels).sum().item()

print(f'テスト精度; {100*correct / total:.2f}%')
```

できました！初手でこの精度、やはり畳み込みはすごい。
```
テスト精度; 97.28%
```

ささっと流しましたが、本稿はGPU setupの記事なので、この辺の詳細は割愛します。

# 所感
チャッピーを使いながらいろいろと試行錯誤を繰り返し、何とかGPU setupできました。もちろんこんなに順調にはいかなくて、エラーが出るたびに質問しまくるという作業を繰り替えています笑

ただ、今まで生成AIをそこまで使ったことがなかったのですが、今回使ってみて作業効率が劇的に上がったので、正直感動しました。課金する価値ありです。今後もいろんなアイデアを具現化してもらって、うまく活用していこうと思います。

長々と記載しましたが、最後まで読んでいただきありがとうございました！！

# 補足
一度すべてアンインストールしてから、やり直したときは問題なく実行できたので、大方問題ないものと認識はしているのですが、インストールや設定で少し抜けているところがあるかもです。すいません。。。参考までに引用させていただいた記事も載せておきます。

# 参考にしたサイト
https://qiita.com/rikinumata/items/b3729ad5144a3e98c6b4

https://qiita.com/Yuhei0531/items/02a716533c414126dce1

https://zenn.dev/opamp/articles/7880812d78226f

https://qiita.com/Matcha_yu/items/4b2b75b4537dad04a37c

https://fallpoke-tech.hatenadiary.jp/entry/2025/02/21/080000