OmniAICreator/Qiita-1.07M huggingface dataset:
能登半島における大隆起地形調査

2024年3月30日実施 石川県輪島市西部の大隆起および過去の隆起活動の痕跡の地形調査
秘密結社オープンフォース  河野悦昌、河野七月、秋山俊也





# 令和6年能登半島地震による隆起


2024年1月1日に発生した能登半島地震においては震源地に近い珠洲市の隆起がよく知られているが、震源地の反対側の輪島市五十州周辺がより顕著な隆起を示している。
過去にこの地点の観測がなされて公表されているが、地震後の現地の情報がほとんど明るみになっておら
ず間接的な情報しか無いので現地での調査を行った。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/567e281d-4311-3fca-e738-1aaf4759db05.png)
衛生観測データによる垂直方向の隆起[^1]




[^1]: 令和６年１月11日 国土地理院発表 国土地理院 地殻変動情報（衛星SAR）「だいち２号」観測データの2.5次元解析による令和6年能登半島地震（2024年1月1日）に伴う地殻変動 https://www.gsi.go.jp/common/000254168.pdf より抜粋


# 観測地点

石川県輪島市皆月湾、および吉浦地区で行った。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/4f0303de-7250-06a4-d2db-fc4f59605048.png)

# 隆起の計測

## 隆起1 皆月湾の簡易測量
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/6d54ca73-6da0-abcc-3880-451eb4858ecb.png)


## 隆起2 石川県輪島市門前町吉浦ぬ の海底隆起の簡易計測

岩の黒と白の境目が、地震前に界面だった場所である。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/6e54ab8e-e8d6-f5da-921f-87ada3b1416c.png)

# 段丘の確認

今回の地震による隆起以外に、過去数千年間に発生したと考えられる隆起が段丘として残っている。その段丘の調査を行った。

## 段丘1 海成段丘の確認 石川県輪島市門前町吉浦北側

先行研究[^2]によって数千年前に形成された段丘がL1面〜L3面として報告されている。その地形の確認を行った。

[^2]:「能登半島北部沿岸の低位段丘および離水生物遺 骸群集の高度分布からみた海域活断層の活動性」  宍倉正展，越後智雄 ，行谷佑一  活断層研究 53号 33～49 2020

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/e7fc6c17-b83e-7aee-34dc-07712c6bcb04.png)


## 段丘2 段丘の観察  石川県輪島市門前町吉浦ぬ

より南西側の断崖となった海岸において、段丘とみなせる地形が確認できた。
新しい順に今回の地震で生成されたα段、それより上に行くに従いβ段、γ段、δ段と名付けた。
先行研究によるL1面〜L3面と照合を行う。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/d1693899-df94-4dbf-0b33-ee7f64092256.png)

# 段丘の簡易計測

 石川県輪島市門前町吉浦ぬ において、段丘2および隆起2の簡易計測を行った。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/fd07067b-fdc8-1548-6948-7fc107dbdfa8.png)

# 段丘2の計算結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/1f6ec1ba-3f7a-16f8-1e21-d64c0479a563.png)
# 考察
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/7b5404fd-8c2d-a803-8c81-765f72c7acd6.png)
段丘1は先行研究により観察できる段丘はL1,L2とみなされ、L1は6000年前もしくは3500年前に形成、
L2は4900年前もしくは2800年前、L3は3500年前または2000年前(数字は概数)とされる。


今回簡易測量を行った段丘2は離水生物遺骸は観察できなかったが、段丘1と同様の隆起活動による段丘
とすると今回の震災による隆起と良く対応し、この地が周期的に大隆起を起こしていることを示唆する
ものである。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/77312897-fc89-88ae-dda9-b8059c94e4b3.png)

## 復興に向けて

今回の皆月湾や吉浦地区にある小漁港は完全に陸地になってしまい、生活の糧としての漁業が失われてしまっている。4mやそれに比類する大隆起が発生した後に、港を浚渫して復旧することが可能かどうかということについて、今回の研究を参考にすることができる。

このような大隆起でダメージを受けた漁港の復旧は、関東大震災時の千葉県南房総での事例がある。そこでは約2年で港の掘り下げなどを行ったのであるが、それと同様のことが行えるかどうか。

今回のレポートでは触れなかったが、隆起2においてはかなり固い泥岩で構成されている。このような岩質を沖合まで浚渫するにはかなり高いコストが必要であると想像する。隆起した一帯すべてが浚渫が困難な地域ということであれば、漁業の復興はある程度港機能を集約した箇所を設定し、そこを復旧、漁業従事者はそこに通勤するというやりかたをせざるを得ないということになる。

cf.,「漁港の復旧の過去事例と能登半島輪島市においての適用可能性」(2024NotoTopographicSurvey)[^3]



しかしながらその後の調査で、場所によっては浚渫のしやすい砂岩質の隆起地帯もありそうということがわかった。そうであるならば少しは復興の道筋を何本か増やすことができるかも知れない。今後も引き続き調査を行う予定である。


[^3]: https://github.com/nanbuwks/20240504MinamibosoGeoSurvey/wiki/漁港の復旧の過去事例と能登半島輪島市においての適用可能性
(DAY2) 俺と学ぶRust言語~画面出力~

## 今日の記事の内容
- 言語ごとの画面出力を比べてみよう
- Rustでは画面出力にマクロを使うよ
- 数値を埋め込んでみよう

# はじめに
[前回](https://qiita.com/FUKAch/items/2fbf04a035b8c8b93400)はDAY1ということでRustの導入を行いました。ついでに「Hello, rust!」と表示させましたね！今日は、改めて画面出力について学びます。

# 他の言語との画面出力の比較
他の言語とRustでの「Hello, world!」を標準出力する際の比較をします。
他の言語代表として、C言語およびPythonと比較してみましょう。
C言語では次のようになります。
```c
#include <stdio.h>
int main(){
    printf("Hello, world!");
    return 0;
}
```
一方、Pythonでは次のようになります。
```python
print("Hello, world!")
```
C言語ではprintf関数、Pythonではprint関数を呼び出しています。
これらに対して、Rustでは次のようになります。
```rust
fn main() {
    println!("Hello, world!");
}
```
Rustではprintln!を呼び出しています。これも関数なのでしょうか。
末尾に"!"（エクスクラメーションマーク、感嘆符）がついています。これは関数ではなく、**マクロ**であることを示しています。
つまりprintln!は普通の関数ではなく、マクロとして定義されているものなのです。
<details><summary>マクロとは</summary>

詳しくは[こちら](https://wa3.i-3-i.info/word11242.html)を参考にしてください。複雑な記述が必要な場面でも、マクロを使うことで短く記述できるようになります。Rustのマクロはプログラムをスマートにして変換するということを覚えておきましょう。
</details>

# プレースホルダ
「プレースホルダってなんだろう」なんて思いながら見てください。（C言語でいう"%d"や"%s"などです。）
数値を文字列に埋め込んで画面出力する方法を確認してみましょう。
C言語では以下のようにします。
```c
#include <stdio.h>
int main(){
    int age=15;
    printf("彼の年齢は%d歳です。", age);
    return 0;
}
```
一方、Pythonでは以下のようにします。
```python
age = 15
print("彼の年齢は{}歳です。".format(age))
```
C言語では「"文字列", 数値」のようにするのに対して、Pythonでは「"文字列".format(数値)」のようにします。
ここで、Rustでは以下のようにします。
```rust
fn main() {
    let age = 15;
    println!("彼の年齢は{}歳です。", age);
}
```
Rustでは、文字列に数値を埋め込んで表示する際にはprintln!マクロを利用します。第一引数に書式を指定し、それ以降で値を指定します。すると、書式の中の"{ }"（波カッコ）の部分を値に置き換えて表示します。この"{ }"を「プレースホルダ(Placeholder)」と呼びます。
また、しれっと変数の定義も行っていますね。Rustでの変数定義は「let 変数名 = 値;」のように書きます。なお、Rustでは **「値を変数に束縛する」** といいます。

:::note warn
ここで注意すべき点は、Rustでの変数は標準で不変です。
:::

# 四則演算
次の問題を、プログラミングを用いて解いてみましょう。
>【問題】 製品の材料として使う金属板を切り出す作業をしています。1枚の金属板の重さは3.2kgです。この板を8等分すると、1つの切り出しパーツの重さは何kgになるでしょうか？さらに、そのパーツを5つ使った場合、合計で何kgの重さになるでしょうか？

さて、きっとプログラミングのことで頭がいっぱいの方にはすこし難しく見えるかもしれませんが、全く難しい問題ではありません。
3.2kgを8等分ですので、3.2[kg] ÷ 8 です。また、それを5つなので、3.2[kg] ÷ 8 × 5 です。
これをRust内で計算し出力します。
```rust
fn main() {
    let metal = 3.2;
    println!("1つのパーツの重さは{}kg", metal / 8.0);
    println!("5つのパーツの重さは{}kg", metal / 8.0 * 5.0);
}
```
実行してみましょう。
```
1つのパーツの重さは0.4kg
5つのパーツの重さは2kg
```
ここで、8.0や5.0のように「.0」を加えて加えて小数点以下の値まできちんと指定しなければなりません。**Rustは型に厳しい言語です。**

# おわりに
おつかれさまでした。今回は、100DaysOfCode 二日目として、Rustの画面出力について学びました。
明日はRustとC言語でFizzBuzz問題を解きます。
ご精読、ありがとうございました。
Go言語でデスクトップアプリを開発できるWailsのデバックログを見やすくする方法

# はじめに

Go言語でWindows,Mac OS,Linuxのデスクトップアプリを簡単に作れるwails

https://wails.io/ja/

のデバッグログを見やすくする方法の紹介です。

WailsはTWSNMP FK（別名 シン・TWSNMP）

https://apps.microsoft.com/detail/9nsqn46p0mvl?hl=ja-jp&gl=LS


https://apps.apple.com/jp/app/twsnmpfk/id6468539128?mt=12

の開発に利用しています。

開発中にデバッグログが見づらかったので改善しました。

# 改善前のデバッグログ

Go言語の標準logパッケージの出力とWailsの標準ログが混在して見づらくまっていました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3874862/4899b346-de11-c6ad-c517-d89770eb42ea.png)

タイムスタンプから始まる行がGo言語の標準logパッケージです。
DEBで始まる行がWailsの標準ログです。開発中にストレスが感じていました。

# Wailsのカスタムログによる改善

Wailsのログに関するドキュメント

https://wails.io/ja/docs/reference/runtime/log

の下の方に、カスタムログについての説明があります。

```go
type Logger interface {
    Print(message string)
    Trace(message string)
    Debug(message string)
    Info(message string)
    Warning(message string)
    Error(message string)
    Fatal(message string)
}
```
というインターフェイスをもったstructをWailsのアプリオプションのLoggerに設定すればよいとのことです。
そこで、カスタムログのパッケージを作りました。


```go
package clog

import (
	"log"

	"github.com/fatih/color"
)

type ColorLogger struct{}

func New() *ColorLogger {
	return &ColorLogger{}
}

func (l *ColorLogger) Print(message string) {
	log.Println(message)
}

func (l *ColorLogger) Trace(message string) {
	log.Printf("%s %s", color.CyanString("[TRACE]"), message)
}

func (l *ColorLogger) Debug(message string) {
	log.Printf("%s %s", color.HiGreenString("[DEBUG]"), message)
}

func (l *ColorLogger) Info(message string) {
	log.Printf("%s %s", color.HiBlueString("[INFO]"), message)
}

func (l *ColorLogger) Warning(message string) {
	log.Printf("%s %s", color.HiYellowString("[WARN]"), message)
}

func (l *ColorLogger) Error(message string) {
	log.Printf("%s %s", color.HiMagentaString("[ERR]"), message)
}

func (l *ColorLogger) Fatal(message string) {
	log.Printf("%s %s", color.HiRedString("[FATAL]"), message)
}
```

このパッケージのNew()で作成したstructをLoggerに設定します。

単に、log.Printlnで出力すればフォーマットは、揃いますが、


https://github.com/fatih/color

を使ってカラー表示できるようになっています。

# 改善後のデバッグログ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3874862/1eee1c49-4ea7-47e8-3a9a-0bbaf880b150.png)


凝ったログパッケージを使うことをも考えましたが、このぐらいで十分見やすくなったと思います。
デーサイのロードマップを完走したので、ツールなどを語ってみる

GitHubが先月発表した最も使われているプログラミング言語が、JavaScriptからPythonに入れ替わりました！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1044781/4f5d5025-235d-e813-9bfe-99c6a86731c3.png)


