2023年12月8日金曜日

居眠り検知のAIを作ってみる。

 最近おじさん、ようやく作りたいAIが作れるようになってきました。

このまえ居眠り検知をするAIを作っている会社の人のデモをみて思ったのです。

これおじさんでも作れる!



eal-Time Eye Blink Detection using Facial Landmarks

https://vision.fe.uni-lj.si/cvww2016/proceedings/papers/05.pdf


眠気を判定!目のまばたき検知をDlibとOpenCVを組み合わせて数十行で作る

https://qiita.com/mogamin/items/a65e2eaa4b27aa0a1c23


ラズパイカメラによる眠気検知とWebストリーミング

https://qiita.com/AkitoArai709/items/b8a23af4042de1aa0fdd


作ってる人たくさんいますね。


これも距離を計算するだけなのね。

おじさんもC++で作ってみました。


--------------------------

#define DLIB_JPEG_SUPPORT 1



#include <dlib_dnn.h>

#include <dlib_gui_widgets.h>

#include <dlib_clustering.h>

#include <dlib_string.h>

#include <dlib_image_io.h>

#include <dlib_image_processing_frontal_face_detector.h>


using namespace dlib;

using namespace std;



float EAR(point p1, point p2, point p3, point p4, point p5, point p6)

{

    float a1=sqrt( (p6.x() - p2.x()) * (p6.x() - p2.x()) + (p6.y() - p2.y()) * (p6.y() - p2.y()));

    float a2 = sqrt((p3.x() - p5.x()) * (p3.x() - p5.x()) + (p3.y() - p5.y()) * (p3.y() - p5.y()));

    float a3 = sqrt((p1.x() - p4.x()) * (p1.x() - p4.x()) + (p1.y() - p4.y()) * (p1.y() - p4.y()));

    return (a1 + a2) / (2 * a3);

}

// ----------------------------------------------------------------------------------------

float detectSleepiness(full_object_detection& fod)

{

    point p1,p2,p3,p4,p5,p6;

    float ear1, ear2;

    float ret = 0;

    p1=fod.part(36);

    p2 = fod.part(37);

    p3 = fod.part(38);

    p4 = fod.part(39);

    p5 = fod.part(40);

    p6 = fod.part(41);

    ear1 = EAR(p1, p2, p3, p4, p5, p6);

    p1 = fod.part(42);

    p2 = fod.part(43);

    p3 = fod.part(44);

    p4 = fod.part(45);

    p5 = fod.part(46);

    p6 = fod.part(47);

    ear2 = EAR(p1, p2, p3, p4, p5, p6);


   // printf("ear1=%f  era2=%f  \n",ear1,ear2);


    ret = ear1+ear2;

    return ret;

}


int main(int argc, char** argv)

{

    

    //const char* face_image = "202304_2_1.jpg";

    //const char* face_image = "kuchikomi1074_TP_V.jpg";

    const char* face_image = "taihige-hiyake001.jpg";


    float sleepiness;

    if (argc >= 2)face_image = argv[1];


    frontal_face_detector detector = get_frontal_face_detector();


    shape_predictor sp;

    deserialize("shape_predictor_68_face_landmarks.dat") >> sp;


    array2d<rgb_pixel> img;

    load_image(img, face_image);

    pyramid_up(img);


    std::vector<rectangle> dets = detector(img);

    cout << "Number of faces detected: " << dets.size() << endl;


    std::vector<full_object_detection> shapes;

    for (unsigned long j = 0; j < dets.size(); ++j)

    {

        full_object_detection shape = sp(img, dets[j]);

        cout << "number of parts: " << shape.num_parts() << endl;

        shapes.push_back(shape);

    }


    sleepiness=detectSleepiness(shapes[0]);

    printf("sleepiness=%f\n",sleepiness);

    cout << "hit enter to terminate" << endl;

    cin.get();

}


--------------------------

本当に簡単に作れるんですね。



2023年11月30日木曜日

顔認証をつくってみた。

 おじさんこの前、顔認証でゲートを通過するところに行きました。

最近だんだん増えてきたよね。

だけれど、きちんと登録したのに何故か通れない。

ふざけやがって・・・・。


なので今回は顔認証システムの作成に挑戦します!


Pythonで手軽に顔認識をやってみる(face-recognition)

https://blog.grasys.io/post/uema/face-recognition/


なるほど、dlibにはすでに顔認証ライブラリがあるのね。

99.38%の正解率らしい。


dlib/examples/dnn_face_recognition_ex.cpp

https://github.com/davisking/dlib/blob/master/examples/dnn_face_recognition_ex.cpp


ここに顔認証のサンプルがあります。
これをちょっと改造するだけじゃん!
顔認証は顔を検出して、次元縮小して、比べたい画像の特徴ベクトルの引き算して距離を求めるだけ。
なんだ引き算するだけじゃん。

dlib/examples/dnn_metric_learning_on_images_ex.cpp

学習のソースコードもとっても簡単だし。顔データもすべてそろっている。
ネットはテンプレートで組む時代なのね。
300万人の顔を学習させたのね。
なんかそこら辺の日本の企業を超えている気がする。
しかもこれ、resnetでmetric learningしているので、顔だけでなく植物の名前など画像ならなんでも学習させることが可能です。曲がったキュウリとかの異常検知もできそうですね。
凄すぎる。

志村けんやチョコプラのIKKOをきちんと認証できるかやってみました。

--------------------------------
#define DLIB_JPEG_SUPPORT 1


#include <dlib_dnn.h>
#include <dlib_gui_widgets.h>
#include <dlib_clustering.h>
#include <dlib_string.h>
#include <dlib_image_io.h>
#include <dlib_image_processing_frontal_face_detector.h>

using namespace dlib;
using namespace std;


template <template <int,template<typename>class,int,typename> class block, int N, template<typename>class BN, typename SUBNET>
using residual = add_prev1<block<N,BN,1,tag1<SUBNET>>>;

template <template <int,template<typename>class,int,typename> class block, int N, template<typename>class BN, typename SUBNET>
using residual_down = add_prev2<avg_pool<2,2,2,2,skip1<tag2<block<N,BN,2,tag1<SUBNET>>>>>>;

template <int N, template <typename> class BN, int stride, typename SUBNET> 
using block  = BN<con<N,3,3,1,1,relu<BN<con<N,3,3,stride,stride,SUBNET>>>>>;

template <int N, typename SUBNET> using ares      = relu<residual<block,N,affine,SUBNET>>;
template <int N, typename SUBNET> using ares_down = relu<residual_down<block,N,affine,SUBNET>>;

template <typename SUBNET> using alevel0 = ares_down<256,SUBNET>;
template <typename SUBNET> using alevel1 = ares<256,ares<256,ares_down<256,SUBNET>>>;
template <typename SUBNET> using alevel2 = ares<128,ares<128,ares_down<128,SUBNET>>>;
template <typename SUBNET> using alevel3 = ares<64,ares<64,ares<64,ares_down<64,SUBNET>>>>;
template <typename SUBNET> using alevel4 = ares<32,ares<32,ares<32,SUBNET>>>;

using anet_type = loss_metric<fc_no_bias<128,avg_pool_everything<
                            alevel0<
                            alevel1<
                            alevel2<
                            alevel3<
                            alevel4<
                            max_pool<3,3,2,2,relu<affine<con<32,7,7,2,2,
                            input_rgb_image_sized<150>
                            >>>>>>>>>>>>;

// ----------------------------------------------------------------------------------------

frontal_face_detector detector;
shape_predictor sp;
anet_type net;


matrix<float, 0, 1> get_face_descriptors(const char* fn,const char* sfn=nullptr)
{
    std::vector<matrix<float, 0, 1>> face_descriptors;
    matrix<rgb_pixel> img;
    load_image(img, fn);
    //image_window win(img);

    std::vector<matrix<rgb_pixel>> faces;
    for (auto face : detector(img))
    {
        auto shape = sp(img, face);
        matrix<rgb_pixel> face_chip;
        extract_image_chip(img, get_face_chip_details(shape, 150, 0.25), face_chip);
        faces.push_back(move(face_chip));
        draw_rectangle(img, face, dlib::rgb_pixel(255,0,0));
        //win.add_overlay(face);
    }

    if (faces.size() == 0)
    {
        return face_descriptors[0];
    }
   face_descriptors = net(faces);

   if (sfn != nullptr) {
       save_bmp(img, sfn);
   }
   //cin.get();
   
   return face_descriptors[0];
}

