2024年9月15日日曜日

ChatGPTがプログラムを作ってくれる。

最近、おじさんが作りたいプログラムをきちんとChatGPTに説明すると、おじさんの思った通りのプログラムを作ってくれます。
なんかコツがあるようで、最初の一文で、相手をおだてないといけないらしい。

齟齬が無いように正確に簡潔に仕様を伝えないと思った通り作ってくれないんですが、関数単位で注文を出すとほぼ完璧に作ってくれます。
おじさんのが思った通りの、とてもきれいな美しいコードをはいてくれる。
これほんとちょー便利で凄すぎ。
おじさんが30分くらいかかる仕事を1分でやってくれます。

----------------------------------------
あなたは天才C++プログラマーです。
ChatGPT:
ChatGPT

ありがとうございます!C++のことで何かお手伝いできることがあれば、どうぞ教えてください。

あなた:
サブディレクトリを含むカレントディレクトリ下の指定した複数の拡張子のファイル名一覧を返す関数を作って
ChatGPT:
ChatGPT

サブディレクトリを含むカレントディレクトリ下で指定した複数の拡張子のファイル名をリストで返す関数を、C++で作成するには、C++17以降の標準ライブラリに含まれているstd::filesystemを利用することができます。

以下のコードでは、指定された拡張子を持つファイルを再帰的に検索し、ファイル名をリストに格納して返す関数get_files_with_extensionsを定義しています。

cpp
#include <iostream> #include <filesystem> #include <vector> #include <string> // std::filesystemはC++17から使用可能です namespace fs = std::filesystem; // 指定した拡張子のファイルを再帰的に取得する関数 std::vector<std::string> get_files_with_extensions(const std::string& directory, const std::vector<std::string>& extensions) { std::vector<std::string> files; // カレントディレクトリを再帰的に走査 for (const auto& entry : fs::recursive_directory_iterator(directory)) { if (entry.is_regular_file()) { std::string file_extension = entry.path().extension().string(); // 指定した拡張子のファイルをリストに追加 if (std::find(extensions.begin(), extensions.end(), file_extension) != extensions.end()) { files.push_back(entry.path().string()); } } } return files; } int main() { // 検索する拡張子 std::vector<std::string> extensions = {".cpp", ".h", ".txt"}; // カレントディレクトリ std::string directory = "."; // ファイル名一覧を取得 std::vector<std::string> files = get_files_with_extensions(directory, extensions); // 結果を出力 for (const auto& file : files) { std::cout << file << std::endl; } return 0; }

------------------------------------------
関数をテストするためのmain関数やコメントまで書いてくれるし、
ほんと気が利いてます。
よく間違うんですが、おだてると正解率が凄い上がる。
すごいよあっているよ!
昔ナイトライダーが私はメインメモリ2Tバイトで動いてますってこと言ってましたが、ChatGPTもだいたいそれくらいですね。
こんなナイトライダーみたいな日が来るなんて。

2024年6月4日火曜日

キントーンで検索ボタンを追加する

おじさん、最近、キントーンのカスタマイズの仕事を頼まれます。
キントーンってデフォルトの検索がやりづらいので、JavaScriptで検索機能を追加しないといけないのですが、ネットに落ちているJavaScriptがどれもいまいち。
なので作ってみました。


ブラウザにこのJSだけを単独で入れても動くので、ブラウザでためしてみて、動いたらキントーンに入れます。