生成AIブームがその引き金になったと言われています。



これはデータサイエンティストとして喜ばしいことですね。（実際にはJavaScriptからTypeScriptへの移行がおこなわれているのも要因の一つでしょうが。）




このまま1位を保っていきたいですね。





さて、今回、QiitaのR言語アドベントカレンダーに参加することになりました。（Rコミュニティは狭く深いので、こういうイベントには定期的に参加したいです🔥）




何を書こうかと悩みましたが、そういえば今年、




データサイエンスのロードマップを完走したので、そのフィールドやツールなどを言語ベースで語ってみる




ことにしました。



ちなみに、完走したロードマップが[こちら](https://roadmap.sh/ai-data-scientist)です：

![roadmap.sh_ai-data-scientist (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1044781/80c2fae0-02a8-1c0e-1703-78adc6ab20e4.png)



統計学入門から始まり、MLOpsまでデータサイエンスのある程度をカバーできるロードマップになっています。（ここにビジネス力・問題解決力などが含まれればもっといいロードマップになりそうです。）

ちなみに、最後の項目の修了証がこちらです：



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1044781/03587f39-a6bf-73a1-6a3f-35004569116c.png)





さて、このようにしてデータサイエンスのロードマップを完走したわけですが、この経験と数年の実務経験を踏まえて、



個人的にデータサイエンスのフィールドやツールなどを言語ベースで語ってみようと思います。




データサイエンスの大まかな仕事内容と、それに関するツールを自分的に図解したものがこちらです：
![図解.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1044781/771cea28-cf40-85ee-ab64-52d7165667d1.jpeg)



世界的に有名なデータサイエンス講師の[Noah Gift](https://noahgift.com/)さんの図を少し調整しています。


データのクオリティとビジネスか機械学習寄りかの2軸で表しています。





ビジネス領域に今回の主役のRが分布しています。




データ分析の始めのステップ、「データの概要を掴む(EDA)」にとても最適な言語です。


レガシーな統計分析、因果推論、効果測定なども小回りのきくRが使いやすいです。


実務での報告や発表はRStudioのRmdリポートのまましていた時もありましたが、


パワーポイントやGoogleスライドなどビジネス寄りの人たちの好む/使えるツールでプレゼンすることも大事です。


簡単な可視化はcsvデータを挿入し、パワポ内でグラフなどを作ってあげると、データも一緒に配れるので便利です。




ダッシュボードはリアルタイム性が重要になってくるのでシステムにそのままインプリできるPythonが使いやすいです。


ちなみにShinyとは、綺麗なインタラクティブWebアプリケーションが作れる元R言語のライブラリです。ちょっと前にPythonもサポートし始めているので、試してみるとダッシュボードの質がもっとよくなるかもしれません。



Tableau, Power BI、そしてGoogle Analyticsはこの辺りだと定番ですね。



R&D分野はPython一択でしょう。豊富なライブラリと巨大なコミュニティが後押ししてくれます。




さて、いよいよAI/ML領域になってきます。



今年Pythonが急激に人気になった要因です。


こちらもTensorflowをはじめ豊富なライブラリと巨大なコミュニティがPythonを後押ししてくれます。



ただ、それだけではつまらないので、Rustの紹介をします。



現在MLOpsやDevOps界隈ではRustがメキメキと力をつけて来ています。




先ほど名前が出たNoah Giftさんが教えるMLOpsの授業でも、PythonよりRustが強く推薦されていました。



Rustとは高速でメモリ効率が高く、安全性を重視したシステムプログラミング言語で、その可読性にも長けています。




現に冒頭で紹介したGitHubの記事でもRustが特に伸びて来ているという記載もありました。



クラウドリソースを使ってMLOpsを実現する際はRustを使うと、素早く安全にデータ処理が実現できます。



まだ使った事のないデータサイエンティストの方は機会があったら使ってみてもいいかもしれません！
[備忘録]　Youtubeを見ながらUnityの勉強　8日目

# はじめに
　こんにちは，Umamusume22です。しばらくunityの勉強をサボっていました。業務でUnityを使っているのですがUnityが分からないので自主的に勉強を始めました。とりあえず、Youtubeを見ながらUnityの勉強を行います。学んだことはここの記事にアウトプットしていきます。
 今日は以下の動画を見てUnityの勉強を行いました

 https://youtu.be/APchcG-n86o?si=V4M2n2r48SxfBjIp

 https://youtu.be/0jis419_Nw8?si=zbnDeTBnL0khTzfn

 
 # 備忘録
 -  GetComponentはコンポーネントを捕まえている
 -  .はその機能をつけている　(例：        playRb.AddForce(Vector3.forward);)
 -  GetKeyDownはキーボードのボタンを押すときに使う

# 実際に書いたソースコード
``` Player.cs
using UnityEngine;

public class Player : MonoBehaviour
{
    public int power;
    // RigidBodyを入れるための箱 PlayRbというのを作成
    Rigidbody playerRb;


    // Start is called once before the first execution of Update after the MonoBehaviour is created
    void Start()
    {
        // PlayerRbという箱の中にコンポーネントを捕まえてきて入れます。その時のコンポーネントはRigidBoy
        playerRb = GetComponent<Rigidbody>();

        // playerRbの機能を使って力を加える　向きは前
        // playerRb.AddForce(Vector3.forward * power);

    }

    // Update is called once per frame
    void Update()
    {
        // 十字キーで動かす  右矢印キーが押されたら
        if(Input.GetKey(KeyCode.RightArrow)){

            // 右向きの力を加える
            playerRb.AddForce(Vector3.right);


        }

        // 十字キーで動かす  左矢印キーが押されたら
        if(Input.GetKey(KeyCode.LeftArrow)){

            // 左向きの力を加える
            playerRb.AddForce(Vector3.left);


        }

        // 十字キーで動かす  前矢印キーが押されたら
        if(Input.GetKey(KeyCode.UpArrow)){

            // 前向きの力を加える
            playerRb.AddForce(Vector3.forward);


        }

        // 十字キーで動かす  下矢印キーが押されたら
        if(Input.GetKey(KeyCode.DownArrow)){

            // 下向きの力を加える
            playerRb.AddForce(Vector3.back);


        }

        // スペースキーが押されたら
        if(Input.GetKeyDown(KeyCode.Space)){

            // 前向きの力を加える
            playerRb.AddForce(Vector3.up * power);


        }
    }
}



```


# 最後に
　勉強した内容を備忘録にしました。備忘録の内容が短くてすみません。Rigidbodyという重力の計算を行う機能を使いました。

 

ここまで記事を読んでいただきありがとうございました！

※ウマ娘の声をフーリエ変換した記事や水栓の開閉判定をLineに通知する記事も書いています．suzuが私です．興味がある方はぜひご覧ください！
https://vigne-cla.com/31-1/#toc5

※noteもやっています．
https://note.com/madoka235/n/nbba2153326e1

ぜひフォローよろしくお願いします!
報連相のための毎日特訓

先日、内定式に行った際、入社までに勉強しておくことを改めて質問しました。
想定では、技術的なことを事前に勉強しておくように言われると思っていたのですが、日本語の勉強をしておくように言われました。理由を聞くと、報連相が新人には案外難しく、ポエムのような文章になってしまうことが多々あるらしいです。つまり報連相がきちんとできるように事前に勉強しておくことは重要だとか。
私は、正直あまり勉強する気が起きなかったのですが、今までの経験上、自分より年上の方の意見は大事にしておく方が良いと考え直し、Qiitaで毎日学んだことをアウトプットする習慣を付けることにしました。継続力も身につけられて、日々どういう成長を遂げたのか記録できるこのアイデアは一石二鳥ならぬ一石n鳥なのです！
現在は、「Webを支える技術」という本を読んでいます。なにか具体的な成果物を作る前の土台作りは非情報系出身の自分には必要だと思い、読んでいます。12月中にこれを読み切り、簡単にフロントの勉強をこなし、一月からはフレームワークのインプットに取り掛かることが理想です。
明日からも頑張ろう自分！
Salesforce ApexコードがApexトリガーから呼び出されているかどうかを知りたい：Trigger.isExecuting

SalesforceのTrigger.isExecutingは、トリガーが実行中であるときに`true`となるコンテキスト変数です。詳しくは[こちら](https://developer.salesforce.com/docs/atlas.ja-jp.apexcode.meta/apexcode/apex_triggers_context_variables.htm)を参照してください。
この変数を使用すると、コードがトリガー内で実行されていることを確認できます。これは、次のような複数のエントリポイントからロジックが呼び出される場合に特に便利です：

- トリガー
- Lightning Web Components
- Visualforceページおよびコンポーネント
- APEX RESTおよびSOAP Webサービス
- バッチApex
- スケジュールされたApex
- Queueable Apex
- Futureメソッド
- Invocableメソッド
- Apex匿名実行
- カスタムREST/SOAPサービス

### Trigger.isExecutingの使用方法
Trigger.isExecutingが役立ついくつかのシナリオを以下に示します：

1. **トリガー実行コンテキストの確認**  
   コードがトリガー内で実行されているかどうかを確認し、特定のロジックを条件付きで実行する場合に使用します。

   ```apex
   if (Trigger.isExecuting) {
       // トリガー実行に特有のコード
   }
   ```

2. **無限ループの回避**  
   トリガーがメソッドを呼び出してレコードを変更すると、再度トリガーが発火する可能性があります。Trigger.isExecutingを使用して、コードがトリガーによって呼び出されているかどうかを確認し、無限ループを防止します。

   ```apex
   public class AccountHelper {
       public static void updateAccount(Account acc) {
           if (!Trigger.isExecuting) {
               // 無限ループを防いでコードを更新する
               update acc;
           }
       }
   }
   ```

### 注意ポイント
- **トリガー内では常に`true`である**  
  トリガー内では、Trigger.isExecutingは常に`true`です。そのため、ほとんどの場合、`if (Trigger.isExecuting == true)`のようなコードは不要です。

- **ループ条件としては使用しない**  
  Trigger.isExecutingをwhileループで使用するのは間違いです。これは、実行中に変わることはなく、トリガー内では常に`true`であり続けます。

  ❌ 間違った使用例：
  ```apex
  while (Trigger.isExecuting) {     // 無限ループ - これでは停止しない }
  ```

### まとめ
今回はTrigger.isExecutingについて解説しました。ご意見や間違いがありましたら、コメントでご指摘いただけると幸いです。

### 参照
https://developer.salesforce.com/docs/atlas.ja-jp.apexcode.meta/apexcode/apex_triggers_context_variables.htm
テストの性能について

##
例えば、「この hotfix をリグレッションテストして」と言われたとします。でも、ちょっと待ってください。そのホットフィックスは、データを広範囲で破壊する可能性のある修正だとしたら、はたしてリグレッションテストだけでテストは完了するでしょうか。ホットフィックスなので、急いで直したいものではあるのですが、影響の大きなもののテストを、リグレッションテストだけで終わらせるのは、危険が大きいでしょう。

## テストの性能とは
ここで、もしリグレッションテストのカバレッジが、十分に網羅性の高い物なら良いのかもしれません。ですが、網羅性の高いリグレッションはメンテナンスコストが高く、網羅的なものよりは、よく使う遷移や重要な操作などの、リスクを避けるような作りになっているかもしれません。リグレッションテストだけで、テスト充分性が担保できているかは、ポリシーとリソース次第です。

こういった、手持ちのリグレッションテストセット（テストスイート）の、内容によっては、テストが足りず、さらに事故になる可能性があるかどうかを判断して、進める必要があります。この判断基準の一つになるのが、テストの性能です。

## テストのポリシーとは
例えば、現在使っているリグレッションテストが、
- 最低限のユーザーが良く使う操作だけで構成されている
- 分岐のオプションをすべて網羅している

の、いずれかによって、リグレッションテストの性能と呼べるものは変わってきます。前者なら、「ユーザーのビジネスが止まらない程度の最低限の保証ができる」性能のテストといえますし、後者なら、「オプションを一通り網羅しつつも、メンテナンスがきっちりできていないと網羅性の保証がしかねる」性能のテスト、と言えるでしょう。
この、テストを行った後にどういう品質が担保できるか、ということを説明できるかどうかがポイントになります。

## 品質のコントロールがしやすくなる

![TestStrategy2023.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156898/c4c90c99-c326-f585-2626-f01827976079.png)



テストのポリシーが説明できるということは、それに合致したテストの目的も説明できるようになります。そして、テストの性能を組み合わせてテストセットを構成すれば、テスト全体を説明できるようになります。

このマップは、それぞれ目的をもったテスト群で構成されています。これらで、クライテリアをコントロールしています。この、テストの性能が調整できるというのは、よくいわれる、説明責任を果たせる、ということでもあります。

## つまり、テストの性能とは
こんな風に、一口にテスト、といっても、テストケースの意図によって、その期待できる保証内容は全然変わります。これを私は、テストの性能（保証できる内容）、と呼んでいます。
VScodeで文字を上書きする方法


# VScodeで文字を上書きする方法

[Visual Studio Code 1.96](https://code.visualstudio.com/updates/v1_96)から，文字を上書きする機能が追加されました．

機能は以下の公式の動画を見てもらうとわかりやすいです．

![Overtype-mode.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670528/d98c3449-c5d7-8edd-1351-643004f8b5aa.gif)

## 使い方

Windowsユーザーであれば，`Insert`キーを押すことで，上書きモードに切り替えることができます．

Macユーザーであれば，`option` + `command` + `o`を押すことで，上書きモードに切り替えることができます．

もしくは，`command` + `shift` + `p`でコマンドパレットを開き，`Overtype`(日本語では「上書き」)と入力することで，上書きモードに切り替えることができます．

## カーソルのタイプを変更する

カーソルのタイプを変更することもできます．

設定の[@id:editor.overtypeCursorStyle](vscode://settings/editor.overtypeCursorStyle)で変更してみてください．

種類は以下の通りです．いずれも，aをovertypeする位置にカーソルを置いています．

1. line

![line](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670528/000a63b9-ff7c-e434-23e0-e44818257d64.png)

2. block[デフォルト]

![block](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670528/ea8d21c1-4dea-21e2-2f6e-0a897949d37b.png)

3. underline

![underline](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670528/1a1d0b23-4999-78dc-b405-87bd7b40cfa6.png)

4. line-thin

![line-thin](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670528/5b9d2bdb-a7d6-99e7-86f9-398e86f69877.png)

5. block-outline

![block-outline](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670528/46b6dced-3806-378b-3076-deabbdf44bad.png)

6. underline-thin

![underline-thin](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670528/5afa18cf-347e-bb38-f38d-9d9ee5fe00fd.png)


## まとめ

最近はvscodeのアップデートが嬉しいものが多くていいですね．

今後のアップデートにも期待です！
UKでの存在チェックSQL、LIMIT句は必要か？

## 背景
プロジェクト内で、レコードの存在チェックをする際
以下のようにWHERE句でUKまたはPKが指定されている場合、末尾にLIMIT句を設けるべきか否かが話題に上がった。

```MySQL:指定ユーザーの存在チェック
SELECT 
    1
FROM 
    users
WHERE 
    user_id = #{userId}
LIMIT
    1
```

> 意見①：UKだしLIMIT句は不要でいいんじゃない？
意見②：他の存在チェックのSQLで、条件にUKを使用していないものもある。統一感を出すためにも、UKでもLIMIT句つける方針が良いのでは？
意見③：つけたところでパフォーマンス向上するんですかね？


## 結論
<strong>LIMIT句つけてもパフォーマンスはほぼ変化しない。


## 理由
SQLは、以下の順序で実行されます。
<ol>
<li>from：対象テーブルの指定
<li>join：結合するテーブルの指定
<li>where：条件絞り込み
<li>group by：グループ化
<li>sum,avgなど：集合関数
<li>having：グループ化後の絞り込み
<li>select, distinct：抽出項目の指定
<li>order by：並べ替え
<li>limit：取得件数の指定
</ol>

上記の通り、limitで件数を絞るのは最後になるため、前述のUKを条件に指定した存在チェックのSQLのパフォーマンスの改善という意味では、あまり意味を成さないことがわかりました。

## 最終結論
上記の調査をもとに、最終的にうちのチームでは、なくても良いが統一感を出しましょう。ということになり、基本的に存在チェックはLIMIT句を設ける運びとなりました。

---
以上
[Rails]関連レコードの一致条件による対象レコードの検索

# はじめに

おはこんばんにちは。お疲れ様です。

今回は、多対多関係にあるレコードで
**紐づいている関連先レコードの情報で条件判定を行い、一致した関連元レコードを取得する**
といったことを行いましたので備忘録として残しておこうと思います。

## 環境

||version|
|---|---|
|Ruby|3.0.3|
|Rails|6.1.4|

# 前提

以下の関係性をもつテーブルがあるとします。

![スクリーンショット 2024-12-25 182922.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193405/77a80265-78be-5eff-4a92-398bf33701ab.png)

題材として大学を想定します。
User(学生)テーブルとLecture(講義)テーブルがあり、中間テーブルとしてUserLectureテーブルがあるとします。

# 要件

今回行いたいのは、
特定の複数の講義をすべて受講している、登録が新しい学生を取得したいと思います。

講義は、英語、ドイツ語、フランス語、イタリア語とします。

要するに、`上の4つの言語に関する講義をすべて受講している入学して間もない大学生`を探したいと思います。

# 結論

以下のように実装を行いました。

```model.rb
# lecture_ids = Lecture
#  .where(name: ["英語", "ドイツ語", "フランス語", "イタリア語",])
#  .pluck(:id)

# 対象のlectureを受講しているuserを絞り込み取得する
def find_user_by_taking_all_lectures(lecture_ids)
  # 対象のlectureを受講しているuserを絞り込み
  users = User.order(created_at: :DESC)
    .joins(:lectures)
    .where(lectures: {id: lecture_ids})

  # なければ早期終了
  return if users.blank?

  # lectureが1件しかなければ上記の検索処理のみで取得可能なため早期終了
  return users.first if lecture_ids.count == 1

  # 指定されたlecture全てを受講しているユーザーIDを取得
  target_user_ids = users.pluck(:id)
    .group_by(&:itself)
    .transform_values(&:count)
    .select{|_, count| count == lectures_count}
    .keys  

  # 最初のユーザーを取得して返す
  return users.find_by(id: target_user_ids.first)
end
```

# 解説

流れは以下のようになっています。

1. Userを降順で並び替えて、`lecture_ids`で絞り込む
2. `lecture_ids`の数でフィルターする
3. フィルターした中から最初の値でUser検索

## 1. Userを並び替えて絞り込み

以下の部分ですね。

```rb
users = User.order(created_at: :DESC)
  .joins(:lectures)
  .where(lectures: {id: lecture_ids})
```

SQL的には以下のようになりますね。

```SQL
SELECT "users".* FROM "users" 
INNER JOIN "user_lectures" 
    ON "user_lectures"."user_id" = "users"."id" 
INNER JOIN "lectures" 
    ON "lectures"."id" = "user_lectures"."lecture_id" 
WHERE "lectures"."id" IN (1, 2, 3, 4) -- メソッドの引数として渡された指定されたlecture id
ORDER BY users.created_at DESC
```
例えば、IDが「3」のuserは4つの講義を受けているとします。
次に、IDが「2」のuserは4つのうち、3つの講義を受けていて、
IDが「1」のuserは4つのうち、2つだけ講義を受けているとします。

この場合、出力結果をIDだけにすると、以下のようになります。

```rb
# 1の結果
[3, 3, 3, 3, 2, 2, 2, 1, 1]
```

IDが「3」のuserは、4つすべてを受講しているため4つ出力されます。
同様に、IDが「2」のuserは3つ、
IDが「1」のuserは2つ出力されます。

これをうまくやろうというわけです。

## 2.講義数でフィルターする

以下の部分ですね。

```rb
target_user_ids = users.pluck(:id)
  .group_by(&:itself)
  .transform_values(&:count)
  .select{|_, count| count == lectures_count}
  .keys  
```

出力結果は以下のようになります。

```rb
# 2の結果
[3]
```

過程としては、まず重複しているIDをグループ化してその数を数えます。

```rb
# users.pluck(:id)
#  .group_by(&:itself)
#  .transform_values(&:count)

# ID=>count
{3=>4, 2=>3, 1=>2}
```

今回は、指定した講義すべて（4つ）を受講しているUserが欲しい。
つまり、4回出力されている値を取得すればよいということになります。

```rb
# .select{|_, count| count == lectures_count}
# lectures_countは4
{3=>4}

# .keys  
[3]
```

よって、「3」という値が取得できます。

## 3.フィルターした中から最初の値でUser検索

以下の部分ですが、さくっと検索して終わりです。

```rb
# 2の結果より、target_user_ids = [3]
# 必ず1つの値とは限らないので、
# すでにorderされている2の結果から最初の値を使用
users.find_by(id: target_user_ids.first)
```

# 最後に

やっていることは単純ですが、はじめに実装するときは悩みました。

また、パフォーマンスも担保しつつということで、記述した通りになりましたが
よりよい方法があれば教えていただきたいです。

なんかの役に立つことを願って、また次の記事で会いましょう
Migration Evaluator Collectorがどうしても覚えられない人向け

# **Migration Evaluator Collectorのポイント**
1. **目的**
   - オンプレミス環境を分析し、AWS移行のコストや最適な設計を評価するためのデータ収集ツール
   - サーバースペックや使用状況の情報を集める

2. **仕組み**
   - Collectorがデータを収集し、Migration Evaluatorにアップロード
   - AWSから移行プランが提供される

3. **セットアップ**
   - サポートされているOSでCollectorを実行
   - (例) Windows/Linux環境
   - 結果をAWSのMigration Evaluatorサービスに送信

4. **特徴**
   - セキュアで簡単、数日で分析結果を確認可能
   - 手間がかからないため移行計画の初期段階で役立つ。

---

## **語呂合わせ**

**「評価するマイコレクター」**
- 「評価」= Migration Evaluator
- 「マイ」= Migrationの頭文字
- 「コレクター」= Collector

**「移行の評価はCollectorにお任せ」**
  - Collectorが情報を集め、Evaluatorが分析

---

## **記憶のためのステップ例**
1. **Migration Evaluatorとは何かを理解する**  
   → オンプレ環境を評価しAWS移行をシミュレーションするサービス。

2. **Collectorの役割を覚える**  
   → データを収集しEvaluatorに渡す。

3. **セットアップ手順を簡略化する**
   - Collectorをインストール
   - データ収集
   - AWSにアップロード

## フロー図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2746730/aeb4b3f6-0ecd-b98a-c858-358cb76c17d2.png)
24/12/25 読書記録 ~土台からしっかり学ぶソフトウェアテストのセオリー~

# 書籍
[土台からしっかり学ぶソフトウェアテストのセオリー](https://amzn.asia/d/hvYdYEd)


# 第1章 ソフトウェアテストの目的

## 1-5 リグレッションテスト

ソフトウェアを変更した時の意図しない変更を確認するテスト。
「退行テスト」や「回帰テスト」と呼ぶ。
自動化がとても効果的。

課題と感じている内容だ。

## 1-7 ソフトウェアテストで気をつけること
JSTQB Foundation Level シラバスで「テストの7原則」というガイドラインで、ソフトウェアテストで注意すべき点が紹介されている。

### 原則1：テストは欠陥があることを示せるが、欠陥がないことを示せない
これは確かに。
テストが全てパスしたとしても、不具合が生じないソフトウェアである証明にはならない。

### 原則2：全数テストは不可能
こちらも当たり前ではある。
同値分割テスト、境界値テストで効率的にテストを行う内容が後述されていると予想

### 原則3：早期テストで時間とコストを節約
欠陥の発見が遅くなるほど、修正コストが大きくなる。
早く見つけるに越したことはない。

### 原則4：欠陥の偏在
ソフトウェアの欠陥は一部の機能に集中しがち。
これは確かにそうかも。
あと、機能が拡張され続け、機能に関わる処理が長く続いている時に生じやすい傾向にある。

### 原則5：殺虫剤のパラドックスにご用心
同じ殺虫剤を使い続けると、虫も耐性がつき、効果が低くなることの例え。
あまりイメージはできないかも

### 原則6：テストは状況次第
いつも同じようなテストを行えば良いわけではなく、開発体制で内容が変わることもある。

### 原則7：「バグゼロ」の落とし穴
仮に大規模なテストができたとしても、完璧で正しいソフトウェアになるとは限らない。
ステークホルダーの期待を満たしているか？も必要。
Flutter位置情報ライブラリの比較: Geolocator vs. Location

**Flutter位置情報ライブラリの比較: Geolocator vs. Location**
Flutterで利用される位置情報ライブラリ「Geolocator」と「Location」の特徴、違い、業務レベルでの活用シーンについて解説します。

---

**1. Geolocator**

**概要**
Geolocatorは、位置情報を取得するための高機能なライブラリです。現在地の取得、位置情報の継続的な更新、距離計算など、幅広い機能を提供します。

**主な特徴**
・プラットフォームサポート: iOS、Android、Web、macOS、Linux

・位置情報取得: 高精度な緯度・経度情報を取得可能

・リアルタイム更新: 位置情報のストリーミング更新に対応

・距離計算: 2点間の距離を簡単に計算する機能を提供

・権限管理: 位置情報の権限をリクエスト・確認する機能を内蔵

・バッテリー効率: 精度設定を調整してバッテリー消費を最適化

**メリット**
・シンプルなAPIで現在地取得やリアルタイムのストリーミング更新が可能

・サービスの初期化が不要で、必要なときに使用可能

・定期的なアップデートでメンテナンスがしっかり行われている

**デメリット**
・特にAndroidでのバックグラウンド追跡において、権限設定がやや複雑

・ジオフェンスのような高度な機能の実装には学習コストが必要

**活用例**
・配達アプリや物流管理システムなど、高精度で定期的な位置情報更新が必要な場合

・ユーザー間の距離計算を必要とするアプリ

---
**2. Location**

**概要**
Locationライブラリは、位置情報取得においてシンプルで使いやすいAPIを提供します。特にバックグラウンドでの位置追跡や権限管理が直感的に行える点が特徴です。

**主な特徴**
・プラットフォームサポート: iOS、Android

・前景・背景追跡: フォアグラウンドとバックグラウンドの両方で位置情報追跡が可能

・権限管理: ユーザー権限を直感的に操作できるツールを提供

・デバイス設定のアクセス: アプリ内でGPSを有効化する機能を搭載

・アクティビティ認識: ユーザーの移動タイプ（例: 歩行中、車移動中）を検出可能

**メリット**
・シンプルなセットアップで初心者でも使いやすい

・ネイティブなバックグラウンド追跡に対応

・ユーザーの位置情報設定をアプリから直接調整可能

**デメリット**
・プラットフォームサポートが限定的（Web、デスクトップ非対応）

・高度な計算や複雑なロジックにはやや不向き

**活用例**
・バックグラウンドでの位置追跡を必要とするアプリ（例: フィットネスアプリ、ランニングトラッカー）

・ユーザーが簡単にGPS設定を変更できるようなユーティリティアプリ

---

**3. 比較表**

| 特徴 | Geolocator | Location | 
|---------|---------|---------|
| プラットフォーム   | iOS, Android, Web, macOS,  | iOS, Android   | 
| リアルタイム追跡   | 対応   | 対応   | 
| 権限管理   | 標準機能   | より直感的な操作が可能   | 
| バックグラウンド追跡   | カスタマイズが必要   | ネイティブ対応   | 
| アクティビティ認識   | 非対応   | 対応   |
| 距離計算   | 標準機能  | 非対応   | 
| 学習コスト   | 高め   | 低め   | 
---

**4. 推奨選択基準**
**・Geolocator**
高精度な位置情報取得が必要で、幅広いプラットフォームで動作させたい場合に適しています。特に、物流や地図アプリなど、位置情報計算が求められるケースで有効です。

**・Location**
シンプルなバックグラウンド追跡やアクティビティ認識が必要な場合に適しています。フィットネスや移動追跡アプリなど、軽量な実装を求めるプロジェクトに向いています。

---
**注意事項**

業務で利用する際には、アプリの要件やサポートプラットフォームを考慮し、適切なライブラリを選択してください。また、位置情報に関する法規制（例: GDPRや個人情報保護法）にも十分配慮する必要があります。
DSPyの極意：LLMモデル性能のモジュール型最適化

## DSPyとは？
DSPyは、LLMをモジュール型の自己改善パイプラインとして扱うフレームワークです。主な構成要素は以下の3つです：

- Signatures（署名）: 入出力関係を定義するブループリント。
- Modules（モジュール）: タスクを効率的に処理するためのコンポーネント。
- Teleprompters（最適化ツール）: モジュールの性能を向上させるための最適化エンジン。

## DSPyの主な特徴
他のフレームワークと比較したDSPyの利点を見てみましょう。

1. 制御された生成
他フレームワーク（例: Guidance, LMQL）: テンプレートベースの生成を提供するが、手動設定が必要。
DSPy: テレプロンプターによる自動最適化で、一貫した結果を提供
2. スキーマ駆動型生成
他フレームワーク（例: Marvin, Instructor）: 定義済みスキーマを使用するが、柔軟性が低い。
DSPy: 自然言語署名で幅広いタスクをサポート
3. モジュール型プログラミング
他フレームワーク（例: LangChain）: プロトタイピングには便利だが、カスタマイズ性に欠ける。
DSPy: 高度な最適化戦略を提供し、複雑なパイプラインを構築可能
4. オープンエージェント
他フレームワーク（例: AutoGPT, MetaGPT）: 固定されたプロンプトに依存。
DSPy: 継続的な自己改善が可能なカスタマイズパイプラインを構築

## DSPyの主要コンポーネント
### 1. 署名
署名はタスクの入出力関係を自然言語で定義するブループリントです。

例:

```python
sig_1 = dspy.Signature("質問 -> 答え")
sig_2 = dspy.Signature("ドキュメント -> 要約")
sig_3 = dspy.Signature("質問, 文脈 -> 答え")
```

### 2. モジュール
モジュールは特定のタスクを処理するための組み込み機能を提供します。

モジュールの種類
- Predictモジュール: シンプルな入力と出力のマッピングを提供。
- ChainOfThought（CoT）モジュール: 複雑なタスクを段階的に処理。
- ProgramOfThought（PoT）モジュール: 抽象度の高いタスクを処理。

例: アクションアイテムの抽出

```python
class ExtractActionItems(dspy.Signature):
    """
    テキストからアクションアイテムを抽出し、Pythonリストとして返します。
    """
    Text = dspy.InputField(desc="テキスト")
    Extracted_action_items = dspy.OutputField(desc="アクションアイテムのリスト")
 
action_items_extractor = dspy.Predict(ExtractActionItems)
response = action_items_extractor(Text=Text)
```

### 3. 最適化ツール
DSPyのテレプロンプターは、モジュールの性能を継続的に改善する最適化エンジンです。

種類
- Few-Shot学習: ラベル付きデータから最適なプロンプトを生成。
- 指示最適化: 効率的な指示を生成し、最適化。
- ファインチューニング最適化: 小規模モデル向けに重みを調整。

例: Few-Shot最適化

```python
optimizer = dspy.teleprompt.BootstrapFewShot()
optimized_model = optimizer.compile(module, trainset=get_examples())
```

## DSPyを使ったユースケース：フィードバック要約の最適化
シナリオ
アプリのフィードバックを要約し、感情分析やアクションアイテムを抽出するタスクを想定。

### タスクの定義
```python
class FeedbackSummary(dspy.Signature):
    feedback_text = dspy.InputField()
    sentiment = dspy.OutputField()
    topics = dspy.OutputField()
    action_items = dspy.OutputField()
```

### モジュールの作成
```python
class SummarizeFeedback(dspy.Module):
    def __init__(self):
        super().__init__()
        self.summary = dspy.ChainOfThought(FeedbackSummary)

    def forward(self, feedback_text):
        return self.summary(feedback_text=feedback_text)
```

### トレーニングデータの追加
```python
def get_examples():
    return [
        dspy.Example(
            feedback_text="新機能は素晴らしいが、ドキュメントが不足している。",
            sentiment="ポジティブ",
            topics="新機能, ドキュメント",
            action_items="ドキュメントの改善"
        )
    ]
```

### 最適化の実施
```python
optimizer = dspy.teleprompt.BootstrapFewShot()
optimized_summarizer = optimizer.compile(SummarizeFeedback(), trainset=get_examples())
```

## 参考

https://dspy.ai/
【UE5】Font の Distance Field を試してみる

UE5.5 のリリースノートでフォントの距離フィールド（Distance Field）が紹介されていますが、具体的な使い方を紹介されているページが見当たらなかったので書いてみます。

先にざっくりまとめると、プロジェクト設定で有効化し、フォントフェイスの有効化フラグを立て、FontSignedDistance ノードを使ったマテリアルを作成し、TextBlock のフォントマテリアルに設定し、Material Is Stencil のチェックを入れたら適用できます。

詳しく説明してきます。

# 手順①　プロジェクト設定
プロジェクト設定の「エンジン - ユーザーインターフェイス」の「距離フィールドのフォントビジュアライゼーションを有効化」にチェックを入れる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3970621/99df0e8a-3c0b-abee-7908-e0d231a38ca6.png)

# 手順②　フォントの Distance Field を有効にする
フォントフェイスのアセットに対して Distance Field を設定する必要があるので、既に使っているフォントに対して使いたい場合は複製してください。
ここではエンジンの Robot フォントを複製してそれぞれの名前に _SDF をつけています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3970621/ac773408-0a87-9494-aaad-6cc1c27c2e6d.png)

各フォントフェイスを開き、Enable Distance Field Rendering にチェックを入れます。
チェックを入れると細かいパラメータが出てきますが、とりあえず試す分にはデフォルト値で良いでしょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3970621/35901de5-8c8d-4671-54dd-c7c9929918d3.png)

一通りフォントフェイスの設定が終わったら、忘れずフォントアセットが参照しているフォントフェイスを _SDF をつけたアセットに差し替えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3970621/cd004179-5811-f942-bf68-066474b59ea8.png)

# 手順③　フォントマテリアルを作成
マテリアルのアセットを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3970621/467ff07e-c2fc-0b2e-9aba-aba51125b464.png)

Material Domain は UserInterface、Blend Mode は Translucent にします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3970621/a14ba81b-fa75-a8f4-41d6-1b92165c4352.png)