void save_face_descriptors(const char* fn, const char* sfn,const char* name)
{
    std::vector<matrix<float, 0, 1>> face_descriptors;
    matrix<rgb_pixel> img;
    load_image(img, fn);
    //image_window win(img);

    std::vector<matrix<rgb_pixel>> faces;
    for (auto face : detector(img))
    {
        auto shape = sp(img, face);
        matrix<rgb_pixel> face_chip;
        extract_image_chip(img, get_face_chip_details(shape, 150, 0.25), face_chip);
        faces.push_back(move(face_chip));
        draw_rectangle(img, face, dlib::rgb_pixel(255, 0, 0));
        draw_string(img, dlib::point(face.left(),face.top() + face.height()), name, rgb_pixel(255, 0, 0));
        //win.add_overlay(face);
    }

    if (faces.size() == 0)
    {
        return;
    }
    face_descriptors = net(faces);

    if (sfn != nullptr) {
        save_bmp(img, sfn);
    }
}


struct face_file {
    const char* name;
    const char* fname;
};

std::vector<struct face_file> face_files = {
    {"shimuraken","shimuraken.jpg"},
    {"matsuo","matsuo.jpg"},
    {"ikko","ikko.jpg"},
};

std::vector<const char*> test_files = {
    "shimura_001.jpg",
    "ikko_001.jpg",
    "matsuo_001.jpg",
};

int main(int argc, char** argv)
{

    detector = get_frontal_face_detector();
    deserialize("shape_predictor_5_face_landmarks.dat") >> sp;
    deserialize("dlib_face_recognition_resnet_model_v1.dat") >> net;



    std::vector<matrix<float, 0, 1>> face_descriptors;
    for (int i = 0; i < face_files.size(); i++) {
        face_descriptors.push_back(get_face_descriptors(face_files[i].fname));
    }
    for (int i = 0; i < face_files.size(); i++) {
        matrix<float, 0, 1> face_descriptors2 = get_face_descriptors(test_files[i]);
        printf("------------\n");
        printf("%s\n", test_files[i]);
        //for (int j = 0; j < face_files.size(); j++) {
        //    printf("    length=%f  name=%s  \n", length(face_descriptors[j] - face_descriptors2), face_files[j].name);
        //}
        float len;
        const char* name;
        int pos;
        char outname[256];
        pos = 0;
        len = length(face_descriptors[0] - face_descriptors2);
        name = face_files[0].name;
        for (int j = 1; j < face_files.size(); j++) {
            if (len < length(face_descriptors[j] - face_descriptors2))continue;
            pos = j;
            len = length(face_descriptors[j] - face_descriptors2);
            name = face_files[j].name;
        }
        printf("length=%f  name=%s  \n", len, name);
        sprintf(outname, "out_%s.bmp", name);
        save_face_descriptors(test_files[i], outname,name);
    }

    cout << "hit enter to terminate" << endl;
    cin.get();
}


--------------------------------


結果



文字が小さくて読みにくいですが、仮装しててもきちんと顔認証できるじゃん。
すげー。
顔認証システムって数時間で作れるのね。


2023年9月25日月曜日

激安の真空管プリアンプを作る その2

おじさん、前回紹介した激安真空管プリアンプキットをもう一つ買って、コンデンサーを交換する改造してみました。

このキット本当に謎です。

6J1の真空管は2本で2000円くらいするんですが、その真空管付きのキットも2000円。

なんでそうなるの?

キットを売っている会社もいくつかあり、コンデンサーがセラミックコンデンサーだったりフィルムコンデンサーだったり。部品も微妙に違います。

さすがにセラミックコンデンサーはダメだろ!

ちゃんとした品質のキット売ろうとしている感じが全くないですね。


http://audiolife.sblo.jp/article/185249378.html

このサイトのようにコンデンサーをオーディオ用電解コンデンサーと高級フィルムコンデンサーに交換します。

安い電解コンデンサーとセラミックコンデンサーなんてコンデンサーの本来の特性してないからね。



うーん。これ一瞬でかなり音がよくなったことがわかるくらい音質が改善する。
このキットはもともと音がいいと思っていたのですが・・・。

低音がしっかりして音が超クリアになるじゃん。

真空管があったまっていってどんどん音がよくなっていくのが快感になってしまった。


Mrs.GreenAppleの私は最強の音楽を聴いて評価しているのですが、この改造が最強な気がする。

ネットで書かれているように真空管とかをロシアの軍用グレードのものに交換するともっと音が良くなるのだろうか?

どんどんはまっていく・・・。

おそロシア。




2023年9月14日木曜日

激安の真空管プリアンプを作る

 おじさん、amazonで買って放置してあった真空管アンプを作ってみました。

プリアンプって書いてありますが、ヘッドフォンアップとしても使えるっぽい?です。



真空管の駆動に必要な高電圧が、倍電圧整流回路で簡単に作れることがネットで広まり、小型で安値な真空管アンプキットが1500円くらいで買えるようになりました。


こんな回路図をしているようです。
これ最初に考えた人頭いいね。
このCircuitLABのサイトも楽しいね。いろんな回路を何時間でも見てられる。
ご覧の通り回路のほとんどが高電圧を作るための回路です。

作って音を聞いてみて思ったことは、思ったより音がいい。

これ五十年前にこの音質に出会っていたら超感動したろうな。

さらに、これをちょっと改造すればたぶんもっと音良くなる。


こんな風に、カソードフォロワの出力で安定を狙った回路とかみんなどんどん回路図をGithubのようにアップデートしていくのね。すげー。

https://arereno.blogspot.com/2020/04/6j1-diy_14.html

回路も安定化させていろいろ試したくなってきた。


やべー、コンデンサーも高級なものに変えたくなってきた。

http://audiolife.sblo.jp/article/185249378.html


やっぱ世の中同じこと考える人たくさんいるのね。


2023年8月17日木曜日

llama.cppでLLMの学習をさせる

 おじさんが花火の場所取りをしている間に、ものすごい勢いでLLMの技術が進歩している。

最近LLMはCPUだけで0からスクラッチで学習させるのが目標らしい。




15Mに満たない言語モデルで小さな物語を紡ぐ

https://note.com/bakushu/n/nd834ff25394f


baby-llama

https://github.com/ggerganov/llama.cpp/pull/1360


llama.cpp でフルの学習メモ

https://zenn.dev/syoyo/articles/e9eb5211bb4e8b


llama.cpp

https://github.com/ggerganov/llama.cpp



へーーーーーーー。

LLMってまず計算するフレームワークが正しく実装されているか確かめるために、まずsin関数を学習させるのね。

そして実装ができたら、英語のシェイクスピアの文章を学習させるのね。

最後に超巨大データで学習させるのね。

日本語の場合、構文解析のわかちがきのところの高性能かつシンプルな実装のライブラリがないのね。


とっても勉強になる。

こんなに簡単にLLMの学習ってできるのね。

LLM最初のころは原子力発電所一基分くらいの電力と金が要ると言われていたのに・・・。


まぁ今日は初回なのでbaby-llamaをビルドして、サイン波を学習させてみました。



----------------------------------

init model

init_kv_cache

Example 1

error_before_opt: 506.75

error_after_opt:  128.53

best samples after optimization:

       X

      X

       X

       X

       X

       X

     X

    X

Example 9

error_before_opt: 132.24

error_after_opt:  101.97

Example 17

error_before_opt: 104.96

error_after_opt:  62.03

Example 25

error_before_opt: 134.28

error_after_opt:  58.35

Example 33

error_before_opt: 115.25

error_after_opt:  64.25

Example 41

error_before_opt: 125.32

error_after_opt:  62.99

Example 49

error_before_opt: 96.77

error_after_opt:  57.14

Example 57

error_before_opt: 98.44

error_after_opt:  58.38

Example 65

error_before_opt: 136.89

error_after_opt:  71.56

best samples after optimization:

       X

       X

       X

     X

    X

   X

 X

 X

Example 73

error_before_opt: 104.19

error_after_opt:  65.09

Example 81

error_before_opt: 103.45

error_after_opt:  57.70

Example 89

error_before_opt: 107.56

error_after_opt:  57.80

Example 97

error_before_opt: 97.15

error_after_opt:  65.41

Example 105

error_before_opt: 107.30

error_after_opt:  67.93

Example 113

error_before_opt: 114.04

error_after_opt:  75.12

Example 121

error_before_opt: 115.25

error_after_opt:  71.37

Example 129

error_before_opt: 104.39

error_after_opt:  71.55

best samples after optimization:

  X

    X

   X

  X

 X

 X

 X

  X

Example 137

error_before_opt: 99.17

error_after_opt:  75.65

Example 145

error_before_opt: 100.43

error_after_opt:  68.08

Example 153

error_before_opt: 98.71

error_after_opt:  71.94

Example 161

error_before_opt: 103.10

error_after_opt:  68.90

Example 169

error_before_opt: 117.62

error_after_opt:  70.84

Example 177

error_before_opt: 79.23

error_after_opt:  63.81

Example 185

error_before_opt: 101.08

error_after_opt:  70.64

Example 193

error_before_opt: 98.38

error_after_opt:  67.66

best samples after optimization:

 X

 X

 X

 X

  X

   X

    X

     X

