メインコンテンツへスキップ
見出し画像

Google Colab で RWKV を試す - RWKVパッケージ版

    「Google Colab」で「RWKV」を試したので、まとめました。

    ・rwkv 0.7.3

    前回

    1. RWKV

    「RWKV」は、TransformerレベルのLLM性能を備えたRNNです。高性能、高速推論、VRAMの節約、高速学習、長い文脈長、自由な埋め込みを実現しています。

    2. Colabでの実行

    Colabでの実行手順は、次のとおりです。

    (1) メニュー「編集→ノートブックの設定」で、「ハードウェアアクセラレータ」で「GPU」を選択。

    (2) Googleドライブのマウント。

    # Googleドライブのマウント
    from google.colab import drive
    drive.mount('/content/drive')

    (3) 作業フォルダへの移動。

    # 作業フォルダへの移動
    import os
    os.makedirs("/content/drive/My Drive/work", exist_ok=True)
    %cd '/content/drive/My Drive/work'

    (4) モデルをダウンロードして、作業フォルダ (work) に配置。
    RWKVのモデルとして、Pileのみ学習させたベースモデルとInstructionチューニングしたRavenがあります。Ravenはバージョン (v1〜v9…) と言語種別 (Eng、EngAndMore、EngChnJpn、ChnEngなど) もあります。

    ・Pile (ベースモデル)
     ・
    rwkv-4-pile-14b
     ・
    rwkv-4-pile-7b
     ・
    rwkv-4-pile-3b
     ・
    rwkv-4-pile-1b5
     ・
    rwkv-4-pile-430m
     ・
    rwkv-4-pile-169m

    ・
    Raven (Instructionチューニングモデル)
     ・RWKV-4-Raven-14B-v<n>-XXX
     ・RWKV-4-Raven-7B-v<n>-XXX
     ・RWKV-4-Raven-3B-v<n>-XXX
     ・RWKV-4-Raven-1B5-v<n>-XXX

    今回は、「RWKV-4-Raven-7B-v7-EngAndMore-20230404-ctx4096.pth」を使いました。

    (5) トークンファイルをダウンロードして、作業フォルダ (work) に配置。

    ・20B_tokenizer.json

    (6) パッケージのインストール。

    # パッケージのインストール
    !pip install rwkv

    (7) 環境変数の準備。

    # 環境変数の準備
    import os
    os.environ['RWKV_JIT_ON'] = '1'
    os.environ["RWKV_CUDA_ON"] = '0'

    「RWKV_CUDA_ON」は、C++コンパイラとCUDAが必要ですが、CUDA カーネルをコンパイルして10倍高速にします。

    (8) モデルとパイプラインの準備。

    from rwkv.model import RWKV
    from rwkv.utils import PIPELINE, PIPELINE_ARGS
    
    # モデルとパイプラインの準備
    model = RWKV(
        model="./RWKV-4-Raven-7B-v7-EngAndMore-20230404-ctx4096", 
        strategy="cuda fp16")
    pipeline = PIPELINE(model, "./20B_tokenizer.json")

    ◎ model
    モデルパスを指定します。セパレータには「\」ではなく「/」を使用します。長いctxが必要な場合は、「ctx4096」モデルを使用します。

    ◎ strategy
    cpu or cuda と精度を指定します。

    ・fp16 = GPU に良い (CPU非サポート)
    ・fp32 = CPU に良い
    ・bf16 = 精度が悪い (CPUサポート)

    設定例は、次のとおりです。

    ・'cpu fp32' = 全レイヤー cpu fp32
    ・'cuda fp16' = 全レイヤー cuda fp16
    ・'cuda fp16i8' = 全レイヤー int8 量子化によるcuda fp16
    ・'cuda fp16i8 *10 -> cpu fp32' = 最初の10レイヤー cuda fp16i8、次のレイヤー cpu fp32 (速度を上げるには10を増やす)
    ・'cuda:0 fp16 *10 -> cuda:1 fp16 *8 -> cpu fp32' = 最初の10レイヤー cuda:0 fp16、次の8レイヤー cuda:1 fp16、次のレイヤー cpu fp32

    (9) パイプライン引数の準備。

    # パイプライン引数の準備
    args = PIPELINE_ARGS(
        temperature = 1.0,
        top_p = 0.7, 
        top_k = 100, 
        alpha_frequency = 0.25, 
        alpha_presence = 0.25, 
        token_ban = [],
        token_stop = [0],
        chunk_len = 256) 

    ・temperature : 温度
    ・top_p : top-P
    ・top_k : top-K (0は無視)
    ・alpha_frequency : 同じテキスト出力をへらすため出力トークンに課すペナルティ (-2〜2)
    ・alpha_presence : 同じトークンの繰り返しを減らすため出力トークンに課すペナルティ (-2〜2)
    ・token_ban : 禁止トークン
    ・token_stop : 停止トークン
    ・chunk_len : チャンク長。入力を分割してVRAM節約で、短いほうが遅い。

    ・frequency_penalty : 出力トークンに課すペナルティ。同じテキスト出力の可能性を減らす(デフォルト:0, -2〜2)
    ・presence_penalty : 出力トークンに課すペナルティ。同じトークンの繰り返し可能性を減らす(デフォルト:0, -2〜2)

    「alpha_frequency」「alpha_presence」について詳しくは、以下を参照。

    (9) Instructプロンプトを生成する関数の準備。
    「ChatRWKV」の「+i」と同じ処理になります。

    # Instructプロンプトの生成
    def generate_prompt(instruction, input=None):
        if input:
            return f"""Below is an instruction that describes a task, paired with an input that provides further context. Write a response that appropriately completes the request.
    
    # Instruction:
    {instruction}
    
    # Input:
    {input}
    
    # Response:
    """
        else:
            return f"""Below is an instruction that describes a task. Write a response that appropriately completes the request.
    
    # Instruction:
    {instruction}
    
    # Response:
    """

    (10) パイプラインの実行。

    # Instructプロンプトの生成
    prompt = generate_prompt("日本で一番人気のアニメは?")
    print("--[prompt]--\n" + prompt + "----")
    
    # パイプラインの実行
    result = pipeline.generate(prompt, token_count=200, args=args)
    print(result)
    画像

    【おまけ】 ストリーミング出力

    pipeline.generate()のcallbackでストリーミング出力も可能です。

    # パイプラインの実行
    def my_print(s):
        print(s, end='', flush=True)
    pipeline.generate(prompt, token_count=200, args=args, callback=my_print)

    関連

    次回



     
     

    npaka

     
     
    プログラマー。iPhone / Android / Unity / ROS / AI / AR / VR / RasPi / ロボット / ガジェット。年2冊ペースで技術書を執筆。アニソン / カラオケ / ギター / 猫 twitter : @npaka123

    あなたへのおすすめ