FontSignedDistance ノードを配置します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3970621/cf64e5ae-815c-046d-dff7-6b0f7fbbfb6c.png)

ひとまず Contents Example を参考にこんな感じにしてみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3970621/b6681851-eac1-9dd5-b0b1-74f7851dbdab.png)

必要に応じてマテリアルインスタンスも作成しておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3970621/90173772-bf69-af1f-a7b5-ba88397b4570.png)

マテリアルインスタンスでパラメータをこんな感じにしました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3970621/ea3ce550-7fb6-9fbd-cf3e-03373a7d8126.png)


# 手順④　UMG で Text Block に設定

UMG のテキストブロックの詳細パネルで、手順②で作成したフォントと、手順③で作成したマテリアル（or マテリアルインスタンス）を設定して、Material Is Stencil にチェックを入れます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3970621/418cbde1-9b0e-dbc3-67c1-b64512e9b8d9.png)

これでマテリアルで設定した Glow が適用されます。
一度ここまで作っておけばあとは手順④だけで手軽に適用できます。

もしこのマテリアルで思った色がでない場合、別途 Color and Opacity 等で色を付けていないかチェックしてみてください。

# 後記

公式の Content Examples（機能別サンプル）の UI_UMG レベルの右奥のほうに Glow 以外にもいくつかサンプルがあるので、チェックしてみてください。