Example 201

error_before_opt: 102.50

error_after_opt:  80.97

Example 209

error_before_opt: 118.92

error_after_opt:  80.08

Example 217

error_before_opt: 91.98

error_after_opt:  71.79

Example 225

error_before_opt: 103.32

error_after_opt:  80.62

Example 233

error_before_opt: 99.25

error_after_opt:  81.21

Example 241

error_before_opt: 94.08

error_after_opt:  68.46

Example 249

error_before_opt: 102.03

error_after_opt:  71.46

Generating 128 tokens.

X

 X

  X

    X

     X

      X

       X

       X

       X

      X

     X

    X

   X

  X

 X

 X

 X

 X

  X

   X

     X

      X

       X

       X

       X

       X

      X

     X

    X

   X

  X

 X

 X

 X

 X

  X

   X

     X

      X

       X

       X

       X

       X

      X

     X

    X

   X

  X

 X

 X

 X

 X

  X

   X

     X

      X

       X

       X

       X

       X

      X

     X

    X

   X

  X

 X

 X

 X

 X

  X

   X

     X

      X

       X

       X

       X

       X

      X

     X

    X

   X

  X

 X

 X

 X

 X

  X

   X

     X

      X

       X

       X

       X

       X

      X

     X

    X

   X

  X

 X

 X

 X

 X

  X

   X

     X

      X

       X

       X

       X

       X

      X

     X

    X

   X

  X

 X

 X

 X

 X

  X

   X

     X

      X

       X

       X

       X

       X

      X

     X

    X

   X

  X

 X

 0.04 0.20 -1.42 -0.04 -0.93 3.49 -1.37 0.02 0.32 -3.07 -0.33 0.68 0.86 -1.37 1.00 -1.12 -0.16 1.14 0.16 -0.07 1.54 -0.90 0.17 0.99 2.63 0.24 -0.10 0.87 -0.17 -0.39 -1.45 -2.40

 0.44 0.45 -0.08 0.06 -0.70 1.09 -0.72 2.58 1.13 -0.41 0.45 0.01 -0.30 -0.53 -0.18 2.71 -0.81 0.08 0.33 0.54 1.85 -0.35 0.91 2.00 0.56 0.42 -0.10 0.50 -0.54 1.89 -3.25 -1.20

 -0.09 -0.03 0.15 -0.04 0.23 4.76 -0.08 0.29 -0.12 0.11 -0.20 0.00 0.06 -0.05 -0.03 -0.38 0.20 0.23 -0.06 -0.04 0.18 0.11 -0.06 0.13 0.28 -0.11 -0.00 -0.02 -0.07 0.61 -0.77 -1.70

 1.43 1.26 0.28 0.65 -1.15 2.28 1.23 0.26 1.87 -1.88 0.98 0.43 0.15 0.07 0.12 0.64 -1.33 -2.07 0.10 0.50 -1.24 -0.33 0.05 -1.34 -0.83 0.77 -0.03 1.07 0.31 -0.97 -0.10 -3.70

 0.35 -2.55 1.76 -1.51 0.73 1.24 -0.75 2.51 2.16 -0.23 -0.74 -1.53 0.65 1.19 0.69 -2.06 -0.97 0.32 -0.21 -1.94 2.18 0.16 -1.29 -1.29 2.12 -0.55 -1.55 -0.85 1.21 -1.00 -0.50 -1.79

 -0.94 1.05 -0.23 1.87 0.34 0.84 -2.52 -0.24 0.95 -1.08 1.97 1.85 0.76 -1.72 -0.55 -1.35 -0.68 -0.01 -1.59 1.92 1.96 -0.64 -3.58 -0.59 -0.47 0.13 -0.56 0.46 -2.63 -1.47 -0.40 -0.49

 1.42 0.31 0.21 -0.02 -0.55 1.23 -1.93 -1.36 1.42 -0.78 -1.91 -0.05 0.74 -1.48 -0.33 -1.24 -0.83 3.10 0.47 -0.50 -0.57 0.01 -0.32 -0.37 -1.56 -0.51 0.17 0.84 1.09 0.35 -0.33 -1.73

 0.97 0.74 -0.66 0.93 -0.24 1.83 1.27 -0.00 0.72 -1.95 0.02 -0.16 0.97 0.46 0.61 2.08 0.66 2.54 -0.37 0.40 1.40 0.45 0.03 0.61 -0.47 -0.34 -0.11 0.62 -0.50 -4.70 0.28 0.21

done


----------------------------------

できた。





2023年6月9日金曜日

Stable Diffusionをする

 おじさん、特にStable Diffusionには興味ないんですが、c++用のAIライブラリをmake使わずにひたすらいろいろなプラットフォーム用移植する勉強の一環で、Stable DiffusionのC++版をスクラッチでフルビルドしてみました。


論文:High-Resolution Image Synthesis with Latent Diffusion Models", Rombach, R., Blattmann, A., Lorenz, D., Esser, P., Ommer, B. (CVPR'22)

https://arxiv.org/abs/2112.10752


論文解説

https://zenn.dev/tomo_makes/books/4ed97f06d02a38/viewer/142053


ソース

https://github.com/EdVince/Stable-Diffusion-NCNN


ncnnという中国語?のライブラリを使わないといけないのね。

txt2imgとかimg2imgとかいろんなものが含まれています。

これ本当に動くのかなぁ。





---------------------------------


----------------[  init   ]---------------- 6.21G / 6.22G

----------------[ prompt  ]---------------- 6.22G / 6.22G

----------------[ encoder ]---------------- 6.41G / 6.41G

----------------[diffusion]----------------

step: 1/37      102223.67ms

step: 2/37


---------------------------------


うーん、これWindowsでCPUのみで行うと、1stepに100秒かかります。

これ結果出すのに1時間かかるね。


なんかテストは少女を生成しないといけないようなので、生成してみました。

---------------------------------


---------------------------------

できた!



2023年6月2日金曜日

日本語の大規模言語モデルRinnaを動かす

おじさん1日1AIをしています。

毎日AIの勉強を一つします。

毎日2、3時間くらいで、調べて、データ作成して、ビルドして、実験して、かなり大変。

誰かおじさんに働かなくて良いだけのお金くれないかなぁ。

そうしたらおじさんAIの研究をします。


最近LoRAで日本語にファインチューニングした言語モデルが増えてきました。

そのおかげで、おじさんのように、GPUなしのC++で大規模言語モデルの学習やファインチューニングをしようとしている人も増えてきました。


https://zenn.dev/syoyo/articles/946c17666e10fb


ついにおじさんのやり方がが主流になるときが。

でもおじさん夜な夜な適当に勉強しているので、みんなに先を越されている・・・。

なるほど、最近ファインチューニング関係の論文が凄いのね。


QLoRA

https://github.com/artidoro/qlora/tree/main

https://zenn.dev/syoyo/articles/6918defde8a807

QLoRAだと微分値を求めるところが少なくGPU一枚でファインチューニングできるらしい


Fine-Tuning Language Models with Just Forward Passes

https://github.com/princeton-nlp/MeZO

https://arxiv.org/abs/2305.17333

フォワードのみだからC++で簡単にファインチューニングできる?



上記のサイトによると昨日、日本語のRinnaのモデルがC++で動くようになったらしいので、さっそくおじさんもGPUなしPCでやってみました。

---------------------

redpajama.exe -m "C:\trash\pytorch\redpajama.cpp-master\examples\redpajama\scripts\output_dir\ggml-japanese-gpt-neox-3.6b-instruction-ppo-f16.bin" -p "こんにちは"

main: seed = 1685673288

gptneox.cpp: loading model from C:\trash\pytorch\redpajama.cpp-master\examples\redpajama\scripts\output_dir\ggml-japanese-gpt-neox-3.6b-instruction-ppo-f16.bin

gptneox.cpp: can't use mmap because tensors are not aligned; convert to new format to avoid this

gptneox_model_load_internal: format     = ggmf v1 (old version with no mmap support)

gptneox_model_load_internal: n_vocab    = 32000

gptneox_model_load_internal: n_ctx      = 512

gptneox_model_load_internal: n_embd     = 2816

gptneox_model_load_internal: n_head     = 22

gptneox_model_load_internal: n_layer    = 36

gptneox_model_load_internal: n_rot      = 128

gptneox_model_load_internal: use_parallel_residual = 0

gptneox_model_load_internal: ftype      = 1 (mostly F16)

gptneox_model_load_internal: n_parts    = 1

gptneox_model_load_internal: model size = 12B

gptneox_model_load_internal: ggml ctx size = 7048095.00 KiB

gptneox_model_load_internal: mem required  = 8930.91 MiB (+ 1608.00 MiB per state)

..................................................................................................

.

.

gptneox_init_from_file: kv self size  =  198.00 MiB


