Open19

生成AI系の環境構築メモ

Megumu UedaMegumu Ueda

自分じゃPythonの開発もほぼしたことないので何もわかってない素人です

まっさらな状態からスタート
OS: Win11
グラボ: RTX4080

Megumu UedaMegumu Ueda

pyenv-winをインストール

Gitコマンドインストール

https://github.com/pyenv-win/pyenv-win/blob/master/docs/installation.md#git-commands

PowerShellを開く
手順の%USERPROFILE%を書き換えて実行

git clone https://github.com/pyenv-win/pyenv-win.git "$HOME\.pyenv"

PowerShellを開きなおす
以下のコマンドはそのままでOK

[System.Environment]::SetEnvironmentVariable('PYENV',$env:USERPROFILE + "\.pyenv\pyenv-win\","User")

[System.Environment]::SetEnvironmentVariable('PYENV_ROOT',$env:USERPROFILE + "\.pyenv\pyenv-win\","User")

[System.Environment]::SetEnvironmentVariable('PYENV_HOME',$env:USERPROFILE + "\.pyenv\pyenv-win\","User")

PowerShellを開きなおす(開き直さなくても良い気はするけど)
以下のコマンドはそのままでOK

[System.Environment]::SetEnvironmentVariable('path', $env:USERPROFILE + "\.pyenv\pyenv-win\bin;" + $env:USERPROFILE + "\.pyenv\pyenv-win\shims;" + [System.Environment]::GetEnvironmentVariable('path', "User"),"User")
Megumu UedaMegumu Ueda

Pythonのインストール

インストール可能なバージョンを確認
最新にするとワーニングがでるので3.10.6を入れる

pyenv install -l
pyenv install 3.10.6
pyenv global 3.10.6
Megumu UedaMegumu Ueda

C++コンパイラが必要なのでインストール
以下サイトの下の方にあるBuild Toolsをインストールする

https://visualstudio.microsoft.com/ja/downloads/

インストーラーが起動するので1個目のC++ビルドができるようになるやつを選択してインストール
インストール後、Power Shellからパスが通ったコマンドプロンプトが起動できるようになる

Megumu UedaMegumu Ueda

Stable Diffusion WebUI

Clone

ファイルパスに日本語があるとダメなので注意
最初、デスクトップ配下でコピーしたら怒られた(「デスクトップ」じゃなくて「Desktop」にしてくれたら良いのに・・・)

git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui.git

書き換え

PyTorchのバージョンを最新+CUDAサポートに変えてみる
CUDAが使えるかどうかはNVIDIAのコントロールパネルでわかる

Pythonのパスに現在のものを設定

実行

webui-user.bat

実行するとoutputフォルダに画像が保存されていく

はまったところ

1回実行したあとに、ディレクトリを変更したり、Pythonのバージョンを変えたりなどした場合、Stable Diffusionのvenvディレクトリに環境が残ってるので失敗する
venvフォルダは初回実行時に作られるので、環境が変わった場合は削除して再実行

XL

参考:https://aitechworld.info/stable-diffusion-sdxl/
モデルをダウンロードしてmodelフォルダ配下に格納、UIから再設定
画像サイズを1024以上にする必要がある

Megumu UedaMegumu Ueda

Stable Diffusion WebUI Forge

Clone

git clone https://github.com/lllyasviel/stable-diffusion-webui-forge.git

実行

webui-user.batを同じように修正して実行するだけ

Megumu UedaMegumu Ueda

ControlNet用のModelを追加で持ってくることでControlNet利用が可能
ControlNetは追加のExtensionは不要で最初から入ってる
XLを使う場合はXL用のモデルを使わないエラーになる

Megumu UedaMegumu Ueda

Code Llama

LM Studio

なんやかんや頑張るよりLM Studioとやらを使う方が手っ取り早そうなのでまずは使ってみる

https://lmstudio.ai/

Download

LM Studioの検索画面から探して、この人のを入れてみる

https://huggingface.co/TheBloke

実行

自分のGitHubのコードから適当なコードを投げてみる

Megumu UedaMegumu Ueda

Chat with RTX

インストール

ここからインストーラーをダウンロードして動かすだけ
https://www.nvidia.com/ja-jp/ai-on-rtx/chat-with-rtx-generative-ai/

試す

それなりのスピードで動く
RAGなのでDatasetで指定したフォルダのデータを事前知識として動くのかな

Megumu UedaMegumu Ueda

AI model defaultにするとRAGじゃなくて普通に答えてくれた
修正したいコードを伝えたら一応提案してくれたけど、コンテキストサイズが小さくて長いのは無理だった
Datasetとして.tsとか指定できるかなと思ったけど、作ってるアプリのsrcフォルダを指定したらエラーになったのでダメなのかな

Megumu UedaMegumu Ueda

Wisper

参考:https://qiita.com/reriiasu/items/920227cf604dfb8b7949

環境構築

Cloneする

git clone https://github.com/reriiasu/speech-to-text.git
cd speech-to-text

仮想化してpipインストールを実行(コマンドプロンプト)

python3 -m venv venv
.\venv\Scripts\activate.bat
pip install -r requirements.txt

動かす

python -m speech_to_text

Chromeがインストールされていないと動かないので、なければインストール。
起動するとブラウザが起動する。
以下を操作。

  • AppSettingsでマイクを選択
  • ModelSettingsでモデルを選択
  • Transribe Settingsで言語を選択

Start Stranscriptionを押して開始。
選択したModelがない場合は初回はダウンロードが走る。


(画像は適当にYouTubeを再生して音声認識させたもの)

Megumu UedaMegumu Ueda

使い方が悪いのか、動かしてると止まるな
CPUが全く動いてないので止まってる

Megumu UedaMegumu Ueda

Style-Bert-VITS2

こちら
https://zenn.dev/litagin/articles/034819a5256ff4

git clone https://github.com/litagin02/Style-Bert-VITS2.git
cd Style-Bert-VITS2
python3 -m venv venv
venv\Scripts\activate
pip install torch torchaudio --index-url https://download.pytorch.org/whl/cu118
pip install -r requirements.txt
python initialize.py

Editorの起動

python server_editor.py --inbrowser

APIサーバーの起動

python server_fastapi.py

WebUIの起動

python app.py

起動後、説明を見ながらぽちぽちで学習が可能

Megumu UedaMegumu Ueda

ReazonSpeech

こちら
https://research.reazon.jp/projects/ReazonSpeech/

venv\Scripts\activate
git clone https://github.com/reazon-research/ReazonSpeech
pip install setuptools
pip install Cython
pip install ReazonSpeech/pkg/nemo-asr

適当にWebサーバー化してAPI対応

import os
from flask import Flask, request, jsonify, make_response
from flask_cors import CORS
import tempfile
import logging
import json
from reazonspeech.nemo.asr import load_model, transcribe, audio_from_path

app = Flask(__name__)
CORS(app)  # どこからでもリクエストを受け付けるようにCORSを設定

# ログ設定
logging.basicConfig(level=logging.INFO)

# reazonspeech
model = load_model()

@app.route('/transcribe', methods=['POST'])
def handle():
    if 'audio' not in request.files:
        return jsonify({'error': 'No audio file provided'}), 400
    
    audio_file = request.files['audio']
    
    # ファイルを一時的に保存
    temp_dir = tempfile.gettempdir()
    audio_path = os.path.join(temp_dir, audio_file.filename)
    audio_file.save(audio_path)

    # 文字起こし前のログ
    logging.info(f"Received audio file: {audio_file.filename}")
    
    # reazonspeech
    audio = audio_from_path(audio_path)
    transcription_text = transcribe(model, audio)
    
    # 一時ファイルを削除
    os.remove(audio_path)

    # 文字起こし後のログ
    logging.info("Transcription completed.")
    logging.info(f"Transcription result: {transcription_text.text}")
    
    # 結果をJSON形式で返す
    response = make_response(json.dumps({'transcription': transcription_text.text}, ensure_ascii=False))
    response.mimetype = "application/json"
    return response

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5001)
Megumu UedaMegumu Ueda

Dify

DifyのAPIをstreamingで呼び出すサンプル
例外処理考慮なしで、ワークフローの最後だけ取得
出力が長いと1回の「data:」が尻切れになるみたいなのでJSONパースエラーになった場合は次のchunkにくっつけてもう1回JSONパースするようにしている

 // 参考: https://zenn.dev/himanushi/articles/99579cf407c30b

const callDifyByStreaming = async (input) => {
  const completion = await fetch(DIFY_URL, {
    headers: {
      "Content-Type": "application/json",
      Authorization: AUTHORIZATION_HEADER,
    },
    method: "POST",
    body: JSON.stringify({
      inputs: input,
      response_mode: "streaming",
      user: USER,
    }),
  });

  const reader = completion.body?.getReader();

  if (completion.status !== 200 || !reader) {
    return "error";
  }

  let result = "";

  const decoder = new TextDecoder("utf-8");
  try {
    let texts = "";
    let allOutput = [];
    const read = async () => {
      const { done, value } = await reader.read();
      if (done) return reader.releaseLock();
      const chunk = decoder.decode(value, { stream: true });

      texts += chunk;
      const json = texts
        .split("data:")
        .map((data) => {
          if (data) {
            try {
              const event = JSON.parse(data);
              allOutput.push(event);
              fs.writeFileSync("outputs.json", JSON.stringify(allOutput));
              if (event.event === "workflow_finished") {
                const result = event.data;
                return result.outputs;
              }
            } catch (e) {
              texts = `data:${data}`;
            }
          }
          return "";
        })
        .filter((data) => data)[0];
      if (json) {
        result = json;
      }
      return read();
    };
    await read();
  } catch (e) {
    console.error(e);
  }
  reader.releaseLock();

  return result;
};

GPT-o1にPython化してもらったサンプル

async def callDifyByStreaming(input):
    timeout = aiohttp.ClientTimeout(total=None)
    async with aiohttp.ClientSession(timeout=timeout) as session:
        async with session.post(
            DIFY_URL,
            headers={
                "Content-Type": "application/json",
                "Authorization": AUTHORIZATION_HEADER,
            },
            json={
                "inputs": input,
                "response_mode": "streaming",
                "user": USER,
            }
        ) as response:
            if response.status != 200:
                return "error"

            result = ""
            try:
                texts = ""
                allOutput = []
                async for value in response.content.iter_chunked(1024):
                    chunk = value.decode('utf-8')
                    texts += chunk
                    parts = texts.split('data:')
                    texts = ''
                    for i, data in enumerate(parts):
                        data = data.strip()
                        if not data:
                            continue
                        try:
                            event = json.loads(data)
                            allOutput.append(event)
                            with open("outputs.json", "w", encoding="utf-8") as f:
                                json.dump(allOutput, f, ensure_ascii=False)
                            if event.get('event') == 'workflow_finished':
                                result = event['data']['outputs']
                                return result
                        except json.JSONDecodeError:
                            # JSONのパースに失敗した場合、未処理のデータをテキストに戻す
                            texts = 'data:' + 'data:'.join(parts[i:])
                            break  # 次のチャンクを待つためにループを抜ける
                # ループ終了後、未処理のデータが残っている可能性があるため処理する
                data = texts.strip()
                if data:
                    parts = data.split('data:')
                    for data_part in parts:
                        data_part = data_part.strip()
                        if not data_part:
                            continue
                        try:
                            event = json.loads(data_part)
                            allOutput.append(event)
                            with open("outputs.json", "w", encoding="utf-8") as f:
                                json.dump(allOutput, f, ensure_ascii=False)
                            if event.get('event') == 'workflow_finished':
                                result = event['data']['outputs']
                                return result
                        except json.JSONDecodeError:
                            pass
                return result
            except Exception as e:
                print(e)
                return result
Megumu UedaMegumu Ueda

AWS Claude

事前にセッショントークンを取得している前提
参考:https://zenn.dev/fujiwara/scraps/25abc374adab52

import AnthropicBedrock from "@anthropic-ai/bedrock-sdk";
import dotenv from "dotenv";

dotenv.config();

const client = new AnthropicBedrock({
  awsSessionToken: process.env.AWS_SESSION_TOKEN,
  awsRegion: process.env.AWS_REGION,
});

async function main() {
  const message = await client.messages.create({
    model: "anthropic.claude-3-5-sonnet-20240620-v1:0",
    max_tokens: 256,
    messages: [{ role: "user", content: "Hello, world" }],
  });
  console.log(message);
}
main().catch(console.error);
Megumu UedaMegumu Ueda

Qwen2.5-Coder

以下にあるサンプルプログラムを試す
https://weel.co.jp/media/tech/qwen2-5-coder/

33Bは動かせないと思うので7Bで試す。

python3 -m venv venv
venv\Scripts\activate
pip install torch --index-url https://download.pytorch.org/whl/cu121
pip install transformers
pip install 'accelerate>=0.26.0'

結果

Sure! Here is an implementation of the Quick Sort algorithm in Python:

def quick_sort(arr):
    if len(arr) <= 1:
        return arr
    else:
        pivot = arr[len(arr) // 2]
        left = [x for x in arr if x < pivot]
        middle = [x for x in arr if x == pivot]
        right = [x for x in arr if x > pivot]
        return quick_sort(left) + middle + quick_sort(right)

# Example usage:
arr = [3, 6, 8, 10, 1, 2, 1]
sorted_arr = quick_sort(arr)
print(sorted_arr)

This implementation uses the Lomuto partition scheme, where the pivot is chosen as the middle element of the array. The array is then partitioned into three sub-arrays: elements less than the pivot, elements equal to the pivot, and elements greater than the pivot. These sub-arrays are recursively sorted.


動いたけどめっちゃ遅い