TensorFlowを利用するWSGIサーバの構築に向けたPython3環境の構築（完結・Amazon Linux 2023編）

# まえがき
Python3環境構築シリーズ3部作も、今回のAmazon Linux2023をもって締めくくりとなりました。いろいろなことがありましたが、ひとつ気づいたことがあります。

今回、いい機会なので、Amazon Linux 2023のインスタンスを作ったのですが、AMIの選択肢は以下の画像のようになっていました。

![AMI images](https://hashimoto-net.jp/images/AMI_Images.png "AMI images")

これは自分にとっても初耳なので、驚きでした。TensorFlowは扱いが難しいパッケージであるために、「Deep Learning OSS」と称して、AWSの側でも AMI イメージを用意しているのですね。

今回の記事は、tensorflow2.16.1をターゲットとしているため、ほぼ同様のことが出来るのではないかと思います。そういった意味では、使用されているLinuxをAWSのDeep Learning OSS 相当にするチャンスではないか、と。

## 前提
+ OS: Amazon Linux 2023
+ Python: version python-3.9.18
+ Chat-GPT API：GPT-4V

## 環境作成
以下を行い、OSのアップデートを行ってください。

```
$ sudo dnf check-update
$ sudo dnf upgrade
$ sudo dnf upgrade --security
```


## WSGIサーバのインストール
Apache です。
```
$ sudo dnf install httpd
```
WSGI環境構築につきましては、前回の記事にリンクがありますので、参照ください。

### ビルド関連パッケージのインストール
```
$ sudo dnf groupinstall "Development Tools"
```
```
$ sudo dnf install libstdc++-devel glibc-devel
```

## OpenSSLのインストール
```
$ cd /usr/local/src
$ wget https://www.openssl.org/source/openssl-3.0.7.tar.gz
$ sudo tar xvzf openssl-3.0.7.tar.gz
$ cd openssl-3.0.7
$ sudo ./Configure
$ sudo make
$ sudo make install
```

## bzip2のインストール
```
$ cd /usr/local/src
$ sudo git clone https://git.code.sf.net/p/bzip2/bzip2 bzip2-bzip2
$ cd bzip2-bzip2
$ sudo make
$ sudo make install
```

## sqlite3 のインストール
```
$ sudo wget https://www.sqlite.org/2024/sqlite-autoconf-3450300.tar.gz
$ sudo tar -xvzf sqlite-autoconf-3450300.tar.gz
$ ./configure
$ make
$ sudo make install
```

# ここから本番です
## Python3.9.18のmakeとインストール
```
$ export CFLAGS="-I/usr/local/src/openssl-3.1.2/include/openssl -I/usr/local/src/bzip2-bzip2" 
$ export LDFLAGS="-L/usr/local/lib -L/usr/local/lib64 -L/usr/local/bin/sqlite3 -L/usr/local/bin/bzip2" 
$ export LD_RUN_PATH=/usr/local/lib:/usr/lib:/usr/lib64
$ export LD_LIBRARY_PATH=/usr/local/lib:/usr/lib:/usr/lib64
$ export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
$ export OPENSSL_LDFLAGS=-L/usr/local/src/openssl-3.1.2/include/openssl
$ export OPENSSL_INCLUDES=-I/usr/local/src/openssl-3.1.2/include/openssl
```

Python3をソースからインストールする。
```
$ cd /usr/local/src
$ sudo wget https://www.python.org/ftp/python/3.9.18/Python-3.9.18.tgz
$ sudo tar xvzf Python-3.9.18.tgz
$ cd Python-3.9.18
```

```
$ vi Modules/Setup
```

下記を参考に214～217行目をコメント解除。

```
    212 # Socket module helper for SSL support; you must comment out the other
    213 # socket line above, and possibly edit the SSL variable:
    214 SSL=/usr/local/ssl
    215 _ssl _ssl.c \
    216         -DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \
    217         -L$(SSL)/lib -lssl -lcrypto
```

下記を実行
```
$ ./configure --prefix=/usr/local/python-3.9.18 --enable-optimizations --with-lto
$ sudo make -j 8
$ sudo make altinstall
```

また、pip が使用できない状況になっていることが考えられるので、次の記載について実行を行う。

```
vi ~/.bashrc
```

以下を記載する。
```
PATH=$PATH:/usr/local/python-3.9.18/bin
export PATH
```

```
source ~/.bashrc
```

```
cd ~
wget https://bootstrap.pypa.io/get-pip.py
python3.9 get-pip.py
```

### ライブラリのインストール

```
pip install tensorflow==2.16.1 
```
インストールできたことの確認。
```
python3.9 -c "import tensorflow as tf; print( tf.__version__ )"
```
更にインストール。
```
pip install tensorRT
pip install Flask
pip install Image
```

以下のコマンドで後述のソースを実行する。
```
python3.9 App_02.py
```

```App_02.py
#!/usr/local/python-3.9.18/bin/python3.9
# -*- coding: utf-8 -*-
import sys
sys.path.append('')
sys.path.append('/home/ec2-user/.local/lib/python3.9/site-packages')

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import models
from flask import Flask, request, jsonify
from tensorflow.keras.models import save_model as saver
from tensorflow.keras.models import load_model as loader
import os
from PIL import Image
import numpy as np

app = Flask(__name__)

# 下記と同名のフォルダを、実行環境と同一の階層に作成する
UPLOAD_FOLDER = 'uploads/'
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER

# ディレクトリを作成
os.makedirs('models', exist_ok=True)

# モデルの入力形状を定義
input_shape = (1, 784)
input_layer = keras.layers.Input(shape=input_shape)

# 後続のレイヤーを追加
x = keras.layers.Dense(128, activation='relu')(input_layer)
x = keras.layers.Dropout(0.2)(x)
output_layer = keras.layers.Dense(10, activation='softmax')(x)

# モデルの作成
model = models.Model(inputs=input_layer, outputs=output_layer)
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])

# モデルを保存
saver(model, 'models/my_model.h5')

# 保存されたモデルの読み込み
gpt4_model = loader('models/my_model.h5')

@app.route('/flask/upload', methods=['POST'])
def upload_file():
    if 'image' not in request.files:
        return "No file part", 400
    file = request.files['image']
    if file.filename == '':
        return "No selected file", 400

    filepath = os.path.join(app.config['UPLOAD_FOLDER'], file.filename)
    file.save(filepath)

    # 画像を前処理し、モデルに入力
    processed_image = process_image(filepath)
    result = call_gpt4(processed_image)

    # ファイルを削除
    os.remove(filepath)

    # JSON値を返却
    return jsonify(result)

def process_image(filepath):
    image = Image.open(filepath).convert('L')  # グレースケールに変換
    image = image.resize((28, 28))            # (28, 28) サイズにリサイズ
    image_array = np.array(image)
    image_array = image_array / 255.0          # 正規化
    image_array = image_array.flatten()        # フラットに変換
    image_array = np.expand_dims(np.expand_dims(image_array, axis=0), axis=1)  # (1, 784) に変換
    return image_array

def call_gpt4(image_array):
    # モデルの予測を呼び出し
    predictions = gpt4_model.predict(image_array)
    response = {"predictions": predictions.tolist()}  # 必要に応じて変換
    return response

if __name__ == '__main__':
    app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024  # 最大16MBのファイルサイズを許可
    app.debug = True
    app.run()
```

以下を上記サーバに向けて実行。
```
curl -X POST -F image=@/usr/local/src/Python-3.9.18/Mac/BuildScript/resources/background.jpg http://localhost:5000/flask/upload
```
画像がアップロードされ、少数のリストが返却されれば成功です。

ことの発端や WSGI 環境の構築に関しては、下記の記述及びリンク先を参照してください。

https://qiita.com/hashimotonet/items/8327654449fd54a33e03

# あとがき
今回は、たまたまCharGPT使用中に、話題の画像アップロードを試そうとしました。その際に提示されたモジュールは、OSそのままの設定では動かなかったことで、今回の環境作成作業をすることとなりました。

以前から使用している環境では、他の方が執筆されたありがたい文章を参照させていただくことで、無事に環境を作成することが出来ました。

また、この問題はどこに行っても付きまとう、環境の問題であるに違いない、と最初の環境がある程度完成したところで思っていました。

そのような事情から、各種のケースにおける、TensorFlowの稼働環境を作る、という命題をいくつかの環境において担保することを考えました。これを助けと思ってくださる方もあるのではなかろうかと。

今回の文章が、Deep Learningの世界にとって欠かせないTensorFlowの活用に関しての前進のための一歩となればと思い、ひいてはこれを介して深層学習の世界に自分を含めた人材が貢献できるようになれば、と思っています。