system_info: n_threads = 4 / 4 | AVX = 0 | AVX2 = 0 | AVX512 = 0 | AVX512_VBMI = 0 | AVX512_VNNI = 0 | FMA = 0 | NEON = 0 | ARM_FMA = 0 | F16C = 0 | FP16_VA = 0 | WASM_SIMD = 0 | BLAS = 0 | SSE3 = 0 | VSX = 0 |

sampling: repeat_last_n = 64, repeat_penalty = 1.100000, presence_penalty = 0.000000, frequency_penalty = 0.000000, top_k = 40, tfs_z = 1.000000, top_p = 0.950000, typical_p = 1.000000, temp = 0.800000, mirostat = 0, mirostat_lr = 0.100000, mirostat_ent = 5.000000

generate: n_ctx = 512, n_batch = 512, n_predict = 128, n_keep = 0



こんにちは。今日は曇りがちな天気でした。昨日は、家族とテニスをしたり、外でバーベキューをしたりしました。テニスはとても楽しかったです。また、海に行ったり、公園に行って散歩したりもしました。とてもリラックスできました。今日は、自宅でゆっくり過ごしています。ゲームやビデオを観たりして、楽しんでいます。明日は、家族と一緒にドライブに行く予定です。とても楽しみにしています。良い一日を過ごしてくださいね。



gptneox_print_timings:        load time =  8633.80 ms

gptneox_print_timings:      sample time =   127.78 ms /   128 runs   (    1.00 ms per run)

gptneox_print_timings: prompt eval time =  5968.87 ms /     4 tokens ( 1492.22 ms per token)

gptneox_print_timings:        eval time = 197970.49 ms /   127 runs   ( 1558.82 ms per run)

gptneox_print_timings:       total time = 206822.82 ms

---------------------


なんというきれいな日本語



2023年5月31日水曜日

日本語の大規模言語モデルllamaを動かす。

 おじさん、日本語に対応しているLLMを動かしたくていろいろ調べてみました。

https://gigazine.net/news/20230403-llama-cpp-ram/

------------------------

2023年2月にMetaが発表した大規模言語モデル「LLaMA」は、従来のGPT-3よりも小規模でありながらGPT-3に匹敵する性能を単体GPUの環境でも示すことが可能とされており、2023年3月にはエンジニアのジョージ・ゲルガノフ氏がM1などのsearch Apple シリコン搭載MacでLLaMAを動作させる「llama.cpp」を公開しました。そんな中、プログラマーのジャスティン・タニー氏がllama.cppが動作する際のメモリ使用量を減らすアップデートを行い、LLaMAの一部モデルに至っては6GB未満のRAMで動作することが報告されています。

------------------------

なるほど、llama.cppを使えばその辺のスペックのPCでChat-GPTのようなものが動くのね。

しかもたくさんの日本語のモデルが公開されているじゃないか!


https://zenn.dev/syoyo/articles/f869a3fda15f45


https://medium.com/axinc/llama-cpp%E3%81%A8lora%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%A6pc%E4%B8%8A%E3%81%A7%E6%97%A5%E6%9C%AC%E8%AA%9Ellm%E3%83%A2%E3%83%87%E3%83%AB%E3%82%92%E5%AE%9F%E8%A1%8C%E3%81%99%E3%82%8B-31195fd54737


https://zenn.dev/syoyo/articles/946c17666e10fb


llama.cppはソースが毎日ものすごい変更されているようで、タグのバージョンが一致しないと公開されているモデルがデータが動かないようです。

llama.cppってllamaだけじゃなくてrinnaとかいろんなモデルも動くのね。

おじさん、「llama.cpp-master-63d2046」を取ってきて古いIntelMACでビルドして動かしてみました。




------------------------


$ ./main -m ../ggml-vic7b-q4_0.bin -p "こんにちは"

main: build = 0 (unknown)

main: seed  = 1685513870

llama.cpp: loading model from ../ggml-vic7b-q4_0.bin

llama_model_load_internal: format     = ggjt v2 (latest)

llama_model_load_internal: n_vocab    = 32000

llama_model_load_internal: n_ctx      = 512

llama_model_load_internal: n_embd     = 4096

llama_model_load_internal: n_mult     = 256

llama_model_load_internal: n_head     = 32

llama_model_load_internal: n_layer    = 32

llama_model_load_internal: n_rot      = 128

llama_model_load_internal: ftype      = 2 (mostly Q4_0)

llama_model_load_internal: n_ff       = 11008

llama_model_load_internal: n_parts    = 1

llama_model_load_internal: model size = 7B

llama_model_load_internal: ggml ctx size =  72.75 KB

llama_model_load_internal: mem required  = 5809.34 MB (+ 1026.00 MB per state)

llama_init_from_file: kv self size  =  256.00 MB


system_info: n_threads = 6 / 12 | AVX = 1 | AVX2 = 1 | AVX512 = 0 | AVX512_VBMI = 0 | AVX512_VNNI = 0 | FMA = 1 | NEON = 0 | ARM_FMA = 0 | F16C = 1 | FP16_VA = 0 | WASM_SIMD = 0 | BLAS = 1 | SSE3 = 1 | VSX = 0 | 

sampling: repeat_last_n = 64, repeat_penalty = 1.100000, presence_penalty = 0.000000, frequency_penalty = 0.000000, top_k = 40, tfs_z = 1.000000, top_p = 0.950000, typical_p = 1.000000, temp = 0.800000, mirostat = 0, mirostat_lr = 0.100000, mirostat_ent = 5.000000

generate: n_ctx = 512, n_batch = 512, n_predict = -1, n_keep = 0



 こんにちは私は東京都、渋谷区の小学生です。当初私は日本語が複雑でしたが、徐歴uraの出ましい動画を見ると私は日本語がきっかけになりました。よろしいお手? microphone(mikeroop) 読み取ればよいですね」


このように、徐歴uraの動画を見ると日本語がきっかけになり、学端を解消しました。今、学端に違反しないようにお手? Mikeroop 読み取ればよいですね。


その後、徐歴uraが日本語の練習を行っている動画を見たり、広葉大輔などから学んだことを活用しました。今、日本語で書き上げることができます。


その中でも特におそらえ難しい日本語である「拝? Her Majesty the Queen's 」という用語が、徐歴uraが紹介した動画を見て学びました。感謝し合い。 [end of text]


llama_print_timings:        load time =   767.94 ms

llama_print_timings:      sample time =   229.23 ms /   351 runs   (    0.65 ms per token)

llama_print_timings: prompt eval time =   751.15 ms /     7 tokens (  107.31 ms per token)

llama_print_timings:        eval time = 55632.42 ms /   350 runs   (  158.95 ms per token)

llama_print_timings:       total time = 56655.94 ms

yomeinoMac-mini:llama.cpp-master-63d2046 yomei$ 

----------------------------


こりゃすげーすごい速さで答えが出てきます。

おーあなた小学生なのね?

やっぱ4Gバイトの7Bのモデルだと日本語がへたくそだねー。

10Gある13Bのモデルだとこれよりきれいな日本語で答えが出るみたいなので10Gダウンロードしよう。

2023年5月30日火曜日

oneDNNを使ってみる。

 最近、大規模なディープラーニングの学習にはoneDNNが使われています。

おじさんの大好きなC++なのでさっそくビルドして使ってみました。



ディープラーニングのフレームワークっていろんなライブラリに依存しているのですが、これは他に依存ライブラリなくて単体でビルド可能です。


ビルドしてみると確かに簡単にビルドできるし、いろんなCPUやGPU、スレッドモデル、分散処理に対応しています。

だから富岳とかのスパコンでも簡単に移植して動かせるのね。


Windows用にビルドできたんだけど、おじさんスパコン持っていないので何に使おうかなぁ。


とりあえずCNNの学習サンプルは動いた。

--------------------------------

#include <assert.h>


#include <math.h>


#include "oneapi_dnnl_dnnl.hpp"


#include "example_utils.hpp"


using namespace dnnl;