https://www.fab.com/listings/4d251261-d98c-48e2-baee-8f4e47c67091
LLMファインチューニング：基礎から実践までのA-to-Z

## LLMファインチューニングとは？
ファインチューニングは、事前学習済みのLLMのパラメータを調整し、特定のタスクに最適化するプロセスです。これは、既存の専門家に新しいスキルを教えることに似ています。たとえば、一般的なLLMを財務分析に特化させる場合、四半期ごとの収益報告やSEC提出書類、財務ニュース記事などのデータセットを用いてトレーニングを行います。これにより、モデルは財務要約の生成や傾向の特定、過去データに基づいた予測を高精度で行えるようになります。

## ファインチューニングの種類
LLMのファインチューニングには以下の5つの主要な手法があります。

### 1. 指示チューニング（Instruction Fine-Tuning）
特定の指示に従う能力を高める方法です。プロンプト形式のデータセットを用いてモデルをトレーニングします。

データ形式: JSON Lines（.jsonl）形式
プロンプト例:
```json
{
  "prompt": "質問: {question} 文脈: {context}",
  "completion": "{answer}"
}
```

### 2. 会話型チューニング（Chat Fine-Tuning）
対話型AIの性能向上を目的とした手法です。ユーザーとアシスタント間の対話データを活用します。

