独自のDockerImageを作成して、GitHub ActionsからDocker Hubにpushする【Docker】【GitHubActions】

はじめに

Dockerを使っていると自分でimageをカスタマイズしたくなることがあると思います
今回は、Simpleなカスタマイズしたimageを作成して、GitHub Actions上で自動でDocker Hubにpushするところまでを作っていきます

環境

  • Docker
  • Docker Hub(アカウントが必要.無料アカウントでOK)

準備

docker hubのTokenを作成

まずは docker hubの Access Tokensを作成します。

今回は、Write(upload)も追加します

GitHub Secretの登録

GitHub Actionsからdocker hubにpushしたいので、usernameや tokenを Repository secrets に登録します

Docker imageの作成

今回は、python3.10をベースに起動したら hello World + 現在の時間 を表示するimageを作成します

# 使用するベースイメージを指定
FROM python:3.10

# ワーキングディレクトリを設定
WORKDIR /usr/src/app

# 日本時間での現在の日付と時刻を取得し、それを"Hello World"メッセージと一緒に出力するPythonスクリプトを作成
RUN echo "import datetime; print('Hello World at', datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=9), 'JST')))" > hello.py

# Dockerコンテナが起動したときに実行するコマンドを指定
CMD ["python", "./hello.py"]

GitHub Actionsによる自動化

docker imageを作ってもdocker hubにpushするのが手動だと大変なので、GitHub Actionsから自動で行えるようにします
また、作成したimageが正しく動いているかのデバッグもpushの後に処理して見れるようにします

DockerHubにpush時にuploadをするActionの作成

先ほど登録した user name とtokenを使って、ログインを行います

    - name: Login to Docker Hub
      uses: docker/login-action@v3.0.0
      with:
        username: ${{ secrets.DOCKER_HUB_USERNAME }}
        password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}

Actionの設定ファイルは以下です

name: Docker Build and Push

on:
  push:
    branches:
      - main

jobs:
  build-and-push:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout Repository
      uses: actions/checkout@v4.1.1

    - name: Login to Docker Hub
      uses: docker/login-action@v3.0.0
      with:
        username: ${{ secrets.DOCKER_HUB_USERNAME }}
        password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}

    - name: Build and Push Docker Image
      uses: docker/build-push-action@v5.1.0
      with:
        context: .
        file: ./Dockerfile
        push: true
        tags: ayousanz/test1:latest

uploadしたimageのデバッグ用のActionの作成

上記のActionsが終わるまで、成功したら実行されるようにします

if: ${{ github.event.workflow_run.conclusion == 'success' }}

Actionの設定ファイルは以下です

name: Docker Image Test

on:
  workflow_run:
    workflows: ["Docker Build and Push"]
    types:
      - completed

jobs:
  test:
    runs-on: ubuntu-latest
    if: ${{ github.event.workflow_run.conclusion == 'success' }}
    steps:
    - name: Checkout Repository
      uses: actions/checkout@v4.1.1

    - name: Pull Docker Image from Docker Hub
      run: docker pull ayousanz/test1:latest

    - name: Run Docker Image
      run: docker run --rm ayousanz/test1:latest

    # ここでテストコマンドを実行
    - name: Test Command
      run: echo "Run your test commands here"

Bert-VITS2をGoogle Colobで学習をする(失敗メモ)

はじめに

VITS2よりも精度がよく、演技等もうまく出せるというBert-VITS2で学習をしていきます

結論 学習は成功した?もの生成した音声がうまくいっておらず、成功はしていません

環境

参考サイト

こちらの記事を参考に進めていきます

zenn.dev

詰まったところ

追加でインストールしたライブラリ

!pip install --upgrade tensorflow-probability
!pip install kaleido cohere openai tiktoken

Qwen/Qwen-Audio-ChatをGoogle Colobで動かす

環境

準備

ライブラリをインストールします

!pip install transformers==4.32.0 accelerate tiktoken einops transformers_stream_generator==0.0.4 scipy torchvision pillow tensorboard matplotlib

実行

ft16やbf16は対応していないっぽくて、動かなかったです また音声データはサンプルのものを使用しています

from transformers import AutoModelForCausalLM, AutoTokenizer
from transformers.generation import GenerationConfig
import torch
torch.manual_seed(1234)

# Note: The default behavior now has injection attack prevention off.
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen-Audio-Chat", trust_remote_code=True)