void simple_net(engine::kind engine_kind) {

    using tag = memory::format_tag;

    using dt = memory::data_type;


    auto eng = engine(engine_kind, 0);

    stream s(eng);


    // Vector of primitives and their execute arguments

    std::vector<primitive> net_fwd, net_bwd;

    std::vector<std::unordered_map<int, memory>> net_fwd_args, net_bwd_args;


    const int batch = 32;


    std::vector<float> net_src(batch * 3 * 227 * 227);

    std::vector<float> net_dst(batch * 96 * 27 * 27);


    // initializing non-zero values for src

    for (size_t i = 0; i < net_src.size(); ++i)

        net_src[i] = sinf((float)i);


    // AlexNet: conv

    // {batch, 3, 227, 227} (x) {96, 3, 11, 11} -> {batch, 96, 55, 55}

    // strides: {4, 4}


    memory::dims conv_src_tz = {batch, 3, 227, 227};

    memory::dims conv_weights_tz = {96, 3, 11, 11};

    memory::dims conv_bias_tz = {96};

    memory::dims conv_dst_tz = {batch, 96, 55, 55};

    memory::dims conv_strides = {4, 4};

    memory::dims conv_padding = {0, 0};


    std::vector<float> conv_weights(product(conv_weights_tz));

    std::vector<float> conv_bias(product(conv_bias_tz));


    // initializing non-zero values for weights and bias

    for (size_t i = 0; i < conv_weights.size(); ++i)

        conv_weights[i] = sinf((float)i);

    for (size_t i = 0; i < conv_bias.size(); ++i)

        conv_bias[i] = sinf((float)i);


    // create memory for user data

    auto conv_user_src_memory

            = memory({{conv_src_tz}, dt::f32, tag::nchw}, eng);

    write_to_dnnl_memory(net_src.data(), conv_user_src_memory);

    auto conv_user_weights_memory

            = memory({{conv_weights_tz}, dt::f32, tag::oihw}, eng);

    write_to_dnnl_memory((void *)conv_weights.data(), conv_user_weights_memory);

    auto conv_user_bias_memory = memory({{conv_bias_tz}, dt::f32, tag::x}, eng);

    write_to_dnnl_memory(conv_bias.data(), conv_user_bias_memory);


    // create memory descriptors for convolution data w/ no specified

    // format tag(`any`)

    // tag `any` lets a primitive(convolution in this case)

    // chose the memory format preferred for best performance.

    auto conv_src_md = memory::desc({conv_src_tz}, dt::f32, tag::any);

    auto conv_bias_md = memory::desc({conv_bias_tz}, dt::f32, tag::any);

    auto conv_weights_md = memory::desc({conv_weights_tz}, dt::f32, tag::any);

    auto conv_dst_md = memory::desc({conv_dst_tz}, dt::f32, tag::any);


    // create a convolution primitive descriptor

    auto conv_pd = convolution_forward::primitive_desc(eng, prop_kind::forward,

            algorithm::convolution_direct, conv_src_md, conv_weights_md,

            conv_bias_md, conv_dst_md, conv_strides, conv_padding,

            conv_padding);


    // create reorder primitives between user input and conv src if needed

    auto conv_src_memory = conv_user_src_memory;

    if (conv_pd.src_desc() != conv_user_src_memory.get_desc()) {

        conv_src_memory = memory(conv_pd.src_desc(), eng);

        net_fwd.push_back(reorder(conv_user_src_memory, conv_src_memory));

        net_fwd_args.push_back({{DNNL_ARG_FROM, conv_user_src_memory},

                {DNNL_ARG_TO, conv_src_memory}});

    }


    auto conv_weights_memory = conv_user_weights_memory;

    if (conv_pd.weights_desc() != conv_user_weights_memory.get_desc()) {

        conv_weights_memory = memory(conv_pd.weights_desc(), eng);

        net_fwd.push_back(

                reorder(conv_user_weights_memory, conv_weights_memory));

        net_fwd_args.push_back({{DNNL_ARG_FROM, conv_user_weights_memory},

                {DNNL_ARG_TO, conv_weights_memory}});

    }


    // create memory for conv dst

    auto conv_dst_memory = memory(conv_pd.dst_desc(), eng);


    // finally create a convolution primitive

    net_fwd.push_back(convolution_forward(conv_pd));

    net_fwd_args.push_back({{DNNL_ARG_SRC, conv_src_memory},

            {DNNL_ARG_WEIGHTS, conv_weights_memory},

            {DNNL_ARG_BIAS, conv_user_bias_memory},

            {DNNL_ARG_DST, conv_dst_memory}});


    // AlexNet: relu

    // {batch, 96, 55, 55} -> {batch, 96, 55, 55}

    memory::dims relu_data_tz = {batch, 96, 55, 55};

    const float negative_slope = 0.0f;


    // create relu primitive desc

    // keep memory format tag of source same as the format tag of convolution

    // output in order to avoid reorder

    auto relu_pd = eltwise_forward::primitive_desc(eng, prop_kind::forward,

            algorithm::eltwise_relu, conv_pd.dst_desc(), conv_pd.dst_desc(),

            negative_slope);


    // create relu dst memory

    auto relu_dst_memory = memory(relu_pd.dst_desc(), eng);


    // finally create a relu primitive

    net_fwd.push_back(eltwise_forward(relu_pd));

    net_fwd_args.push_back(

            {{DNNL_ARG_SRC, conv_dst_memory}, {DNNL_ARG_DST, relu_dst_memory}});


    // AlexNet: lrn

    // {batch, 96, 55, 55} -> {batch, 96, 55, 55}

    // local size: 5

    // alpha: 0.0001

    // beta: 0.75

    // k: 1.0

    memory::dims lrn_data_tz = {batch, 96, 55, 55};

    const uint32_t local_size = 5;

    const float alpha = 0.0001f;

    const float beta = 0.75f;

    const float k = 1.0f;


    // create a lrn primitive descriptor

    auto lrn_pd = lrn_forward::primitive_desc(eng, prop_kind::forward,

            algorithm::lrn_across_channels, relu_pd.dst_desc(),

            relu_pd.dst_desc(), local_size, alpha, beta, k);


    // create lrn dst memory

    auto lrn_dst_memory = memory(lrn_pd.dst_desc(), eng);


    // create workspace only in training and only for forward primitive

    // query lrn_pd for workspace, this memory will be shared with forward lrn

    auto lrn_workspace_memory = memory(lrn_pd.workspace_desc(), eng);


    // finally create a lrn primitive

    net_fwd.push_back(lrn_forward(lrn_pd));

    net_fwd_args.push_back(

            {{DNNL_ARG_SRC, relu_dst_memory}, {DNNL_ARG_DST, lrn_dst_memory},

                    {DNNL_ARG_WORKSPACE, lrn_workspace_memory}});


    // AlexNet: pool

    // {batch, 96, 55, 55} -> {batch, 96, 27, 27}

    // kernel: {3, 3}

    // strides: {2, 2}


    memory::dims pool_dst_tz = {batch, 96, 27, 27};

    memory::dims pool_kernel = {3, 3};

    memory::dims pool_strides = {2, 2};

    memory::dims pool_dilation = {0, 0};

    memory::dims pool_padding = {0, 0};


    // create memory for pool dst data in user format

    auto pool_user_dst_memory

            = memory({{pool_dst_tz}, dt::f32, tag::nchw}, eng);

    write_to_dnnl_memory(net_dst.data(), pool_user_dst_memory);


    // create pool dst memory descriptor in format any

    auto pool_dst_md = memory::desc({pool_dst_tz}, dt::f32, tag::any);


    // create a pooling primitive descriptor

    auto pool_pd = pooling_forward::primitive_desc(eng, prop_kind::forward,

            algorithm::pooling_max, lrn_dst_memory.get_desc(), pool_dst_md,

            pool_strides, pool_kernel, pool_dilation, pool_padding,

            pool_padding);


    // create pooling workspace memory if training

    auto pool_workspace_memory = memory(pool_pd.workspace_desc(), eng);


    // create a pooling primitive

    net_fwd.push_back(pooling_forward(pool_pd));

    // leave DST unknown for now (see the next reorder)

    net_fwd_args.push_back({{DNNL_ARG_SRC, lrn_dst_memory},

            // delay putting DST until reorder (if needed)

            {DNNL_ARG_WORKSPACE, pool_workspace_memory}});


    // create reorder primitive between pool dst and user dst format

    // if needed

    auto pool_dst_memory = pool_user_dst_memory;

    if (pool_pd.dst_desc() != pool_user_dst_memory.get_desc()) {

        pool_dst_memory = memory(pool_pd.dst_desc(), eng);

        net_fwd_args.back().insert({DNNL_ARG_DST, pool_dst_memory});

        net_fwd.push_back(reorder(pool_dst_memory, pool_user_dst_memory));

        net_fwd_args.push_back({{DNNL_ARG_FROM, pool_dst_memory},

                {DNNL_ARG_TO, pool_user_dst_memory}});

    } else {

        net_fwd_args.back().insert({DNNL_ARG_DST, pool_dst_memory});

    }


    //-----------------------------------------------------------------------

    //----------------- Backward Stream -------------------------------------

    // ... user diff_data ...

    std::vector<float> net_diff_dst(batch * 96 * 27 * 27);

    for (size_t i = 0; i < net_diff_dst.size(); ++i)

        net_diff_dst[i] = sinf((float)i);


    // create memory for user diff dst data

    auto pool_user_diff_dst_memory

            = memory({{pool_dst_tz}, dt::f32, tag::nchw}, eng);

    write_to_dnnl_memory(net_diff_dst.data(), pool_user_diff_dst_memory);


    // Backward pooling

    // create memory descriptors for pooling

    auto pool_diff_src_md = memory::desc({lrn_data_tz}, dt::f32, tag::any);

    auto pool_diff_dst_md = memory::desc({pool_dst_tz}, dt::f32, tag::any);


    // backward primitive descriptor needs to hint forward descriptor

    auto pool_bwd_pd = pooling_backward::primitive_desc(eng,

            algorithm::pooling_max, pool_diff_src_md, pool_diff_dst_md,

            pool_strides, pool_kernel, pool_dilation, pool_padding,

            pool_padding, pool_pd);


    // create reorder primitive between user diff dst and pool diff dst

    // if required

    auto pool_diff_dst_memory = pool_user_diff_dst_memory;

    if (pool_dst_memory.get_desc() != pool_user_diff_dst_memory.get_desc()) {

        pool_diff_dst_memory = memory(pool_dst_memory.get_desc(), eng);

        net_bwd.push_back(

                reorder(pool_user_diff_dst_memory, pool_diff_dst_memory));

        net_bwd_args.push_back({{DNNL_ARG_FROM, pool_user_diff_dst_memory},

                {DNNL_ARG_TO, pool_diff_dst_memory}});

    }


    // create memory for pool diff src

    auto pool_diff_src_memory = memory(pool_bwd_pd.diff_src_desc(), eng);


    // finally create backward pooling primitive

    net_bwd.push_back(pooling_backward(pool_bwd_pd));

    net_bwd_args.push_back({{DNNL_ARG_DIFF_DST, pool_diff_dst_memory},

            {DNNL_ARG_DIFF_SRC, pool_diff_src_memory},

            {DNNL_ARG_WORKSPACE, pool_workspace_memory}});


    // Backward lrn

    auto lrn_diff_dst_md = memory::desc({lrn_data_tz}, dt::f32, tag::any);

    const auto &lrn_diff_src_md = lrn_diff_dst_md;


    // create backward lrn primitive descriptor

    auto lrn_bwd_pd = lrn_backward::primitive_desc(eng,

            algorithm::lrn_across_channels, lrn_diff_src_md, lrn_diff_dst_md,

            lrn_pd.src_desc(), local_size, alpha, beta, k, lrn_pd);


    // create reorder primitive between pool diff src and lrn diff dst

    // if required

    auto lrn_diff_dst_memory = pool_diff_src_memory;

    if (lrn_diff_dst_memory.get_desc() != lrn_bwd_pd.diff_dst_desc()) {

        lrn_diff_dst_memory = memory(lrn_bwd_pd.diff_dst_desc(), eng);

        net_bwd.push_back(reorder(pool_diff_src_memory, lrn_diff_dst_memory));

        net_bwd_args.push_back({{DNNL_ARG_FROM, pool_diff_src_memory},

                {DNNL_ARG_TO, lrn_diff_dst_memory}});

    }


    // create memory for lrn diff src

    auto lrn_diff_src_memory = memory(lrn_bwd_pd.diff_src_desc(), eng);


    // finally create a lrn backward primitive

    // backward lrn needs src: relu dst in this topology

    net_bwd.push_back(lrn_backward(lrn_bwd_pd));

    net_bwd_args.push_back({{DNNL_ARG_SRC, relu_dst_memory},

            {DNNL_ARG_DIFF_DST, lrn_diff_dst_memory},

            {DNNL_ARG_DIFF_SRC, lrn_diff_src_memory},

            {DNNL_ARG_WORKSPACE, lrn_workspace_memory}});


    // Backward relu

    auto relu_diff_src_md = memory::desc({relu_data_tz}, dt::f32, tag::any);

    auto relu_diff_dst_md = memory::desc({relu_data_tz}, dt::f32, tag::any);

    auto relu_src_md = conv_pd.dst_desc();


    // create backward relu primitive_descriptor

    auto relu_bwd_pd = eltwise_backward::primitive_desc(eng,

            algorithm::eltwise_relu, relu_diff_src_md, relu_diff_dst_md,

            relu_src_md, negative_slope, relu_pd);


    // create reorder primitive between lrn diff src and relu diff dst

    // if required

    auto relu_diff_dst_memory = lrn_diff_src_memory;

    if (relu_diff_dst_memory.get_desc() != relu_bwd_pd.diff_dst_desc()) {

        relu_diff_dst_memory = memory(relu_bwd_pd.diff_dst_desc(), eng);

        net_bwd.push_back(reorder(lrn_diff_src_memory, relu_diff_dst_memory));

        net_bwd_args.push_back({{DNNL_ARG_FROM, lrn_diff_src_memory},

                {DNNL_ARG_TO, relu_diff_dst_memory}});

    }


    // create memory for relu diff src

    auto relu_diff_src_memory = memory(relu_bwd_pd.diff_src_desc(), eng);


    // finally create a backward relu primitive

    net_bwd.push_back(eltwise_backward(relu_bwd_pd));

    net_bwd_args.push_back({{DNNL_ARG_SRC, conv_dst_memory},

            {DNNL_ARG_DIFF_DST, relu_diff_dst_memory},

            {DNNL_ARG_DIFF_SRC, relu_diff_src_memory}});


    // Backward convolution with respect to weights

    // create user format diff weights and diff bias memory

    std::vector<float> conv_user_diff_weights_buffer(product(conv_weights_tz));

    std::vector<float> conv_diff_bias_buffer(product(conv_bias_tz));


    auto conv_user_diff_weights_memory

            = memory({{conv_weights_tz}, dt::f32, tag::nchw}, eng);

    write_to_dnnl_memory(conv_user_diff_weights_buffer.data(),

            conv_user_diff_weights_memory);

    auto conv_diff_bias_memory = memory({{conv_bias_tz}, dt::f32, tag::x}, eng);

    write_to_dnnl_memory(conv_diff_bias_buffer.data(), conv_diff_bias_memory);


    // create memory descriptors

    auto conv_bwd_src_md = memory::desc({conv_src_tz}, dt::f32, tag::any);

    auto conv_diff_bias_md = memory::desc({conv_bias_tz}, dt::f32, tag::any);

    auto conv_diff_weights_md

            = memory::desc({conv_weights_tz}, dt::f32, tag::any);

    auto conv_diff_dst_md = memory::desc({conv_dst_tz}, dt::f32, tag::any);


    // create backward convolution primitive descriptor

    auto conv_bwd_weights_pd = convolution_backward_weights::primitive_desc(eng,

            algorithm::convolution_direct, conv_bwd_src_md,

            conv_diff_weights_md, conv_diff_bias_md, conv_diff_dst_md,

            conv_strides, conv_padding, conv_padding, conv_pd);


    // for best performance convolution backward might chose

    // different memory format for src and diff_dst

    // than the memory formats preferred by forward convolution

    // for src and dst respectively

    // create reorder primitives for src from forward convolution to the

    // format chosen by backward convolution

    auto conv_bwd_src_memory = conv_src_memory;

    if (conv_bwd_weights_pd.src_desc() != conv_src_memory.get_desc()) {

        conv_bwd_src_memory = memory(conv_bwd_weights_pd.src_desc(), eng);

        net_bwd.push_back(reorder(conv_src_memory, conv_bwd_src_memory));

        net_bwd_args.push_back({{DNNL_ARG_FROM, conv_src_memory},

                {DNNL_ARG_TO, conv_bwd_src_memory}});

    }


    // create reorder primitives for diff_dst between diff_src from relu_bwd

    // and format preferred by conv_diff_weights

    auto conv_diff_dst_memory = relu_diff_src_memory;

    if (conv_bwd_weights_pd.diff_dst_desc()

            != relu_diff_src_memory.get_desc()) {

        conv_diff_dst_memory = memory(conv_bwd_weights_pd.diff_dst_desc(), eng);

        net_bwd.push_back(reorder(relu_diff_src_memory, conv_diff_dst_memory));

        net_bwd_args.push_back({{DNNL_ARG_FROM, relu_diff_src_memory},

                {DNNL_ARG_TO, conv_diff_dst_memory}});

    }


    // create backward convolution primitive

    net_bwd.push_back(convolution_backward_weights(conv_bwd_weights_pd));

    net_bwd_args.push_back({{DNNL_ARG_SRC, conv_bwd_src_memory},

            {DNNL_ARG_DIFF_DST, conv_diff_dst_memory},

            // delay putting DIFF_WEIGHTS until reorder (if needed)

            {DNNL_ARG_DIFF_BIAS, conv_diff_bias_memory}});


    // create reorder primitives between conv diff weights and user diff weights

    // if needed

    auto conv_diff_weights_memory = conv_user_diff_weights_memory;

    if (conv_bwd_weights_pd.diff_weights_desc()

            != conv_user_diff_weights_memory.get_desc()) {

        conv_diff_weights_memory

                = memory(conv_bwd_weights_pd.diff_weights_desc(), eng);

        net_bwd_args.back().insert(

                {DNNL_ARG_DIFF_WEIGHTS, conv_diff_weights_memory});


        net_bwd.push_back(reorder(

                conv_diff_weights_memory, conv_user_diff_weights_memory));

        net_bwd_args.push_back({{DNNL_ARG_FROM, conv_diff_weights_memory},

                {DNNL_ARG_TO, conv_user_diff_weights_memory}});

    } else {

        net_bwd_args.back().insert(

                {DNNL_ARG_DIFF_WEIGHTS, conv_diff_weights_memory});

    }


    // didn't we forget anything?

    assert(net_fwd.size() == net_fwd_args.size() && "something is missing");

    assert(net_bwd.size() == net_bwd_args.size() && "something is missing");


    int n_iter = 1; // number of iterations for training

    // execute

    while (n_iter) {

        // forward

        for (size_t i = 0; i < net_fwd.size(); ++i)

            net_fwd.at(i).execute(s, net_fwd_args.at(i));


        // update net_diff_dst

        // auto net_output = pool_user_dst_memory.get_data_handle();

        // ..user updates net_diff_dst using net_output...

        // some user defined func update_diff_dst(net_diff_dst.data(),

        // net_output)


        for (size_t i = 0; i < net_bwd.size(); ++i)

            net_bwd.at(i).execute(s, net_bwd_args.at(i));

        // update weights and bias using diff weights and bias

        //

        // auto net_diff_weights

        //     = conv_user_diff_weights_memory.get_data_handle();

        // auto net_diff_bias = conv_diff_bias_memory.get_data_handle();

        //

        // ...user updates weights and bias using diff weights and bias...

        //

        // some user defined func update_weights(conv_weights.data(),

        // conv_bias.data(), net_diff_weights, net_diff_bias);


        --n_iter;

    }


    s.wait();

}


