Windows11でTensorflow（Keras）をインストールしGPUで学習させる

# 0. はじめに
&emsp;学生時代にPytorchを使って識別系AIを触ってました（画像分類、物体検出、セマンティックセグメンテーション、異常検知と一通り触ってました）が、仕事では全く活かせる業務ではないため、久々にAI触りたいなと思い、環境構築しました。
&emsp;せっかくなら使ったことのないフレームワークのTensorflow（Keras）も使ってみたいと思い、手持ちのGPU搭載PCに環境構築を試したところ、少し手こずったところがあるので記事として残します。

※ 生成AIが流行っている中、識別系AIを始めるという少し時代遅れの記事となりますが、識別系AIを始めてみようとされている方にとって少しでも参考になればうれしいです。



###  開発環境
- **OS** : _Windows 11 Home_
- **CPU** : _Intel Core i5-12400F_
- **GPU** : _NVIDIA GeForce RTX 3060_
- **メモリ** : _32GB_ 

###  構築する環境
- Python：3.8～3.10のどれか
- Tensorflow：2.10.0　<font color="red">**← ここが大事！！**</font>
- CUDA：11.2.2
- cuDNN：8.1.1
:::note warn
結論！
[TensorFlow公式](https://www.tensorflow.org/install/pip?hl=ja#windows-native)にも書いてありますが、**Tensorflow2.10**がWindowsでGPUをサポートする最後のバージョンとなってます。
また、それに合わせて**CUDA Toolkit**は**11.2**、**cuDNN**が**8.1**をダウンロードていきます。

<font color="lightblue">**ここさえ守っていれば問題なく使えるはずです!**</font>

:::

[５．Tensorflowをインストール](#５．Tensorflowをインストール)まで行えばTensorflowの環境構築完了です。[６．Tensorflow（Keras）を使って学習してみる](#６．Tensorflow（Keras）を使って学習してみる)以降はサンプルとしてコードを載せてますので、学習させてみたい方は参考にしてください。

それでは始めましょう

# １. Pythonをインストール
&emsp;公式Pythonインストーラを使います。
１．[Python公式ページ](https://www.python.org/downloads/)からインストーラをダウンロードする
２．インストーラを起動し「Add Python to PATH」にチェックを入れる。
３．「Install Now」を押してインストールする。
４．ターミナルやコマンドプロンプトで以下のコマンドを使い、Pythonが正しくインストールされたことを確認
```bash
python --version
```
以下のような結果が表示されればインストール完了！
```bash
>> Python 3.10.9
```
# ２．VSCodeをインストール
:::note warn
Pythonのエディタとしてインストールするだけなので、他のを使う方、すでに入っている方は飛ばしてください。
:::


１．[Visual Studio Code - Download](https://code.visualstudio.com/download)からWindows10,11版をダウンロードする
![VSCode.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1258472/c1647862-2e4c-eead-6b1c-480bc3824a8f.jpeg)
２．インストーラを起動しVSCodeをインストールする
![VSCode_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1258472/b5dff42d-87b6-2ffa-1ac7-ce5012563489.jpeg)
デフォルトのまま進んでいき「インストールをクリック」
![VSCode_3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1258472/33108924-d5b7-b727-d6fe-8b446db667a3.jpeg)
![スクリーンショット 2024-10-11 232612.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1258472/79d1eb32-9a7f-46ac-b063-e946f262adeb.png)
３．VSCodeを開き左側の「Extensions」を開き「Python」をインストールする
![VSCode_4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1258472/780fb634-5b68-17d5-a833-4ecc7e125e2e.jpeg)
![VSCode_5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1258472/5bbdd6ca-a41d-528b-8662-fd37dd38d5c8.jpeg)
※ その他便利な拡張機能が用意されているため適宜インストールしてください。こちらの記事が参考になります↓
[Qiita - Visual Studio Codeに入れるべき拡張機能【2023年最新版】](https://qiita.com/midiambear/items/f38686bd4d139e0cd46c)

# ３．CUDA Toolkitをインストール
１．[NVIDIA DEVELOPER - CUDA Toolkit Archive](https://developer.nvidia.com/cuda-toolkit-archive)からCUDA Toolkit 11.2.2をダウンロード↓

![cuda toolkitインストール.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1258472/106bff26-fe8b-8236-7148-ae2be3bab79e.jpeg)

使う環境に合わせて選択
※ Windows11がありませんがWindows10を選択で大丈夫です。
![cuda toolkitインストール_環境.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1258472/cef35ca5-e8a9-f336-23d2-4d991aee6c02.jpeg)

２．ダウンロードしたインストーラを起動しCUDA Toolkitをインストールする
デフォルトのままで進んでいきインストールしたらコマンドプロンプトで以下を実行
```bash
nvcc -V
```
以下のような表示がされればインストール完了
```bash
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2021 NVIDIA Corporation
Built on Sun_Feb_14_22:08:44_Pacific_Standard_Time_2021
Cuda compilation tools, release 11.2, V11.2.152
Build cuda_11.2.r11.2/compiler.29618528_0
```
また環境変数に以下が追加されているはずです
![cuda toolkit path.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1258472/9fa71e07-54a8-df63-6752-40a1d5f489ea.jpeg)

# ４．cuDNNをインストール
１．[NVIDIA DEVELOPER-cuDNN](https://developer.nvidia.com/cudnn-downloads)にアクセスし以下の順でダウンロードするcuDNNを選択する
（NVIDIA Developer アカウントが必要）
![cuDNN_1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1258472/e65ebbb6-741d-c9e6-6eeb-11578c7bad92.jpeg)
![cuDNN_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1258472/1ccb5aef-7302-8c46-300e-75bcf2c22897.jpeg)
![cuDNN_3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1258472/74d23972-69f2-2ef1-b42c-06049b896f9d.jpeg)
![cuDNN_4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1258472/991a51de-5e17-1d66-7743-70152805b8b0.jpeg)

２．ダウンロードしたファイルを解凍し、bin, include, lib フォルダを CUDA のインストール先 (C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.2) に全コピーする。

３．環境変数に以下を追加する
![cuDNN_5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1258472/1e3deb60-e2c0-7b6a-7082-e8ab81c6b5fb.jpeg)
追加したら再起動して設定を反映させる。

コマンドプロンプトで以下を実行してエラーが出ないか確認する。
```bash
where cudnn64_8.dll
```
```bash
>>> C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.2\bin\cudnn64_8.dll
```
# ５. Tensorflowをインストール
１．ワーキングディレクトリを作成し以下を「requirements.txt」として保存する。

:::note warn
注意！
何度も書きますが **tensorflow==2.10**をインストールします。その他（tensorboard、tensorflow_probability）はこれに対応するバージョンを指定しています。
※ numpyは2.0以降だと動かない可能性があります。
:::

```tex
numpy<2.0
matplotlib==3.6.3
tensorflow==2.10
tensorboard==2.10
tensorflow_probability==0.18.0
```
２・仮想環境を構築する
　そのままライブラリをインストールしてもいいですが、環境が壊れる可能性があるので、ここではvenvで仮想環境を構築して整えます。
※ 仮想環境を構築しない人は３．へ進んでください。

ワーキングディレクトリへ移動
```bash
cd [ワーキングディレクトリのパス]
```
仮想環境を構築　※ envは環境名でお好きな名前にして下さい
```bash
python -m venv env
```
仮想環境に切り替え
```bash
emv\Scripts\activate
```
３．ライブラリをインストールする

下記コマンドで一括インストール
```bash
pip install -r requirements.txt
```
下記コマンドでインストールしたライブラリ一覧が表示されるためtensorflow 2.10.0が入っていればOK！
```bash
pip list
```

これでTensorflow、Kerasを使う環境構築ができました。
６．からは[CIFAR-10](https://www.cs.toronto.edu/~kriz/cifar.html)という10クラスの画像分類用データセットを使って、実際に学習できるようプログラムを載せています。よかったら参考にしてください

↓

# ６．Tensorflow（Keras）を使って学習してみる
１．VSCodeを開き作成したワーキングディレクトリを開く
[５．Tensorflowをインストール](#５．Tensorflowをインストール)で作成したワーキングディレクトリを開いてください。
![train_1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1258472/549f66f6-185c-0dcd-382f-fa8f940f06e6.jpeg)
２．以下の構成でファイル、フォルダをを作成する
![スクリーンショット 2024-10-25 205940.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1258472/5327e687-1668-adfe-44aa-0b35b987969f.png)

各pythonファイルのコードは以下のとおりです。
またプログラムを実行するときは「右クリック」→「Run Python」→「Run Python File in Terminal」で実行できます。
![スクリーンショット 2024-10-25 211041.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1258472/0db9d501-87ef-61e6-ff8b-5ae30c8a10a1.png)
※　VSCodeはそのワーキングディレクトリにある仮想環境を自動で選択して実行してくれるのでとても便利です。
　　envの環境が使われない（ライブラリのインポートエラーがでるなど）場合は画面右下の環境を選択し「.\env\Scripts\python.exe」を選択すればできます。
![スクリーンショット 2024-10-25 211751.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1258472/7aed30ac-63e3-af62-ad1e-f5294f1c30aa.png)

### dataset.py
CIFAR-10のデータセットをロードするためのファイルです。
```python
# dataset.pyの中身
from tensorflow.keras import datasets, utils

def load_CAIFAR10_datasets():
    (x_train, y_train), (x_test, y_test) = datasets.cifar10.load_data()

    NUM_CLASSES = 10

    x_train = x_train.astype("float32") / 255.0
    x_test = x_test.astype("float32") / 255.0

    y_train = utils.to_categorical(y_train, NUM_CLASSES)
    y_test = utils.to_categorical(y_test, NUM_CLASSES)

    return x_train, y_train, x_test, y_test

def main():
    x_train, y_train, x_test, y_test = load_CAIFAR10_datasets()
    # データの形を表示
    print("train_data:", x_train.shape)
    print("train_label:", y_train.shape)
    print("test_data:", x_test.shape)
    print("test_label:", y_test.shape)

if __name__ == "__main__":
    main()
```

### model.py
モデルの形を作るためのファイルです。2つ用意していますのでお好きな方を使ってください。
・MLPが全結合層のみのモデル
・CNNが畳み込み層を使ったモデル
```python
# model.pyの中身
from tensorflow.keras import layers, models

def build_model_MLP(num_classes):
    input_layer = layers.Input(shape=(32, 32, 3))
    x = layers.Flatten()(input_layer)
    x = layers.Dense(200, activation="relu")(x)
    x = layers.Dense(150, activation="relu")(x)
    output_layer = layers.Dense(num_classes, activation="softmax")(x)

    model = models.Model(input_layer, output_layer)

    return model

def build_model_CNN(num_classes):
    input_layer = layers.Input(shape=(32, 32, 3))
    # 1層目----------------------------------------
    x = layers.Conv2D(
        filters = 8,
        kernel_size = 3,
        strides = 1,
        padding = "same",
    )(input_layer)
    x = layers.BatchNormalization()(x)
    x = layers.ReLU()(x)
    x = layers.MaxPooling2D(pool_size=(2, 2))(x)
    # 2層目----------------------------------------
    x = layers.Conv2D(
        filters = 32,
        kernel_size = 3,
        strides = 1,
        padding = "same",
    )(x)
    x = layers.BatchNormalization()(x)
    x = layers.ReLU()(x)
    x = layers.MaxPooling2D(pool_size=(2, 2))(x)
    # 3層目-----------------------------------------
    x = layers.Conv2D(
        filters = 64,
        kernel_size = 3,
        strides = 1,
        padding = "same",
    )(x)
    x = layers.BatchNormalization()(x)
    x = layers.ReLU()(x)
    x = layers.MaxPooling2D(pool_size=(2, 2))(x)
    # 全結合層--------------------------------------
    x = layers.Flatten()(x)
    x = layers.Dense(64)(x)
    x = layers.BatchNormalization()(x)
    x = layers.ReLU()(x)
    output_layer = layers.Dense(num_classes, activation="softmax")(x)

    model = models.Model(input_layer, output_layer)

    return model

def main():
    num_classes = 10

    # モデルを選択 --------------------------
    # MLP
    #model = build_model_MLP(num_classes)
    # CNN
    model = build_model_CNN(num_classes)
    # --------------------------------------

    print(model.summary())

if __name__ == "__main__":
    main()
```

### train.py
モデルを学習するためのファイル
main関数のバッチサイズやエポック数（データセット１通り学習を何回行うか）を変更できます。
```python
# train.pyの中身
import matplotlib.pyplot as plt
from tensorflow.keras import optimizers
from model import build_model_MLP, build_model_CNN
from dataset import load_CAIFAR10_datasets

def save_history_as_fig(history):
    # ロスのグラフを保存
    plt.figure(figsize=(10, 5))
    plt.plot(history.history['loss'], label='Training Loss')
    plt.plot(history.history['val_loss'], label='Validation Loss')
    plt.title('Loss over Epochs')
    plt.xlabel('Epochs')
    plt.ylabel('Loss')
    plt.legend()
    plt.grid(True)
    plt.savefig('historys/CNN_loss_plot.png')  # ここでロスのグラフをPNG形式で保存

    # 精度のグラフを保存
    plt.figure(figsize=(10, 5))
    plt.plot(history.history['accuracy'], label='Training Accuracy')
    plt.plot(history.history['val_accuracy'], label='Validation Accuracy')
    plt.title('Accuracy over Epochs')
    plt.xlabel('Epochs')
    plt.ylabel('Accuracy')
    plt.legend()
    plt.grid(True)
    plt.savefig('historys/CNN_accuracy.png')  # ここで精度のグラフをPNG形式で保存

def train(batch_size, epochs, save_weight=True, save_history=True):
    # dataset読み込み
    x_train, y_train, x_test, y_test = load_CAIFAR10_datasets()

    # model
    num_classes = 10
    # model = build_model_MLP(num_classes)
    model = build_model_CNN(num_classes)
    opt = optimizers.Adam(learning_rate = 0.001)

    # train ========================
    model.compile(
        loss = "categorical_crossentropy",
        optimizer = opt,
        metrics = ["accuracy"]
    )
    history = model.fit(
        x_train, 
        y_train, 
        batch_size=batch_size, 
        epochs=epochs, 
        shuffle=True,
        validation_data=(x_test, y_test)
    )

    # save model
    if save_weight == True:
        #model.save('weights/full_model_MLP.h5')
        model.save('weights/full_model_CNN.h5')
    if save_history == True:
        save_history_as_fig(history)

def main():
    batch_size = 32
    epochs = 50
    train(batch_size, epochs)

if __name__ == "__main__":
    main()
```
学習が完了すると「historys」フォルダに学習結果の推移が保存されます。↓MLPの例
![MLP_loss_plot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1258472/326e26a7-04fd-186c-a996-ec67bc1da543.png)
![MLP_accuracy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1258472/b24cb08b-ad48-61ac-23d7-1bb952870445.png)
また「weights」フォルダに学習された重みが保存されますので、次の章でそれを使って予測させてみましょう。

# ７．学習したモデルを使ってテストデータを予測してみる
### predict.py
学習したモデルを使って予測するためのファイル
model_pathに保存された重みのパスを指定して実行すると結果が表示されます。
```python
# pred.pyの中身
import numpy as np
import matplotlib.pyplot as plt
from tensorflow.keras.models import load_model
from dataset import load_CAIFAR10_datasets

# CIFAR-10
CLASSES = np.array(
    [
        "airplane",
        "automobile",
        "bird",
        "cat",
        "deer",
        "dog",
        "frog",
        "horse",
        "ship",
        "truck",
    ]
)

def display_results(x_test, output, gt):
    num = 10
    sampling_num = np.random.choice(range(len(x_test)), num)
    print(sampling_num)

    fig = plt.figure(figsize=(15, 3))
    fig.subplots_adjust(hspace=1.0, wspace=0.1)

    for i, idx in enumerate(sampling_num):
        img = x_test[idx]
        ax = fig.add_subplot(1, num, i+1)
        ax.axis("off")
        ax.text(
            0.5,
            -0.35,
            "pred = " + str(output[idx]),
            fontsize=10,
            ha="center",
            transform=ax.transAxes,
        )
        ax.text(
            0.5,
            -0.7,
            "gt = " + str(gt[idx]),
            fontsize=10,
            ha="center",
            transform=ax.transAxes,
        )
        ax.imshow(img)
    fig.savefig("results/pred.png")

def pred(model_path):
    # load model
    model = load_model(model_path)
    # dataset
    _, _, x_test, y_test = load_CAIFAR10_datasets()

    # predict =============================
    preds = model.predict(x_test)
    output = CLASSES[np.argmax(preds, axis=-1)]
    gt = CLASSES[np.argmax(y_test, axis=-1)]

    display_results(x_test, output, gt)

def main():
    model_path = "weights/full_model_CNN.h5"
    pred(model_path)

if __name__ == "__main__":
    main()
```
出力結果↓
![pred.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1258472/ad107968-0972-2e62-7f4f-d7b7c2501385.png)

誤検知もあり、精度としてはまだよくありませんがTensorflow（Keras）を使って学習ができました！
ぜひこのコードをベースにモデルの変更やデータセットの変更（MNISTやFashion-MNISTなど）、学習のさせ方などいろいろ試してみてください。

# ８．まとめ
　今回はWindows11でGPUを使ってTensorflowを学習できる環境構築を行いました。バージョンによってはサポートされていないことがありますので、今後もっとしっかり使っていく方はWSL2経由で利用されることをお勧めします。（公式推奨方法 [Github-Tensorflow](https://github.com/tensorflow/tensorflow/releases?page=3))
 ![スクリーンショット 2024-10-26 174710.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1258472/e1daf8e0-8128-1328-8596-d8ccd5258b29.png)

以上、本記事を読んでいただきありがとうございました