データ形式: .jsonl形式で、ユーザーとアシスタントの会話を格納。
```json
{
  "dialog": [
    {"content": "エンパイアステートビルの高さは？", "role": "user"},
    {"content": "443メートル（アンテナを含む）。", "role": "assistant"}
  ]
}
```

### 3. ドメイン適応型チューニング（Domain Adaptation Fine-Tuning）
特定の業界や分野に特化したデータセットでモデルを調整します。

データ形式: .txtや.jsonで業界特化型のテキストを提供。
例: AmazonのSEC提出書類を使用して、法務や財務分野向けのモデルをトレーニング。

### 4. 少数ショット学習（Few-Shot Learning）
ラベル付きデータが少ない場合に有効な手法です。少数の例をプロンプトとして提供し、モデルにタスクを理解させます。

利用例: 法的文書のスタイルを数例提供し、類似の文書を生成。
出力: データ量が少ない状況でも高性能なモデル。

### 5. 転移学習（Transfer Learning）
広範なデータセットで得た知識を、関連する特定タスクに応用する手法です。

実装例: Sentiment分類に特化したLLaMA 8Bモデルを用いた感情分析タスク。
出力: 汎用性を持ちながら特定タスクにも対応可能なモデル。

## ベストプラクティス
ファインチューニングの成功には以下のポイントが重要です：