# use cuda device
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen-Audio-Chat", device_map="cuda", trust_remote_code=True).eval()

# Specify hyperparameters for generation (No need to do this if you are using transformers>4.32.0)
model.generation_config = GenerationConfig.from_pretrained("Qwen/Qwen-Audio-Chat", trust_remote_code=True)

# 1st dialogue turn
query = tokenizer.from_list_format([
    {'audio': 'https://qianwen-res.oss-cn-beijing.aliyuncs.com/Qwen-Audio/1272-128104-0000.flac'}, # Either a local path or an url
    {'text': '話している人は何と言っていますか?'},
])
response, history = model.chat(tokenizer, query=query, history=None)
print(response)
# The person says: "mister quilter is the apostle of the middle classes and we are glad to welcome his gospel".

# 2nd dialogue turn
response, history = model.chat(tokenizer, '会話の中で大事な部分を要約してください', history=history)
print(response)

Qwen/Qwen-7B-Chat-Int4をGoogle Colobで動かす

はじめに

Qwen/Qwen-72Bが公開されたのですが、動かせるGPU RAMがないため 以下の7B版を動かしてみます

huggingface.co

環境

  • Goolgle Colob

準備

ライブラリをインストールします

!pip install transformers==4.32.0 accelerate tiktoken einops scipy transformers_stream_generator==0.0.4 peft deepspeed
!pip install auto-gptq optimum

推論

モデルのロード等を行います

from transformers import AutoTokenizer, AutoModelForCausalLM

# Note: The default behavior now has injection attack prevention off.
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen-7B-Chat-Int4", trust_remote_code=True)

model = AutoModelForCausalLM.from_pretrained(
    "Qwen/Qwen-7B-Chat-Int4",
    device_map="auto",
    trust_remote_code=True
).eval()

まずは、挨拶から聞いてみます

response, history = model.chat(tokenizer, "こんにちは", history=None)
print(response)

次にいつもの質問をしてみます

response, history = model.chat(tokenizer, "まどマギで一番可愛いキャラはなんですか?", history=None)
print(response)

なんか日本の文化はちゃんと学んでいないみたいですね

GoogleColobでTheBloke/calm2-7B-chat-AWQを動かす

はじめに

今更ですが、CALM2のAWQ版を動かしてみます。

huggingface.co

環境

  • Google Colob A100 (GPU RAMを25GB使うため、無料枠だと無理でした)

準備

必要なライブラリの追加します

!pip -q install --upgrade accelerate autoawq
!pip install torch==2.1.0+cu121 torchtext==0.16.0+cpu torchdata==0.7.0 --index-url https://download.pytorch.org/whl/cu121

autoawqだけを入れようとすると以下のエラーで怒られたので、issueを参考にしています

ImportError                               Traceback (most recent call last)
<ipython-input-2-e1b236244288> in <cell line: 1>()
----> 1 from awq import AutoAWQForCausalLM
      2 from transformers import AutoTokenizer
      3 
      4 model_name_or_path = "TheBloke/calm2-7B-chat-AWQ"
      5 

5 frames
/usr/local/lib/python3.10/dist-packages/awq/modules/linear.py in <module>
      2 import torch
      3 import torch.nn as nn
----> 4 import awq_inference_engine  # with CUDA kernels
      5 
      6 

ImportError: libcudart.so.12: cannot open shared object file: No such file or directory

---------------------------------------------------------------------------
NOTE: If your import is failing due to a missing package, you can
manually install dependencies using either !pip or !apt.

To view examples of installing some common dependencies, click the
"Open Examples" button below.

github.com

推論

from awq import AutoAWQForCausalLM
from transformers import AutoTokenizer

print("start")

model_name_or_path = "TheBloke/calm2-7B-chat-AWQ"

# Load tokenizer
tokenizer = AutoTokenizer.from_pretrained(model_name_or_path, trust_remote_code=False)
# Load model
model = AutoAWQForCausalLM.from_quantized(model_name_or_path, fuse_layers=True,
                                          trust_remote_code=False, safetensors=True)

prompt = "Tell me about AI"
prompt_template=f'''USER: {prompt}
ASSISTANT:
'''

print("*** Running model.generate:")

token_input = tokenizer(
    prompt_template,
    return_tensors='pt'
).input_ids.cuda()

# Generate output
generation_output = model.generate(
    token_input,
    do_sample=True,
    temperature=0.7,
    top_p=0.95,
    top_k=40,
    max_new_tokens=512
)