int main(int argc, char **argv) {

    return handle_example_errors(simple_net, parse_engine_kind(argc, argv));

}

--------------------------------




2023年5月24日水曜日

GPTでPytorchを使ったニュートン法をやってみる

おじさん、最近、自動微分とか自動ベクトル化の勉強にはまっています。

JAXとかfunctorchとかものすごい勢いで開発されてるし。

ここでLLMが500億円で計算できるか50億円で計算できるか決まるしね。

だけどドキュメントがまったくない・・・・・。

--------

Why functorch?

This library is currently under heavy development - if you have suggestions on the API or use-cases you'd like to be covered, please open an github issue or reach out. We'd love to hear about how you're using the library.

functorch is JAX-like composable function transforms for PyTorch.

--------

このへん、ちょー開発中なのね。

おじさん、自動微分ってディープラーニングだけじゃなくて、制御や物理シミュレーションや数値計算、株価予想とかいろいろ面白い使い方があると思っているのですが、自動微分を使ったニュートン法とかの基礎的なサンプルコードがないからまだ誰も使ってないと思っています。

株価の予想に自動微分使って一儲けできないかなぁ。とか書くとめちゃくちゃ怪しいメールがたくさん来ます。


おじさんChatGPTに、PytorchのC++APIを使ってニュートン法を自動微分でするサンプルをお願いしてみました。