1. データの質と量
高品質かつ関連性の高いデータセットを準備します。曖昧なデータを避け、タスクに合った多様な例を含めましょう。

2. ハイパーパラメータの調整
学習率やバッチサイズ、エポック数を最適化します。異なる設定を試すことで最適な結果を得られます。

3. 過学習の防止
トレーニングエポックを制限し、バリデーションセットでモデル性能を監視します。同じパターンを繰り返す応答が出る場合は過学習の兆候です。

4. アンダーフィットへの対応
タスクの学習が不十分な場合は、データセットを増やすか、トレーニング時間を延長します。

5. 記憶喪失の管理（Catastrophic Forgetting）
ファインチューニングによって元の知識が失われないよう、一般タスクの性能を定期的に評価します。

## 応用的なヒント
- レイヤー凍結: モデルの基礎知識を維持しながら、特定タスクに関連する層のみを調整。
- パラメータ効率型ファインチューニング（PEFT）: 小規模な新しい重みを追加し、トレーニングパラメータを削減。
LLMリトレーニング

## プロンプトとアノテーションの役割
プロンプトとアノテーションは、LLMをリトレーニングする際の鍵となる要素です：

### 1. プロンプト
モデルに応答を生成させる指示を提供します。たとえば、「特定の係数を持つ二次方程式を生成せよ」といった具体的なタスクを指示します。

### 2. アノテーション
モデルの応答にラベルを付け、間違いを訂正します。これにより、モデルは自身の誤りから学び、性能を向上させます。

## リトレーニングのステップ
LLMをリトレーニングする際の基本的なプロセスは以下の通りです。

### 1. プロンプトの提供
まず、モデルに適切なプロンプトを提供します。以下はその例です：

プロンプト例
「係数が2、3、5の二次方程式を生成してください。」

### 2. 応答のラベル付けと訂正
生成された応答を確認し、正確性に基づいてラベルを付け、不正解または曖昧な応答に対しては、正しい数学式とその解説を提供します。

### 3. モデルの性能向上
プロンプトとアノテーションのサイクルを繰り返すことで、モデルの精度を徐々に向上させます。

### 4．誤った応答の修正（アノテーション）
間違った応答を分析し、修正します。

### 5. リトレーニングの実行
十分な数のプロンプト、ラベル、修正データを収集した後、モデルを再トレーニングします。この際、次のような技術を活用します：

ハイパーパラメータの調整
学習率やエポック数を最適化します。

転移学習（Transfer Learning）
モデルの既存知識を活かし、新しいデータを統合します。

## 継続的学習
LLMは、トレーニングを繰り返すことでその性能を向上させます。しかし、一度で完了するものではありません。継続的な評価、フィードバック、改良が必要です。プロンプトとアノテーションを繰り返し試すことで、モデルの性能を維持し、新たな課題に対応できる柔軟性を持たせることが可能になります。
Pydantic の使い方5選

背景として、私事ですが私は今年プロダクト開発チームから離れて、半分データエンジニア・半分実験開発みたいな仕事をしています。この新しい仕事において、MLやデータ周りのエコシステムが強いPythonをメインに使っています。

本題に戻ると、今回は個人のPydanticモデルの使い方、あるいはPydanticモデルを基本要素にしたライブラリを紹介しようと思います。