# Get the tokens from the output, decode them, print them
token_output = generation_output[0]
text_output = tokenizer.decode(token_output)
print("LLM output: ", text_output)

"""
# Inference should be possible with transformers pipeline as well in future
# But currently this is not yet supported by AutoAWQ (correct as of September 25th 2023)
from transformers import pipeline

print("*** Pipeline:")
pipe = pipeline(
    "text-generation",
    model=model,
    tokenizer=tokenizer,
    max_new_tokens=512,
    do_sample=True,
    temperature=0.7,
    top_p=0.95,
    top_k=40,
    repetition_penalty=1.1
)

print(pipe(prompt_template)[0]['generated_text'])
"""

いつもの質問も聞いてみます。

推論に必要なリソース

berkeley-nest/Starling-LM-7B-alphaをStreamで動かしてみる

初めに

(非商用ですが)性能がいいとのことなので、実際に試してみます

モデル

huggingface.co

環境

準備

今回はStreamで実行したいので、その部分も書いていきます

8bit量子化でロードしようとするとエラーが出たので、諦めてfloat16でロードします

import torch
from transformers import AutoTokenizer, AutoModelForCausalLM
from transformers import TextStreamer

tokenizer = AutoTokenizer.from_pretrained("berkeley-nest/Starling-LM-7B-alpha")
model = AutoModelForCausalLM.from_pretrained("berkeley-nest/Starling-LM-7B-alpha",torch_dtype=torch.float16, low_cpu_mem_usage=True)
streamer = TextStreamer(tokenizer, skip_prompt=True, skip_special_tokens=True)
model = model.to("cuda:0")

推論

以下のコードで推論を実行していきます

text = "自然言語処理とは何か"
tokenized_input = tokenizer.encode(text, add_special_tokens=False, return_tensors="pt").to(model.device)
with torch.no_grad():
    output = model.generate(
        tokenized_input,
        max_new_tokens=10000,
        do_sample=True,
        top_p=0.95,
        temperature=0.7,
        pad_token_id = 32000,
        streamer=streamer,
    )[0]

推論速度

GPUがL4というのもありますが、それなりの速度が出ていました

推論時 GPU RAM

float16で訳18GB程度でした

自然言語処理とは何か

まどマギで一番可愛いキャラはなんですか?

日本で一番高い山はなんですか?

Google Colobでisek-ai/SDPrompt-RetNet-300Mを動かす

はじめに

こちらのポストを見て、単語からプロンプトを生成していてすごい!?となったので実際に動かしてみます

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

!pip install transformers safetensors timm

実装

from transformers import AutoModelForCausalLM, AutoTokenizer, TextStreamer

MODEL_NAME = "isek-ai/SDPrompt-RetNet-300M"

DEVICE = "cuda"

tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
model = AutoModelForCausalLM.from_pretrained(
    MODEL_NAME,
    trust_remote_code=True,
).to(DEVICE)

streamer = TextStreamer(tokenizer)

prompt = "<s>1girl"

inputs = tokenizer(prompt, return_tensors="pt").to(model.device)

_ = model.generate(
    inputs["input_ids"],
    max_new_tokens=256,
    do_sample=True,
    top_p=0.9,
    top_k=20,
    temperature=0.9,
    streamer=streamer,
)

出力が以下のようになりました

<s> 1girl, blue hair, boots, commentary request, computer, cyberpunk, hatsune miku, highres, huke, long hair, monitor, multiple monitors, skirt, solo, thigh boots, thighhighs, very long hair, vocaloid, zettai ryouiki</s>

別のパターンでも試してみます

prompt = "<s>dog"

inputs = tokenizer(prompt, return_tensors="pt").to(model.device)

_ = model.generate(
    inputs["input_ids"],
    max_new_tokens=256,
    do_sample=True,
    top_p=0.9,
    top_k=20,
    temperature=0.9,
    streamer=streamer,
)
<s> dog jumps over hill, dog looks like elephant with trunk!!!!, intricate, epic lighting, cinematic composition, hyper realistic, 8 k resolution, unreal engine 5, by artgerm, tooth wu, dan mumford, beeple, wlop, rossdraws, james jean, marc simonetti, artstation</s

所感

自然言語から単語を抽出してプロンプトにできれば良さそうですが、プロンプトの内容が単語レベルから推測されるものがざっくりしているので、実際には少し調節が必要な感じです