けど、最新の部分ってChatGPTもわからない・・・。というかChatGPTって誰かが書いたコードをコピペしかできないでしょ。動かない適当なコードばっかりはくし、オリジナルのコード全くかけない。


しょーがないなー。

というわけで、まだ世界でだれも作っていない、バックプロパゲーションの基礎の基礎であるニュートン法をC++でPytorchの自動微分機能を使ってするサンプルを自分で書いてみました。

----------------------------------

 #include <torch_torch.h>


torch::Tensor f(const torch::Tensor& x_tensor)

{

torch::Tensor y = x_tensor * x_tensor - 2;

return y;

}


float newtonMethod(float x) {

torch::Tensor x_tensor = torch::tensor(x, torch::requires_grad());

torch::Tensor y;


for (int i = 0; i < 5; ++i) {

y = f(x_tensor);

y.backward();


torch::Tensor grad = x_tensor.grad();


x_tensor.data() -= (y / grad).data();

x_tensor.grad().zero_();

std::cout << x_tensor.item<float>() << std::endl;

}

return x_tensor.item<float>();

}


int main() {

float initial_guess = 5.0;

float result = newtonMethod(initial_guess);

std::cout << "Approximate solution: " << result << std::endl;

return 0;

}

----------------------------------

oneDnn+flashlightも使ってみたいのでいろいろ調べているのですが、どのライブラリもAPI似てますね。


結果

----------------------------------

2.7

1.72037

1.44146

1.41447

1.41421

Approximate solution: 1.41421

----------------------------------

できた!

これを変数でなくて複雑なベクトル関数でやるとバックプロパゲーションになるのね。



2023年5月10日水曜日

C++でトップダウン型自動微分をする

C++で書かれたAIの学習プログラムが少ない理由に、トップダウン型の自動微分ができないからというのがあります。

自動微分ができないと、バックプロパゲーションするときに偏微分値を手動で計算してさらにそれをコーディングしないと求められなくて、学習やレイヤー設計が簡単にできないようです。

この問題クリアしないと、組み込みやスパコンでC++で学習させたりできないじゃん。

みんなどうやって自動微分しているのか調べてみました。



・FB


https://pytorch.org/tutorials/advanced/cpp_autograd.html

PytorchってC++で自動微分ができるんですね。すげー。

Pytorchは自動ベクトル化もできるのでC++とかもでもきるんだろうか?


・Google

TensorFlow2じゃないと自動微分できないし、PythonのautogradやJAXライブラ使っているのでC++で自動微分できません。力わざとお金の力で解決?

なんとGoogleが負けている。なんという過酷な開発競争


・PFN

https://www.preferred.jp/ja/news/pr20181203-1/

PFNもC++で自動微分するの大変だったのね。

でも撤退。県外。


・OpenAI


https://github.com/oneapi-src/oneDNN

OneDNNというC++自動微分できるライブラリを自分たちで作っている!

そりゃそうだよね。そうしないとChatGPTとか計算できないよね。



色々調べてみると、どうやらFBのPytorchとOpenAIのOneDNNくらいしかC++で自動微分できないのね。

しかもカスタムのベクトル関数をC++で自動微分できるのはPytorchしかない・・・

悲しい。


ボトムアップ型の自動微分ならば二重数で計算するだけなんですが、トップダウン型のベクトルの自動微分ってそんなに実装するの大変なの?


自動微分をC++で簡単に使うことができる様にしました。

https://github.com/takahiro1127/AutomaticDifferentiation


トップダウン型の自動微分を実装する

https://olanleed.hatenablog.com/entry/2023/04/16/203423


自動微分(Automatic differentiation)のSurvey論文の参照

https://lib-arts.hatenablog.com/entry/diff_implement2



どうやらスカラー型の自動微分のライブラリしか簡単に試せる実装はないらしいです。

任意のベクトル関数の自動微分をするってけっこう大変なのね。

勉強になるねぇ。

自動微分できないと、自動ベクトル化や最適化とかもできなさそうで、負の連鎖になるように思うんですが、どうなんでしょう?


ということで、誰も日本人でC++でベクトルのトップダウン型自動微分をやっている人がいないので、以前Windowsでカスタムビルドできるようにした、pytorchのC++で自動微分してみました。


----------------------

#include <iostream>

#include <torch_torch.h>



int main()

{


auto model = torch::nn::Linear(4, 3);


auto input = torch::randn({ 3, 4 }).requires_grad_(true);

auto output = model(input);


// Calculate loss

auto target = torch::randn({ 3, 3 });

auto loss = torch::nn::MSELoss()(output, target);


// Use norm of gradients as penalty

auto grad_output = torch::ones_like(output);

auto gradient = torch::autograd::grad({ output }, { input }, /*grad_outputs=*/{ grad_output }, /*create_graph=*/true)[0];

auto gradient_penalty = torch::pow((gradient.norm(2, /*dim=*/1) - 1), 2).mean();


// Add gradient penalty to loss

auto combined_loss = loss + gradient_penalty;

combined_loss.backward();


std::cout << input.grad() << std::endl;


return 0;

}



----------------------



----------------------

-0.0678 -0.1252  0.0566  0.0149

 0.2211 -0.0657  0.0009 -0.0186

-0.0982  0.0493  0.0301  0.0358

[ CPUFloatType{3,4} ]

----------------------


できた。

これでおじさんもC++でディープラーニングのレイヤ設計やモデル設計ができるようになりました。


2023年3月15日水曜日

GPTを動かす

 なんか最近GPTが流行っているようです。

おじさんも自分のマシンでGPTを動かしたくなってきました。



ということで、C++で動くGPUがいらないGPTを探してみました。

https://github.com/ggerganov/ggml/tree/master/examples/gpt-j

GPTってソースとってくれば10分くらいでマシンが作れるんですね。

これ本当に動くの?