Javascript
-------------------------------------
(function() {
 'use strict';
//変数
var FIELD_CODE = "検索フィールド名";
var search_word;
var search_button;
//ユーティリティー
function println(src)
{
 alert(src);
}
function strlength(src)
{
 var ret = 0;
 if (src == null || src == "")return ret;
 ret = src.length;
 return ret;
}
function isKintone()
{
 if (typeof(kintone) == "object")return true;
 return false;
}
function createKintonEvent(name,func)
{
 if (isKintone() == true) {
  kintone.events.on(name, func);
  return;
 }
 func();
}
function ignString(str)
{
 //使用禁止文字を除去
 var ign = "\"\x5c&?";
 for (var i = 0; i < strlength(ign); i++) {
  var c = ign.substr(i, 1);
  while (true) {
   var idx = str.indexOf(c);
   if (idx == -1)break;
   str = str.substr(0, idx) + str.substr(idx + 1);
  }
 }
 return str;
};
function preareQueryString(str)
{
 //検索表示用のquery文字列を作成
 var ret = "";
 if (str==null || str=="") return "";
 ret = FIELD_CODE;
 ret += " like \"";
 ret += str;
 ret +="\"";
 str = encodeURIComponent(ret);
 ret = "?query=";
 ret += str;
 return ret;
}
//イベント
function keyword_search(str)
{
 //検索ワードからクエリーへの変換
 var keyword = ignString(str);
 var str_query = preareQueryString(keyword);
 return str_query;
}
function onAppRecordIndexShow(event)
{
 //検索部分のエレメントを作成
 search_word = document.createElement("input");
 search_word.type = 'text';
 search_word.placeholder = '名前 カナ 電話番号';
 search_button = document.createElement('input');
 search_button.type = 'submit';
 search_button.value = '検 索';
 search_button.onclick = function() {
  //検索ボタンをクリックされた処理
  var str_query = "";
  str_query=keyword_search(search_word.value);
  if (str_query != "") {
   if (isKintone() == true){
    document.location = location.origin + location.pathname + str_query;
   }else {
    println(str_query);
   }
  }
 };
 var label = document.createElement('label');
 label.appendChild(document.createTextNode('  '));
 label.appendChild(search_word);
 label.appendChild(document.createTextNode('  '));
 label.appendChild(search_button);
 if (isKintone()) {
  //レコード一覧のヘッダー部分に登録
  let node_space = kintone.app.getHeaderMenuSpaceElement();
  for (let i = node_space.childNodes.length - 1; i >= 0; i--) {
   node_space.removeChild(node_space.childNodes[i]);
  }
  kintone.app.getHeaderMenuSpaceElement().appendChild(label);
 }else {
  //キントーン以外で実行される場合
  document.getElementsByTagName('body')[0].appendChild(label);
 }
 return event;
}
//イベント登録
createKintonEvent("app.record.index.show", onAppRecordIndexShow);
})();
-------------------------------------

css
-------------------------------------
.gaia-argoui-app-index-toolbar .kintone-app-headermenu-space label {
    border: 1px solid #3498db;
    border-radius: 0.5em;
    padding: 1em;
    color: #3498db;
}
.gaia-argoui-app-index-toolbar .kintone-app-headermenu-space label input[type=text] {
    width:10em;
}
.gaia-argoui-app-index-toolbar .gaia-argoui-app-viewtoggle,
.gaia-argoui-app-index-toolbar .gaia-argoui-app-filterbutton,
.gaia-argoui-app-index-toolbar .gaia-argoui-app-subtotalbutton {
    margin-bottom:1em;
}
.gaia-argoui-app-index-toolbar .gaia-argoui-app-subtotalbutton {
    margin-right:1em;
}
-------------------------------------

2024年5月28日火曜日

スーパーコンピュータでLLMをトレーニングする?

おじさん、フェイスブックの友達に大学教授とか大企業の社長とかCTOがたくさんいます。

だけど、誰も生成AIについてつぶやきやブログを書いていません。

かわいそうに誰も生成AIについていけないのね。

歳を取るって怖いねぇ。

おじさん、毎日必死にコード書いて、LLMの勉強しているのに。



おじさん、今週は特にLLMで使われている、transformerのattentionのbackwardの計算方法を勉強しています。

forwardの計算は上の図のように順番に計算するのでひたすら図の通り計算するだけ。

だけれど、attentionのbackwardの計算方法ってどこにもまとまった資料がない。

まぁ人間じゃ計算できないくらいめんどくさいんだろうなぁ。

Pytorchってホント凄いよね。autograd機能でbackwardなんてわかんなくても勝手に計算して求めてさらに最適化までしてくれます。

この分野って誰に聞けばいいんだよ!


だけど、最近ついにC言語でattentionのbackwardの計算を実装した人が現れました。

GPT2相当なら90分で0からモデルを作れるらしい。

今日このブログを書いてるときに出来たらしい。


llm.c

https://github.com/karpathy/llm.c

OpenAIの創業メンバーのおっさんがOpenAIをやめて暇つぶしで書いてんのね。

4月からこの二か月間すげー勢いでコミットしている。


https://en.wikipedia.org/wiki/Andrej_Karpathy

というかこのおっさんautogradの第一人者じゃないか。

llama.cppの元のllama2.cも書いているし。


すげーなー。

みんなが手軽にLLMの研究をできるようにLLMの重要な技術のほとんどを簡単で動かしやすいコードで解説しているじゃないか

