Flask + Stable DiffusionでWebアプリ開発のメモ
Windowsでやろうとするも、pyenv自体はWindowsに非対応だし微妙なので、WSL2でとりあえずやってみる。完全にメモ用ですすみません
Streamlitでは非同期処理ができないらしく、時間の計測ができないので諦める(調査不足だった)
代わりにFlaskを使うことにする
使う(予定の)もの
- WSL2
- Python
- Poetry
- pyenv
-
Streamlistreamlit-drawable-canvas
- Flask
- bootstrap-flask
環境構築
コマンドを色々実行していく。PowerShellはWindows側のシェルで、BashはUbuntuのデフォルトシェル。
WSL2
wsl --install
で普通に入れる。仮想化の有効化とかはググれば出てくるので略。
wsl --update
もしておいたほうがいいかも。
今回はUbuntuを使う
Ubuntu
Ubuntuを最初に起動すると初期設定のウィザードが始まるので、指示に従ってusernameやパスワードなどを設定する。パスワードは安全な場所にメモっておく。
以下はほとんどこの記事のままなので、元記事見たほうがいいかも…(ありがとうございます)
Ubuntuのライブラリのアップデート
sudo apt update
sudo apt upgrade
でUbuntuのライブラリ類をアップデートする。
pyenvを入れる
pyenvの依存関係を入れる
sudo apt install libssl-dev libffi-dev libncurses5-dev zlib1g zlib1g-dev libreadline-dev libbz2-dev libsqlite3-dev make gcc
pyenv本体を入れる
curl https://pyenv.run | bash
環境変数を設定
echo '' >> ~/.bashrc
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(pyenv init --path)"' >> ~/.bashrc
この4つのコマンドで環境変数を設定する(らしい)。
Ubuntuからログアウトする
exit
とかのコマンドを実行して一旦Ubuntuからログアウトする。再起動が必須かは不明だが、自分はログインし直しでOKだった。一旦ログアウトしないと、入れたpyenvが使えないので注意する。
Ubuntuにログインしてインストールを確認
pyenv --version
を実行してエラーが出ずに実行できたらOK。pyenvのバージョンが表示されるはず。
使いたいバージョンのPythonをインストール
pyenv install <Pythonのバージョン番号>
で使いたいバージョンのPythonをインストールする。今回は3.10.6
を使う(Stable Diffusionの関係上)。インストール可能なバージョンの一覧は
pyenv install --list
で表示できる。
ディレクトリを移動
使いたいバージョンのPythonをインストールしたら、今度は適当なディレクトリまでcd <移動先ディレクトリのアドレス>
コマンドで移動する。適切なディレクトリが無ければ、mkdir <ディレクトリ名>
で開発用のディレクトリを作ってそこに移動する。
ディレクトリにPythonのバージョンを設定
pyenv local <Pythonのバージョン番号>
で、そのディレクトリにPythonのバージョンを設定する。今回は3.10.6
。設定できたら、そのディレクトリに.python-version
というファイルが生成されているはずなので、一応ls -all
コマンドで表示させてみる(隠しファイルなので-all
が無いと表示できない)。
Poetry
Poetryのインストール
公式のドキュメント
curl -sSL https://install.python-poetry.org | python3 -
を実行してPoetry(Pythonのパッケージマネージャ)を入れる。
fish(その他のシェルでも)でパスを通す方法
curl -sSL https://install.python-poetry.org | python3 -
を実行した際に表示されるexport PATH="$HOME/.poetry/bin:$PATH"
みたいなものを、/.config/fish/config.fishに書き込む(config.fishは設定ファイル)。
本当はfishにはfish_add_path
とかset
とかがあるらしいが、よく分かっていないので、とりあえずBash互換(?)のこれでしのいだ
Ubuntuに入りなおす
これもUbuntuにログインし直す(再起動?)が必要なので、やる
インストール確認
poetry --version
を実行して、正常に実行されるか確認する。正常ならOK。
簡単な使い方集
Poetry
プロジェクトを作る
Poetryのプロジェクトを作成したいディレクトリに移動したら、そこで
poetry init --python ^3.10.6
を実行する。これは、Pythonの3.10.6
を使ってPoetryプロジェクトを作成するというコマンド。
poetry init
コマンドを実行するとPoetryの対話型の環境構築ウィザードが始まる。
-
Package Name
は今回は~~streamlit-ai
~~flask-ai
にした。入力してEnter。 -
Version
も適当でいいのでそのままEnter。 -
Discription
は無くていいので空欄のままEnter。 -
Auther
はまだこの段階では決めないのでn
とだけ入力してEnter。 -
License
も未定なのでそのままEnter。 - その後も色々聞かれるが、デフォルトの回答である
yes
で多分いいと思うのでそのままEnter。 - 最後の
生成しますか?
ももちろんEnter。
これが終われば、そのディレクトリにPoetryのプロジェクトが作成完了しています。
パッケージの追加
poetry add <Pythonのパッケージ名>
で、その環境にPythonのパッケージを追加する。
今回は、とりあえずflask
とbootstrap-flask
を入れるので、
poetry add flask
poetry add bootstrap-flask
この2つを(poetry init
済みのディレクトリで)実行する。
使うのをやめたStreamlitの部分
今回は、とりあえずstreamlit
とstreamlit-drawable-canvas
を入れるので、
poetry add streamlit
poetry add streamlit-drawable-canvas
この2つを(poetry init
済みのディレクトリで)実行する。
Pythonファイルの実行
Pythonファイルを実行するには、以下のコマンドを実行する。
poetry run python <実行するファイルの名前>
例えば、今回使うFlaskで、公式ドキュメントに載っているようにhello.py
に記述したプログラムを実行する場合は以下。
poetry run flask --app hello run
このコマンドは、通常はflask --app hello run
だけで実行できるプログラムを、Poetryの仮想環境を使わずに実行している。
Poetryの仮想環境を使う場合
poetry shell
flask --app hello run
これでOK。仮想環境から出るには
exit
を実行する。exit
を忘れなければ仮想環境に入ってから実行するほうがいいかも?
使うのをやめたStreamlitの部分2
例えば、今回使うStreamlitのデフォルトプロジェクトの場合は以下。
poetry run python -m streamlit hello
このコマンドは、通常はpython -m streamlit hello
だけで実行できるプログラムを、Poetryの仮想環境を使わずに実行している。
Poetryの仮想環境を使う場合
poetry shell
python -m streamlit hello
これでOK。仮想環境から出るには
exit
を実行する。
使わないことにしたStreamlitの部分
Poetryの仮想環境を使う場合、
python -m streamlit hello
ではなく、
streamlit run hello
でも良いっぽい
Flask
Flaskのインストール
poetry init
済みのディレクトリで、以下のコマンドを実行するだけ
poetry add flask
一回入れたものの、いらない気がする工程
今回はWebのフロントエンド実装のために、CSSフレームワークとしてBootstrapを使うので、bootstrap-flaskも入れる
poetry add bootstrap-flask
Bootstrap5の導入
FlaskだけではWebの表示部分を制御することができないので、表示部分はHTML+CSS+JavaScriptで実装する。そこで、CSSフレームワークにBootstrap5を使う。
ディレクトリ移動
Bootstrapのファイルをダウンロードして展開するので、自分の都合の良いディレクトリに移動しておく。
ちなみに、配置は以下の通りにします。
flask-ai
│ ├── flaskr
│ │ ├── app.py
│ │ ├── saved_canvas
│ │ ├── static
│ │ │ ├── css
│ │ │ │ ├── bootstrap.css
│ │ │ │ ├── bootstrap.css.map
│ │ │ │ ├── ︙
│ │ │ │ └── style.css
│ │ │ └── js
│ │ │ ├── bootstrap.bundle.js
│ │ │ ├── ︙
wgetしてダウンロード
Bootstrapのダウンロードページにダウンロードのリンクがあるので、それをコピーして、Ubuntuのターミナルで以下を実行する。
wget <コピーしたURL(末尾は.zipのはず)>
執筆時点では以下の通り。
wget https://github.com/twbs/bootstrap/releases/download/v5.3.0/bootstrap-5.3.0-dist.zip
Zipの解凍(展開)のためにunarコマンドを使えるように
Zipファイルを解凍するコマンドは入ってないので、解凍のためにunar
コマンドを使えるようにする。
なんかunzip
とかよりunar
のほうがいいらしいので。[1]
sudo apt install unar
これをUbuntuのターミナルで実行すればOK。
Zipを解凍
以下のコマンドでZipを解凍する。
unar <ダウンロードしたZipファイルのファイル名>
(必要なら)ファイルの移動
先に示したようなディレクトリ構造になるよう、ファイルを移動させる。ファイル・ディレクトリの移動はmv
コマンドを使うが、ディレクトリ名の変更にもmv
コマンドを使う[2]。
ディレクトリ名の変更
mv <今のディレクトリ名> <変更後のディレクトリ名>
mv templetes/ templates/
ファイル名の変更
ファイル名を変更したい場合も、同様の要領でできる。
mv <今のファイル名> <変更後のファイル名>
mv tekitou.png tekitou2.png
Flaskのディレクトリ構造
ここは正直大規模化したときに破綻しそうなので怖いけど、とりあえずGPT-4くんが提示したディレクトリ構造にしてみる(動きはする)
ディレクトリ構造が以下。flask-ai
がpoetry init
したディレクトリ。
flask-ai
│ ├── flaskr
│ │ ├── app.py
│ │ ├── saved_canvas
│ │ ├── static
│ │ │ ├── css
│ │ │ │ ├── bootstrap-grid.css
│ │ │ │ ├── bootstrap-grid.css.map
│ │ │ │ ├── bootstrap-grid.min.css
│ │ │ │ ├── bootstrap-grid.min.css.map
│ │ │ │ ├── bootstrap-grid.rtl.css
│ │ │ │ ├── bootstrap-grid.rtl.css.map
│ │ │ │ ├── bootstrap-grid.rtl.min.css
│ │ │ │ ├── bootstrap-grid.rtl.min.css.map
│ │ │ │ ├── bootstrap-reboot.css
│ │ │ │ ├── bootstrap-reboot.css.map
│ │ │ │ ├── bootstrap-reboot.min.css
│ │ │ │ ├── bootstrap-reboot.min.css.map
│ │ │ │ ├── bootstrap-reboot.rtl.css
│ │ │ │ ├── bootstrap-reboot.rtl.css.map
│ │ │ │ ├── bootstrap-reboot.rtl.min.css
│ │ │ │ ├── bootstrap-reboot.rtl.min.css.map
│ │ │ │ ├── bootstrap-utilities.css
│ │ │ │ ├── bootstrap-utilities.css.map
│ │ │ │ ├── bootstrap-utilities.min.css
│ │ │ │ ├── bootstrap-utilities.min.css.map
│ │ │ │ ├── bootstrap-utilities.rtl.css
│ │ │ │ ├── bootstrap-utilities.rtl.css.map
│ │ │ │ ├── bootstrap-utilities.rtl.min.css
│ │ │ │ ├── bootstrap-utilities.rtl.min.css.map
│ │ │ │ ├── bootstrap.css
│ │ │ │ ├── bootstrap.css.map
│ │ │ │ ├── bootstrap.min.css
│ │ │ │ ├── bootstrap.min.css.map
│ │ │ │ ├── bootstrap.rtl.css
│ │ │ │ ├── bootstrap.rtl.css.map
│ │ │ │ ├── bootstrap.rtl.min.css
│ │ │ │ ├── bootstrap.rtl.min.css.map
│ │ │ │ └── style.css
│ │ │ └── js
│ │ │ ├── bootstrap.bundle.js
│ │ │ ├── bootstrap.bundle.js.map
│ │ │ ├── bootstrap.bundle.min.js
│ │ │ ├── bootstrap.bundle.min.js.map
│ │ │ ├── bootstrap.esm.js
│ │ │ ├── bootstrap.esm.js.map
│ │ │ ├── bootstrap.esm.min.js
│ │ │ ├── bootstrap.esm.min.js.map
│ │ │ ├── bootstrap.js
│ │ │ ├── bootstrap.js.map
│ │ │ ├── bootstrap.min.js
│ │ │ ├── bootstrap.min.js.map
│ │ │ ├── countdown.js
│ │ │ └── draw.js
│ │ └── templates
│ │ └── index.html
│ ├── poetry.lock
│ └── pyproject.toml
デフォルトではstatic
やjs
,templetes
などのディレクトリは無いので、自分で作ってそこにさらに自分でHTMLやらJavaScriptのファイルを作成していくことになるのですが、ディレクトリ名を間違えるとエラーで動かなくなるので注意が必要です。特に、templetes
はスペルミスしやすい(templatesにしてて2時間溶かした顔)。
__pychache__
はアプリを動かすとその時に自動で作られるので気にしなくてOKです。
treeコマンドの導入
デフォルトではtree
コマンド[3]が使えないと思うので、これも入れる。
sudo apt install tree
以下のようにすると、カレントディレクトリ以下のディレクトリ構造が表示される。
tree .
サンプルを動かす
GPT-4に聞いて吐かせたサンプルプログラムを以下に示します。コピペすれば動きはするはず。
from flask import Flask, render_template, request
import os
import base64
import re
from datetime import datetime
template_dir = os.path.abspath('./templates')
app = Flask(__name__, template_folder=template_dir)
@app.route("/")
def home():
return render_template('index.html')
@app.route('/saved_canvas', methods=['POST'])
def save_canvas():
img_data = request.form['img'] # POSTリクエストから画像データを取得
img_data = re.sub('^data:image/.+;base64,', '', img_data) # data URLのヘッダ部分を削除
# 現在の時刻からファイル名を生成
now = datetime.now()
filename = now.strftime("%Y-%m-%d-%H%M-%S") + ".png"
# 保存先ディレクトリを指定
save_dir = '自分の環境に合わせて変える、~/dev/python/quickdiffusion/files/saved_canvasとか'
if not os.path.exists(save_dir):
os.makedirs(save_dir) # ディレクトリが存在しない場合は作成
with open(save_dir + filename, "wb") as fh:
fh.write(base64.b64decode(img_data)) # 画像データをデコードしてファイルに書き込む
return "", 200 # 正常終了のステータスコードを返す
if __name__ == '__main__':
app.run(debug=True)
document.getElementById("startButton").addEventListener("click", function() {
var timeleft = 10;
var countdownTimer = setInterval(function(){
if(timeleft <= 0){
clearInterval(countdownTimer);
document.getElementById("message").innerHTML = "Finished";
// カウントダウンが0になったらキャンバスの内容をサーバーに送信
sendCanvasData();
} else {
document.getElementById("message").innerHTML = timeleft + " seconds remaining";
}
timeleft -= 1;
}, 1000);
// Canvasをクリア
canvas.clear();
});
// 画像を表示する機能
document.getElementById('myImage').src = "path/to/your/image.png";
// キャンバスのデータをサーバーに送信する関数
function sendCanvasData() {
var dataURL = canvas.toDataURL(); // canvasの内容をPNGのdata URL形式で取得
var xhr = new XMLHttpRequest();
xhr.open("POST", "/save_canvas", true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send("img=" + encodeURIComponent(dataURL)); // data URLをPOSTリクエストのボディに含めて送信
}
// Javascriptファイル: draw.js
var canvas = new fabric.Canvas('myCanvas', {
backgroundColor: 'rgb(255,255,255)' // 背景を白に設定
});
var isDrawing = false;
canvas.isDrawingMode = false; // 初期状態では描画できないようにする
canvas.freeDrawingBrush.width = 5; // 線の太さを5に設定
canvas.freeDrawingBrush.color = "black"; // 線の色を黒に設定
canvas.on('mouse:down', function(o){
isDrawing = true;
});
canvas.on('mouse:up', function(o){
isDrawing = false;
});
// スタートボタンが押されたら描画可能にする
document.getElementById("startButton").addEventListener("click", function() {
canvas.isDrawingMode = true;
});
<!doctype html>
<html lang="ja">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Bootstrap CSS -->
<link href="{{ url_for('static', filename='css/bootstrap.min.css') }}" rel="stylesheet">
<!-- Custom CSS -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
<!-- Include Fabric.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.3.1/fabric.min.js"></script>
<title>My App</title>
</head>
<body>
<div class="container">
<div class="row">
<div class="col text-center">
<h1 id="message">Click the button to start countdown</h1>
</div>
</div>
<div class="row">
<div class="col">
<canvas id="myCanvas" width="400" height="250" style="border:1px solid #d3d3d3;">
</canvas>
</div>
<div class="col">
<img id="myImage" src="#" />
</div>
</div>
<div class="row">
<div class="col text-center">
<button id="startButton" class="btn btn-primary">Start</button>
</div>
</div>
</div>
<!-- jQuery and Bootstrap Bundle (includes Popper) -->
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<script src="{{ url_for('static', filename='js/bootstrap.bundle.min.js') }}"></script>
<!-- Custom JavaScript -->
<script src="{{ url_for('static', filename='js/countdown.js') }}"></script>
<script src="{{ url_for('static', filename='js/draw.js') }}"></script>
</body>
</html>
body {
background-color: #f8f9fa;
}
#myCanvas {
background-color: #ffffff;
width: 200%;
height: 750px;
}
#myImage {
width: 100%;
height: auto;
}
#startButton {
margin-top: 20px;
}
h1 {
margin: 50px 0;
}
コマンドラインから画像を開く
カウントダウンが0になると画像が保存されるようにしているが、実際きちんと保存されているかは確認しないと分からない。それを確認するときに、コマンドラインから画像を開きたいと思うので、eog
コマンドを使えるようにする(eogはEye of GNOME Image Viewerの頭文字)
sudo apt install eog
eogの使い方
eog <ファイル名>
eog 2023-01-29.png
これだけ
WSL2とVisual Studio Codeで快適に開発する
WSL2にUbuntuを入れ、テキストエディタにVSCodeを使っている場合は、拡張機能をインストールすることで快適に使えるようになります。
詳細は以下の記事を参考にしてください。記事のDocker以下の部分は関係ないです
Git/GitHubの使い方
まずはこのあたりを読むと分かりやすいと思います。要点がしっかりまとまっていて参考になります。
Gitのインストール
Gitもコマンドで入れます。WSL2を使っていても、WindowsにGitを入れる必要はありません。
sudo apt install git-all
以下のコマンドを実行して、バージョンが表示されればOKです。
git --version
Gitの初期設定
Gitのユーザー名とメールアドレスを設定します。ユーザー名はなんでもいいらしいですが、分かりやすいのでGitHubのユーザー名にしておくのがいいと思います。
git config --global user.name <設定するユーザー名>
git config --global user.name digitalsp
メールアドレスは、GitHubの登録に使ったメールアドレスにします。GitHubでメールアドレスを非公開にしている場合(Settings
→Emails
のKeep my email addresses privateチェックボックスに☑している場合)、そのままのメールアドレスが使えないので、GitHubアカウントの設定(Settings
→Emails
)で、設定するメールアドレスをコピーしてきます。
<数字>+<ユーザー名>@users.noreply.github.com
みたいなのがそれです。
git config --global user.email <設定するメールアドレス>
git config --global user.email xxxxxxxx+digitalsp@users.noreply.github.com
設定できたら、確認のために以下を実行してください。user.email=<設定したメールアドレス>
とuser.name=<設定したユーザー名>
が表示され、設定されていればOKです。
git config --list | grep user
GitHub CLIのインストール
GitHubをシェルから使えるようにするGitHub CLIをインストールします。シェルで以下のコマンドを実行します。
sudo apt update
sudo apt install gh
多分これで入ると思いますが、入らない場合は以下を実行してください
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \
&& sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg \
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
&& sudo apt update \
&& sudo apt install gh -y
sudo apt update
sudo apt install gh
以下を実行し、バージョン名が表示されればOKです
gh --version
GitHubにログイン
GitHub CLIを使ってGitHubにログインします。まずは、以下のコマンドを実行します。
gh auth login
表示される指示に従えばログインできるはずです。指示は英語なので翻訳してください。
GitHub上のリポジトリをクローン
GitHubリポジトリをローカルにクローン(≒ダウンロード)します。
gh repo clone <リポジトリのオーナー>/<リポジトリ名>
# octocat/Hello-Worldというリポジトリをクローンする場合
gh repo clone octocat/Hello-World
ブランチを分ける
ブランチを分けます。このコマンドを実行しないと、main
ブランチに変更が記録されてしまうので、必ず実行しましょう。
git checkout -b <新しいブランチ名>
Gitに記録させるファイルを追加
以下のコマンドを実行して、Gitに変更履歴を記録させるファイルを追加します。
git add <ファイル/ディレクトリの指定>
# そのディレクトリ以下の全てのファイル/ディレクトリを追加する場合
git add .
# 任意のファイル(ここでは`sample.txt`)を追加する場合
git add sample.txt
Gitに記録させたくないファイルがあり、それが多い場合は、.gitignore
というファイルで追加しないファイルを設定します。今回は、私が一通り設定した.gitignore
をGitHubに上げていて、GitHubからリポジトリをクローンしたら、この.gitignore
ファイルも同時にダウンロードされるので、特に設定は不要です。今回開発に使うのは非公開リポジトリですし、今回は問題になることは無いかと思いますが、GitHubのリポジトリがごちゃごちゃするので、プログラムの動作に関係のないファイルや、アクセストークンなどの機密情報が書かれたファイルなどはgit add
しないほうがよいです。
変更をCommitして記録
変更したファイルの変更を記録します。このコマンドは、開発が一段落したとき、例えば機能追加が終わったときなどに実行します。大量の変更を1度のCommitに含めると可読性が下がるので、適当な変更量に留めるのがよいです。適当な変更量の目安としては、1つのコミットの変更内容が、下記記事にあるコミット種別1つに収まる程度です。つまり、改善と機能追加を1つにまとめるのは多すぎ(1つに詰め込みすぎ)ということになります。
Commitには、変更がどのようなものであるかをコミットメッセージとして記述します。コミットメッセージの書き方については、だいたい以下の記事に従ってもらえればOKです(厳密に従う必要は無いです)。
上記記事の、通常版のコミット種別を採用します。…偉そうに書いていますが自分も初めてみたいなものなので、そんなに気にしすぎないでください…!
コマンド
コマンドは以下の通りです。git commit
を行うと、テキストエディタが起動すると思うので、そこに上述のコミット種別などのコミットメッセージを書いていきます。書き終わって保存できたら、ファイルを閉じるとコマンドが実行できます。
git commit
リモートリポジトリ(GitHubのリポジトリ)にPush
Commitした変更を、リモートリポジトリ(今回はGitHub上のリポジトリ)に反映します。これをPushといいます。
git push origin <(さっき作った)ブランチ名>
Pull Requestの作成
Pull Requestを作成します。Pull Requestとは、あるブランチに他のブランチを合わせてほしいと要求することです。今回は、主となるmain
ブランチに、他のブランチ(自分で作ったブランチ)を統合するように要求することになります。
gh pr create --base main --head <(さっき作った)ブランチ名>
これで、Pull Requestを作成できます。もしくは、(説明はしませんが)Push後に、GitHubのWebを開いて、今回のリポジトリのページから、GUIでPull Requestを作成することも可能です。
Mergeを待つ
PR(Pull Requestの略)を送ったら、管理者である私がPRを承認して、ブランチをMerge(マージ、統合という意味)します。ここで管理者以外ができることはないので、しばしお待ち下さい。
Merge後
PRがマージされたら、自分のPCのプログラムを更新しなければなりません。そこで、以下のコマンドを実行します。
git checkout main
git pull origin main
これで、自分のローカル環境にも、マージされたPRが反映されます。
管理者的マージメモ
PRが来たときは以下のようにする。
git fetch
でローカルにPRなどのブランチを反映
remote: Enumerating objects: 10, done.
remote: Counting objects: 100% (10/10), done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 6 (delta 2), reused 6 (delta 2), pack-reused 0
Unpacking objects: 100% (6/6), 1.42 KiB | 483.00 KiB/s, done.
From https://github.com/digitalsp/{リポジトリ名}
* [new branch] add_firstpage -> origin/add_firstpage*
こんな感じになればfetch
はOK。
git branch -a
ブランチ一覧を表示。
* main
remotes/origin/HEAD -> origin/main
remotes/origin/add_firstpage
remotes/origin/main
PRが来てるブランチのブランチ名を確認する。
git checkout -b add_firstpage origin/add_firstpage
git checkout -b <ローカルリポジトリでの表示ブランチ名> <origin/リモートブランチ名>
現在のブランチをPRが来ているブランチに切り替える。
M pyproject.toml
Branch 'add_firstpage' set up to track remote branch 'add_firstpage' from 'origin'.
Switched to a new branch 'add_firstpage'
こんな感じならOK。これでローカルで動作確認ができるようになったので、動作確認なんかをして、あとはGitHubのWebからマージする。
Intel OneAPI Toolkitを入れる
自分の手持ちPCのGPUはIntelなので、めんどくさいがUbuntuにIntel OneAPI Toolkitを入れる(パッケージ名はintel-basekit
)
インストール
intel-basekitのインストール
wget -O- https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB \ | gpg --dearmor | sudo tee /usr/share/keyrings/oneapi-archive-keyring.gpg > /dev/null
echo "deb [signed-by=/usr/share/keyrings/oneapi-archive-keyring.gpg] https://apt.repos.intel.com/oneapi all main" | sudo tee /etc/apt/sources.list.d/oneAPI.list
sudo apt update
これでパッケージの取得先を設定
sudo apt list intel-basekit -a
これでインストール可能なパッケージの一覧を表示
今回実行したところ、以下の出力があった
sudo apt list intel-basekit -a
Listing... Done
intel-basekit/all 2024.0.1-43 amd64
intel-basekit/all 2024.0.0-49522 amd64
intel-basekit/all 2023.2.0-49384 amd64
intel-basekit/all 2023.1.0-46401 amd64
intel-basekit/all 2023.0.0-25537 amd64
intel-basekit/all 2022.3.1-17310 amd64
intel-basekit/all 2022.3.0-8767 amd64
intel-basekit/all 2022.2.0-262 amd64
intel-basekit/all 2022.1.2-146 amd64
intel-basekit/all 2022.1.1-119 amd64
intel-basekit/all 2021.4.0-3422 amd64
intel-basekit/all 2021.3.0-3219 amd64
intel-basekit/all 2021.2.0-2883 amd64
intel-basekit/all 2021.1.0-2659 amd64
自分はvladmandic/automaticで既にOneAPI経由でStable Diffusionを使っていて、このライブラリは最新版が2024年1月(?)のものを使っているので、多分2024.0.0-49522
だろうと推測して入れることにした(実は2024.0.0
っぽいのはあとの工程をやっているときに気づいたが、なんか自動で2024.0.0
が入ったり入らなかったりしていたので気にしないことにした。多分最初からやるなら2024.0.0
のほうがいいと思う)。具体的なコマンドは以下の通り。ちなみに全部で14GBある超巨大ファイル群なので、空き容量に注意する。
sudo apt-get install intel-basekit=2024.0.0-49522
Pythonのパッケージのインストール
vladmandic/automaticのインストールスクリプト部分を参考に、poetry install
でPythonのパッケージを入れようとしたところ、パッケージの参照先URLが違うことに気づき、調べてみると、PyPlに無いパッケージを入れる方法を使うらしい。
記事の内容に従って、URLを設定して入れてみる。
インストールスクリプト部分の抜粋(457行目~)
if "linux" in sys.platform:
torch_command = os.environ.get('TORCH_COMMAND', 'torch==2.1.0a0 torchvision==0.16.0a0 intel-extension-for-pytorch==2.1.10+xpu --extra-index-url https://pytorch-extension.intel.com/release-whl/stable/xpu/us/')
os.environ.setdefault('TENSORFLOW_PACKAGE', 'tensorflow==2.14.0 intel-extension-for-tensorflow[xpu]==2.14.0.1')
poetry source add torch_ipex --priority=explicit https://pytorch-extension.intel.com/release-whl/stable/xpu/us/
これで、優先度Explicit
(最高?)でURLが追加される。あとは、ダウンロード元をさっき指定したやつにしてインストールするだけ。ちなみにファイルサイズがクソデカいらしく、コマンドの実行に15分くらいかかるほか、ストレージの容量も10GB単位で減るので注意。
poetry add torch==2.1.0a0 torchvision==0.16.0a0 intel-extension-for-pytorch==2.1.10+xpu --source torch_ipex
これで指定バージョンが入るはず。Intel公式の方法とかだとpipを使っているが、今回使っているのはpipではなくPoetryなので、こういうダウンロード元を指定する操作が必要。
Updating dependencies
Resolving dependencies... (879.8s)
Package operations: 21 installs, 0 updates, 0 removals
• Installing mpmath (1.3.0)
• Installing typing-extensions (4.9.0)
• Installing annotated-types (0.6.0)
• Installing certifi (2024.2.2)
• Installing charset-normalizer (3.3.2)
• Installing filelock (3.13.1)
• Installing fsspec (2024.2.0)
• Installing idna (3.6)
• Installing networkx (3.2.1)
• Installing pydantic-core (2.16.2)
• Installing sympy (1.12)
• Installing urllib3 (2.2.1)
• Installing numpy (1.26.4)
• Installing packaging (23.2)
• Installing pillow (10.2.0)
• Installing psutil (5.9.8)
• Installing pydantic (2.6.1)
• Installing requests (2.31.0)
• Installing torch (2.1.0a0+cxx11.abi)
• Installing intel-extension-for-pytorch (2.1.10+xpu)
• Installing torchvision (0.16.0a0+cxx11.abi)
Writing lock file
こういうのが出るので、実行が終わればOK。
テスト用スクリプトを実行すると、ImportError: libmkl_gnu_thread.so.2: cannot open shared object file: No such file or directory
というエラーが出ていた。
インストール確認用テストスクリプト
import os
import os
os.system("source /opt/intel/oneapi/setvars.sh")
import torch
import intel_extension_for_pytorch as ipex
print(torch.__version__)
print(ipex.__version__)
[print(f'[{i}]: {torch.xpu.get_device_properties(i)}') for i in range(torch.xpu.device_count())]
見落としていたが、Intelのクイックスタートガイドには以下のコマンドを実行せよと書かれていた。参考にしていたこのページだと分かりづらい書き方で(フルパスじゃないのでコピペ実行すると実行できない)ちょっとハマってしまった。
結局、これ↑に助けられた。
source /opt/intel/oneapi/compiler/latest/env/vars.sh
source /opt/intel/oneapi/mkl/latest/env/vars.sh
この2つのコマンドを実行して初めて使えるようになるらしい。
このコマンドを実行してもなお、以下のエラーが出る。libiomp5.so
が見つからないとかいうエラーだけど、さっき入れたintel-basekit
には含まれていないのか…?自動で入るんじゃないのか…?
torchvisionは使うだろうし直したいが、無視してもいいっぽい的なメッセージが出てくるので無視することにする。torchvision.ioってStable Diffusionで使うんだろうか…?
torchvision.ioが無いことの警告メッセージ
sh: 1: source: not found
/home/user/.cache/pypoetry/virtualenvs/quickdiffusion-QB0ctf98-py3.10/lib/python3.10/site-packages/torchvision/io/image.py:13: UserWarning: Failed to load image Python extension: ''If you don't plan on using image functionality from `torchvision.io`, you can ignore this warning. Otherwise, there might be something wrong with your environment. Did you have `libjpeg` or `libpng` installed before building `torchvision` from source?
warn(
Traceback (most recent call last):
File "/home/user/dev/python/flask-ai/quick_diffusion/files/test.py", line 4, in <module>
import intel_extension_for_pytorch as ipex
File "/home/user/.cache/pypoetry/virtualenvs/quickdiffusion-QB0ctf98-py3.10/lib/python3.10/site-packages/intel_extension_for_pytorch/__init__.py", line 94, in <module>
from .utils._proxy_module import *
File "/home/user/.cache/pypoetry/virtualenvs/quickdiffusion-QB0ctf98-py3.10/lib/python3.10/site-packages/intel_extension_for_pytorch/utils/_proxy_module.py", line 2, in <module>
import intel_extension_for_pytorch._C
ImportError: libiomp5.so: cannot open shared object file: No such file or directory
どうやらlibiomp5.so
はこのGitHubリポジトリにあるらしい。が、リポジトリのオーナー(Intel)がリポジトリをアーカイブにしてて、どうやら開発は止まったままになっているらしい。他に現役のリポジトリがあるのか?
どうやら/opt/intel/oneapi/compiler/
以下にファイルがあるっぽいというのがこの記事で分かったので見てみる。
/opt/intel/oneapi/compiler/2024.0/lib
にファイルがあった。
libiomp5.a
libiomp5.dbg
libiomp5.so
libiomp5_db.so
libiompstubs5.a
libiompstubs5.so
こんな感じでファイルがあったので、これっぽい。ただ、なぜ存在するのにリンクされてないのかが謎。こういうもんなの…?
見つかったとはいえ、どうやってリンクを貼ればいいかが不明すぎる。
ChatGPTに聞いてみたところ、テストプログラムに書いてたos.system("source /opt/intel/oneapi/setvars.sh")
はそこに書いても意味ないとのことだったので、シェルからコマンド(source /opt/intel/oneapi/setvars.sh
)としてテストプログラムの実行前に実行してみた。
すると、以下のような出力が現れた。
source /opt/intel/oneapi/setvars.shの出力
:: initializing oneAPI environment ...
bash: BASH_VERSION = 5.1.16(1)-release
args: Using "$@" for setvars.sh arguments:
:: advisor -- latest
:: ccl -- latest
:: compiler -- latest
:: dal -- latest
:: debugger -- latest
:: dev-utilities -- latest
:: dnnl -- latest
:: dpcpp-ct -- latest
:: dpl -- latest
:: ipp -- latest
:: ippcp -- latest
:: mkl -- latest
:: mpi -- latest
:: tbb -- latest
:: vtune -- latest
:: oneAPI environment initialized ::
これが必要だったのか~~~イケるか~~~??と思いながらテストプログラムを実行したら、今度は同じような見つからないエラーで、別のファイルが見つからないとエラーが出た。エラーは以下。
libze_loader.so.1が見つからないエラー
/home/user/.cache/pypoetry/virtualenvs/quickdiffusion-QB0ctf98-py3.10/lib/python3.10/site-packages/torchvision/io/image.py:13: UserWarning: Failed to load image Python extension: ''If you don't plan on using image functionality from `torchvision.io`, you can ignore this warning. Otherwise, there might be something wrong with your environment. Did you have `libjpeg` or `libpng` installed before building `torchvision` from source?
warn(
Traceback (most recent call last):
File "/home/user/dev/python/flask-ai/quick_diffusion/files/test.py", line 4, in <module>
import intel_extension_for_pytorch as ipex
File "/home/user/.cache/pypoetry/virtualenvs/quickdiffusion-QB0ctf98-py3.10/lib/python3.10/site-packages/intel_extension_for_pytorch/__init__.py", line 94, in <module>
from .utils._proxy_module import *
File "/home/user/.cache/pypoetry/virtualenvs/quickdiffusion-QB0ctf98-py3.10/lib/python3.10/site-packages/intel_extension_for_pytorch/utils/_proxy_module.py", line 2, in <module>
import intel_extension_for_pytorch._C
ImportError: libze_loader.so.1: cannot open shared object file: No such file or directory
このlibze_loader.so.1
というのは、Intel Level Zeroとかいう技術の一部らしい。が、今回はそもそもマシン上に存在してすらいない(find /home -iname libze_loader.so.1
で検索したがヒット0)。なにそれ…
しょうがないので、ネット上にあるパッケージをダウンロードしてきて、手動で入れることにした
libze_loader.so.1
が含まれていると思われるパッケージがあるのがこのGitHubリポジトリ
とりあえず、最新版で不具合が出たらだるいので、少し古めのv1.15.13
にしてみたhttps://github.com/oneapi-src/level-zero/releases/download/v1.15.13/
wget https://github.com/oneapi-src/level-zero/releases/download/v1.15.13/level-zero_1.15.13+u22.04_amd64.deb
で.deb
ファイルをダウンロードし、そこでsudo apt-get install level-zero_1.15.13+u22.04_amd64.deb
をしたところ、なぜかE: Unable to locate package level-zero_1.15.13+u22.04_amd64.deb
というエラーが。何が悪いのか全くわからないが、ググるとgdebi
を使えばいいという情報があったので試す。
上記記事の通りに
sudo apt-get install gdebi
でgdebi
をインストールし、その後
sudo gdebi level-zero_1.15.13+u22.04_amd64.deb
で無事パッケージをインストールできた。なんでパッケージインストールにもめんどくさい手順を踏まねばならないのか…
この手順のあと、同じようにテストプログラムを実行すると、以下のようになり、とりあえずIntel® Extension for TensorFlowはインストールできたようだ。ただ、肝心のTorchvisionの警告は消えていないので、どうやらそれはまた別途対処が必要らしい…
/home/user/.cache/pypoetry/virtualenvs/quickdiffusion-QB0ctf98-py3.10/lib/python3.10/site-packages/torchvision/io/image.py:13: UserWarning: Failed to load image Python extension: ''If you don't plan on using image functionality from `torchvision.io`, you can ignore this warning. Otherwise, there might be something wrong with your environment. Did you have `libjpeg` or `libpng` installed before building `torchvision` from source?
warn(
2.1.0a0+cxx11.abi
2.1.10+xpu
まとめ
Ubuntuを起動させたらpoetry shell
で仮想環境に入る度に、最初に毎回以下の3つのコマンドを実行する。
source /opt/intel/oneapi/compiler/latest/env/vars.sh
source /opt/intel/oneapi/mkl/latest/env/vars.sh
source /opt/intel/oneapi/setvars.sh
コピペ用
source /opt/intel/oneapi/compiler/latest/env/vars.sh && source /opt/intel/oneapi/mkl/latest/env/vars.sh && source /opt/intel/oneapi/setvars.sh
無いファイルがあったらとりあえず入れてみる。
更新中…
TorchVisionは諦めたものの、どういうわけか色々と追加でエラーが出てきたので色々入れた。覚えている範囲で書き残しておく。
libGL.so.1
さぁAIモデルを使おうと思ったら出たエラー。
ImportError: libGL.so.1: cannot open shared object file
入ってない場合があるらしい。以下のコマンドで解決。
sudo apt-get install libgl1-mesa-dev
lzma
どうやらWSL2とかでPythonを使っているとあることらしい。一旦pyenvでPythonをアンインストールする。
sudo apt-get install liblzma-dev
その後、上記コマンドでlzmaをインストールしてから、再度pyenvでPythonをインストールして解決。