スクラッチで書かれていて、*.cのファイル3個しかないし。

フル版だと72Gバイトのメモリと学習済みデータがいるらしい。

スモール版だと12Gバイトで動くらしい。

学習済みデータも置いてあるし。なんと親切な。

ちょーお手軽じゃん。


とりあえずAndroid版とM1-Mac版とIntel-Mac版とVisualC++版がビルドできた。


-----------------------

yomeinoMac-mini:jni yomei$ 

yomeinoMac-mini:jni yomei$ ./test -m ggml-model-gpt-j-6B.bin -p "Who are you ?"

main: seed = 1678930370

gptj_model_load: loading model from 'ggml-model-gpt-j-6B.bin' - please wait ...

gptj_model_load: n_vocab = 50400

gptj_model_load: n_ctx   = 2048

gptj_model_load: n_embd  = 4096

gptj_model_load: n_head  = 16

gptj_model_load: n_layer = 28

gptj_model_load: n_rot   = 64

gptj_model_load: f16     = 1

gptj_model_load: ggml ctx size = 13334.86 MB

gptj_model_load: memory_size =  1792.00 MB, n_mem = 57344

gptj_model_load: ................................... done

gptj_model_load: model size = 11542.79 MB / num tensors = 285

main: number of tokens in prompt = 4


Who are you ?

I am a professional web developer who lives on the north of England. I have an affinity for Linux, Open Source Software, and general geekery. I am currently learning Ruby


....

-----------------------

Intel Macで動かしたら、すげー動く!。

僕のマシンだと解答が出始めるのに10分くらいかかります。

あんた、Rubyを勉強しているね。偉いねー。


行列の掛け算を数十回するだけでなぜか会話ができてしまう。

これ手軽にデバッグできるから、AttentionとかTransformerの動きを勉強するのに最適だね。



2023年1月9日月曜日

中学校の入試問題をプログラムで解く。

 あけましておめでとうございます。ことしもよろしくお願いします。

おじさん、毎年この時期に新聞とかに載っている入試問題をといています。

暇つぶしに解いていたら、なんと中学入試の問題にプログラムコンテストの問題が混じっているではないか!




https://www10.schoolweb.ne.jp/weblog/files/1320077/doc/86294/1393171.pdf

このPDFの10ページの[2]の問2。


おじさん、年とともにどんどん問題を解くのに時間がかかり、解けなくなっていきます。かなしい。

この問題、たぶん3分くらいでとけないといけないのですが、24時間以上間考えてもわからない。


おじさん忠実に問題を解いていますが、この問題、相当難しい。

問題を複雑にしているポイントは3つ。



一つ目は、赤色+赤色の定義。


「赤色+赤色」を「赤色+赤色=赤色」とするのか、「赤色+赤色=2×赤色」とするのか演算処理が定義がされていない。

加法混色で赤色と青色と緑色がそれぞれ個数に関係なく兎に角3種類あれば白色なのか。

赤色と青色と緑色が同じ数だけある場合のみが白色なのか。

別の言い方をすると、「赤色+赤色+緑色+青色」を白色と扱うかピンクっぽい色って扱うか。


二つ目は、使って良いかい中電灯の個数。

かい中電灯を何個使っていいか問題には書かれていない。

仮にかい中電灯を2個だけでなく3個以上使って良く、かつ、「赤色+赤色=赤色」を定義する場合、結構な数の組み合わせになる。

ためしに答案用紙の広さを見ると一行分しかないじゃない。

超ちっちゃく書かないと答案用紙にはいらない!


三つ目は灰色を使うかどうか。

「赤色+緑色+青色」を白色と定義した場合、「2×赤色+2×緑色+2×青色」という白色を超える白色のパターンがでてしまう。これを白色とするのか、それとも「赤色+緑色+青色」を灰色として「2×赤色+2×緑色+2×青色」のみを白色とするのか。

白色と黒色と灰色って定義が難しい。



この問題、そもそも一つ目の問題を後者として問題を解くと答えの総数が減るんですが、灰色問題が出てきてしまって問題がとけない。一つ目の問題を前者として問題を解くと答えの総数が多くて大変なことになります。



なので、ありそうな答えの込み合わせをすべてプログラムで組んでみました。


----------------------------

#include <stdio.h>

#include <string.h>


#define R 1

#define G 10

#define B 100


int kaicyu[] = {

    R,G,R + G, R+B,G+B

};

const char* name[] = {

    "赤色","緑色","黄色","赤むらさき色","空色"

};


#define isR(a) (a%10)

#define isG(a) ((a/10)%10)

#define isB(a) ((a/100)%10)


#define syokusu(a) (((a&1)!=0)+((a&2)!=0)+((a&4)!=0)+((a&8)!=0)+((a&16)!=0))



int main()

{

    int i, c, m, j;

    char buf[256];


    printf("ptn1\n");

    printf("----------\n");

    for (i = 1; i <= 31; i++)

    {

        buf[0] = 0;

        c = 0;

        for (m = 1, j = 0; j < 5; j++, m <<= 1) {

            if (i & m) {

                c += kaicyu[j];

                if (buf[0] != 0)strcat(buf, "と");

                strcat(buf, name[j]);

            }

        }

        if (isR(c) && isG(c) && isB(c)) {

            printf("%s\n", buf);

        }

    }

    printf("\n");


    printf("ptn2\n");

    printf("----------\n");

    for (i = 1; i <= 31; i++)

    {

        buf[0] = 0;

        c = 0;

        for (m = 1, j = 0; j < 5; j++, m <<= 1) {

            if (i & m) {

                c += kaicyu[j];

                if (buf[0] != 0)strcat(buf, "と");

                strcat(buf, name[j]);

            }

        }

        if (isR(c) == isG(c) && isR(c) == isB(c)) {

            printf("%s\n", buf);

        }

    }

    printf("\n");


    printf("ptn3\n");

    printf("----------\n");

    for (i = 1; i <= 31; i++)

    {

        buf[0] = 0;

        c = 0;

        for (m = 1, j = 0; j < 5; j++, m <<= 1) {

            if (i & m) {

                c += kaicyu[j];

                if (buf[0] != 0)strcat(buf, "と");

                strcat(buf, name[j]);

            }

        }

        if (isR(c) == 2 && isG(c) == 2 && isB(c) == 2) {

            printf("%s\n", buf);

        }

    }

    printf("\n");


    printf("ptn4\n");

    printf("----------\n");

    for (i = 1; i <= 31; i++)

    {

        buf[0] = 0;

        c = 0;

        for (m = 1, j = 0; j < 5; j++, m <<= 1) {

            if (i & m) {

                c += kaicyu[j];

                if (buf[0] != 0)strcat(buf, "と");

                strcat(buf, name[j]);

            }

        }

        if (isR(c) == 1 && isG(c) == 1 && isB(c) == 1) {

            printf("%s\n", buf);

        }

    }

    printf("\n");


    printf("ptn5\n");

    printf("----------\n");

    for (i = 1; i <= 31; i++)

    {

        buf[0] = 0;

        c = 0;

        for (m = 1, j = 0; j < 5; j++, m <<= 1) {

            if (i & m) {

                c += kaicyu[j];

                if (buf[0] != 0)strcat(buf, "と");

                strcat(buf, name[j]);

            }

        }

        if (syokusu(i)==2 && isR(c) && isG(c) && isB(c) ) {

            printf("%s\n", buf);

        }

    }

    printf("\n");


    return 0;

}

----------------------------



----------------------------

ptn1

----------

緑色と赤むらさき色

赤色と緑色と赤むらさき色

黄色と赤むらさき色

赤色と黄色と赤むらさき色

緑色と黄色と赤むらさき色

赤色と緑色と黄色と赤むらさき色

赤色と空色

赤色と緑色と空色

黄色と空色

赤色と黄色と空色

緑色と黄色と空色

赤色と緑色と黄色と空色

赤むらさき色と空色

赤色と赤むらさき色と空色

緑色と赤むらさき色と空色

赤色と緑色と赤むらさき色と空色

黄色と赤むらさき色と空色

赤色と黄色と赤むらさき色と空色

緑色と黄色と赤むらさき色と空色

赤色と緑色と黄色と赤むらさき色と空色


ptn2

----------

緑色と赤むらさき色

赤色と空色

赤色と緑色と赤むらさき色と空色

黄色と赤むらさき色と空色


ptn3

----------

赤色と緑色と赤むらさき色と空色

黄色と赤むらさき色と空色


ptn4

----------

緑色と赤むらさき色

赤色と空色


ptn5

----------

緑色と赤むらさき色

黄色と赤むらさき色

赤色と空色

黄色と空色

赤むらさき色と空色

----------------------------


中学校の入学試験ってとっても難しい。

うーん、これ本当にとけた小学生いるのだろうか・・・。

どれが正解なんだ???。

SAPIXの先生か誰か答えを教えてください。