Pydanticとは から始めたい方に [この記事](https://zenn.dev/yosemat/articles/dd69000307f468) をおすすめします。

## TypedDict・dataclassの代わりに

私自身は頭悪くてワーキングメモリが小さいため、コード補完やタイプ検査にすごく依存しています。

TypedDictはまだDictであるし、スペルミスや型ミスマッチをガードしてくれない。dataclassはkeyを保証してもvalueは見てくれない。

Pydantic modelにすれば、実行時のタイプ検査が付いてくる。

## JSONEncoder JSONDecoderの代わりに

前項の補足ですが、Pydanticモデルを定義すれば、JSONとのシリアライズ・ディシリアライズが自動で付いてきて、複数のPydanticモデルでクラスも自動でネスティングJSONとの相互変換が簡単似できます。

また datatimeのようなよく使うけどJSONにないクラスでも、JSONにシリアライズ・ディシリアライズするデフォルト設定が付いていて、自分で決めなくて良くなります。（ただし他の言語との相互利用がある場合、Pydanticで定義した非JSONフィールドがどうやって解釈するがを確認したほうがいいです）

## Relational DB 操作に: SQLModel

[SQLModel](https://sqlmodel.tiangolo.com/) はsqlalchemy ベースのORM ライブラリです。

モデルをPydantic風に定義すれば、DBローインスタンスをデータクラス感覚で利用できて、。SQLAlchemyベースの他のツール（例えばマイグレーション生成・管理の[alembic](https://alembic.sqlalchemy.org/en/latest/) ) は依然利用できます。

ただし下のsqlalchemyをうまく隠しきれたとは言えなく、sqlalchemyのローレベルAPIをしばしば使わないといけない。代用品というより、タイプ検査を強化した不完全なwrapper と言えるでしょう。

## ElasticSearch 操作に: esorm

[esorm](https://esorm.readthedocs.io/en/latest/) はPydanticベースのElasticSearch ORMです。

ElasticSearchのより細かなデータ型にPythonのタイプを用意していて、これら使えば Index Mappingが（デフォルト設定で満足すれば）一発でできちゃいます。もちろんESに書き込むもの、ESから読み込んだものが自動でPydanticの検査に通過することで型検査の恩恵を受けられます。

## JSONスキーマの生成に

JSON自体はAPI用のシリアライズフォマットとして広く使われていて、ただし言語を跨ぐ限定・検査をできる仕組みというと、個人調査によるとJSON Schema以外サポートがいいものがほぼないです。

PydanticはJSON schemaの生成機能を内蔵していて、JSONEncoderのときのようにネストモデルでも定義すれば、[model_json_schema](https://docs.pydantic.dev/latest/concepts/json_schema/) で一発でJSON schemaができちゃいます。これを活用すれば、他のシステムにデータかインタフェースを提供する場合はよりセーフにできるでしょう。

私自身は今年LLMの応用を色々探索していて、OpenAIを始めLLMプロバイダはモデルレスポンスのフォマットを限定する場合、限定方法はほとんどJSON schemaになります。

<!--

## おまけ: 他のスキーマありフォマットからのCode生成に
 
Parquetのようなデータ交換フォマットにスキーマ、これらを

-->
Windows11のWSL 2のインストールメモ

参考：

https://qiita.com/sakue_103/items/eb3174ffbd410acdbd6a

上記記事を参考に、windows11上に機械学習の環境構築をしました。

コントロールパネル->プログラム->Windowsの機能の有効化または無効化から、Linux用Windowsサブシステムにチェックを入れ、再起動します。

WSLにUbuntuをインストールします。

Ubuntu22.04のインストール
```bash
> wsl --install -d Ubuntu-22.04
```

Ubuntuを立ち上げたところ、以下のようなエラーが出ました。

```bash
Installing, this may take a few minutes...
WslRegisterDistribution failed with error: 0x800701bc
Error: 0x800701bc WSL 2 ???????????? ??????????????????????? https://aka.ms/wsl2kernel ?????????

Press any key to continue...
```

以下のコマンドでWSL を再インストールしたら解決しました。
```
> wsl --update
```
MeePet に mosquitto をインストールする

## 
以前、 Node-Red 単体でも MQTT Broker が使えることを確認したが、その前に行った mosquitto のインストールについても記事化しておく。 
Aedes MQTT broker は MQTT V5 で接続できなかったが、 mosquitto だと MQTT V5 で接続可能なため、用途によっては mosquitto の方が適しているかもしれない。

## mosquitto のインストール
公式サイトには Linux でのインストールに snap や Ubuntu レポジトリを使うよう書いてある。

https://mosquitto.org/download/

Termux も pkg(apt) は使えるので、 `pkg install mosquitto` をしたところ、あっさりインストールできた。

ただし、そのままでは自機でしか使えないため、他の PC ・機器が接続できるよう設定を変更する必要がある。

https://qiita.com/ekzemplaro/items/95c31c684a2faef656d1

```bash: /data/data/com.termux/files/usr/etc/mosquitto/mosquitto.conf
listener 1883
allow_anonymous true
```
この2行を探し、コメントアウトを外してオプションを書き換え・書き足す。

さらに、 mosquitto.conf を読み込ませるため、 `-c` オプションを付けて起動する必要があるという。

https://yasurok2.wordpress.com/2021/08/20/making-termux-installation-mqtt-ready/

前後でコンソール出力を比較してみると
![mosquitto1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3943774/478f3996-d908-be18-c054-c7c0c2e8a44b.png)
![mosquitto2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3943774/4854771e-7891-5da0-0218-5e7721a0a8b4.png)

同一 LAN 使用を前提として `allow_anonymous` を `true` に設定しているため、 subscribe 側の設定はサーバーIPアドレスとトピックだけでよい。
Node-Red で Publish した情報が MQTTX と MyMQTT で受信できることを確認した。
Meta-LLaMA 3.1 8BモデルをUnslothでText-to-SQLに適応

## Meta LLaMA 3.1 8Bモデルとは？
Metaが開発したLLaMA 3.1 8Bは、80億パラメータを持つ高性能な言語モデルです。このモデルは、計算効率と性能のバランスが取れており、自然言語処理（NLP）の幅広いタスクに対応可能です。特に、Text-to-SQLタスクでは、自然言語入力から正確なSQLクエリを生成する能力を発揮します。

## Unslothライブラリとは？
Unslothは、LLMの効率的なファインチューニングをサポートするライブラリです。特に、量子化されたモデルを提供し、計算リソースが限られた環境でも大規模モデルを適応させることができます。

## Text-to-SQLタスクへの適応
### モデルの初期化
まず、Unslothライブラリを使用して、事前学習済みのLLaMA 3.1 8Bモデルを初期化します。

```python
from unsloth import FastLanguageModel

max_seq_length = 2048  # シーケンス長
load_in_4bit = True    # 4bit量子化でメモリ削減

model, tokenizer = FastLanguageModel.from_pretrained(
    model_name="unsloth/Meta-Llama-3.1-8B-bnb-4bit",
    max_seq_length=max_seq_length,
    load_in_4bit=load_in_4bit,
)
```

### パラメータ効率化ファインチューニング（PEFT）
次に、PEFT（Parameter-Efficient Fine-Tuning）を使用してモデルを調整します。LoRA（Low-Rank Adaptation）を適用することで、効率的にモデルを適応させます。

```python
model = FastLanguageModel.get_peft_model(
    model,
    r=16,  # 低ランクの次元数
    target_modules=["..."],  # 調整対象のモジュール
    lora_alpha=16,
    lora_dropout=0,
    bias="none",
)
```
3. データセットの準備
Text-to-SQLタスク用にカスタムデータセットを準備します。

### データ生成
ChatGPTや既存のデータセットを利用して、質問（question）、文脈（context）、SQLクエリ（sql_query）の組み合わせを作成します。

### データセットのフォーマット
定義したプロンプトテンプレートを用いてデータをフォーマットします。

```python
sql_prompt = """Below is input question that user ask, context is given to help user's question, generate SQL response for user's question.

### Input:
{}

### Context:
{}

### SQL Response:
{}"""

def formatting_prompts_func(examples):
    instructions = examples["context"]
    inputs = examples["question"]
    outputs = examples["sql_query"]
    texts = []
    for instruction, input, output in zip(instructions, inputs, outputs):
        text = sql_prompt.format(instruction, input, output) + "<EOS>"
        texts.append(text)
    return {"text": texts}
データセットのロード
CSVやExcelファイル形式のデータをHugging Face形式に変換します。

```python
from datasets import load_dataset, Dataset

df = pd.read_excel('fine-tuning-dataset_latest.xlsx')
dataset = Dataset.from_pandas(df)
train_test_split = dataset.train_test_split(test_size=0.2)
train_dataset = train_test_split['train']
validation_dataset = train_test_split['test']
dataset = dataset.map(formatting_prompts_func, batched=True)
```

### トレーニング設定
以下のようにトレーニング設定を定義します。

```python
from trl import SFTTrainer
from transformers import TrainingArguments

trainer = SFTTrainer(
    model=model,
    tokenizer=tokenizer,
    train_dataset=dataset,
    dataset_text_field="text",
    max_seq_length=max_seq_length,
    args=TrainingArguments(
        per_device_train_batch_size=2,
        gradient_accumulation_steps=4,
        warmup_steps=5,
        num_train_epochs=1,
        learning_rate=2e-4,
        logging_steps=1,
        output_dir="outputs",
    ),
)
```
###  モデルのトレーニングと保存
モデルをトレーニングし、ファインチューニング済みモデルを保存します。

```python
trainer.train()
trainer.model.save_pretrained("fine_tuned_model")
tokenizer.save_pretrained("fine_tuned_model")
print("Training complete.")
```
LoRA: LLMを効率的にファインチューニングする技術

## ファインチューニングの課題
LLMのファインチューニングには、以下のような2つの課題があります：

1. 計算コストの増加
全パラメータを微調整するには膨大な計算リソースが必要です。一部の研究では、追加の層を導入し、それ以外のパラメータを固定してトレーニングを行う手法が検討されました。しかし、この方法は計算の並列処理を阻害し、推論速度が低下します。

2. 知識のトレードオフ
既存のモデルが持つ知識を保持しつつ、新しいタスク用の情報を追加するのは難しい課題です。直接パラメータを調整すると、元の性能を損なうリスクがあります。

## LoRAの実装とアーキテクチャ
LoRAの実装はシンプルですが、非常に効率的です。

実装手順
行列の初期化

A：ランダムなガウス分布で初期化
B：ゼロ行列で初期化
適用範囲の選定
LoRAは、特にアテンションメカニズムのクエリ（Query）、キー（Key）、バリュー（Value）行列に適用されます。これにより、効率性と性能のバランスを実現します。

低ランクパラメータの調整
GPT-3モデルでは、行列のランクを4に設定することで、VRAM消費量を350GBからわずか35MBに削減。

## パフォーマンス評価と結果
他手法との比較
LoRAの性能を他のファインチューニング手法（PreEmbedやAdapter）と比較した結果、LoRAは少ないパラメータで優れた結果を示しました。特にGPT-3のような大規模モデルにおいて、その優位性が顕著です。

- 少数パラメータでの高精度
LoRAはわずか470万パラメータの調整でも、競合手法を上回る精度を達成しました。

- 大規模モデルへの適用
モデルサイズが大きいほど、LoRAの効率性が顕著に現れます。たとえば、RoBERTaのような比較的小規模なモデルでは効果が限定的でしたが、GPT-3ではLoRAの効果が最大化されました。
個人学習メモ useEffectの無限ループ解決

# はじめに
　独学でプログラミングを勉強しながら学んだことについて記録したと考えています。もし内容に誤りや改善点があれば、ご指摘いただけると幸いです。:pray:

# アプリの概要 
　現在作っているものは、「達成したい目標（goal）、目標を達成するための計画（plan）、さらに計画を分解して小さしたタスク（task）に分解して効率的に目標を達成、管理できるアプリ」になります。

# 問題
 　問題になった部分はタスクの完了値を(isCompleted)更新すると、無限ループのエラーになったのが問題でした。
```
const TaskList: React.FC = () => {
  const { tasks } = useAppSelector((state) => state.task);
  const { selectedPlan } = useAppSelector((state) => state.plan);
  const dispatch = useAppDispatch();
  const [editingTaskId, setEditingTaskId] = useState<string | null>(null);

  useEffect(() => {
    if (selectedPlan) {
      dispatch(taskList(selectedPlan._id));
    }
  }, [selectedPlan,tasks]);

  const handleStatusClick = (task: ITask) => {
    const nextStatus = !task.isCompleted;

    const updatedCompleted = { ...task, isCompleted: nextStatus };
    dispatch(
      updateTask({
        taskId: task._id,
        planId: task.plan_id,
        taskData: updatedCompleted,
      })
    )
  };
```

### 無限ループの流れ　
- selectedPlanがある場合、計画(plan)を選択した場合`dispatch(taskList(selectedPlan._id))`が実行されtasksの状態が更新されます。
- tasksがuseEffectの依存配列に含まれているため、tasksが更新されることでuseEffectが再実行されます。
- 再び`dispatch(taskList(selectedPlan._id))`が実行され、tasksが更新される流れになっています。

# 解決策
```
const TaskList: React.FC = () => {
  const { tasks } = useAppSelector((state) => state.task);
  const { selectedPlan } = useAppSelector((state) => state.plan);
  const dispatch = useAppDispatch();
  const [editingTaskId, setEditingTaskId] = useState<string | null>(null);

  useEffect(() => {
    if (selectedPlan) {
      dispatch(taskList(selectedPlan._id));
    }
  }, [dispatch, selectedPlan]);

  const handleStatusClick = (task: ITask) => {
    const nextStatus = !task.isCompleted;

    const updatedCompleted = { ...task, isCompleted: nextStatus };
    dispatch(
      updateTask({
        taskId: task._id,
        planId: task.plan_id,
        taskData: updatedCompleted,
      })
    ).then(() => {
      if (selectedPlan) {
        dispatch(taskList(selectedPlan._id));
      }
    });
  };
```

- useEffectの依存関係からtasksを削除しました。
- handleStatusClickから完了値(isCompleted)を更新と`dispatch(taskList(selectedPlan._id))`を実行するように修正しました。
- このように修正することで、tasksを依存配列に含めることなく、完了値(isCompleted)が更新されるとtaskListの再取得するため無限ループの解決出来ました。

# まとめ
　依存関係によって無限ループされる問題はよく出てくる問題見たいですが、解決方法がわからなくて原因を見つけて、解決するまで時間がかかりました。まだまだ足りない部分が多いと思いました。:cry::cry:
Node-REDはBunの夢を見るか?（実践編）

（画像再キャプチャ＆執筆継続中…）

### 後書き〜昨年からの続きとして
昨年、2023年9月に Bun 1.0 が正式公開されたので、Node-RED は果たして動くのか？それは使えるレベルに達しているのか？を確かめるべく、記事を作りかけた…。一部に気になったり、深掘りしたくなった事があり、そちらに手を出してたら、記事にまとめ切れなくなったまま新年を迎え、いつの間にか忘却の彼方に飛んでいってしまったの出会った（反省）
ローカルとDockerコンテナーにLLMを実行してみた件

### はじめに
ハッカソンのきっかけで、ローカルLLMを用いた開発に挑戦することになった。デプロイを考えてDockerコンテナ化もしようとした。
### 目次
1. 初めてのローカルLLM
1. Dockerコンテナ内にLLMを実行

### 1. 初めてのローカルLLM
コマンドラインからオープンソースLLMを実行できる[ollama](https://ollama.com/)という非常に便利なフレームワークがある。[ここ](https://ollama.com/download)からダウンロードできる。以下はmac上での実行例。
インストールした後、コマンドラインに ```ollama serve``` を書くとlocalhost:11434でサーバーが立ち上がったよのログとAPIの色んなHTTPリクエストに関する情報が表示される。以下はHTTPリクエスト一覧の部分。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3923736/e18c1c68-fa64-349c-2ffc-507a3be9876e.png)

localhost:11434に行くと「Ollama is running」が表示されて、ちゃんと実行できていることを確認できる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3923736/6447e25d-3068-0c4f-b12c-eb223382ce79.png)

APIの試しとしてlocalhost:11434/api/versionを打つと、GETリクエストが送られて、バージョンが記載してあるリスポンスが帰ってくる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3923736/dfb161cd-2a25-7e84-be4c-df8b91a4da1f.png)

これはターミナルに```ollama --version```を書くことに相当する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3923736/505ffa6a-3f20-1d52-7be2-e644fe850290.png)

実行できていることを確認したので、LLMをインストールしてみよう。[Ollamaのモデル一覧](https://ollama.com/search)から好きなモデルを探してモデル名をコピーする。そしてターミナルに```ollama pull モデル名```と書いてダウンロードが開始する。```ollama list```でダウンロード済みのモデルが確認できる。

ダウンロード終わったあと、```ollama run モデル名```でモデルを実行できる。なおインストールされていないモデルを実行しようとすると勝手にダウンロードしてくれるので、すぐに実行したいなら```ollama run モデル名```だけで良い。

今回はGoogleのGemmaの日本語の文章にファインチューニングされた```schroneko/gemma-2-2b-jpn-it```を利用することにした。モデルの詳細は[こちら](https://huggingface.co/google/gemma-2-2b-jpn-it)。
ターミナルに```ollama run schroneko/gemma-2-2b-jpn-it```を書くと、Pythonの対話モードのように```>>>```の記号が表示されて、対話が開始される。システムプロンプトがすでに設定されているが```/set system "お好きなプロンプト"```で再設定できる。他のコマンドは[こちら](https://github.com/ollama/ollama?tab=readme-ov-file#cli-reference)。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3923736/6c7f1353-8055-a667-4f80-8b013ec69d0c.png)
これでローカルLLMを実行できた！
これからは対話ができるし、開発しているアプリからHTTPリクエストでモデルを活用できる。PostmanやHTTPieなどで色んなリクエストを試すとよい。だが、リスポンスのjsonの解釈が複雑になってくるのでLangchainの利用をおすすめする。

### 2. Dockerコンテナ内にLLMを実行してみた
このLLMをアプリに使う目的だったけど、アプリもコンテナ化するつもりで、LLMもコンテナ化しないといけないことになった。ネットに調べたらモデルのファイルが```~/.ollama/models```に保存されていることが分かった（macの場合)。けど、そのディレクトリに```blobs```と```manifest```というディレクトリがあってモデルのデータそこにわかれているしファイル名がハッシュになっていた。コンテナ起動の際に```~/.ollama```の中身丸ごとをコンテナの```root/.ollama```にコピーしてもいい気もしたけど他のモデルも入っていたので重すぎた。
ハッカソン中で時間に追われていたので、普通にDocker Desktopでコンテナのターミナルからollamaとモデルをインストールしちゃった。
そうして普通に実行できたけど、動作が非常に遅かった。対話しようとしたら、LLMの回答がリアルタイムに生成されるはずのに、30秒ごとに一トーケンのペースで出力されていたし、回答が全然間違っていた。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3923736/b6d69c46-f00b-1a73-80a5-69b99bf1711a.png)

これのせいで実装方法の実用性を考えなおすことになった。ハッカソン中にはさすがにLLMのコンテナ化を諦めたが、今度コンテナのリソースを調整して、再挑戦したいと思っている。

### 終わりに
Gemmaをファインチューニングしたschronekoさんに感謝
Nx のバックエンドとして EMLX を使用し、 EXLA や TorchX と比較する

## はじめに

MLX は Apple Silicon を利用した機械学習ライブラリです

https://github.com/ml-explore/mlx

EMLX は Nx のバックエンドとして MLX を使用します

https://github.com/elixir-nx/emlx

EMLX を使うことで、 MacBook 上での機械学習が高速化できるはず

ということで、ベンチマークしてみました

## 実行環境

- 端末: MacBook Pro 13インチ、M2、2022
- チップ: Apple M2
- コアの総数:	8（パフォーマンス: 4、効率性: 4）
- メモリ: 24 GB
- Elixir: 1.18.1
- Erlang: 27.2

## Livebook の起動

MacBook 上で起動するため、 Livebook をソースコードから実行します

```bash
git clone -b v0.14.5 https://github.com/livebook-dev/livebook.git
cd livebook
mix setup
ELIXIR_ERL_OPTIONS="-epmd_module Elixir.Livebook.EPMD" mix phx.server
```

## セットアップ

新しいノートブックを開き、セットアップセルで必要なモジュールをインストールします

```elixir
Mix.install([
  {:nx, "~> 0.9"},
  {:exla, "~> 0.9"},
  {:torchx, "~> 0.9"},
  {:emlx, github: "elixir-nx/emlx"},
  {:kino_benchee, "~> 0.1"}
])
```

KinoBenchee はベンチマークのためのモジュールです

## ベンチマーク

ベンチマーク用のモジュールを定義します

```elixir
defmodule MyBenchmark do
  def add(backend) do
    tensor = Nx.iota({200, 200}, type: {:f, 64}, backend: backend)
    Nx.add(tensor, tensor)
  end

  def dot(backend) do
    tensor = Nx.iota({200, 200}, type: {:f, 64}, backend: backend)
    Nx.dot(tensor, tensor)
  end

  def run_add() do
    Benchee.run(
      %{
        "binary" => fn -> add(Nx.BinaryBackend) end,
        "exla" => fn -> add(EXLA.Backend) end,
        "torchx" => fn -> add(Torchx.Backend) end,
        "emlx" => fn -> add(EMLX.Backend) end
      },
      memory_time: 2,
      reduction_time: 2
    )
  end

  def run_dot() do
    Benchee.run(
      %{
        "binary" => fn -> dot(Nx.BinaryBackend) end,
        "exla" => fn -> dot(EXLA.Backend) end,
        "torchx" => fn -> dot(Torchx.Backend) end,
        "emlx" => fn -> dot(EMLX.Backend) end
      },
      memory_time: 2,
      reduction_time: 2
    )
  end
end
```

加算でベンチマークを実行します

```elixir
MyBenchmark.run_add()
```

実行結果

![スクリーンショット 2024-12-26 0.00.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/0a4a12f4-01be-8e3c-b2c6-fd37dfc46f6c.png)

EMLX が他を圧倒しています

バイナリバックエンドの 1617 倍、 TorchX の 32 倍、 EXLA の 18 倍高速です

内積でベンチマークを実行します

```elixir
MyBenchmark.run_add()
```

実行結果

![スクリーンショット 2024-12-26 0.02.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/f835efee-1b08-db6c-c39e-a02b6905ab41.png)

内積だと更に顕著です

バイナリバックエンドの 332335 倍、 TorchX の 52 倍、 EXLA の 32 倍も高速です

## まとめ

Apple Silicon の性能を余すことなく発揮できる EMLX を活用できれば、 MacBook で AI を高速に動かせそうです

対応関数が増えることを期待しています