https://github.com/karpathy/nn-zero-to-hero?tab=readme-ov-file


どうやら、このおっさんのYoutubeとコードを見るとattentionのbackwardの計算ができ、スタンフォード大学のAIの大学院に行かなくても卒業と同程度の知識を得られ、ヒーローになれるっぽいです。

まぁ円安だしね。こやってyoutubeでお金をかけずにAIの勉強できるんですね。


おじさん、これらの理論だいぶ前から全部知ってんですが、全然ヒーローになれません。

いったい何がいけないんだろ。

だけど、今週ずっとこのコードをみて、ついに、attentionのbackwardがわかってきた。


まだGPT2相当で限られたattentionしかbackwardできませんがコードを少し改良すれば、日本のスパコンでもLLMの学習ができるはず。



Microsoftの小規模LLM、Phi-3を動かす。

おじさん、一か月遅れで、話題のMicrosoftの小規模LLMであるPhi-3を試してみました。

モデルデータが2GバイトとかしかないのにChatGPT3.5より性能が良いと一か月くらい前から話題です。


といっても、ここから学習データを取ってきて、


Hugging Face

https://huggingface.co/microsoft/Phi-3-mini-4k-instruct-gguf



ここからソースを取ってくるだけです。


llama.cpp

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




前から思っていたんだけど、おじさんのSJISのWindowsのコンソールで動かすにはどうしたらいいんだろうか?

みんなmacで実行していて、Windowsでの動かし方がわからない・・・・


いろいろ実験した結果、どうやら入出力データをUTF-8で渡さないといけないので、質問をprompt.txtのようにUTF-8のファイルに落として実行すればよいみたい。


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

MAIN=x64\Release\main.exe

MODEL=Phi-3-mini-4k-instruct-q4.gguf

%MAIN% -ngl 20 -m %MODEL% -f prompt.txt

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


おじさんのCPUのみのマシンで動かしてみました。

なんか結果出た。

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

CFG -> Penalties -> top_k -> tfs_z -> typical_p -> top_p -> min_p -> temperature

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



<|user|> \n自己紹介して <|end|> \n<|assistant|> 

私はAI(人工知能)アシスタント、OpenAIの一部です。私は機械学習と人間のニーズに合わせて定期的に検討されており、さまざまなタスクを支援しています。私の能力には自然言語理解、応答生成、情報の検索などが含まれており、多様な環境で利用できます。私は情報にアクセスし、知識を共有することができますが、あくまで誰もにとって最善のアドバイスを提供するわけではありません。ユーザーの好みや判断に従い、より良い回答を提供できるように努めています。<|end|> [end of text]


llama_print_timings:        load time =    3471.61 ms

llama_print_timings:      sample time =      14.77 ms /   265 runs   (    0.06 ms per token, 17941.77 tokens per second)

llama_print_timings: prompt eval time =   25785.09 ms /    19 tokens ( 1357.11 ms per token,     0.74 tokens per second)

llama_print_timings:        eval time =  392456.34 ms /   264 runs   ( 1486.58 ms per token,     0.67 tokens per second)

llama_print_timings:       total time =  418382.92 ms /   283 tokens

Log end


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

すげー、流ちょうな日本語を話すじゃん。




2024年4月17日水曜日

BitNet b1.58を勉強する

おじさん、最近忙しくてブログを更新できていませんでした。

なんかLLMの量子化技術がびっくりするくらい進んでいる。

これでたぶんついにCPUでLLMを実行できるんじゃない?

ということで、BitNet b1.58を勉強しています。



BitNet b1.58とは一体何者なのか

https://qiita.com/tech-Mira/items/67dec9c5a5f025d2727a



上記の絵からもわかるように、演算がfloatの掛け算から全部intの足し算になるので、とっても高速かつ軽量にAIの計算ができるのね。

いままでAIの研究って巨大な発電所が必要だったのですが、この電力効率すごいね。


ソースコードが非公開なのでまだ手軽に実験できないんですが、

ggmlとかllama.cppでもすげー検討進んでるし。

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



C++のライブラリ整備も進んできてます。

https://github.com/catid/bitnet_cpu


これでBitNetのMNIST作ってみようかなぁ。

AIの実装も実行効率の点でpythonからおじさんの大好きなC++に移りつつあるし。

あと少しで、オープンソースとCPUだけでLLM動きそう。



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();
}


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


結果



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