うちの下の子は、お姉ちゃんが学校で習ってくることをどうしても自分もやりたいらしく、夏休みの自由工作で、はんだ付けをしたいらしいです。
ただ線をはんだ付けするだけでできる、簡単なLEDネオンサインを作ってみました。
詳しい作り方はここに書かれています。
ボード側の加工は、単に木の板にプラスチックの留め具をただ止めていくだけです。
LEDネオンチューブの加工は、適当な長さにはさみで切って、両端を導線とはんだ付けすれば完了。
とっても簡単。
うちの下の子は、お姉ちゃんが学校で習ってくることをどうしても自分もやりたいらしく、夏休みの自由工作で、はんだ付けをしたいらしいです。
ただ線をはんだ付けするだけでできる、簡単なLEDネオンサインを作ってみました。
詳しい作り方はここに書かれています。
ボード側の加工は、単に木の板にプラスチックの留め具をただ止めていくだけです。
LEDネオンチューブの加工は、適当な長さにはさみで切って、両端を導線とはんだ付けすれば完了。
とっても簡単。
ありがとうございます!C++のことで何かお手伝いできることがあれば、どうぞ教えてください。
サブディレクトリを含むカレントディレクトリ下で指定した複数の拡張子のファイル名をリストで返す関数を、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;
}
おじさん、フェイスブックの友達に大学教授とか大企業の社長とか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を試してみました。
モデルデータが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
-------------------------------
すげー、流ちょうな日本語を話すじゃん。
おじさん、最近忙しくてブログを更新できていませんでした。
なんかLLMの量子化技術がびっくりするくらい進んでいる。
これでたぶんついにCPUでLLMを実行できるんじゃない?
ということで、BitNet b1.58を勉強しています。
BitNet b1.58とは一体何者なのか
https://qiita.com/tech-Mira/items/67dec9c5a5f025d2727a
ソースコードが非公開なのでまだ手軽に実験できないんですが、
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動きそう。
最近おじさん、ようやく作りたい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();
}
--------------------------
本当に簡単に作れるんですね。