<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
    <channel>
        <title><![CDATA[A Day in the Life - 記事]]></title>
        <description><![CDATA[Yuichi Tateno (セコン)による、日記以外の記事一覧]]></description>
        <link>https://secon.dev</link>
        <generator>RSS for Node</generator>
        <lastBuildDate>Sat, 24 Oct 2026 06:01:17 GMT</lastBuildDate>
        <atom:link href="https://secon.dev/other_feed" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[多言語 Static Embedding モデル 'bekko-static-embedding-v1' を公開]]></title>
            <description><![CDATA[<p>多言語の Static Embedding モデル、<a href="https://huggingface.co/hotchpotch/bekko-static-embedding-v1">bekko-static-embedding-v1</a> を公開しました。Static Embedding の中では情報検索性能で SoTA で、多言語検索ではほかの多言語 Static Embedding を約11ポイント、英語検索でも英語専用の Static Embedding を約2ポイント上回ります。</p>
<p>Static Embedding は Transformer を使っておらず、トークンごとに決まったベクトルを持ち、文章のベクトルはその平均を取るだけです。GPU も不要で、multilingual-e5-small などのモデルと比べて <a href="https://huggingface.co/blog/static-embeddings">CPU で100〜400倍高速</a>に動かせます。</p>
<p>bekko-static-embedding-v1 では独自に学習した20万語彙の tokenizer を使い、40言語、約8.1億組のテキストペアを16,384のバッチサイズで対照学習しました。</p>
<p>Transformer モデルにもタスクによっては競争力がある性能です。MMTEB の検索タスクでは、12層の Transformer モデルである multilingual-e5-small との差が約1ポイントでした。</p>
<h2>性能比較</h2>
<h3>他の Static Embedding との比較</h3>
<p>bekko-static-embedding-v1 は、多言語検索と英語検索のどちらでも、比較した公開 Static Embedding をすべて上回りました。</p>
<ul>
<li><strong>多言語検索</strong>：MNanoBEIR（14言語×13タスク、nDCG@10 × 100）は43.76で、<a href="https://huggingface.co/sentence-transformers/static-similarity-mrl-multilingual-v1">static-similarity-mrl-multilingual-v1</a>（32.29）と <a href="https://huggingface.co/minishlab/potion-multilingual-128M">potion-multilingual-128M</a>（32.23）を約11ポイント上回りました。</li>
<li><strong>英語検索</strong>：NanoBEIR-en（13タスク）は53.71で、英語専用の <a href="https://huggingface.co/RikkaBotan/stable-static-embedding-fast-retrieval-mrl-en-v2">stable-static-embedding-fast-retrieval-mrl-en-v2</a>（以下 SST-v2、51.57）と <a href="https://huggingface.co/sentence-transformers/static-retrieval-mrl-en-v1">static-retrieval-mrl-en-v1</a>（50.35）を上回り、512次元に切り詰めても（52.82）両モデルより高いスコアです。</li>
<li><strong>MMTEB</strong>：131タスクの平均は50.18で、2つの多言語 Static Embedding より約3ポイント高く、Retrieval カテゴリでは8.75ポイントと12.10ポイントの差がつきました。</li>
<li><strong>マトリョーシカ次元</strong>：512次元に切り詰めても、検索スコア平均の低下は約0.9ポイントです。</li>
</ul>
<table>
<thead>
<tr>
<th>Static Embedding</th>
<th>言語</th>
<th>dims</th>
<th>NanoBEIR-en</th>
<th>MNanoBEIR</th>
<th>MMTEB Retrieval</th>
<th>MMTEB 平均</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="https://huggingface.co/hotchpotch/bekko-static-embedding-v1">bekko-static-embedding-v1</a></td>
<td>多言語</td>
<td>1024</td>
<td>53.71</td>
<td>43.76</td>
<td>49.96</td>
<td>50.18</td>
</tr>
<tr>
<td><a href="https://huggingface.co/sentence-transformers/static-similarity-mrl-multilingual-v1">static-similarity-mrl-multilingual-v1</a></td>
<td>多言語</td>
<td>1024</td>
<td>43.51</td>
<td>32.29</td>
<td>41.21</td>
<td>47.24</td>
</tr>
<tr>
<td><a href="https://huggingface.co/minishlab/potion-multilingual-128M">potion-multilingual-128M</a></td>
<td>多言語</td>
<td>256</td>
<td>37.07</td>
<td>32.23</td>
<td>37.86</td>
<td>47.23</td>
</tr>
<tr>
<td><a href="https://huggingface.co/sentence-transformers/static-retrieval-mrl-en-v1">static-retrieval-mrl-en-v1</a></td>
<td>英語</td>
<td>1024</td>
<td>50.35</td>
<td>未集計</td>
<td>未集計</td>
<td>未集計</td>
</tr>
<tr>
<td><a href="https://huggingface.co/RikkaBotan/stable-static-embedding-fast-retrieval-mrl-en-v2">SST-v2</a></td>
<td>英語</td>
<td>512</td>
<td>51.57</td>
<td>未集計</td>
<td>未集計</td>
<td>未集計</td>
</tr>
</tbody>
</table>
<p><em>表1：既存の Static Embedding との比較。
NanoBEIR-en は英語検索13タスク、MNanoBEIR は14言語の検索182タスク、MMTEB は分類なども含む131タスクの平均です。
検索列は上位10件の順位と関連度を測る nDCG@10 × 100、MMTEB は各タスクの主指標を100倍した値です。</em></p>
<h3>文脈ありモデルとの比較</h3>
<p>Transformer の層をまったく持たないモデルは、Transformer のエンコーダにどこまで近づけるのでしょうか。
比較対象には、小型の多言語検索モデルとしてよく使われる <a href="https://huggingface.co/intfloat/multilingual-e5-small">multilingual-e5-small</a>（12層、アクティブパラメータ2,160万）を選びました。</p>
<table>
<thead>
<tr>
<th>モデル</th>
<th align="right">Transformer 層</th>
<th align="right">アクティブパラメータ</th>
<th align="right">NanoBEIR-en</th>
<th align="right">MNanoBEIR</th>
<th align="right">MMTEB Retrieval</th>
<th align="right">MMTEB 平均</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>bekko-static-embedding-v1</strong></td>
<td align="right"><strong>0</strong></td>
<td align="right"><strong>0</strong></td>
<td align="right">53.71</td>
<td align="right">43.76</td>
<td align="right">49.96</td>
<td align="right">50.18</td>
</tr>
<tr>
<td>multilingual-e5-small</td>
<td align="right">12</td>
<td align="right">21.6M</td>
<td align="right">58.37</td>
<td align="right">51.17</td>
<td align="right">50.9</td>
<td align="right">56.4</td>
</tr>
<tr>
<td><a href="https://huggingface.co/hotchpotch/bekko-embedding-v1-a8m">bekko-embedding-v1-a8m</a></td>
<td align="right">4</td>
<td align="right">7.7M</td>
<td align="right"><strong>60.34</strong></td>
<td align="right"><strong>52.65</strong></td>
<td align="right"><strong>56.2</strong></td>
<td align="right"><strong>56.7</strong></td>
</tr>
</tbody>
</table>
<p><em>表2：文脈ありモデルとの比較。
NanoBEIR-en と MNanoBEIR は HAKARI-Bench の nDCG@10 × 100 です。
multilingual-e5-small と bekko-embedding-v1-a8m の MMTEB は、同じ131タスクと集計方法による <a href="https://huggingface.co/hotchpotch/bekko-embedding-v1-a8m">bekko-embedding-v1-a8m のモデルカード</a>の値です。
アクティブパラメータはトークン埋め込み表を除いた数です。</em></p>
<p>MMTEB の Retrieval では、Transformer の層を1つも動かさずに、multilingual-e5-small との差が約1ポイント（49.96と50.9）でした。
Nano dataset の検索や MMTEB 全体の平均ではまだ multilingual-e5-small の方が高く、MMTEB 平均の差の多くは BitextMining、Reranking、STS によるものです。</p>
<p>小さな Transformer を動かせる環境なら、自分が公開している <a href="https://huggingface.co/hotchpotch/bekko-embedding-v1-a8m">bekko-embedding-v1-a8m</a> は、アクティブパラメータ770万で表のすべての列で multilingual-e5-small を上回り、CPU でも動きます。
また検索では BM25 も強力なベースラインなので、後半で詳しく比較します。</p>
<blockquote>
<p>自分は bekko-static-embedding-v1 の作者で、評価に使った HAKARI-Bench の開発者でもあります。</p>
</blockquote>
<h2>Static Embedding の仕組み</h2>
<p><strong>静的埋め込み（Static Embedding）</strong> は、文章を <strong>tokenizer</strong> でトークンに分け、トークンごとに決まったベクトルを割り当てるモデルです。
文章のベクトル化は、表から各トークンのベクトルを引いて平均を取るだけです。
Transformer の層を通す計算がないので、ベクトルを高速に作れます。</p>
<h2>Sentence Transformers での使い方</h2>
<p>モデルは Sentence Transformers からそのまま読み込めます。
次の例では、「寿司はおいしい」を英語、フランス語、スペイン語、中国語でベクトル化しています。</p>
<pre><code class="hljs language-python"><span class="hljs-keyword">from</span> sentence_transformers <span class="hljs-keyword">import</span> SentenceTransformer

model = SentenceTransformer(<span class="hljs-string">"hotchpotch/bekko-static-embedding-v1"</span>, device=<span class="hljs-string">"cpu"</span>)
vectors = model.encode(
    [
        <span class="hljs-string">"Sushi is delicious."</span>,
        <span class="hljs-string">"Les sushis sont délicieux."</span>,
        <span class="hljs-string">"El sushi es delicioso."</span>,
        <span class="hljs-string">"寿司很好吃。"</span>,
    ],
    normalize_embeddings=<span class="hljs-literal">True</span>,
)
<span class="hljs-built_in">print</span>(vectors.shape)  <span class="hljs-comment"># (4, 1024)</span>
<span class="hljs-built_in">print</span>(model.similarity(vectors, vectors))</code></pre>
<p>クエリと文書は同じ方法でベクトル化でき、<code>query:</code> や <code>passage:</code> のような接頭辞は不要です。
短いベクトルを使いたいときは、<code>truncate_dim</code>（32、64、128、256、512、1024）を指定します。</p>
<pre><code class="hljs language-python">compact = model.encode([<span class="hljs-string">"A short query"</span>], truncate_dim=<span class="hljs-number">512</span>, normalize_embeddings=<span class="hljs-literal">True</span>)</code></pre>
<h2>MMTEB での評価</h2>
<p>多言語での埋め込み性能を測る <strong>MMTEB（Massive Multilingual Text Embedding Benchmark）</strong> は、検索、文章分類、クラスタリング、文同士の意味的な近さを測る <strong>STS（Semantic Textual Similarity）</strong> などを含むベンチマークです。
今回は、その中の <code>MTEB(Multilingual, v2)</code> に含まれる131タスクで、出力を切り詰めない1024次元を評価しました。</p>
<p>比較対象は、Sentence Transformers の <a href="https://huggingface.co/sentence-transformers/static-similarity-mrl-multilingual-v1">static-similarity-mrl-multilingual-v1</a> と、Model2Vec 系の <a href="https://huggingface.co/minishlab/potion-multilingual-128M">potion-multilingual-128M</a> です。
比較モデルは公開されている評価結果を使い、同じ131タスクで平均を取りました。</p>
<table>
<thead>
<tr>
<th>カテゴリ</th>
<th>タスク数</th>
<th>bekko-static-embedding-v1</th>
<th>static-similarity-mrl-multilingual-v1</th>
<th>potion-multilingual-128M</th>
<th>差</th>
</tr>
</thead>
<tbody>
<tr>
<td>全タスク</td>
<td>131</td>
<td>50.18</td>
<td>47.24</td>
<td>47.23</td>
<td>+2.93</td>
</tr>
<tr>
<td>Classification</td>
<td>43</td>
<td>52.40</td>
<td>48.60</td>
<td>52.36</td>
<td>+3.81</td>
</tr>
<tr>
<td>Clustering</td>
<td>16</td>
<td>40.03</td>
<td>30.67</td>
<td>37.63</td>
<td>+9.36</td>
</tr>
<tr>
<td>MultilabelClassification</td>
<td>5</td>
<td>14.99</td>
<td>14.74</td>
<td>15.95</td>
<td>+0.25</td>
</tr>
<tr>
<td>Retrieval</td>
<td>18</td>
<td>49.96</td>
<td>41.21</td>
<td>37.86</td>
<td>+8.75</td>
</tr>
<tr>
<td>Reranking</td>
<td>6</td>
<td>51.59</td>
<td>49.45</td>
<td>47.39</td>
<td>+2.14</td>
</tr>
<tr>
<td>STS</td>
<td>16</td>
<td>64.50</td>
<td>64.02</td>
<td>61.23</td>
<td>+0.47</td>
</tr>
<tr>
<td>BitextMining</td>
<td>13</td>
<td>43.68</td>
<td>50.62</td>
<td>40.72</td>
<td>-6.94</td>
</tr>
<tr>
<td>PairClassification</td>
<td>11</td>
<td>72.81</td>
<td>74.34</td>
<td>71.39</td>
<td>-1.53</td>
</tr>
<tr>
<td>InstructionReranking</td>
<td>3</td>
<td>-1.65</td>
<td>-1.24</td>
<td>-2.08</td>
<td>-0.41</td>
</tr>
</tbody>
</table>
<p><em>表3：MMTEB の各タスクの主指標 × 100 を、カテゴリごとに平均した値です。
「差」は bekko-static-embedding-v1 − static-similarity-mrl-multilingual-v1 です。</em></p>
<p>全タスク平均は bekko-static-embedding-v1 が50.18で、static-similarity-mrl-multilingual-v1 の47.24、potion-multilingual-128M の47.23を約3ポイント上回りました。</p>
<p>比較した2モデルとの差がそろって大きいのは Retrieval です。
bekko-static-embedding-v1 は49.96で、static-similarity-mrl-multilingual-v1 を8.75ポイント、potion-multilingual-128M を12.10ポイント上回っています。
多言語の検索は、このモデルの強みです。</p>
<p>static-similarity-mrl-multilingual-v1 に対しては、9カテゴリ中6カテゴリで上回りました。
カテゴリ別の差が最も大きいのは Clustering の+9.36ポイントで、STS は+0.47ポイントとほぼ同等です。</p>
<p>一方、対訳文を探す BitextMining、文のペアを分類する PairClassification、指示付きの InstructionReranking では、static-similarity-mrl-multilingual-v1 の方が高くなりました。
特に BitextMining は43.68と50.62で、6.94ポイントの差があります。
対訳文の抽出や文ペアの分類が主な用途なら、static-similarity-mrl-multilingual-v1 も並べて試すとよいでしょう。</p>
<h2>HAKARI-Bench による英語検索の評価</h2>
<p>検索性能は、<a href="https://github.com/hakari-bench/hakari-bench">HAKARI-Bench</a> の Nano dataset で評価しました。
Nano dataset は、既存の検索ベンチマークを小さくした評価セットです。
以下の HAKARI-Bench の表は、nDCG@10 を100倍し、各タスクを等しい重みで平均した値です。</p>
<p>英語検索には、13タスクと合計649クエリからなる <strong>NanoBEIR-en</strong> を使いました。
比較する静的モデルは、英語検索用の <a href="https://huggingface.co/sentence-transformers/static-retrieval-mrl-en-v1">static-retrieval-mrl-en-v1</a> と <a href="https://huggingface.co/RikkaBotan/stable-static-embedding-fast-retrieval-mrl-en-v2">SST-v2</a> です。
文脈を使う <a href="https://huggingface.co/intfloat/multilingual-e5-small">multilingual-e5-small</a> と、自分が公開している文脈ありの小型モデル <a href="https://huggingface.co/hotchpotch/bekko-embedding-v1-a8m">bekko-embedding-v1-a8m</a>、単語の一致や出現頻度から順位を付ける <strong>BM25</strong> も、検索方式を選ぶための参考として並べます。</p>
<table>
<thead>
<tr>
<th>モデル</th>
<th>方式</th>
<th>出力次元</th>
<th>NanoBEIR-en</th>
</tr>
</thead>
<tbody>
<tr>
<td>bekko-static-embedding-v1</td>
<td>静的、多言語</td>
<td>1024</td>
<td>53.71</td>
</tr>
<tr>
<td>bekko-static-embedding-v1</td>
<td>静的、多言語</td>
<td>512</td>
<td>52.82</td>
</tr>
<tr>
<td>static-retrieval-mrl-en-v1</td>
<td>静的、英語検索</td>
<td>1024</td>
<td>50.35</td>
</tr>
<tr>
<td>SST-v2</td>
<td>静的、英語検索</td>
<td>512</td>
<td>51.57</td>
</tr>
<tr>
<td>potion-multilingual-128M</td>
<td>静的、多言語</td>
<td>256</td>
<td>37.07</td>
</tr>
<tr>
<td>multilingual-e5-small</td>
<td>文脈あり、多言語</td>
<td>384</td>
<td>58.37</td>
</tr>
<tr>
<td>bekko-embedding-v1-a8m</td>
<td>文脈あり、多言語</td>
<td>384</td>
<td>60.34</td>
</tr>
<tr>
<td>BM25</td>
<td>単語ベース</td>
<td>sparse</td>
<td>57.15</td>
</tr>
</tbody>
</table>
<p><em>表4：NanoBEIR-en のタスク平均。
bekko-static-embedding-v1 は1024次元と512次元、比較する埋め込みモデルは各モデルの標準出力次元です。</em></p>
<p>bekko-static-embedding-v1 の1024次元は53.71で、英語検索用の SST-v2（51.57）と static-retrieval-mrl-en-v1（50.35）を上回りました。
512次元でも、同じ出力次元の SST-v2 より1.25ポイント高く、13タスク中10タスクで上回っています。</p>
<p>ただし埋め込み表の大きさは異なり、bekko-static-embedding-v1 の約2.05億パラメータに対して、SST-v2 は約1,560万パラメータです。</p>
<p>英語検索だけで見れば、bekko-embedding-v1-a8m（60.34）、multilingual-e5-small（58.37）、BM25（57.15）の方が高いスコアで、Static Embedding との差はまだ残っています。</p>
<h2>多言語検索と BM25 の比較</h2>
<p>多言語検索では、static-similarity-mrl-multilingual-v1、potion-multilingual-128M、multilingual-e5-small、bekko-embedding-v1-a8m、BM25 と比較しました。
<strong>MNanoBEIR</strong> は14言語×13タスクの計182件です。
HAKARI-Bench ではこのほかにコード検索、長文検索、日本語検索なども含めた37ベンチマーク、550タスクを評価しており、ここではそのうち10ベンチマークを示します。</p>
<table>
<thead>
<tr>
<th>ベンチマーク</th>
<th>タスク数</th>
<th>bekko-static-embedding-v1（1024次元）</th>
<th>bekko-static-embedding-v1（512次元）</th>
<th>static-similarity-mrl-multilingual-v1</th>
<th>potion-multilingual-128M</th>
<th>multilingual-e5-small</th>
<th>bekko-embedding-v1-a8m</th>
<th>BM25</th>
</tr>
</thead>
<tbody>
<tr>
<td>MNanoBEIR</td>
<td>182</td>
<td>43.76</td>
<td>42.89</td>
<td>32.29</td>
<td>32.23</td>
<td>51.17</td>
<td>52.65</td>
<td>46.46</td>
</tr>
<tr>
<td>NanoMMTEB-v2</td>
<td>18</td>
<td>43.30</td>
<td>42.87</td>
<td>36.08</td>
<td>35.22</td>
<td>44.55</td>
<td>50.25</td>
<td>45.50</td>
</tr>
<tr>
<td>NanoMIRACL</td>
<td>18</td>
<td>68.03</td>
<td>67.67</td>
<td>45.37</td>
<td>47.79</td>
<td>78.71</td>
<td>75.57</td>
<td>57.15</td>
</tr>
<tr>
<td>NanoRTEB</td>
<td>14</td>
<td>37.50</td>
<td>36.53</td>
<td>25.73</td>
<td>25.58</td>
<td>47.11</td>
<td>54.98</td>
<td>35.53</td>
</tr>
<tr>
<td>NanoCoIR</td>
<td>10</td>
<td>58.19</td>
<td>57.55</td>
<td>48.01</td>
<td>45.38</td>
<td>69.15</td>
<td>74.68</td>
<td>54.36</td>
</tr>
<tr>
<td>NanoBRIGHT</td>
<td>20</td>
<td>26.38</td>
<td>26.31</td>
<td>20.27</td>
<td>19.67</td>
<td>17.58</td>
<td>31.49</td>
<td>27.90</td>
</tr>
<tr>
<td>NanoMLDR</td>
<td>13</td>
<td>55.72</td>
<td>54.55</td>
<td>35.96</td>
<td>34.89</td>
<td>39.20</td>
<td>54.48</td>
<td>73.96</td>
</tr>
<tr>
<td>NanoLongEmbed</td>
<td>6</td>
<td>61.96</td>
<td>60.58</td>
<td>48.90</td>
<td>43.90</td>
<td>50.14</td>
<td>68.19</td>
<td>82.17</td>
</tr>
<tr>
<td>NanoJMTEB-v2</td>
<td>11</td>
<td>65.36</td>
<td>64.40</td>
<td>51.37</td>
<td>51.61</td>
<td>71.65</td>
<td>75.93</td>
<td>74.65</td>
</tr>
<tr>
<td>NanoIndicQA</td>
<td>11</td>
<td>35.35</td>
<td>35.23</td>
<td>34.91</td>
<td>53.69</td>
<td>70.09</td>
<td>65.12</td>
<td>56.53</td>
</tr>
</tbody>
</table>
<p><em>表5：各ベンチマーク内のタスク平均、nDCG@10 × 100。
static-similarity-mrl-multilingual-v1 は1024次元、potion-multilingual-128M は256次元、multilingual-e5-small と bekko-embedding-v1-a8m は384次元です。
NanoMMTEB-v2 は HAKARI-Bench の検索用セットで、前述の分類なども含む MMTEB とは別の評価です。</em></p>
<p>static-similarity-mrl-multilingual-v1 に対して、bekko-static-embedding-v1 の1024次元は37ベンチマークすべての平均で上回りました。
タスク単位でも、550件中523件で上回り、27件で下回っています。</p>
<p>potion-multilingual-128M に対しては、37ベンチマーク中36の平均で上回り、タスク単位では550件中520件で上回りました。
例外は NanoIndicQA で、potion-multilingual-128M が53.69、bekko-static-embedding-v1 が35.35でした。</p>
<p>一方、文脈を使うモデルとの差はまだ残っています。
multilingual-e5-small は37ベンチマーク中28、bekko-embedding-v1-a8m は36の平均で bekko-static-embedding-v1 を上回り、MNanoBEIR ではそれぞれ51.17と52.65です。</p>
<p>長文検索の NanoMLDR と NanoLongEmbed では multilingual-e5-small を上回りましたが、これには multilingual-e5-small の入力上限が512トークンであることも影響しています。
入力上限が8192トークンの bekko-embedding-v1-a8m と比べると、NanoLongEmbed では bekko-embedding-v1-a8m が68.19と高く、NanoMLDR では bekko-static-embedding-v1 が55.72と54.48でわずかに上回りました。</p>
<h3>検索に Static Embedding を使うべきか</h3>
<p>検索だけが目的なら、BM25 で十分なことも多いでしょう。
今回の評価でも、BM25 は37ベンチマーク中21の平均で bekko-static-embedding-v1 を上回り、タスク単位では550件中342件で上回りました。
長文検索の NanoMLDR と NanoLongEmbed、日本語の NanoJMTEB-v2 では、BM25 が大きく上回っています。</p>
<p>一方、自然言語の質問から文書を探す NanoMIRACL では、bekko-static-embedding-v1 が68.03、BM25 が57.15で、Static Embedding の方が10.88ポイント高くなりました。
検索タスクによっては、Static Embedding の方が適しています。</p>
<p>BM25 は単語の一致で文書を探すため、質問と文書で言い回しが異なる場合には埋め込み検索が役立ちます。
どちらが適しているかは、実際の検索対象で両方を試してみるのが確実です。</p>
<h2>マトリョーシカ次元と INT8 の選択</h2>
<p>1024、512、256、128、64、32次元は、<strong>Matryoshka Representation Learning（MRL）</strong> でまとめて学習しました。
MRL は、ベクトルの先頭側に有用な情報を集め、先頭の一部だけを取り出しても使えるようにする学習方法です。
用途に合わせてベクトルの長さを選び、保存容量や検索時の計算量を減らせます。</p>
<p>重みの保存精度は、FP16 に加えて INT8 も用意しています。
ここでの INT8 はモデルの重みを8 bit整数にしたもので、出力ベクトルを整数にする操作とは別です。</p>
<table>
<thead>
<tr>
<th>次元</th>
<th>NanoBEIR-en FP16</th>
<th>NanoBEIR-en INT8</th>
<th>MNanoBEIR FP16</th>
<th>MNanoBEIR INT8</th>
<th>Overall FP16</th>
<th>Overall INT8</th>
</tr>
</thead>
<tbody>
<tr>
<td>1024</td>
<td>53.71</td>
<td>53.70</td>
<td>43.76</td>
<td>43.77</td>
<td>45.88</td>
<td>45.89</td>
</tr>
<tr>
<td>512</td>
<td>52.82</td>
<td>52.79</td>
<td>42.89</td>
<td>42.88</td>
<td>45.03</td>
<td>45.02</td>
</tr>
<tr>
<td>256</td>
<td>50.83</td>
<td>50.82</td>
<td>41.04</td>
<td>41.03</td>
<td>43.29</td>
<td>43.28</td>
</tr>
<tr>
<td>128</td>
<td>47.83</td>
<td>47.97</td>
<td>38.03</td>
<td>38.04</td>
<td>40.12</td>
<td>40.12</td>
</tr>
<tr>
<td>64</td>
<td>43.96</td>
<td>44.04</td>
<td>32.87</td>
<td>32.87</td>
<td>34.82</td>
<td>34.81</td>
</tr>
<tr>
<td>32</td>
<td>35.74</td>
<td>35.72</td>
<td>24.97</td>
<td>24.96</td>
<td>26.46</td>
<td>26.44</td>
</tr>
</tbody>
</table>
<p><em>表6：マトリョーシカ次元と重みの保存精度による検索スコア。
Overall は550タスク平均で、すべて nDCG@10 × 100です。
INT8 は ONNX の結果です。</em></p>
<p>1024次元から512次元にすると、ベクトルの長さは半分になり、検索スコアの低下は NanoBEIR-en と MNanoBEIR のどちらも約0.9ポイントでした。
256次元では、低下が2.88と2.72ポイントに広がります。
それでも MNanoBEIR では、128次元の38.03が1024次元の static-similarity-mrl-multilingual-v1（32.29）を上回ります。
INT8 と FP16 の差は、どの次元でも0.15ポイント未満でした。</p>
<p>自分なら、まず512次元から試し、メモリを抑えたいときは INT8 の512次元か256次元を選びます。</p>
<h3>使う次元の重みだけを読み込む</h3>
<p>Sentence Transformers の <code>truncate_dim</code> は出力ベクトルを切り詰めますが、読み込むのは全1024次元分の表です。
512次元や256次元しか使わないなら、そのぶんのメモリは無駄になります。</p>
<p>そこで、1つの次元の重みだけを持つ ONNX と OpenVINO のファイルもリポジトリに置いています。
<a href="https://huggingface.co/hotchpotch/bekko-static-embedding-v1#onnx-and-openvino-files">モデルカード</a>には、形式、次元数、保存精度を選んで読み込む小さな <code>get_model()</code> ヘルパーを載せています。</p>
<pre><code class="hljs language-python"><span class="hljs-keyword">from</span> transformers.dynamic_module_utils <span class="hljs-keyword">import</span> get_class_from_dynamic_module

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_model</span>(<span class="hljs-params">backend=<span class="hljs-string">"onnx"</span>, dim=<span class="hljs-number">512</span>, precision=<span class="hljs-string">"int8"</span>, revision=<span class="hljs-string">"main"</span></span>):</span>
    repo = <span class="hljs-string">"hotchpotch/bekko-static-embedding-v1"</span>
    ext = {<span class="hljs-string">"onnx"</span>: <span class="hljs-string">"onnx"</span>, <span class="hljs-string">"openvino"</span>: <span class="hljs-string">"xml"</span>}[backend]
    <span class="hljs-keyword">return</span> get_class_from_dynamic_module(
        <span class="hljs-string">"bekko_static_backend.BekkoStaticBackend"</span>, repo, revision=revision,
    ).load_sentence_transformer(
        repo, revision=revision, backend=backend,
        file_name=<span class="hljs-string">f"<span class="hljs-subst">{backend}</span>/model_<span class="hljs-subst">{precision}</span>_dim<span class="hljs-subst">{dim}</span>.<span class="hljs-subst">{ext}</span>"</span>,
    )

model = get_model(backend=<span class="hljs-string">"onnx"</span>, dim=<span class="hljs-number">512</span>, precision=<span class="hljs-string">"int8"</span>)</code></pre>
<table>
<thead>
<tr>
<th>次元</th>
<th>FP16 重み</th>
<th>INT8 重み</th>
</tr>
</thead>
<tbody>
<tr>
<td>1024</td>
<td>409.6 MB</td>
<td>205.6 MB</td>
</tr>
<tr>
<td>512</td>
<td>204.8 MB</td>
<td>103.2 MB</td>
</tr>
<tr>
<td>256</td>
<td>102.4 MB</td>
<td>52.0 MB</td>
</tr>
<tr>
<td>128</td>
<td>51.2 MB</td>
<td>26.4 MB</td>
</tr>
<tr>
<td>64</td>
<td>25.6 MB</td>
<td>13.6 MB</td>
</tr>
<tr>
<td>32</td>
<td>12.8 MB</td>
<td>7.2 MB</td>
</tr>
</tbody>
</table>
<p><em>表7：次元別に配布するモデルファイルのサイズ（10進の MB）。
ONNX と OpenVINO は同じサイズで、tokenizer（約5.1 MB）は含みません。</em></p>
<p>たとえば INT8 の512次元は103.2 MBで、FP16 の1024次元（409.6 MB）の約4分の1です。
256次元なら52.0 MBまで小さくなります。</p>
<h2>どのモデルを選ぶか</h2>
<p>今回の結果から、自分なら次のように選びます。</p>
<ul>
<li>多言語の埋め込みを軽い計算で作りたい場合は、bekko-static-embedding-v1 の512次元から試す。</li>
<li>検索だけが目的なら、対象言語に合った BM25 と並べて比較する。</li>
<li>対訳文の抽出や文ペアの分類が中心なら、static-similarity-mrl-multilingual-v1 も比較する。</li>
<li>検索精度を優先し、Transformer の計算を許容できるなら、multilingual-e5-small や bekko-embedding も候補に入れる。</li>
</ul>
<blockquote>
<p><a href="https://huggingface.co/hotchpotch/bekko-embedding-v1-a8m">bekko-embedding</a> は、bekko-static-embedding-v1 とは異なり、Transformer の attention で文脈を扱う埋め込みモデルです。
Transformer 部分の重みを小さくしており、たとえば bekko-embedding-v1-a8m は約770万のアクティブパラメータで、CPU でも推論できます。
今回の比較でも、bekko-embedding-v1-a8m は NanoBEIR-en が60.34、MNanoBEIR が52.65で、どちらも multilingual-e5-small より高いスコアでした。
検索性能と推論速度のバランスを重視したい場合は、bekko-embedding も検討するとよいでしょう。</p>
</blockquote>
<h2>学習の方法</h2>
<h3>独自 tokenizer の設計と比較</h3>
<p>Static Embedding では、tokenizer が作る単位が、そのまま平均するベクトルの単位になります。
そこで、多言語 BERT や Gemma 2 の既存語彙に加えて、学習データに合わせた語彙を試しました。
多言語の静的モデル <a href="https://huggingface.co/sentence-transformers/static-similarity-mrl-multilingual-v1">static-similarity-mrl-multilingual-v1</a> が使う <code>bert-base-multilingual-uncased</code> も比較対象にしています。</p>
<p>独自語彙の学習には、単語をさらに小さな断片に分けられる <strong>WordPiece</strong> を使いました。
まず、Wikipedia と FineWeb から同数ずつ文書を取り、英語の3万語彙を学習します。
次に、英語のトークンIDを保ったまま39言語分の語彙を追加し、全体を20万語彙にしました。</p>
<p>語彙の選択には、学習データの10%を使って各 tokenizer で学習した8モデルを比較しました。
評価は、多言語検索の MNanoBEIR（14言語×13タスク）と NanoMIRACL（18言語）の計200件です。
nDCG@10 を100倍し、200件を等しい重みで平均しています。</p>
<p>表の「uncased」は大文字と小文字を区別しない設定、「cased」は区別する設定です。
「script-balanced」は、文字体系ごとの偏りを調整した候補を指します。
語彙数の「k」は千を表し、たとえば「200k、英語30k」は全20万語彙のうち英語3万語彙を先に確保した構成です。</p>
<table>
<thead>
<tr>
<th>tokenizer</th>
<th>1024次元</th>
<th>512次元</th>
</tr>
</thead>
<tbody>
<tr>
<td>多言語 BERT uncased</td>
<td>37.87</td>
<td>37.17</td>
</tr>
<tr>
<td>多言語 BERT cased</td>
<td>38.51</td>
<td>38.01</td>
</tr>
<tr>
<td>Gemma 2</td>
<td>38.73</td>
<td>38.08</td>
</tr>
<tr>
<td>独自100k、英語24k、uncased</td>
<td>40.19</td>
<td>39.29</td>
</tr>
<tr>
<td>独自100k、英語30k、uncased</td>
<td>39.86</td>
<td>39.21</td>
</tr>
<tr>
<td>独自200k、英語30k、cased</td>
<td>41.60</td>
<td>40.69</td>
</tr>
<tr>
<td>独自200k、英語30k、script-balanced</td>
<td>41.20</td>
<td>40.40</td>
</tr>
<tr>
<td>独自200k、英語30k、uncased（採用）</td>
<td>41.89</td>
<td>41.18</td>
</tr>
</tbody>
</table>
<p><em>表8：tokenizer 別の検索スコア、nDCG@10 × 100。
8モデルは同じデータと学習設定で比較しました。
この10%実験では正式版とは異なる対照学習の損失を使っており、正式版モデルのスコアとは直接比較できません。</em></p>
<p>最も高かったのは、20万語彙、英語3万語彙の uncased 版でした。
1024次元の41.89は、多言語 BERT uncased の37.87、Gemma 2 の38.73を上回ります。
この結果から、正式版にも同じ tokenizer を採用しました。</p>
<h3>学習データとハイパーパラメータ</h3>
<p>モデルの学習には、<a href="https://huggingface.co/datasets/hotchpotch/bekko-embedding-v1-unsupervised">bekko-embedding の unsupervised データセット</a> を使いました。
元のデータは、<a href="https://arxiv.org/abs/2607.25180">Bekko Embedding 論文</a>で説明した多言語データです。</p>
<p>そのうち40言語を対象とする265のデータ構成から、約8.1億件のテキストペアを学習に使いました。</p>
<p>対象の40言語は、英語、アラビア語、ブルガリア語、ベンガル語、カタルーニャ語、チェコ語、デンマーク語、ドイツ語、ギリシャ語、スペイン語、エストニア語、ペルシア語、フィンランド語、フランス語、ヘブライ語、ヒンディー語、クロアチア語、ハンガリー語、インドネシア語、イタリア語、日本語、韓国語、オランダ語、ノルウェー語、ポーランド語、ポルトガル語、ルーマニア語、ロシア語、スロバキア語、スロベニア語、セルビア語、スウェーデン語、スワヒリ語、テルグ語、タイ語、トルコ語、ウクライナ語、ベトナム語、ヨルバ語、中国語です。</p>
<p>学習する組には、文書のタイトルと本文、質問と回答、検索向けに生成したクエリ、対訳ペアなどが含まれます。
対訳データは NLLB English HQ を残し、ほかの対訳系列を選択から外しました。
MIRACL の train split や NLI に由来するデータも含みます。</p>
<p>埋め込み表はランダムに初期化し、対応するテキストの組が近くなるように学習します。
損失には、同じバッチ内のほかの候補と区別する <strong>Multiple Negatives Ranking Loss（MNRL）</strong> を使い、全1024次元と各マトリョーシカ次元に適用しました。
教師モデルの出力ベクトルを模倣する蒸留は行っていません。</p>
<table>
<thead>
<tr>
<th>設定</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>モデル</td>
<td>ランダム初期化した静的埋め込み表と平均プーリング</td>
</tr>
<tr>
<td>語彙数、埋め込み次元</td>
<td>200,000、1,024</td>
</tr>
<tr>
<td>埋め込み表のパラメータ数</td>
<td>204,800,000</td>
</tr>
<tr>
<td>データ</td>
<td>40言語を対象とする265構成、約8.14億行</td>
</tr>
<tr>
<td>損失</td>
<td>MNRL、温度0.03（scale = 1 / 0.03）</td>
</tr>
<tr>
<td>MRL 次元</td>
<td>32、64、128、256、512、1,024</td>
</tr>
<tr>
<td>MRL の重み</td>
<td>0.025、0.05、0.1、0.15、0.3、1.0（上の次元順）</td>
</tr>
<tr>
<td>エポック、更新回数</td>
<td>1、49,727</td>
</tr>
<tr>
<td>グローバルバッチサイズ</td>
<td>16,384</td>
</tr>
<tr>
<td>学習率</td>
<td>0.25</td>
</tr>
<tr>
<td>スケジュール</td>
<td>10% warmup と cosine decay</td>
</tr>
<tr>
<td>最適化</td>
<td>AdamW、weight decay 0、β₂ = 0.999、ε = 1e−8</td>
</tr>
<tr>
<td>学習精度</td>
<td>BF16 mixed precision、学習後のマスター重みは FP32</td>
</tr>
<tr>
<td>学習時の入力上限</td>
<td>512トークン</td>
</tr>
<tr>
<td>seed</td>
<td>42</td>
</tr>
<tr>
<td>データの取り出し</td>
<td>構成ごとの件数に比例したサンプリング、バッチ内の重複を抑制</td>
</tr>
</tbody>
</table>
<p><em>表9：正式モデルの学習設定。</em></p>
<h3>再現用スクリプト</h3>
<p>モデルのリポジトリには、<a href="https://huggingface.co/hotchpotch/bekko-static-embedding-v1/tree/main/training_scripts">tokenizer 学習、モデル学習、FP16 書き出しのスクリプト</a> を置いています。
学習設定とデータの選択設定も含めているので、データの選択から FP16 での書き出しまでを追えます。</p>
<h2>HAKARI-Bench の結果</h2>
<p>HAKARI-Bench の結果は、<a href="https://huggingface.co/spaces/hakari-bench/leaderboard#model_filter=multilingual-e5-small+bekko-embedding-v1-a8m+static">leaderboard</a> で確認できます。
リンク先では、<code>multilingual-e5-small</code>、<code>bekko-embedding-v1-a8m</code> と、名前に <code>static</code> を含むモデルを比較できます。</p>
<h2>参考文献と関連実装</h2>
<ul>
<li>Yuichi Tateno, <a href="https://arxiv.org/abs/2607.25180">Bekko Embedding: Parameter-Efficient Multilingual Retrieval with Ultra-Compact Encoders</a>, 2026。
学習データの背景となる、文脈付き Bekko Embedding の論文。</li>
<li>Yuichi Tateno, <a href="https://arxiv.org/abs/2606.22778">HAKARI-Bench: A Lightweight Benchmark for Comparing Retrieval Architectures and Efficiency Settings under Unified Conditions</a>, 2026。
検索方式や次元削減を比較する軽量評価の設計。</li>
<li>Kenneth Enevoldsen et al., <a href="https://arxiv.org/abs/2502.13595">MMTEB: Massive Multilingual Text Embedding Benchmark</a>, 2025。
多言語の分類、類似度、検索などを評価するベンチマーク。</li>
<li>Aditya Kusupati et al., <a href="https://arxiv.org/abs/2205.13147">Matryoshka Representation Learning</a>, 2022。
先頭の一部の次元でも使える表現を学習する方法。</li>
<li>Nandan Thakur et al., <a href="https://arxiv.org/abs/2104.08663">BEIR: A Heterogeneous Benchmark for Zero-shot Evaluation of Information Retrieval Models</a>, 2021。
異なる検索タスクと検索方式の比較。</li>
<li>Xinyu Zhang et al., <a href="https://arxiv.org/abs/2210.09984">Making a MIRACL: Multilingual Information Retrieval Across a Continuum of Languages</a>, 2023。
18言語の自然言語質問と関連文書の評価データ。</li>
<li>Stephan Tulkens and Thomas van Dongen, <a href="https://github.com/MinishLab/model2vec">Model2Vec: Fast State-of-the-Art Static Embeddings</a>, 2024。
Sentence Transformer から静的埋め込みを作るソフトウェアと技術解説。</li>
<li>Minish Lab, <a href="https://huggingface.co/minishlab/potion-multilingual-128M">potion-multilingual-128M</a>。
Model2Vec 系の多言語モデルと学習方法。</li>
<li>Tom Aarsen, <a href="https://huggingface.co/blog/static-embeddings">Train 400x faster Static Embedding Models with Sentence Transformers</a>。
静的モデルの学習方法と既存2モデルの解説。</li>
<li>RikkaBotan, <a href="https://huggingface.co/blog/RikkaBotan/stable-static-embedding-technical-report">Stable Static Embedding 技術レポート</a>と<a href="https://huggingface.co/blog/RikkaBotan/stable-static-embedding-v2-technical-report">SSE Retrieval MRL v2 技術レポート</a>。
静的な英語検索モデルの設計と評価。</li>
</ul>]]></description>
            <link>https://secon.dev/entry/2026/10/24/100000-bekko-static-embedding</link>
            <guid isPermaLink="false">/entry/2026/10/24/100000-bekko-static-embedding</guid>
            <dc:creator><![CDATA[secondlife / @hotchpotch / Yuichi Tateno]]></dc:creator>
            <pubDate>Sat, 24 Oct 2026 01:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[日本語 Decision モデル "saihai" (采配) と、日本語 Decision モデルベンチマークの公開]]></title>
            <description><![CDATA[<p>TypeSafe AI の System One Decision モデル Jev のような Decision モデルを、日本語のデータセットを多く含めて学習した saihai (采配) を公開しました。学習に利用したデータセットも公開しています。</p>
<ul>
<li><a href="https://huggingface.co/hotchpotch/saihai-v1-8b">saihai-v1-8b</a></li>
<li><a href="https://huggingface.co/hotchpotch/saihai-v1-8b-gguf">saihai-v1-8b-gguf</a></li>
<li><a href="https://huggingface.co/hotchpotch/saihai-v1-310m">saihai-v1-310m</a> (小型モデル)</li>
</ul>
<div style="text-align:center">
<a href="https://huggingface.co/spaces/hotchpotch/S1MB-leaderboard?category=japanese-v1"><img src="https://storage.googleapis.com/secons-site-images/other/blog_images/20261015-saihai-benchmark.webp" alt="日本語 Decision ベンチマーク (S1MB japanese-v1・27 タスク) での saihai-8b と他モデルの比較" width="500"></a>
</div>
<p>saihai-8b は、オープンかつ日本語に強い大規模言語モデル <a href="https://huggingface.co/llm-jp/llm-jp-4.1-8b-thinking">llm-jp-4.1-8b-thinking</a> を基盤モデルとし、Decision モデルとしてのファインチューニングを行った 8B サイズのモデルです。llm-jp のモデルを用いることで、日本のドメイン知識を最大限活かすことができそうですね。ライセンスも llm-jp と同じ Apache 2.0 です。</p>
<p>通常のモデル重みに加えて GGUF も公開しているので、各所で利用されている推論エンジン llama.cpp に最近追加された <code>/v1/systemone</code> API エンドポイントでも利用できるようにしています。</p>
<p>また、小型の saihai-310m も合わせて公開しました。こちらは decoder の LLM ではなく、<a href="https://secon.dev/entry/2026/09/30/100000-bekko-system-one-v0-release/">bekko-system-one</a> と同じアプローチで学習した encoder モデルで、日本語の reranker である <a href="https://huggingface.co/cl-nagoya/ruri-v3-reranker-310m">ruri-v3-reranker-310m</a> をベースにしています。ライセンスは ruri と同じ Apache 2.0 です。</p>
<p>なお、記事の後半にはテクニカルノートも書いているので、技術方面に興味がある方はご覧ください。</p>
<h1>日本語 Decision モデルベンチマーク</h1>
<p>日本語でのモデル性能を測るため、<a href="https://github.com/hotchpotch/S1MB">S1MB (System One Mosaic Benchmark)</a> の日本語ベンチマークセット <a href="https://huggingface.co/datasets/hotchpotch/S1MB-japanese-v1"><code>japanese-v1</code></a> を作成しました。すでに公開されている NLI などの日本語の特定タスクのデータセット 19 タスクと、今回 Decision モデル用に GPT-6.1-Sol を用いて作成した合成データセット 8 タスクを組み合わせたもので、27 タスクのベンチマークとなります。また、評価結果は <a href="https://huggingface.co/spaces/hotchpotch/S1MB-leaderboard?category=japanese-v1">S1MB の leaderboard</a> で確認できます。</p>
<ul>
<li><a href="https://huggingface.co/spaces/hotchpotch/S1MB-leaderboard?category=japanese-v1">https://huggingface.co/spaces/hotchpotch/S1MB-leaderboard?category=japanese-v1</a></li>
</ul>
<p>タスクは回答の型によって次の 3 種類に分けています。</p>
<ul>
<li><strong>Noul</strong>: はい / いいえの二択</li>
<li><strong>Choice</strong>: 複数の候補からの選択</li>
<li><strong>Score</strong>: 0, 1, 2, 3, ... といった段階でのスコア付け</li>
</ul>
<p>結果は以下です。Jev には及ばないまでも、saihai-8b は 8B というモデルサイズながら、そこそこのパフォーマンスですね。</p>
<p>ここでは Jev・GPT-6 Luna の API モデルと、パラメータ数が 12B 以下のモデルから選んで掲載しています。27B クラスのモデルなどを含む全体の結果は、leaderboard をご覧ください。各列で Jev・GPT-6 Luna を除いた最良の値を太字にしています。</p>
<table>
<thead>
<tr>
<th>モデル</th>
<th align="right">パラメータ数</th>
<th align="right">Task Avg</th>
<th align="right">Noul</th>
<th align="right">Choice</th>
<th align="right">Score</th>
<th align="right">汎用 Noul</th>
<th align="right">汎用 Choice</th>
<th align="right">汎用 Score</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="https://docs.typesafe.ai/models">Jev 1.13</a></td>
<td align="right">不明</td>
<td align="right">56.33</td>
<td align="right">54.22</td>
<td align="right">71.08</td>
<td align="right">43.70</td>
<td align="right">64.67</td>
<td align="right">75.22</td>
<td align="right">40.45</td>
</tr>
<tr>
<td><a href="https://developers.openai.com/api/docs/guides/decisions">GPT-6 Luna (Decisions API)</a></td>
<td align="right">不明</td>
<td align="right">55.00</td>
<td align="right">62.10</td>
<td align="right">63.55</td>
<td align="right">39.34</td>
<td align="right">67.11</td>
<td align="right">72.89</td>
<td align="right">30.89</td>
</tr>
<tr>
<td><a href="https://huggingface.co/hotchpotch/saihai-v1-8b">saihai-8b</a></td>
<td align="right">8B</td>
<td align="right"><strong>49.77</strong></td>
<td align="right">48.40</td>
<td align="right"><strong>61.78</strong></td>
<td align="right">39.11</td>
<td align="right">52.22</td>
<td align="right">69.31</td>
<td align="right">21.01</td>
</tr>
<tr>
<td><a href="https://huggingface.co/EldanRing/Winnow-12B">Winnow 12B</a></td>
<td align="right">12B</td>
<td align="right">48.54</td>
<td align="right"><strong>49.63</strong></td>
<td align="right">57.19</td>
<td align="right">38.79</td>
<td align="right"><strong>58.22</strong></td>
<td align="right">72.24</td>
<td align="right"><strong>32.34</strong></td>
</tr>
<tr>
<td><a href="https://huggingface.co/PelaAI/KnowLine-4B-Gen3">KnowLine Gen3</a></td>
<td align="right">4B</td>
<td align="right">46.41</td>
<td align="right">43.79</td>
<td align="right">54.97</td>
<td align="right"><strong>40.48</strong></td>
<td align="right">48.44</td>
<td align="right">71.30</td>
<td align="right">21.87</td>
</tr>
<tr>
<td><a href="https://huggingface.co/frontier-infra/jebadiah-9b-v2">Jebadiah 9B v2</a></td>
<td align="right">9B</td>
<td align="right">45.20</td>
<td align="right">42.39</td>
<td align="right">56.29</td>
<td align="right">36.93</td>
<td align="right">56.00</td>
<td align="right"><strong>72.87</strong></td>
<td align="right">25.58</td>
</tr>
<tr>
<td><a href="https://huggingface.co/Cloudflare/clef-flash">Clef Flash</a></td>
<td align="right">9B</td>
<td align="right">45.06</td>
<td align="right">40.39</td>
<td align="right">58.92</td>
<td align="right">35.88</td>
<td align="right">45.56</td>
<td align="right">70.33</td>
<td align="right">22.42</td>
</tr>
<tr>
<td><a href="https://huggingface.co/mohit67890/imajev-4b">Imajev 4B 8k</a></td>
<td align="right">4B</td>
<td align="right">39.02</td>
<td align="right">30.93</td>
<td align="right">53.93</td>
<td align="right">32.20</td>
<td align="right">43.78</td>
<td align="right">70.74</td>
<td align="right">14.28</td>
</tr>
<tr>
<td><a href="https://huggingface.co/togethercomputer/Tev1-4B-experimental">Tev1 4B</a></td>
<td align="right">4B</td>
<td align="right">37.23</td>
<td align="right">29.30</td>
<td align="right">50.80</td>
<td align="right">31.58</td>
<td align="right">43.56</td>
<td align="right">68.19</td>
<td align="right">10.88</td>
</tr>
<tr>
<td><a href="https://huggingface.co/hotchpotch/saihai-v1-310m">saihai-310m</a></td>
<td align="right">315M</td>
<td align="right">30.19</td>
<td align="right">23.29</td>
<td align="right">40.99</td>
<td align="right">26.27</td>
<td align="right">22.44</td>
<td align="right">46.13</td>
<td align="right">0.00</td>
</tr>
<tr>
<td><a href="https://huggingface.co/convaiinnovations/laya-multilingual">Laya multilingual</a></td>
<td align="right">322M</td>
<td align="right">5.29</td>
<td align="right">4.81</td>
<td align="right">11.06</td>
<td align="right">0.00</td>
<td align="right">6.22</td>
<td align="right">8.57</td>
<td align="right">0.00</td>
</tr>
</tbody>
</table>
<p>注意点として、saihai は日本語タスクを解きやすくするため、いくつかのベンチマークタスクの元データセットの train set を学習しているので、ベンチマークの点数は上がりやすくなっています (test set と重複するデータは、できる限り除いています)。その影響を調べた対照実験の結果は後半に載せています。</p>
<p>表の見方は次のとおりです。</p>
<ul>
<li>Noul・Choice・Score の 3 列は、既存データセット由来 19 タスクと合成 8 タスクの計 27 タスクを、それぞれ型ごとに平均した値です。「汎用」の 3 列は、そのうち合成 8 タスクだけを型ごとに平均した値です。</li>
<li>Task Avg は、Noul・Choice・Score の 3 列を等重みで平均した総合値です。「汎用」の 3 列は Task Avg に別途加算されていません。</li>
<li>値は 0〜100 で、小数 2 桁に丸めています。どれも基準値から調整したスコアで、単純な正解率ではありません。</li>
</ul>
<p>saihai-8b は、近いパラメータ数のモデルと比べても健闘していると感じます。評価対象と同じ元データセットの train を一部学習しているとはいえ、日本語の特定タスクを解くモデルとしては、よい結果になりました (後述の比較では、日本語で作られたタスクで特に強い結果でした)。一方、合成タスクの Noul では Winnow 12B や Jebadiah 9B v2 を、Choice では多くのモデルを下回り、Score にも差が見られます。特定タスクでの強さと、柔軟な入力への対応力には差があるようです。</p>
<p>OpenAI の Decision モデルである GPT-6 Luna (Decisions API) は、Task Avg 55.00 と Jev に迫る結果でした。Noul (62.10) と汎用 Noul (67.11) では Jev を上回っています。なお、GPT-6 Luna は API が回答を拒否した判断があり (日本語では 1 件)、その判断は不正解として採点しています。</p>
<p>小型の saihai-310m は、Task Avg 30.19 と、数 B クラスの decoder モデルとはまだ差があります。ただ、同じく encoder アーキテクチャで同程度のサイズの Laya multilingual (Task Avg 5.29) と比べると、かなり良い性能です。特に Choice は 40.99 で、JCommonsenseQA (89.58)・KUCI (82.67)・JNLI (79.00) などではそれなりの性能を示しています。Noul も CommonsenseMoralJA (74.67) や合成の Diverse (65.33) ではそこそこ解けています。一方、知識や数理を問う合成タスクはほぼ解けておらず、汎用 Score は 0.00 でした。また、saihai-310m は評価対象と同じ元データセットの train を、saihai-8b よりもずっと多く学習しているので (後述)、その分スコアは上がりやすくなっている点にご注意ください。</p>
<p>Decision モデルというと、decoder アーキテクチャの大きなモデルが目立ちますが、小型の encoder モデルでも、将来は Decision モデルとして十分な性能のものが現れるのでは、と期待しています。</p>
<h2>既存の日本語データセットの活用</h2>
<p>既存の日本語データセットは、タスクごとに Noul・Choice・Score のどの型が合うかを考えて割り振りました。データは原作者が用意した test set を基本とし、一部は validation や train、もともと分割されていない問題群も使っています (例外は後述)。各タスクは最大 300 件です。なお、この手法に興味がある方は、<a href="https://zenn.dev/ivry/articles/65c1c4242e1156">IVRy さんの「日本語ベンチマークで Jev の性能を検証する」</a>に具体的な方法がわかりやすく書かれているので、参照ください。</p>
<p>これらのデータを、Decision モデルが回答しやすい instruction・state の構造に変換して評価用データセットを作成しました。同時に、train 用のデータが用意されているものは学習用データセットも作成し、saihai の学習にも使っています。なお、train 用のデータには、まれに test set と同じデータが含まれるため、できる限り削除しています。</p>
<p>以下、ベンチマークと同じ元データセットの train を「系列 train」と呼びます。利用したデータセットは以下で、「系列 train の投入」列は、評価問題ではなく、系列 train から学習に使った件数です。</p>
<table>
<thead>
<tr>
<th>データセット</th>
<th>型</th>
<th align="right">評価件数</th>
<th>ライセンス</th>
<th>系列 train の投入</th>
</tr>
</thead>
<tbody>
<tr>
<td>CommonsenseMoralJA</td>
<td>Noul</td>
<td align="right">300</td>
<td>MIT</td>
<td>✓ 400件</td>
</tr>
<tr>
<td>JamC-QA</td>
<td>Choice</td>
<td align="right">300</td>
<td>CC-BY-SA-4.0</td>
<td>—</td>
</tr>
<tr>
<td>JaNLI</td>
<td>Choice</td>
<td align="right">285</td>
<td>CC-BY-SA-4.0</td>
<td>✓ 400件</td>
</tr>
<tr>
<td>JCommonsenseQA</td>
<td>Choice</td>
<td align="right">300</td>
<td>CC-BY-SA-4.0</td>
<td>✓ 400件</td>
</tr>
<tr>
<td>JCulture-MCQ</td>
<td>Noul</td>
<td align="right">283</td>
<td>CC-BY-4.0</td>
<td>—</td>
</tr>
<tr>
<td>JNLI</td>
<td>Choice</td>
<td align="right">300</td>
<td>CC-BY-SA-4.0</td>
<td>✓ 382件</td>
</tr>
<tr>
<td>KUCI</td>
<td>Choice</td>
<td align="right">300</td>
<td>CC-BY-SA-4.0</td>
<td>✓ 400件</td>
</tr>
<tr>
<td>Mintaka (日本語・Boolean)</td>
<td>Noul</td>
<td align="right">300</td>
<td>CC-BY-4.0</td>
<td>✓ 400件</td>
</tr>
<tr>
<td>MMLU-ProX (日本語)</td>
<td>Choice</td>
<td align="right">300</td>
<td>MIT</td>
<td>—</td>
</tr>
<tr>
<td>MMMLU (日本語)</td>
<td>Choice</td>
<td align="right">300</td>
<td>MIT</td>
<td>—</td>
</tr>
<tr>
<td>JSICK (STS)</td>
<td>Score</td>
<td align="right">300</td>
<td>CC-BY-SA-4.0</td>
<td>✓ 395件</td>
</tr>
<tr>
<td>JSTS</td>
<td>Score</td>
<td align="right">300</td>
<td>CC-BY-SA-4.0</td>
<td>✓ 396件</td>
</tr>
<tr>
<td>NanoJMTEB-v2 (検索)</td>
<td>Choice</td>
<td align="right">300</td>
<td>元データ別の条件</td>
<td>—</td>
</tr>
<tr>
<td>JCoLA</td>
<td>Noul</td>
<td align="right">299</td>
<td>CC-BY-SA-4.0</td>
<td>✓ 358件</td>
</tr>
<tr>
<td>Jamp</td>
<td>Choice</td>
<td align="right">300</td>
<td>CC-BY-SA-4.0</td>
<td>✓ 358件</td>
</tr>
<tr>
<td>JSeM</td>
<td>Choice</td>
<td align="right">300</td>
<td>BSD-3-Clause</td>
<td>—</td>
</tr>
<tr>
<td>GPQA (日本語)</td>
<td>Choice</td>
<td align="right">300</td>
<td>CC-BY-4.0</td>
<td>—</td>
</tr>
<tr>
<td>JMMLU Japan</td>
<td>Choice</td>
<td align="right">300</td>
<td>CC-BY-SA-4.0 / CC-BY-NC-ND-4.0 (科目別)</td>
<td>—</td>
</tr>
<tr>
<td>SOBACO Culture</td>
<td>Choice</td>
<td align="right">300</td>
<td>CC-BY-SA-4.0 (gated access)</td>
<td>—</td>
</tr>
</tbody>
</table>
<p>以下は補足です。</p>
<ul>
<li><strong>test set の例外</strong>: JCoLA は元の validation、JSeM はもともと train/test に分かれていない問題群、NanoJMTEB は評価用 split、JMMLU Japan は元の split 指定なし、SOBACO Culture は元の train を使っています。GPQA も元の評価用問題群です。すべてが「原作者が定義した test」というわけではありません。</li>
<li><strong>JSICK</strong> は学習側が Choice、評価側が Score ですが、同じ系列として扱っています。</li>
<li><strong>JMMLU Japan</strong> は日本史・慣用句・公民・地理を各 75 件、<strong>SOBACO Culture</strong> は日本文化の 300 件です。</li>
<li><strong>検索タスク</strong> (NanoJMTEB) は、JMTEB の検索系ベンチマークを元にした、正例 1 件と非正例 3〜5 件から選ぶ Choice です。検索系のベンチマークを複合しているので、ライセンスは行ごとに異なります。</li>
<li><strong>ライセンス</strong>は素材ごとに条件があり、この表は要約です。JMMLU の科目別の利用制限や、検索素材の帰属・再配布条件は元資料をご確認ください。</li>
</ul>
<h2>合成データセット</h2>
<p>ここまでのデータセットは、「特定タスクにフォーカスした」Decision モデルの性能を測るものです。そこで、既存タスクでは測れない「ある程度柔軟な入力に対して、適切な回答を選べるか」を見るタスクを、GPT-6.1-Sol で合成データセットとして生成しました。真の汎化性能を測れているとはいえませんが、便宜上「汎化性能指標」のタスクと呼んでいます。</p>
<p>合成データは 3 系列・8 タスク、合計 2,400 件です。</p>
<table>
<thead>
<tr>
<th>系列</th>
<th>型</th>
<th>件数</th>
<th>見るもの</th>
</tr>
</thead>
<tbody>
<tr>
<td>Diverse</td>
<td>Noul / Choice</td>
<td>各300件</td>
<td>カジュアルな指示、多様な状態・入力形式への対応</td>
</tr>
<tr>
<td>Knowledge hard</td>
<td>Noul / Choice / Score</td>
<td>各300件</td>
<td>知識や文脈に基づく判断</td>
</tr>
<tr>
<td>Math formal hard</td>
<td>Noul / Choice / Score</td>
<td>各300件</td>
<td>数理的な条件や論理的な判断</td>
</tr>
</tbody>
</table>
<p>Diverse には Score タスクがありません。また、以前作った不確実性のタスクは、現在の評価対象から外しています。合成データのライセンスは、OpenAI のモデルを用いて作ったため、CC BY-NC 4.0 としています。また正答は人手による独立したブラインド検証をしていないので、この 8 タスクの点数だけで、あらゆる使い方に汎化できるとは言えません。</p>
<h1>英語ベンチマークでの評価</h1>
<p>saihai は日本語向けのモデルですが、学習データには英語のデータも多く含まれています。そこで、S1MB の英語ベンチマークセット <a href="https://huggingface.co/datasets/hotchpotch/S1MB-english-v1"><code>english-v1</code></a> でも評価しました。english-v1 は 137 タスクで、「汎用」の 3 列は、Diverse と Contextual の合成タスク 6 タスク (各型 2 タスク) を型ごとに平均した値です。列の見方は日本語の表と同じですが、タスクの構成が違うので、日本語の表と数値を直接比べることはできません。</p>
<p>日本語の表と同じモデルに、英語の encoder モデルである <a href="https://huggingface.co/hotchpotch/bekko-system-one-v0-400m">bekko-system-one-v0-400m</a>・Laya・Laya typed-decisions を加えています。各列で Jev・GPT-6 Luna を除いた最良の値を太字にしています。</p>
<table>
<thead>
<tr>
<th>モデル</th>
<th align="right">パラメータ数</th>
<th align="right">Task Avg</th>
<th align="right">Noul</th>
<th align="right">Choice</th>
<th align="right">Score</th>
<th align="right">汎用 Noul</th>
<th align="right">汎用 Choice</th>
<th align="right">汎用 Score</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="https://docs.typesafe.ai/models">Jev 1.13</a></td>
<td align="right">不明</td>
<td align="right">59.59</td>
<td align="right">64.63</td>
<td align="right">67.22</td>
<td align="right">46.92</td>
<td align="right">99.00</td>
<td align="right">98.68</td>
<td align="right">91.14</td>
</tr>
<tr>
<td><a href="https://developers.openai.com/api/docs/guides/decisions">GPT-6 Luna (Decisions API)</a></td>
<td align="right">不明</td>
<td align="right">49.21</td>
<td align="right">54.54</td>
<td align="right">56.23</td>
<td align="right">36.85</td>
<td align="right">91.00</td>
<td align="right">98.03</td>
<td align="right">75.15</td>
</tr>
<tr>
<td><a href="https://huggingface.co/PelaAI/KnowLine-4B-Gen3">KnowLine Gen3</a></td>
<td align="right">4B</td>
<td align="right"><strong>57.30</strong></td>
<td align="right">59.97</td>
<td align="right"><strong>65.49</strong></td>
<td align="right"><strong>46.45</strong></td>
<td align="right">93.00</td>
<td align="right">96.71</td>
<td align="right">74.47</td>
</tr>
<tr>
<td><a href="https://huggingface.co/EldanRing/Winnow-12B">Winnow 12B</a></td>
<td align="right">12B</td>
<td align="right">54.56</td>
<td align="right"><strong>61.38</strong></td>
<td align="right">60.70</td>
<td align="right">41.61</td>
<td align="right"><strong>95.00</strong></td>
<td align="right">98.03</td>
<td align="right"><strong>90.19</strong></td>
</tr>
<tr>
<td><a href="https://huggingface.co/hotchpotch/bekko-system-one-v0-400m">bekko-system-one-v0-400m</a></td>
<td align="right">395M</td>
<td align="right">50.60</td>
<td align="right">51.24</td>
<td align="right">61.32</td>
<td align="right">39.25</td>
<td align="right">52.00</td>
<td align="right">80.30</td>
<td align="right">31.14</td>
</tr>
<tr>
<td><a href="https://huggingface.co/hotchpotch/saihai-v1-8b">saihai-8b</a></td>
<td align="right">8B</td>
<td align="right">50.59</td>
<td align="right">59.96</td>
<td align="right">59.51</td>
<td align="right">32.29</td>
<td align="right">91.00</td>
<td align="right">93.41</td>
<td align="right">71.54</td>
</tr>
<tr>
<td><a href="https://huggingface.co/frontier-infra/jebadiah-9b-v2">Jebadiah 9B v2</a></td>
<td align="right">9B</td>
<td align="right">48.67</td>
<td align="right">53.30</td>
<td align="right">58.23</td>
<td align="right">34.48</td>
<td align="right">92.00</td>
<td align="right">95.39</td>
<td align="right">76.33</td>
</tr>
<tr>
<td><a href="https://huggingface.co/Cloudflare/clef-flash">Clef Flash</a></td>
<td align="right">9B</td>
<td align="right">48.06</td>
<td align="right">51.82</td>
<td align="right">63.05</td>
<td align="right">29.32</td>
<td align="right">89.00</td>
<td align="right"><strong>98.05</strong></td>
<td align="right">66.74</td>
</tr>
<tr>
<td><a href="https://huggingface.co/togethercomputer/Tev1-4B-experimental">Tev1 4B</a></td>
<td align="right">4B</td>
<td align="right">47.07</td>
<td align="right">50.73</td>
<td align="right">53.36</td>
<td align="right">37.11</td>
<td align="right">88.00</td>
<td align="right">94.05</td>
<td align="right">70.15</td>
</tr>
<tr>
<td><a href="https://huggingface.co/mohit67890/imajev-4b">Imajev 4B 8k</a></td>
<td align="right">4B</td>
<td align="right">46.20</td>
<td align="right">53.49</td>
<td align="right">56.70</td>
<td align="right">28.41</td>
<td align="right">92.00</td>
<td align="right">95.39</td>
<td align="right">72.80</td>
</tr>
<tr>
<td><a href="https://huggingface.co/hotchpotch/saihai-v1-310m">saihai-310m</a></td>
<td align="right">315M</td>
<td align="right">40.59</td>
<td align="right">40.92</td>
<td align="right">47.20</td>
<td align="right">33.66</td>
<td align="right">16.00</td>
<td align="right">58.71</td>
<td align="right">13.21</td>
</tr>
<tr>
<td><a href="https://huggingface.co/convaiinnovations/laya-typed-decisions">Laya typed-decisions</a></td>
<td align="right">421M</td>
<td align="right">15.00</td>
<td align="right">20.06</td>
<td align="right">18.93</td>
<td align="right">5.99</td>
<td align="right">22.00</td>
<td align="right">58.80</td>
<td align="right">14.67</td>
</tr>
<tr>
<td><a href="https://huggingface.co/convaiinnovations/laya">Laya</a></td>
<td align="right">421M</td>
<td align="right">13.36</td>
<td align="right">20.19</td>
<td align="right">16.31</td>
<td align="right">3.58</td>
<td align="right">9.00</td>
<td align="right">54.83</td>
<td align="right">15.67</td>
</tr>
<tr>
<td><a href="https://huggingface.co/convaiinnovations/laya-multilingual">Laya multilingual</a></td>
<td align="right">322M</td>
<td align="right">9.28</td>
<td align="right">14.01</td>
<td align="right">13.03</td>
<td align="right">0.79</td>
<td align="right">6.00</td>
<td align="right">36.67</td>
<td align="right">0.75</td>
</tr>
</tbody>
</table>
<p>英語では、saihai-8b は Task Avg 50.59 で、API モデルを除く decoder モデル 7 つの中では 3 番目でした。Noul は 59.96 と比較的高い一方、Score は 32.29 と低めです。汎用 Noul・Choice も 90 を超えており、日本語向けに学習したモデルながら、英語でも必要十分な性能を持っているといえそうですね。</p>
<p>なお、GPT-6 Luna は英語では Task Avg 49.21 と、日本語ほどの順位ではありませんでした。英語では API が回答を拒否した判断が 17 件あり、不正解として採点しているので、その分も多少影響しています。</p>
<p>saihai-310m は 40.59 で、英語の学習データを bekko-system-one のデータセットの約 10% に絞っていることもあり、bekko-system-one-v0-400m (50.60) より低くなりました。特に汎用 Noul・Score は大きく下がっています。</p>
<p>それでも、英語の encoder モデルである Laya (13.36) や Laya typed-decisions (15.00) と比べると、saihai-310m の Task Avg は 2.5 倍以上で、Noul・Choice・Score のいずれも大きく上回っています。一方、汎用の 3 列は Laya 系と同程度 (汎用 Score はやや下回る) で、柔軟な入力への対応は小型 encoder にとってまだ難しいところですね。</p>
<p>また、英語の汎用 Noul・Choice は、多くの decoder モデルが 90 前後に集まっていて差がつきにくくなっています。数値は直接比べられないものの、日本語の合成タスクでは Jev でも汎用 Noul が 64.67 なので、今回作った日本語の合成タスクは、差がつきやすい問題になっているようです。</p>
<h1>saihai モデルの作成</h1>
<p>saihai-8b と saihai-310m はアーキテクチャが異なるので、それぞれ分けて説明します。</p>
<h2>saihai-8b</h2>
<p>モデル作成に使った学習コードとデータセットは、それぞれ公開しています。</p>
<ul>
<li>学習コード: <a href="https://github.com/hotchpotch/saihai">hotchpotch/saihai</a></li>
<li>学習データ: <a href="https://huggingface.co/datasets/hotchpotch/saihai-v1-dataset">hotchpotch/saihai-v1-dataset</a></li>
</ul>
<h3>モデルアーキテクチャ</h3>
<p>saihai-8b は、いわゆる decoder アーキテクチャの LLM で、現在一般的な Decision モデルの学習方法を用いています。Decision モデルの構造は、まだ汎用的なものが定まっていないのが現状です。ただ、推論エンジンの一つである llama.cpp では、<code>/v1/systemone</code> という推論エンドポイントで Perplexity の <a href="https://huggingface.co/perplexity-ai/pplx-decider-v1-27b">pplx-decider-v1-27b</a> の形式が使えるようだったので、それに合わせた構造になるように、学習しています。</p>
<p>学習から推論までの流れは以下です。</p>
<ol>
<li>学習データの候補と、教師の確率分布を対応付けます。正答や出典情報はモデルの入力に含めません。</li>
<li>指示・状態・候補を JSON にし、基盤モデルの chat template に埋め込みます。候補には、tokenizer で 1 token になる A、B などのコードを割り当てます。</li>
<li>回答を始める直前までを入力し、最後の有効 token の hidden state を取り出します。</li>
<li>bias のない FP32 の線形 head で候補の logits を計算し、その問題で使う候補の中で softmax を取ります。head は、元の LM head のうち候補コード token の行から初期化します。</li>
<li>教師の確率分布との cross entropy を損失として、LoRA と候補 head を学習します。backbone は BF16 です。全パラメータを更新するとメモリに載らず、学習も遅くなるため、LoRA を用いています。</li>
<li>配布時には LoRA を merge し、学習した head を元の LM head の候補コード token の行へ書き戻します。推論では 1 回の forward から候補の確率を読み取るだけで、文章や reasoning は生成しません。</li>
</ol>
<p>候補コードは llama.cpp の pplx-decider と同じ規則で、A〜Z、AA〜ZZ のうち単一 token になるものだけを選び、最大 255 候補に対応させています。Noul の候補順は false → true、Score は 2〜10 段階です。pplx の学習方法を丸ごと再現したわけではなく、候補 token の確率を読み出す仕組みを合わせた形ですね。</p>
<h3>学習データ</h3>
<p>学習データには、以下の 3 つを使っています。</p>
<ul>
<li>既存の英語 Decision モデルの学習に使われているデータセット。既存データセットから抽出したものや、合成データセットを含みます</li>
<li>日本語ベンチマークの元データセットのうち、train にあたるもの (系列 train)</li>
<li><a href="https://huggingface.co/llm-jp/llm-jp-4.1-32b-a3b-thinking">llm-jp-4.1-32b-a3b-thinking</a> を用いて作成した、日本語の合成データセット</li>
</ul>
<p>内訳は以下で、合計 33,532 件を学習させています。</p>
<table>
<thead>
<tr>
<th>学習データ</th>
<th align="right">件数</th>
</tr>
</thead>
<tbody>
<tr>
<td>既存の英語素材など・規則データ</td>
<td align="right">16,023</td>
</tr>
<tr>
<td>日本語ベンチマークの系列 train</td>
<td align="right">3,889</td>
</tr>
<tr>
<td>日本語の合成データ</td>
<td align="right">13,620</td>
</tr>
<tr>
<td>合計</td>
<td align="right">33,532</td>
</tr>
</tbody>
</table>
<p>学習は LoRA (rank 16 / alpha 32) を用い、RTX 5090 で約 3.62 時間でした (評価や量子化の時間は含みません)。そのほかの条件は、1 epoch、実効 batch size 16、最大入力長 8,192、seed 42 です。279 件の固定 validation を学習中に 10 回測定していますが、validation が最良の step ではなく、最後の checkpoint を使っています。</p>
<p>なお、モデル重みのライセンス (Apache 2.0) と、学習データの素材ごとのライセンスは別です。</p>
<h2>saihai-310m</h2>
<p>saihai-310m は、<a href="https://secon.dev/entry/2026/09/30/100000-bekko-system-one-v0-release/">bekko-system-one</a> のアプローチで学習した、小型の encoder モデルです。学習コードは bekko-system-one のものを使っています。</p>
<ul>
<li>学習コード・手順: <a href="https://github.com/hotchpotch/bekko-system-one/blob/main/docs/saihai-v1-310m.md">bekko-system-one の saihai-v1-310m 学習ドキュメント</a></li>
<li>学習データ: <a href="https://huggingface.co/datasets/hotchpotch/saihai-v1-310m-dataset">hotchpotch/saihai-v1-310m-dataset</a></li>
</ul>
<h3>モデルアーキテクチャ</h3>
<p>アーキテクチャは bekko-system-one と同じです。簡単に書くと、instruction と state を共有の prefix として一度だけ処理し、その各層の Key/Value を、各候補 (criteria) の処理で再利用します。各候補は共有 prefix と自分自身だけを参照し、候補側の表現からスコアを計算します。長い state を候補の数だけ処理し直さずに済むので、小さなモデルで効率よく推論できます。詳しくは bekko-system-one の記事をご覧ください。</p>
<p>bekko-system-one では、素の encoder よりも、reranker として学習済みのモデルを初期値にした方が性能が上がりました (特に 68M のモデルで、損失 (CE) と各タスクの精度がともに改善しました)。それに倣い、saihai-310m では日本語の高性能 reranker である <a href="https://huggingface.co/cl-nagoya/ruri-v3-reranker-310m">ruri-v3-reranker-310m</a> をベースにしています。ruri-v3-reranker-310m は、<a href="https://huggingface.co/sbintuitions/modernbert-ja-310m">modernbert-ja-310m</a> を元にした <a href="https://huggingface.co/cl-nagoya/ruri-v3-pt-310m">ruri-v3-pt-310m</a> を、reranker として学習したモデルです。パラメータ数は 315M (埋め込み層を除くと 236M) です。</p>
<p>なお、saihai-310m は llama.cpp の <code>/v1/systemone</code> には対応していません。Transformers の <code>AutoModel</code> (<code>trust_remote_code=True</code>) から読み込み、saihai-8b と同じような <code>state</code>・<code>questions</code> 形式の入力で使えます。ただし、入力が長すぎる場合、saihai-8b はエラーにしますが、saihai-310m は入力を切り詰めて推論する点が異なります。</p>
<h3>学習データと学習条件</h3>
<p>学習データは、以下の 3 つを混ぜて使っています。件数は、1 つの問題に含まれる個々の判断の数です。</p>
<table>
<thead>
<tr>
<th>学習データ</th>
<th align="right">判断数</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="https://huggingface.co/datasets/hotchpotch/bekko-system-one-dataset-v0">bekko-system-one のデータセット</a> から、出典ごとの偏りを抑えて約 10% を抽出したもの</td>
<td align="right">840,947</td>
</tr>
<tr>
<td>日本語ベンチマークの系列 train など (7 データセット)</td>
<td align="right">116,771</td>
</tr>
<tr>
<td>日本語の合成データ (llm-jp-4.1-32b-a3b-thinking で作成)</td>
<td align="right">14,400</td>
</tr>
<tr>
<td>合計</td>
<td align="right">972,118</td>
</tr>
</tbody>
</table>
<p>日本語の系列 train は、CommonsenseMoralJA・JCommonsenseQA・JNLI・JSTS・KUCI・Mintaka・JaNLI の 7 データセットです。saihai-8b では各データセット 400 件以下に絞っていましたが、saihai-310m では採用した train をすべて使っているので、件数がずっと多くなっています (例えば KUCI は 69,527 判断)。そのため、対応するタスクのスコアは saihai-8b 以上に上がりやすくなっていると思われます。saihai-8b と同様、評価データの問題とその関連データは除いています。</p>
<p>学習は全パラメータを更新し (LoRA は使っていません)、batch size 512 で全データを 1 epoch、約 2 時間 45 分でした。encoder の学習率は 1e-5、head の学習率は 2e-4、入力長の上限は query 4,096 / 候補 2,048 tokens です。</p>
<p>S1MB の評価は、bekko-system-one と同じく、長い入力を切り詰めて入力長を配分する設定で行っています。</p>
<h1>対照実験</h1>
<p>さて、ベンチマークと同じ傾向のタスクを train に多く含んでいるので、そのせいで性能が高く出ているのでは？という疑問が出ると思います。そこで、saihai-8b について、2 つの対照実験を行いました。最後に、系列 train なしのモデルを外部の Decision モデルとも比べています。</p>
<h2>系列 train を学習しなかった場合との比較</h2>
<p>LLM-jp 4.1 8B を用いた saihai-8b に加え、Qwen3.5 の 3 サイズのモデルに対しても、系列 train を含めて学習したモデルと、除いて学習したモデルを作って比べました。以下は S1MB の Task Avg です。</p>
<table>
<thead>
<tr>
<th>基盤モデル</th>
<th align="right">系列 train あり</th>
<th align="right">系列 train なし</th>
<th align="right">差 (あり − なし)</th>
</tr>
</thead>
<tbody>
<tr>
<td>LLM-jp 8B (saihai-8b)</td>
<td align="right">49.77</td>
<td align="right">47.85</td>
<td align="right">+1.92</td>
</tr>
<tr>
<td>Qwen3.5 0.8B</td>
<td align="right">25.71</td>
<td align="right">20.66</td>
<td align="right">+5.05</td>
</tr>
<tr>
<td>Qwen3.5 4B</td>
<td align="right">45.30</td>
<td align="right">45.73</td>
<td align="right">-0.43</td>
</tr>
<tr>
<td>Qwen3.5 9B</td>
<td align="right">52.15</td>
<td align="right">48.97</td>
<td align="right">+3.18</td>
</tr>
</tbody>
</table>
<p>多くのモデルでは系列 train を学習させた方が強い結果になっていますが、Qwen3.5 4B では除いた方が 0.43 点高くなりました。系列 train を入れればどのモデルでも総合値が上がる、というわけではないですが、基本的にはスコアが上がりやすくなりました。</p>
<p>では、どのタスクで差が出ているのでしょうか。系列 train を使った 10 タスクと、それ以外の 17 タスク (うち、系列 train を使っていない既存データ由来 9 タスク、合成 8 タスク) に分けて、差を見たのが以下です。タスク群の値は各タスクのスコアの単純平均で、差は「あり − なし」です。プラスなら、系列 train を学習した方が高いことを示します。</p>
<table>
<thead>
<tr>
<th>基盤モデル</th>
<th align="right">系列 train 対応 10</th>
<th align="right">それ以外 17</th>
<th align="right">うち既存データ 9</th>
<th align="right">うち合成 8</th>
</tr>
</thead>
<tbody>
<tr>
<td>LLM-jp 8B (saihai-8b)</td>
<td align="right">+8.02</td>
<td align="right">+0.15</td>
<td align="right">+0.88</td>
<td align="right">-0.67</td>
</tr>
<tr>
<td>Qwen3.5 0.8B</td>
<td align="right">+12.95</td>
<td align="right">+0.58</td>
<td align="right">+0.93</td>
<td align="right">+0.19</td>
</tr>
<tr>
<td>Qwen3.5 4B</td>
<td align="right">+8.35</td>
<td align="right">-2.46</td>
<td align="right">-0.50</td>
<td align="right">-4.67</td>
</tr>
<tr>
<td>Qwen3.5 9B</td>
<td align="right">+10.76</td>
<td align="right">-0.58</td>
<td align="right">-0.29</td>
<td align="right">-0.90</td>
</tr>
</tbody>
</table>
<p>LLM-jp 8B では、系列 train を学習したことで、対応する 10 タスクは 8.02 点上がった一方、それ以外の 17 タスクは 0.15 点の上昇にとどまりました。どのモデルでも、対応する 10 タスクだけが大きく上がる同じ傾向で、やはり train を学習した系列のタスクが解きやすくなっている、ということですね。ただ、系列 train を除くと学習データが 33,532 件から 29,643 件に、重みの更新回数も 2,096 回から 1,853 回に減っているので、若干データが減ったことも影響しているかもしれません。</p>
<h2>基盤モデルを変えた場合との比較</h2>
<p>saihai-8b は llm-jp のモデルを使っているので、他のモデルに比べて日本のドメイン理解が強いと思われます。そこで、Qwen3.5 シリーズのいくつかのモデルも同じ学習データで学習させ、違いを見てみましょう。</p>
<p>ここでは、既存データセット由来の 19 タスクを、次の 2 つに分けています。</p>
<ul>
<li><strong>日本語オリジナル 12</strong>: 翻訳ではなく、日本語で一から作られたデータセットの 12 タスクです。日本の知識を問うタスク (後述の文化知識 4) だけでなく、推論や意味の類似度などの言語タスクも含みます。
<ul>
<li>CommonsenseMoralJA、JamC-QA、Jamp、JaNLI、JCoLA、JCommonsenseQA、JCulture-MCQ、JNLI、JSTS、KUCI、JMMLU Japan、SOBACO Culture</li>
</ul>
</li>
<li><strong>翻訳・混在 7</strong>: 英語などからの翻訳を元にしたものと、複数の元データが混ざったものの 7 タスクです。MMLU-ProX・MMMLU・GPQA のような一般知識の問題が多く含まれます。
<ul>
<li>MMLU-ProX、MMMLU、GPQA、Mintaka、JSICK、JSeM、NanoJMTEB</li>
</ul>
</li>
</ul>
<p>どちらも記事用に分けたタスク群で、日本語能力全体を定義したものではありません。Task Avg は S1MB の総合値、それ以外の列はそれぞれのタスク群の単純平均です。</p>
<table>
<thead>
<tr>
<th>モデル</th>
<th align="right">Task Avg</th>
<th align="right">日本語オリジナル 12</th>
<th align="right">翻訳・混在 7</th>
<th align="right">合成 8</th>
</tr>
</thead>
<tbody>
<tr>
<td>saihai Qwen3.5 9B</td>
<td align="right">52.15</td>
<td align="right">61.86</td>
<td align="right">52.41</td>
<td align="right">54.57</td>
</tr>
<tr>
<td><strong>saihai-8b (LLM-jp 8B)</strong></td>
<td align="right">49.77</td>
<td align="right">63.17</td>
<td align="right">45.58</td>
<td align="right">50.83</td>
</tr>
<tr>
<td>saihai Qwen3.5 4B</td>
<td align="right">45.30</td>
<td align="right">57.62</td>
<td align="right">43.04</td>
<td align="right">47.95</td>
</tr>
<tr>
<td>saihai Qwen3.5 0.8B</td>
<td align="right">25.71</td>
<td align="right">34.65</td>
<td align="right">25.42</td>
<td align="right">27.74</td>
</tr>
</tbody>
</table>
<p>全体ではサイズが少し大きい Qwen3.5 9B が上でしたが、日本語オリジナルの 12 タスクでは LLM-jp 8B が少し上でした。一方、翻訳・混在の 7 タスクでは Qwen3.5 9B が 6.83 点上で、日本語で作られた問題に LLM-jp 8B の強みが生かされているようです。また、Qwen3.5 4B・0.8B と比べると、全体スコアも LLM-jp 8B の方が高くなっています。ただし、タスクや型ごとに見ると例外もあります。また、LoRA の rank や学習率もモデルごとに違うので、純粋に基盤モデルだけの差とは言えません。</p>
<h2>系列 train なしの saihai-8b と他モデルとの比較</h2>
<p>最後に、系列 train を使わずに学習した LLM-jp 8B を、他の Decision モデルと比べてみました。ここでの「文化知識 4」は、JamC-QA、JCulture-MCQ、JMMLU Japan、SOBACO Culture の 4 タスクです。</p>
<table>
<thead>
<tr>
<th>モデル</th>
<th align="right">Task Avg</th>
<th align="right">日本語オリジナル 12</th>
<th align="right">文化知識 4</th>
<th align="right">翻訳・混在 7</th>
<th align="right">合成 8</th>
</tr>
</thead>
<tbody>
<tr>
<td>Jev 1.13</td>
<td align="right">56.33</td>
<td align="right">60.93</td>
<td align="right">47.29</td>
<td align="right">65.71</td>
<td align="right">62.57</td>
</tr>
<tr>
<td>Winnow 12B</td>
<td align="right">48.54</td>
<td align="right">52.20</td>
<td align="right">30.05</td>
<td align="right">47.87</td>
<td align="right">57.01</td>
</tr>
<tr>
<td><strong>saihai-8b (系列 train なし)</strong></td>
<td align="right">47.85</td>
<td align="right">55.38</td>
<td align="right">33.61</td>
<td align="right">46.34</td>
<td align="right">51.50</td>
</tr>
<tr>
<td>KnowLine Gen3</td>
<td align="right">46.41</td>
<td align="right">50.17</td>
<td align="right">29.14</td>
<td align="right">49.00</td>
<td align="right">50.37</td>
</tr>
<tr>
<td>Jebadiah 9B v2</td>
<td align="right">45.20</td>
<td align="right">45.73</td>
<td align="right">32.12</td>
<td align="right">51.22</td>
<td align="right">54.72</td>
</tr>
<tr>
<td>Clef Flash</td>
<td align="right">45.06</td>
<td align="right">51.48</td>
<td align="right">35.37</td>
<td align="right">51.25</td>
<td align="right">49.06</td>
</tr>
<tr>
<td>Imajev 4B 8k</td>
<td align="right">39.02</td>
<td align="right">43.24</td>
<td align="right">22.84</td>
<td align="right">45.33</td>
<td align="right">46.52</td>
</tr>
<tr>
<td>Tev1 4B</td>
<td align="right">37.23</td>
<td align="right">41.41</td>
<td align="right">20.16</td>
<td align="right">41.47</td>
<td align="right">44.62</td>
</tr>
</tbody>
</table>
<p>文化知識 4 は日本語オリジナル 12 の一部です。</p>
<p>系列 train を除いた場合でも、この 8 モデルの中では日本語オリジナル 12 タスクで Jev に次ぐ 2 位で、Winnow 12B (gemma-4-12B-it が大元) より高い結果でした。合成 8 タスクも Jev・Winnow・Jebadiah に次ぐ 4 位です。一方、総合値では Winnow が上ですし、文化知識 4 タスクだけなら Clef が上です。翻訳・混在 7 タスクでは 8 モデル中 6 位で、一般知識の問題ではむしろ他のモデルに負けています。「日本について何でも一番詳しい」とまで強く言える結果にはなりませんでした。</p>
<p>なお、ここでの「系列 train なし」は、追加学習から系列 train を除いたという意味です。評価データと意味的に重複するデータがないことや、基盤モデルの事前学習で触れていないことまでは確認していません。</p>
<h1>量子化と llama.cpp 対応</h1>
<p>saihai-8b の GGUF は BF16・Q8_0・Q6_K・Q4_K_M・Q3_K_M・Q2_K の 6 形式を配布しています。この 6 形式で、S1MB japanese-v1 の全 27 タスク・8,067 件を llama.cpp の native <code>/v1/systemone</code> で評価しました。入力は S1MB 標準の llama.cpp adapter で変換し、4 並列、1 slot あたり 8,192 tokens、cache 再利用ありと、6 形式とも同じ条件です。</p>
<table>
<thead>
<tr>
<th>形式</th>
<th align="right">サイズ (GB)</th>
<th align="right">Task Avg</th>
<th align="right">BF16 との差</th>
<th align="right">BF16 との argmax 一致率 (%)</th>
</tr>
</thead>
<tbody>
<tr>
<td>BF16</td>
<td align="right">17.19</td>
<td align="right">49.53</td>
<td align="right">0.00</td>
<td align="right">100.00</td>
</tr>
<tr>
<td>Q8_0</td>
<td align="right">9.13</td>
<td align="right">49.50</td>
<td align="right">-0.03</td>
<td align="right">99.03</td>
</tr>
<tr>
<td>Q6_K</td>
<td align="right">7.05</td>
<td align="right">49.24</td>
<td align="right">-0.29</td>
<td align="right">97.51</td>
</tr>
<tr>
<td>Q4_K_M</td>
<td align="right">5.30</td>
<td align="right">48.87</td>
<td align="right">-0.66</td>
<td align="right">92.10</td>
</tr>
<tr>
<td>Q3_K_M</td>
<td align="right">4.37</td>
<td align="right">46.98</td>
<td align="right">-2.56</td>
<td align="right">87.07</td>
</tr>
<tr>
<td>Q2_K</td>
<td align="right">3.50</td>
<td align="right">38.08</td>
<td align="right">-11.46</td>
<td align="right">71.63</td>
</tr>
</tbody>
</table>
<p>argmax 一致率は、最も確率が高い候補が GGUF の BF16 版と一致した割合で、正解率ではありません。また、Score は数値段階の期待値で採点するため、argmax が一致してもスコアが変わることがあります。</p>
<p>Q8_0 は BF16 との差が 0.03 点ほどで、総合値をほぼ維持しています。Q4_K_M でも低下は 0.66 点ほどですが、argmax 一致率は 92.10% でした。点数が近くても、確率をそのまま使う処理まで同じ挙動になるとは限らないですね。Q3_K_M は約 4.37 GB まで小さくなりますが低下は 2.56 点、Q2_K では 11.46 点と大きく下がりました。これを見ると、ほぼ同等の性能を維持できる Q8_0 や、ベンチマークレベルでは劣化がかなり少ない Q4_K_M あたりが、量子化モデルとしては使いやすそうですね。</p>
<p>速度と VRAM も測っています。RTX 5090 で、同じ 27 タスク・8,067 件を 4 並列で評価したときの処理速度と、GPU メモリ使用量の最大値です。</p>
<table>
<thead>
<tr>
<th>形式</th>
<th align="right">判断/秒</th>
<th align="right">BF16 比</th>
<th align="right">peak VRAM (GiB)</th>
</tr>
</thead>
<tbody>
<tr>
<td>BF16</td>
<td align="right">24.28</td>
<td align="right">1.00x</td>
<td align="right">19.22</td>
</tr>
<tr>
<td>Q8_0</td>
<td align="right">30.44</td>
<td align="right">1.25x</td>
<td align="right">12.39</td>
</tr>
<tr>
<td>Q6_K</td>
<td align="right">28.38</td>
<td align="right">1.17x</td>
<td align="right">10.64</td>
</tr>
<tr>
<td>Q4_K_M</td>
<td align="right">30.58</td>
<td align="right">1.26x</td>
<td align="right">9.21</td>
</tr>
<tr>
<td>Q3_K_M</td>
<td align="right">31.07</td>
<td align="right">1.28x</td>
<td align="right">8.43</td>
</tr>
<tr>
<td>Q2_K</td>
<td align="right">26.56</td>
<td align="right">1.09x</td>
<td align="right">7.70</td>
</tr>
</tbody>
</table>
<p>量子化すると BF16 より 1.1〜1.3 倍ほど速くなり、VRAM は Q8_0 で約 12 GiB、Q4_K_M なら 10 GiB を切ります。一方で、Q8_0 以下は速度にあまり差がなく、Q2_K はむしろ遅くなりました。速度面でも、Q8_0 か Q4_K_M あたりが選びやすそうです。</p>
<p>この速度は、HTTP 通信や採点・保存まで含めた評価全体の処理速度で、1 件あたりのレイテンシではありません。また、1 回だけの計測で、精度の評価とは別に実行しています (重みは配布版と同じですが、64K コンテキスト対応のメタデータ更新前の GGUF で計測しています)。VRAM はドライバなどを含めた観測値です。</p>
<p>なお、Transformers 版の Task Avg は 49.77、GGUF の BF16 版は 49.53 と少し差があります。これは、Transformers 版は saihai 独自の入力変換、GGUF 版は S1MB 標準 adapter の入力変換で評価していて、Score などの表現が異なるためで、量子化による差ではありません。</p>
<p>そのほかの補足です。</p>
<ul>
<li>コンテキスト長は 64K としていますが、今回の評価は短いタスクばかりなので、64K の長い入力での判断品質までは確認できていません。</li>
<li>計測には、llama.cpp の revision <code>3d65c90</code> に、LLM-jp tokenizer の修正 (<a href="https://github.com/ggml-org/llama.cpp/pull/28864">PR #28864</a>) のパッチを当てたものを使っています。この tokenizer の修正パッチを使わないと、若干 token のずれが発生します。将来的には llama.cpp に取り込まれると思います。</li>
</ul>
<h1>Decision モデルと、ベンチマークを作っての感想</h1>
<p><a href="https://huggingface.co/spaces/hotchpotch/S1MB-leaderboard?category=english-v1">S1MB の英語 leaderboard</a> では、すでに 個人や企業が独自に作った 100 以上の Decision モデルが評価されており、ベンチマーク上は Jev よりも性能の高いモデルも出てきています。また、ちょっとした性能のモデルなら、雑にファインチューニングするだけでも作れてしまいます。実際、自分も今回作ってみたのですが、パッと見ある程度うまく機能していそうなモデルは、性能の良い基盤モデルを使えば簡単に作ることができました。saihai-8b も、RTX 5090 1 枚でファインチューニングにかかった時間は 4 時間弱と、短時間で作れています。</p>
<p>ただ Jev の素晴らしいところは、汎化性能が高く、ほとんどの問題に対して適切な回答を選べていることだと思います。そしてこれは、S1MB をはじめ、現在出ているベンチマークでは、まだまだうまく計測できているとは言い難い状況です。TypeSafe AI は、Jev のプレビューリリース時の利用規約で、性能の誤解を招くためなのか、ベンチマーク結果の公開を NG としていました (現在の規約ではその条項はなくなりました)。また、CEO の Diogo Almeida 氏も X で以下のように述べています。</p>
<blockquote>
<p>there's a critical difference between benchmaxxed models and ones made by people who truly care about reliability that, by definition, doesn't show up on benchmarks</p>
<p>(we've somewhat learned this for string LLMs...)</p>
</blockquote>
<p><a href="https://x.com/CompleteSkeptic/status/2106883012856336539">https://x.com/CompleteSkeptic/status/2106883012856336539</a></p>
<p>ある側面だけを切り取ったベンチマークでは汎化性能が測れないので、そんなに意味がない、というのは私も同意見です。TypeSafe があらゆる質問に対する性能を測れるベンチマークを公開してくれれば良いのですが (社内にはあるのではないか、と私は勘繰っています)、そうすると「TypeSafe が考える Decision モデルのあらゆるユースケース」が露呈するわけで、先行者利益で走りたい今、わざわざそれを公開する選択はないのでしょう。</p>
<p>では S1MB japanese-v1 も意味がないのでは？という問いには、半分は yes、半分は no かなと思っています。特定の側面だけであっても、ある程度共通の指針で測れるベンチマークは有益です。ただ、それを鵜呑みにすると、本来とても重要な「汎化性能」を無視することになってしまうので、参考程度に見ていただけたらと思います。本当に必要な性能評価は、自分たちのユースケースでどれぐらいの性能が出るのかを測るベンチマークを、自前で用意することなのかなと。</p>
<p>また、Decision モデルの性能と推論コストのバランスを考えると、現在のスイートスポットは 4B あたりな気がしていますが、将来的には 1B 以下のモデルでも十分な性能が出るのではないか、と思っています。小さいモデル、とりわけエンコーダモデルが好きな身としては、小さなサイズで必要十分なモデルが作れると面白そうだなぁと感じています。今回の saihai-310m はまだその域には届いていませんが、その方向への一歩として公開しました。</p>
<h2>参考 URL</h2>
<ul>
<li><a href="https://zenn.dev/ivry/articles/65c1c4242e1156">日本語ベンチマークで Jev の性能を検証する</a></li>
<li><a href="https://huggingface.co/llm-jp/llm-jp-4.1-8b-thinking">基盤モデル: llm-jp-4.1-8b-thinking</a></li>
<li><a href="https://huggingface.co/llm-jp/llm-jp-4.1-32b-a3b-thinking">日本語合成データの生成モデル: llm-jp-4.1-32b-a3b-thinking</a></li>
<li><a href="https://github.com/hotchpotch/saihai">saihai 学習コード</a></li>
<li><a href="https://huggingface.co/datasets/hotchpotch/saihai-v1-dataset">saihai 学習データ</a></li>
<li><a href="https://secon.dev/entry/2026/09/30/100000-bekko-system-one-v0-release/">bekko-system-one-v0 の公開記事</a></li>
<li><a href="https://github.com/hotchpotch/bekko-system-one/blob/main/docs/saihai-v1-310m.md">saihai-310m の学習ドキュメント (bekko-system-one)</a></li>
<li><a href="https://huggingface.co/datasets/hotchpotch/saihai-v1-310m-dataset">saihai-310m 学習データ</a></li>
<li><a href="https://huggingface.co/cl-nagoya/ruri-v3-reranker-310m">saihai-310m の基盤モデル: ruri-v3-reranker-310m</a></li>
<li><a href="https://github.com/hotchpotch/S1MB">S1MB 評価コード</a></li>
<li><a href="https://huggingface.co/spaces/hotchpotch/S1MB-leaderboard?category=japanese-v1">S1MB 日本語 leaderboard</a></li>
<li><a href="https://huggingface.co/spaces/hotchpotch/S1MB-leaderboard?category=english-v1">S1MB 英語 leaderboard</a></li>
<li><a href="https://huggingface.co/datasets/hotchpotch/S1MB-english-v1">S1MB 英語ベンチマークデータ (english-v1)</a></li>
<li><a href="https://developers.openai.com/api/docs/guides/decisions">GPT-6 Luna: OpenAI Decisions API</a></li>
<li><a href="https://huggingface.co/datasets/hotchpotch/s1mb-result">S1MB 評価結果</a></li>
<li><a href="https://huggingface.co/perplexity-ai/pplx-decider-v1-27b">pplx-decider-v1-27b</a></li>
<li><a href="https://github.com/ggml-org/llama.cpp/blob/master/tools/server/server-decision.cpp">llama.cpp の Decision readout 実装</a></li>
</ul>]]></description>
            <link>https://secon.dev/entry/2026/10/15/100000-saihai-japanese-decision-benchmark</link>
            <guid isPermaLink="false">/entry/2026/10/15/100000-saihai-japanese-decision-benchmark</guid>
            <dc:creator><![CDATA[secondlife / @hotchpotch / Yuichi Tateno]]></dc:creator>
            <pubDate>Thu, 15 Oct 2026 01:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[ブラウザ上でも動く、超小型な System One Decision モデル bekko-system-one を公開]]></title>
            <description><![CDATA[<p>TypeSafe AI の System One Decision モデル、<a href="https://docs.typesafe.ai/concepts/system-one">Jev</a> が、汎用性能が非常に高く、いわゆる classification task で解ける課題なら LLM よりも圧倒的に安価・高速で話題ですね。</p>
<p>そこで今回、小型なモデルだとどれぐらいの性能が出せるのだろうと、System One Decision モデル の <a href="https://github.com/hotchpotch/bekko-system-one">bekko-system-one-v0</a>（以下 BS1）シリーズを制作してみました。汎化性能は Jev の方が圧倒的に上ですが、S1MB（System One Mosaic Benchmark）（注：著者作）では、小さなモデルながら、ほかの大きなサイズのモデル並みの結果が得られています。とりわけ、学習しているドメインのタスクでは、なかなかの精度で利用が可能です。</p>
<ul>
<li>🤗 <a href="https://huggingface.co/collections/hotchpotch/bekko-system-one-v0-6abc47eab9c4fe4ec83d9e30">bekko-system-one collection</a></li>
</ul>
<p>なお対応言語は、英語のみとなっています...。</p>
<h2>ブラウザ上で実行可能</h2>
<p>本モデル(英語のみ対応)は <a href="https://huggingface.co/hotchpotch/bekko-system-one-v0-17m">17M</a>、<a href="https://huggingface.co/hotchpotch/bekko-system-one-v0-68m">68M</a>、<a href="https://huggingface.co/hotchpotch/bekko-system-one-v0-400m">400M</a> パラメーターの3つのサイズのモデルを公開しており、とりわけ 17M や 68M の小型モデルは、ブラウザ上にモデルをロードし、CPU での推論も十分な速度で可能です。</p>
<ul>
<li><a href="https://huggingface.co/spaces/hotchpotch/bekko-system-one-in-browser">ブラウザ上でモデルを動かし、推論するデモ</a></li>
</ul>
<p><img src="https://storage.googleapis.com/secons-site-images/other/blog_images/20260930-bekko-s1-browser.webp" alt="bekko-system-one のブラウザデモ：17M モデルを CPU で実行した結果"></p>
<p>注意: なおこのデモは、BS1 モデルで解きやすいタスクを恣意的に選んでいるため、ぱっと見の性能は良さそうですが、Jev のような「幅広いタスクで高性能」なわけではないので、ご注意ください。</p>
<p>また、17M パラメーターというのは、総パラメーター数が約17Mで、そのうち埋め込みを除くパラメーター数は、たったの約4Mです（ここでは Active Parameters - AP と呼びます）。ブラウザ実行用に、token の lookup table だけを INT8 にしたものを ONNX へと変換しており、モデルファイル単体のサイズは、たったの約29MBとなります。</p>
<h2>評価ベンチマーク</h2>
<p>ブラウザで動いたとして、実際のモデルとしての性能はどんな感じでしょうか。というわけで評価をしてみました。<a href="https://huggingface.co/spaces/hotchpotch/S1MB-leaderboard">S1MB - System One Mosaic Benchmark</a> という、私作のベンチマークを使っています。このベンチマークは、後述のデータセットのうち、test set のデータを中心に、原則100ケースを抽出した、137個(Noul 59, Choice 57, Score 21)のベンチマークで構成されており、Noul、Choice、Score の3軸で評価しています。</p>
<p>S1MB については、<a href="https://huggingface.co/blog/hotchpotch/system-one-mosaic-benchmark/">S1MB記事</a>で書いているので、詳細は割愛しますが、総パラメーター数500M以下に絞ると以下のような結果です。BS1 も、超小型としては、かなり健闘しているのではないでしょうか。なお比較のために Jev 1.13 も載せています。</p>
<table>
<thead>
<tr>
<th>Model</th>
<th align="right">Avg</th>
<th align="right">Noul</th>
<th align="right">Choice</th>
<th align="right">Score</th>
<th align="right">Total Params</th>
<th align="right">Active Params</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="https://docs.typesafe.ai/models">Jev 1.13</a></td>
<td align="right">59.59</td>
<td align="right">64.63</td>
<td align="right">67.22</td>
<td align="right">46.92</td>
<td align="right">—</td>
<td align="right">—</td>
</tr>
<tr>
<td><a href="https://huggingface.co/hotchpotch/bekko-system-one-v0-400m">bekko-system-one-v0-400m</a></td>
<td align="right">50.60</td>
<td align="right">51.24</td>
<td align="right">61.32</td>
<td align="right">39.25</td>
<td align="right">395M</td>
<td align="right">343M</td>
</tr>
<tr>
<td><a href="https://huggingface.co/hotchpotch/bekko-system-one-v0-68m">bekko-system-one-v0-68m</a></td>
<td align="right">40.46</td>
<td align="right">42.91</td>
<td align="right">51.62</td>
<td align="right">26.85</td>
<td align="right">68M</td>
<td align="right">42M</td>
</tr>
<tr>
<td><a href="https://huggingface.co/hotchpotch/bekko-system-one-v0-17m">bekko-system-one-v0-17m</a></td>
<td align="right">27.57</td>
<td align="right">31.43</td>
<td align="right">35.57</td>
<td align="right">15.70</td>
<td align="right">17M</td>
<td align="right">4M</td>
</tr>
<tr>
<td><a href="https://huggingface.co/wfzyx/von">von</a></td>
<td align="right">16.21</td>
<td align="right">20.15</td>
<td align="right">23.99</td>
<td align="right">4.48</td>
<td align="right">395M</td>
<td align="right">343M</td>
</tr>
<tr>
<td><a href="https://huggingface.co/convaiinnovations/laya-typed-decisions">laya-typed-decisions</a></td>
<td align="right">15.00</td>
<td align="right">20.06</td>
<td align="right">18.93</td>
<td align="right">5.99</td>
<td align="right">421M</td>
<td align="right">370M</td>
</tr>
<tr>
<td><a href="https://huggingface.co/convaiinnovations/laya">laya</a></td>
<td align="right">13.36</td>
<td align="right">20.19</td>
<td align="right">16.31</td>
<td align="right">3.58</td>
<td align="right">421M</td>
<td align="right">370M</td>
</tr>
<tr>
<td><a href="https://huggingface.co/convaiinnovations/laya-multilingual">laya-multilingual</a></td>
<td align="right">9.28</td>
<td align="right">14.01</td>
<td align="right">13.03</td>
<td align="right">0.79</td>
<td align="right">322M</td>
<td align="right">125M</td>
</tr>
</tbody>
</table>
<p>AvgはNoul・Choice・Scoreの調整済みスコアを等重みで平均した値です。各スコアは高いほど良く、正解率そのものではありません。</p>
<p>しかしながら、S1MB に含まれる「汎化性能を計測する」ベンチマーク(GPT-6-Astra で生成した合成データセット)では、BS1 モデルは圧倒的に性能が悪いです。これは「特定ドメインを学習したデータセットなら、ある程度の性能は出るが、自由な指示や未知のドメインについては弱い」と言えるでしょう。なので、今回公開した BS1 も「汎化性能を持った System One Decision モデルに達していない」ことから version 0 として、<code>-v0</code> suffix をつけています。</p>
<p>全体評価と同じモデルについて、汎化性能の6ベンチマークに絞った結果です。Avg順に並べています。</p>
<table>
<thead>
<tr>
<th>Model</th>
<th align="right">Avg</th>
<th align="right">General Noul</th>
<th align="right">General Choice</th>
<th align="right">General Score</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="https://docs.typesafe.ai/models">Jev 1.13</a></td>
<td align="right">96.27</td>
<td align="right">99.00</td>
<td align="right">98.68</td>
<td align="right">91.14</td>
</tr>
<tr>
<td><a href="https://huggingface.co/hotchpotch/bekko-system-one-v0-400m">bekko-system-one-v0-400m</a></td>
<td align="right">54.48</td>
<td align="right">52.00</td>
<td align="right">80.30</td>
<td align="right">31.14</td>
</tr>
<tr>
<td><a href="https://huggingface.co/wfzyx/von">von</a></td>
<td align="right">43.19</td>
<td align="right">41.00</td>
<td align="right">65.89</td>
<td align="right">22.67</td>
</tr>
<tr>
<td><a href="https://huggingface.co/hotchpotch/bekko-system-one-v0-68m">bekko-system-one-v0-68m</a></td>
<td align="right">32.48</td>
<td align="right">31.00</td>
<td align="right">57.52</td>
<td align="right">8.90</td>
</tr>
<tr>
<td><a href="https://huggingface.co/convaiinnovations/laya-typed-decisions">laya-typed-decisions</a></td>
<td align="right">31.82</td>
<td align="right">22.00</td>
<td align="right">58.80</td>
<td align="right">14.67</td>
</tr>
<tr>
<td><a href="https://huggingface.co/convaiinnovations/laya">laya</a></td>
<td align="right">26.50</td>
<td align="right">9.00</td>
<td align="right">54.83</td>
<td align="right">15.67</td>
</tr>
<tr>
<td><a href="https://huggingface.co/hotchpotch/bekko-system-one-v0-17m">bekko-system-one-v0-17m</a></td>
<td align="right">18.96</td>
<td align="right">15.00</td>
<td align="right">39.11</td>
<td align="right">2.76</td>
</tr>
<tr>
<td><a href="https://huggingface.co/convaiinnovations/laya-multilingual">laya-multilingual</a></td>
<td align="right">14.47</td>
<td align="right">6.00</td>
<td align="right">36.67</td>
<td align="right">0.75</td>
</tr>
</tbody>
</table>
<p>なお、Jev はドメイン特化性能（特別にそのドメインを学習したわけではないのに、すごいですね）も、汎化性能も、特筆したスコアですね。とりわけ汎化性能のスコアについては、ほぼほぼ満点と言えるでしょう。つまり、汎化性能が高い System One Decision モデルを名乗るには、最低限この汎化性能ベンチマークで、Jev 並みのスコア（つまりほぼ満点）を出せないと、あまり意味がないと思っています。</p>
<h2>モデルサイズと推論速度</h2>
<p>BS1 モデルで、特筆すべきことはモデルサイズと推論速度です。GPU（RTX 5090）を使ったS1MBの26,269件の評価処理は、17Mで約13.33秒、68Mで約34.04秒、400Mで約132.97秒（約2分13秒）でした。17Mでは、モデルロードと各ベンチマークのデータ読み込みなどを含む計測区間の合計でも約21.38秒です。冒頭のデモのように、ブラウザ上でも現実的に動きます。</p>
<p>なおJevはAPI経由となり、通信待ちなどを含む各ベンチマークの評価時間の合計は約58分37秒でした。APIの応答時間はタイミングによって前後するでしょう。ここで示した値は評価処理の計測値で、純粋なモデル計算だけの時間ではありません。また、17Mの約21.38秒もwarmupなどを除く区間の合算で、コマンド開始から終了までの時間ではありません。</p>
<h2>技術アーキテクチャでの取り組み</h2>
<p>Bekko System One（以下 BS1）で工夫したのは、複数の選択肢を判定するときに、共通する入力の処理を使い回すことです。その方法の前に、まず一般的な encoder model で、Jev のような処理をする、よくある方法の二つを解説しましょう。</p>
<h3>cross encoder</h3>
<p>通常の双方向 encoder を使う cross encoder では、以下のように、共通する入力と選択肢を組み合わせて処理します。特殊トークンは模式的な表記です。</p>
<pre><code class="hljs language-text">[CLS] {state} {instruction} [SEP] {criteria A} [SEP]
[CLS] {state} {instruction} [SEP] {criteria B} [SEP]
[CLS] {state} {instruction} [SEP] {criteria C} [SEP]</code></pre>
<p>先頭の CLS トークンの表現や、トークンの表現を平均したベクトル（mean pooling）を、学習済みの head に渡してスコアを求めます。情報検索の reranker でも広く使われている方式です。</p>
<p>入力と選択肢がお互いを参照できるため、細かな対応関係を捉えられます。しかしながら、state が長いと、同じ文章を選択肢の数だけ処理することになります。前半の表現も後半の選択肢によって変わるため、前半が同じ文字列でも、途中の計算結果をそのまま使い回せないのです。</p>
<p>なお情報検索の reranker では、前半に配置する検索クエリが短いことがほとんどのため、共有による計算量削減の効果が小さく、cross encoder でも良いケースが多いですね。</p>
<h3>listwise encoder</h3>
<p>それなら、選択肢をまとめて一回で処理しちゃおう、という方法もあります。全候補を連結する listwise 方式では、例えば以下のように入力します。</p>
<pre><code class="hljs language-text">{state} {instruction} [SEP]
{criteria A} [SEP] {criteria B} [SEP] {criteria C} [SEP]</code></pre>
<p>候補ごとの表現や候補前後の特殊トークンを pooling するなどして、スコアを求めます。共通部分を一度で処理でき、選択肢同士も参照できるのが利点です。</p>
<p>一方、候補が多いと入力全体が長くなります。全トークン間で attention を計算する場合、その計算量は長さの二乗に比例するため、多数の候補をまとめると負担が増えます。cross encoder より常に遅いということではなく、文章の長さや候補数によって向き不向きがあります。</p>
<h3>BS1 の方法 - 共有 prefix</h3>
<p>BS1 では、state と instruction を一つの共有部分（prefix）として処理し、各層の Key/Value、いわゆる K/V を保存して使い回します。</p>
<pre><code class="hljs language-text">{state} {instruction} → 各層の共有 K/V
                          ├─ {criteria A} → score A
                          ├─ {criteria B} → score B
                          └─ {criteria C} → score C</code></pre>
<p>普通の cross encoder と何が違うの？と思われるかもしれませんが、ここでは参照できる範囲を変えています。共有 prefix は選択肢を参照せず、各選択肢は共有 prefix と自分自身だけを参照します。これなら、選択肢が変わっても共有部分の計算結果は変わらないため、一度計算した K/V を再利用できます。</p>
<p>LLM の KV cache と同じように K/V を保存しますが、次のトークンを一つずつ生成するわけではありません。共有部分を処理した後、各選択肢を並列に処理し、候補側の表現を mean pooling して head からスコアを求めます。</p>
<p>候補側だけを pooling していますが、候補の文章しか見ていないわけではありません。各候補は各層で共有部分を参照するため、state と instruction を踏まえた表現になっています。一方、共有部分の先頭に置いた CLS トークンは候補を参照できないので、その表現だけでは候補ごとの判定はできません。</p>
<p>これによって、長い state と instruction を選択肢ごとに処理し直す必要がなくなります。ただし、通常の cross encoder と同じ計算を、そのまま高速化したものではありません。通常の cross encoder では、候補に応じて入力側の表現も変わり、その情報を候補側が再び参照できます。BS1 では、この相互のやり取りを制限する代わりに、共有部分の計算を使い回しています。</p>
<p>そのぶん、細かな対応関係を捉える自由度は通常の cross encoder の方が高いと考えられます。ただ、実際の精度差はタスクや学習条件にもよるでしょう。</p>
<p>なお、state と instruction はまとめて双方向に処理しています。state だけを独立してキャッシュしているわけではないため、instruction を変えた場合は共有部分を再計算します。</p>
<p>また、今回は、criteria 同士が参照できるような attention は含めてません。本来、例えば Choice のようなケースですと、他の criteria を参照した上で回答した方が精度がありそうですが、短時間で試しただけでは、精度が上がる学習ができなかったです。なおこれは無理だ、と言っているわけではなく、私が試した方法でうまくいかなかっただけの可能性も十分あるでしょう。</p>
<h2>大元の base model</h2>
<p>大元の base model としては、<a href="https://huggingface.co/answerdotai/ModernBERT-base">ModernBERT</a> アーキテクチャの英語高性能モデルである <a href="https://arxiv.org/abs/2507.11412">Ettin-encoder</a> を、さらに教師 reranker モデルを用い cross encoder として学習した <a href="https://huggingface.co/cross-encoder/ettin-reranker-17m-v1">Ettin-reranker</a> を利用しています。</p>
<p>ModernBERT などの MLM、いわゆる pretrained model の状態では、検索クエリとドキュメントの関連度を直接スコア化するようには学習していません。情報検索向けデータを学習した Dense Embedding モデルや、cross encoder モデルでは、文章とドキュメントの関連性を理解しているため、今回はすでにそれらを学習済みの Ettin-reranker を使っています。小型ながら、英語 rerank 性能は非常に高いです。今回の BS1 では、Ettin-reranker を base model として用い、追加学習を行いました。</p>
<p>以下は Ettin-encoder、Ettin-reranker を base model とし、各データセットに上限を適用した学習データの全量を、同じ条件で学習させた対照実験の結果です。68Mではreranker初期化が総合CE・各型のaccuracyで良く、17Mでは総合CEは僅差で、Noul・Choiceはreranker、Scoreはencoderが良い結果でした。</p>
<table>
<thead>
<tr>
<th>サイズ</th>
<th>初期化モデル</th>
<th align="right">総合CE ↓</th>
<th align="right">Noul accuracy ↑</th>
<th align="right">Choice accuracy ↑</th>
<th align="right">Score accuracy ↑</th>
</tr>
</thead>
<tbody>
<tr>
<td>17M</td>
<td>Ettin-encoder</td>
<td align="right">0.8694</td>
<td align="right">68.71%</td>
<td align="right">60.14%</td>
<td align="right">56.57%</td>
</tr>
<tr>
<td>17M</td>
<td>Ettin-reranker</td>
<td align="right">0.8713</td>
<td align="right">69.88%</td>
<td align="right">60.77%</td>
<td align="right">53.88%</td>
</tr>
<tr>
<td>68M</td>
<td>Ettin-encoder</td>
<td align="right">0.7625</td>
<td align="right">72.87%</td>
<td align="right">69.78%</td>
<td align="right">58.16%</td>
</tr>
<tr>
<td>68M</td>
<td>Ettin-reranker</td>
<td align="right">0.7180</td>
<td align="right">77.01%</td>
<td align="right">71.13%</td>
<td align="right">61.34%</td>
</tr>
</tbody>
</table>
<p>CEは小さいほど良く、accuracyは大きいほど良い指標です。データセットごとに集計し、二つの入力順序の結果を平均しています。前掲の調整済みスコアとは指標が異なります。各条件1 seedでの比較です。</p>
<h2>データセット</h2>
<p>データセットでは <a href="https://huggingface.co/datasets/hotchpotch/bekko-system-one-dataset-v0">hotchpotch/bekko-system-one-dataset-v0</a> を利用しています。このデータセットは、既存の NLP や情報検索関連のデータセットを、Noul、Choice、Score の3形式として学習しやすいように変換した 153 個の学習データセットで、training set は約659万ケースとなっています。一部は合成データセットも追加してあります。なお、このデータセットの test set は S1MB のベンチマークにも転用しているので、同じドメインの training set で学習した BS1 は S1MB の一部ベンチマークのスコアが上がりやすくなっています。</p>
<p>BS1 では、このデータセットを用いて学習を行いました。学習には RTX 5090 を用い、17M の学習では、たった2時間で学習を終えました。なお 68M では5.5時間、400M では約25時間でした。</p>
<h2>学習のハイパーパラメーター</h2>
<p>学習のハイパーパラメーターやデータセットの件数などは、細かくは解説しませんが、<a href="https://arxiv.org/abs/2607.25180v1">bekko-embedding 論文</a>（私作の、超小型マルチリンガル dense retrieval model の論文です）で書かれている知見を主に、いくつかパラメーターを試し、その範囲で良い結果が得られた値を使っています。</p>
<table>
<thead>
<tr>
<th>項目</th>
<th>17M</th>
<th>68M</th>
<th>400M</th>
</tr>
</thead>
<tbody>
<tr>
<td>Optimizer</td>
<td>AdamW</td>
<td>AdamW</td>
<td>AdamW</td>
</tr>
<tr>
<td>Batch size</td>
<td>512</td>
<td>512</td>
<td>512</td>
</tr>
<tr>
<td>Encoder learning rate</td>
<td>1e-4</td>
<td>3e-5</td>
<td>1e-5</td>
</tr>
<tr>
<td>Head learning rate</td>
<td>5e-4</td>
<td>2e-4</td>
<td>2e-4</td>
</tr>
<tr>
<td>Weight decay</td>
<td>0.01</td>
<td>0.01</td>
<td>0.01</td>
</tr>
<tr>
<td>Warmup ratio</td>
<td>10%</td>
<td>10%</td>
<td>10%</td>
</tr>
<tr>
<td>Learning-rate schedule</td>
<td>Cosine</td>
<td>Cosine</td>
<td>Cosine</td>
</tr>
<tr>
<td>Query / candidate上限</td>
<td>4,096 / 2,048 tokens</td>
<td>4,096 / 2,048 tokens</td>
<td>4,096 / 2,048 tokens</td>
</tr>
</tbody>
</table>
<p>学習用の実装も公開しているので、この実装を使うことで、同様のモデルを学習可能です。興味がある方は、ご利用ください。</p>
<ul>
<li><a href="https://github.com/hotchpotch/bekko-system-one">bekko-system-one：学習・推論コード</a></li>
</ul>
<h2>超小型の System One Decision モデルは実現可能なのか？</h2>
<p>将来は、S1MB の汎化性能ベンチマークでも Jev 並みのスコアに達する、アクティブなパラメーターサイズが100M以下といった、超小型なモデルも可能である、と思っています。それを達成するための、最も重要なことは、学習に必要な高品質な合成データセットです。</p>
<p>TypeSafe AI CEO の Diogo Almeida 氏も「<a href="https://x.com/CompleteSkeptic/status/2100617775823966680">100% of our data is synthetic (but not the type of crap that is just spit out from an LLM obviously)</a>」と言っているように、Noul、Choice、Score で、ありとあらゆる質問と適切なスコアの合成データセットが用意できれば、超小型モデルも実現可能だと思っています。どうしても「モデルアーキテクチャ」に目線が行きがちですが、高品質で齟齬がない多様な合成データセットをどのように作り、それをどのように学習するか、が肝心でしょう。</p>
<p>実際に、私作のマルチリンガル情報検索モデルである <a href="https://huggingface.co/hotchpotch/bekko-embedding-v1-a8m">bekko-embedding</a> シリーズでは、10億以上のデータ（うち1.6億件が合成データセット）を、巨大バッチで学習させることにより、アクティブパラメーターサイズが 8M、25M という超小型サイズのモデルで数倍〜数十倍の情報検索モデルに匹敵する情報検索モデルが作れています。</p>
<p>続いての重要なことは、強力な base model の登場です。実用的なテキスト生成能力を持つ LLM（decoder）を超小型にするのは難しいため、文字列生成にこだわらなければ、もっと小型で性能が良い base model が作れるでしょう。ModernBERT はその例だと思いますが、現状のさらに発展し続けている LLM のモデルアーキテクチャを使い、さらに小型モデルでより良いアーキテクチャと、大量の多様なデータを学習させた base model があれば、その継続タスクの学習に効いてくるでしょう。ただし、合成データセットの方が重要度は非常に高いとは思っています。</p>
<h2>終わりに</h2>
<p>TypeSafe AI の System One Decision モデル、Jev の登場により、汎化性能が高い Classification model の有益性が証明されました。TypeSafe AI の素晴らしい点は、中途半端な汎化性能で出すのでなく、フロンティア LLM に並ぶ性能の超汎化性能を持つモデルを作り上げ、出したことでしょう。</p>
<p>Classification で解決できる課題は、思った以上に広いです。BERT 以降、分類やスコア付けなどの NLP タスクでは Transformer encoder が広く使われてきました。</p>
<p>本記事では、学習したタスクなら、ブラウザ上でも動くほど小さなモデルである程度の精度を出せる、bekko-system-one-v0 を作ったお話でした。学習済みのタスクで小型モデルを試したり、独自データで追加学習したりするための出発点として、モデル・データセット・学習コードを公開しています。</p>
<p>幅広い未知のタスクへの対応は、今後の課題です。前項で述べたとおり、大量の良質なデータセットや、小型モデルアーキテクチャの進化により、十分な汎化性能を持った System One Decision モデルは、きっと開発されるはずです。</p>
<p>この bekko-system-one-v0 が、何らかの価値につながれば幸いです。</p>
<h1>参考URL</h1>
<h2>bekko-system-one</h2>
<ul>
<li><a href="https://huggingface.co/collections/hotchpotch/bekko-system-one-v0-6abc47eab9c4fe4ec83d9e30">bekko-system-one collection</a></li>
<li><a href="https://huggingface.co/hotchpotch/bekko-system-one-v0-17m">bekko-system-one-v0-17m</a></li>
<li><a href="https://huggingface.co/hotchpotch/bekko-system-one-v0-68m">bekko-system-one-v0-68m</a></li>
<li><a href="https://huggingface.co/hotchpotch/bekko-system-one-v0-400m">bekko-system-one-v0-400m</a></li>
<li><a href="https://huggingface.co/spaces/hotchpotch/bekko-system-one-in-browser">ブラウザデモ</a></li>
<li><a href="https://github.com/hotchpotch/bekko-system-one">学習・推論コード</a></li>
<li><a href="https://huggingface.co/datasets/hotchpotch/bekko-system-one-dataset-v0">学習データセット</a></li>
</ul>
<h2>S1MB</h2>
<ul>
<li><a href="https://github.com/hotchpotch/S1MB">評価コード</a></li>
<li><a href="https://huggingface.co/datasets/hotchpotch/s1mb-dataset">評価データセット</a></li>
<li><a href="https://huggingface.co/datasets/hotchpotch/s1mb-result">評価結果リポジトリ</a></li>
<li><a href="https://huggingface.co/spaces/hotchpotch/S1MB-leaderboard">Leaderboard</a></li>
<li><a href="https://huggingface.co/blog/hotchpotch/system-one-mosaic-benchmark/">S1MB の紹介記事</a></li>
</ul>
<h2>base model・関連モデル・資料</h2>
<ul>
<li><a href="https://docs.typesafe.ai/concepts/system-one">TypeSafe AI — System One / Jev</a></li>
<li><a href="https://docs.typesafe.ai/models">TypeSafe AI — モデル一覧</a></li>
<li><a href="https://x.com/CompleteSkeptic/status/2100617775823966680">Diogo Almeida 氏の合成データについての投稿</a></li>
<li><a href="https://github.com/NandhaKishorM/laya">Laya：コード</a> / <a href="https://huggingface.co/convaiinnovations/laya">モデル</a></li>
<li><a href="https://huggingface.co/answerdotai/ModernBERT-base">ModernBERT-base</a></li>
<li><a href="https://arxiv.org/abs/2507.11412">Ettin：Seq vs Seq 論文</a></li>
<li><a href="https://huggingface.co/cross-encoder/ettin-reranker-17m-v1">Ettin-reranker-17m-v1</a></li>
<li><a href="https://huggingface.co/cross-encoder/ettin-reranker-68m-v1">Ettin-reranker-68m-v1</a></li>
<li><a href="https://huggingface.co/cross-encoder/ettin-reranker-400m-v1">Ettin-reranker-400m-v1</a></li>
<li><a href="https://huggingface.co/hotchpotch/bekko-embedding-v1-a8m">bekko-embedding-v1-a8m</a></li>
<li><a href="https://huggingface.co/hotchpotch/bekko-embedding-v1-a25m">bekko-embedding-v1-a25m</a></li>
<li><a href="https://arxiv.org/abs/2607.25180v1">Bekko Embedding 論文</a></li>
<li><a href="https://www.sbert.net/examples/cross_encoder/applications/README.html">Sentence Transformers — Cross-Encoders</a></li>
</ul>]]></description>
            <link>https://secon.dev/entry/2026/09/30/100000-bekko-system-one-v0-release</link>
            <guid isPermaLink="false">/entry/2026/09/30/100000-bekko-system-one-v0-release</guid>
            <dc:creator><![CDATA[secondlife / @hotchpotch / Yuichi Tateno]]></dc:creator>
            <pubDate>Wed, 30 Sep 2026 01:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Jev を用い rerank・関連度でフィルターできるライブラリ jev-reranker を公開]]></title>
            <description><![CDATA[<p>TypeSafe.AI の Jev を用いて、検索結果の rerank はもとより、検索に関連しない不要な情報を削除する relevance filter の機能も持った jev-reranker というライブラリを公開しました。</p>
<ul>
<li><a href="https://github.com/hotchpotch/jev-reranker/">https://github.com/hotchpotch/jev-reranker/</a></li>
</ul>
<p>RAG などで検索を利用している場合、検索結果には引っかかるが、回答生成には不要なデータが返ってくることが多くあります。この場合、LLM に全て不要な結果も含め渡すと、処理速度やトークンコストが余計にかかってしまい、場合によってはハルシネーションを起こしかねません。</p>
<p>また全く適切な検索結果がなかった場合は、LLM に渡す前に処理を切り上げたり、別の検索クエリを検討したりできるので、閾値によって不要なデータを削ることができる、スクリーニング用途にも使える relevance rerank filter は単純な並べ替えの rerank よりも重要になるケースが多々あります。本記事の後半でも述べますが、<a href="https://huggingface.co/datasets/hakari-bench/NanoBEIR-en">NanoHotpotQA</a> では、検索候補の約92%を削減しながら、nDCG@10で0.975を達成しています。</p>
<p><img src="https://raw.githubusercontent.com/hotchpotch/jev-reranker/main/assets/relevance_filter_performance.webp" alt="jev-reranker relevance filtering and performance comparison"></p>
<p>イメージとしてはこんな感じで、関連しないドキュメントはスコアがかなり低く出るので、閾値を使った足切りがしやすいですね。</p>
<h2>relevance rerank filter としての利用例</h2>
<p>以下のように簡単に利用ができます。</p>
<pre><code class="hljs language-sh">uv add jev-reranker</code></pre>
<pre><code class="hljs language-python"><span class="hljs-keyword">from</span> jev_reranker <span class="hljs-keyword">import</span> JevReranker

query = <span class="hljs-string">"How long do I have to return an online order to ACME Shop?"</span>
documents = [
    <span class="hljs-string">"ACME Shop accepts online returns within 30 days of delivery."</span>,
    <span class="hljs-string">"For ACME Shop online orders, submit your return request within 30 days of receiving the item."</span>,
    <span class="hljs-string">"ACME Shop in-store purchases can be returned within 14 days of purchase."</span>,
    <span class="hljs-string">"ACME Shop products come with a one-year repair warranty."</span>,
    <span class="hljs-string">"FooBar Shop accepts online returns within 60 days of delivery."</span>,
]

reranker = JevReranker(api_key=<span class="hljs-string">"YOUR-TYPESAFE-API-KEY..."</span>)
response = reranker.relevance_rerank(query, documents, threshold=<span class="hljs-number">0.2</span>)

<span class="hljs-keyword">for</span> item <span class="hljs-keyword">in</span> response[<span class="hljs-string">"results"</span>]:
    <span class="hljs-built_in">print</span>(<span class="hljs-string">f"<span class="hljs-subst">{item[<span class="hljs-string">'score'</span>]:<span class="hljs-number">.2</span>f}</span>  <span class="hljs-subst">{item[<span class="hljs-string">'text'</span>]}</span>"</span>)</code></pre>
<p>結果の出力例は以下です。後半の3つはなんとなく似ていますが、実際は紛らわしい回答なので、閾値未満のため削除されてます。</p>
<pre><code class="hljs language-text">0.98  ACME Shop accepts online returns within 30 days of delivery.
0.97  For ACME Shop online orders, submit your return request within 30 days of receiving the item.</code></pre>
<h2>relevance rerank と rerank は何が違うの？</h2>
<p>ここが Jev の面白いところで、異なるのは<a href="https://github.com/hotchpotch/jev-reranker/blob/main/src/jev_reranker/instructions.py">インストラクション（指示文）</a>のみです。query に強く関連があるかないかだけで評価すると、ソートに適した rerank になりますし、RAG の検索後処理で利用したいような「質問の回答に関連が低いものは極端に低スコア」のような指示文を入れれば、relevance rerank filter として使うことができます。これも Jev の汎化性能の高さゆえですね。</p>
<h2>Jev の評価結果</h2>
<p>今回は、マルチホップ QA データセットである、HotpotQA の情報検索用にサンプリングされたデータセットの NanoHotpotQA に対して、以下のような評価を行いました。</p>
<ul>
<li>NanoHotpotQA を BM25 と dense（<code>harrier-oss-v1-270m</code>）検索を用いて、Hybrid 検索を行い、Top-100 を抽出。もし Top-100 に正解がない場合は 101 件目に正解を挿入</li>
<li>その結果に対して、nDCG@10 の結果を取得</li>
</ul>
<p>つまり query 50 に対し、各々検索結果上位の 100（or 101）件に対して rerank するようなベンチマークタスクです。結果は以下です。</p>
<table>
<thead>
<tr>
<th>方式</th>
<th align="right">閾値</th>
<th align="right">nDCG@10</th>
<th align="right">残留文書 / query</th>
<th align="right">文書削減率</th>
</tr>
</thead>
<tbody>
<tr>
<td>Hybrid search</td>
<td align="right">—</td>
<td align="right">0.833</td>
<td align="right">100件</td>
<td align="right">0%</td>
</tr>
<tr>
<td><code>rerank</code></td>
<td align="right">0.0</td>
<td align="right">0.969</td>
<td align="right">100件</td>
<td align="right">0%</td>
</tr>
<tr>
<td><code>relevance_rerank</code></td>
<td align="right">0.2</td>
<td align="right"><strong>0.975</strong></td>
<td align="right">7.62件</td>
<td align="right"><strong>92.38%</strong></td>
</tr>
</tbody>
</table>
<p>評価方法と再現手順は、<a href="https://github.com/hotchpotch/jev-reranker/blob/main/docs/eval.md">評価スクリプトの利用ガイド</a> にまとめています。今回の評価では NanoBEIR-en の NanoHotpotQA を使い、候補数を制限せず、50クエリそれぞれの hybrid 検索結果100件を対象にしました。採点方式は listwise、閾値は <code>rerank</code> が <code>0.0</code>、<code>relevance_rerank</code> が <code>0.2</code> です。同じスクリプトで Hybrid search の nDCG@10 も確認できます。</p>
<p>特筆すべきは relevance rerank filter の文書の削減率です。これは、閾値（0.2）未満のスコアのものを全て関連しないとして削除した時の削除率で、1 query あたり、100件の検索結果を平均約7.6件にフィルターで効率よく削除・スクリーニングができています。検索ドキュメントのうち、質問に対する関連性が低いと判定された文書約92%も、この段階で削除ができてるのです。</p>
<p>さらに削除した結果の nDCG@10 も <code>0.975</code> と非常に高く、削除したからといって検索結果が劣化しているわけではありません。</p>
<p>RAG のパイプラインで、query に対して検索結果のドキュメント 100 件を取得して、全て後の LLM に渡すと、前述の通り非常に高コストです。しかしながら、この relevance filter を使うことで、1 query あたり平均約7.6件しか渡さずに済んで、かつその中に正解が含まれています。そのため、低い性能の LLM でもハルシネーションを起こす可能性がグッと低くなるでしょう。</p>
<p>このように、jev-reranker の、とりわけ relevance rerank filter を使うことで、query に関係がない検索結果を大幅に削減することが可能なのです。</p>
<p>また、この閾値も柔軟に変更が可能です。例えば見逃すと損害が大きいシステムでは <code>&#x3C;= 0.05</code> などにできますし、検索に関連しなそうなら大胆に結果を削除して良いなら、<code>&#x3C;= 0.5</code> なども考えられるでしょう。また前述の通り、インストラクション文章を変えれば、自分自身のシステムにあった relevance filter を作成することが可能なのです。これが Jev が注目されている、汎化性能の高さですね。</p>
<p>なお、この結果は、<code>jev-1.13.0</code> の結果に基づいています。Jev のモデルが更新されると、結果が異なる可能性が高いです。</p>
<p>余談ですが、高性能 reranker としてよく使われている、reranker に特化した cross-encoder である <a href="https://huggingface.co/BAAI/bge-reranker-v2-m3">bge-reranker-v2-m3</a> 並みの rerank 性能も、手元では確認できているので、気になる方は評価してみてはいかがでしょうか。</p>
<hr>
<h2>なぜ jev-reranker ライブラリを使うのか？</h2>
<p>実際のところ、Jev の API をそのまま叩いても十分機能するのですが、この jev-reranker は情報検索の実利用で便利な機能を最初から実装しています。</p>
<h3>listwise or pointwise（pairwise）</h3>
<p>Jev では、rerank する際に 2 つの手段が考えられます。1 つは <code>[query, doc1, doc2, ...]</code> など 1 つのコンテキストに全て埋め込む listwise の手法、もう 1 つは <code>[[query, doc1], [query, doc2], ...]</code> と、query と doc の pair を毎回リクエストする pointwise の手法、2 パターンがあります。</p>
<p>jev-reranker ではこの 2 つの方法、両方に対応しています。比較してみたところ、基本的に listwise の方が高速かつ精度が良いので、デフォルトは listwise にしていますが、pointwise の方が良いタスクもあるかもしれません。</p>
<p>また、Jev は現状最大で 32k token しか含めないため、とりわけ listwise の 1 req に全てを詰め込む方法では、max token になってしまいがちです。そのため、適切に文字列長 or token 長で分割してリクエストを送るようにしています。本当は Jev tokenizer が公開されていれば、事前に 32k token を超えていないかが観測できるのですが、残念ながらまだライブラリや API 共に token の長さを事前に測る方法は、公開されていないようです。</p>
<h3>並列性</h3>
<p>毎度 1 つ 1 つを直列で叩くと非常に遅いため、最初からある程度並列リクエストを叩きます。そのため、高速な処理が可能です。もちろん、設定で並列数は変えられますし、レートリミットでエラーになった場合は時間をおいて retry 等々の再開・例外処理も実装されています。</p>
<p>そのため、jev-reranker を使うことで、rerank、relevance filter に適したインストラクションプロンプトはもとより、これらの便利機能も利用可能なので、よかったら使ってみてくださいね。</p>
<ul>
<li><a href="https://github.com/hotchpotch/jev-reranker/">https://github.com/hotchpotch/jev-reranker/</a></li>
</ul>
<h2>Jev の感想というお気持ちというか</h2>
<p>Jev は、巷の評判の通り、LLM では遅く、かといってなんらかの特化 model を学習するにはコストが高すぎる、適切にモデルを作成できる人材がいない、ような用途の隙間にピッタリとハマる、汎化性能が高い structured decision モデルです。</p>
<p>また、汎化性能の高さ、というのも魅力です。検索結果はコンテキストによって優先すべき結果が異なるため、それを instruction により制御できることは、今後重宝されていくでしょう。情報検索タスクの一部である reranker や relevance filter としても、現時点でも性能の高さが窺い知れますね。</p>
<p>そんなわけで、Jev の出現は「今までになかった、隙間を埋める汎化モデル」として非常に喜ばしいですね。また Jev のようなモデルが流行ることによって、別の企業・研究機関なども同様の方向性のモデルを出してくる流れになることは間違い無いでしょうから、その点でも Jev の登場は嬉しいですね。今後の AI 関連技術の発展が見えるような、ワクワクするモデルの登場でした。</p>]]></description>
            <link>https://secon.dev/entry/2026/09/20/100000-jev-reranker</link>
            <guid isPermaLink="false">/entry/2026/09/20/100000-jev-reranker</guid>
            <dc:creator><![CDATA[secondlife / @hotchpotch / Yuichi Tateno]]></dc:creator>
            <pubDate>Sun, 20 Sep 2026 01:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[openai-api-server-via-codex を golang に書き換え]]></title>
            <description><![CDATA[<p>以前作った codex サブスクリプション経由で OpenAI 互換APIの変換プロキシ的なツールである <a href="https://github.com/hotchpotch/openai-api-server-via-codex">openai-api-server-via-codex</a>、個人的に便利に使っている。リリース当初はほぼ反響がなかったんだけど、最近 github star がじわじわ増え出して(と言っても現在30だけど…)、PRもいくつかもらったりした。</p>
<p>リリース当初、考えもなくとりあえず python で作ってしまったのだけど、どう考えてもパフォーマンスが悪いし python である理由もないので、golang で書き換える。エーアイ氏に書き換えていただく。これで速攻立ち上がるようになり、利用メモリも10M以下となったので、常時立ち上げっぱなしでも気にならない感じになった。起動自体は互換性を考慮し、uvx 経由で golang バイナリが立ち上がるようにしている。</p>
<img width="70%" src="https://raw.githubusercontent.com/hotchpotch/openai-api-server-via-codex/main/docs/assets/quick-start.png" alt="Start the Go server with uvx, then call the OpenAI-compatible Responses API" />
<hr>
<p>貰ったPR、たまたまかもしれないが、どれも丁寧に作られている。AI Slop 的な PR ではなく、PR がマージしやすいように色々配慮されて作らていてびっくり。コーディングエージェントの性能も上がったので、その辺のやり方もこなれてきている感じがするね。人間が気をかけることが減って、ありがたい限りだね。</p>]]></description>
            <link>https://secon.dev/entry/2026/08/13/200000-openai-api-server-go-rewrite</link>
            <guid isPermaLink="false">/entry/2026/08/13/200000-openai-api-server-go-rewrite</guid>
            <dc:creator><![CDATA[secondlife / @hotchpotch / Yuichi Tateno]]></dc:creator>
            <pubDate>Thu, 13 Aug 2026 11:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Spotify で再生中アートワークを Pixoo 64 で表示]]></title>
            <description><![CDATA[<p><a href="https://divoom.com/products/pixoo-64/">Divoom Pixoo 64</a>という、64x64 ピクセルの解像度が荒い matrix 液晶のデバイスを購入した。<a href="https://tenderlovemaking.com/2026/01/01/pixoo64-ruby-client/">tenderlove氏の記事</a>を読んで、プログラムから制御できそうで面白い、と思ったのがきっかけ。</p>
<p>やりたかったことは、聴いている音楽(Spotifyを愛用してる)のアートワークを部屋のどこかに表示したかったのだ。だいたいPCかスマフォから、部屋のスピーカで音楽を再生しているのだけど、思った以上にアートワークを見る機会がなく、ランダムに流していると、今流れている曲はなんだろう、と知りたい欲求もちょくちょくあって、どこかで常時表示されていてほしい。</p>
<p>というわけでエーアイ氏に実装していただいた。正確には7ヶ月ぐらい前に作って日々使っているのだけど、ちょっと手直しして公開。Pixoo の API ドキュメントはお世辞にも人間が読みやすい・使いやすいとは言えないのだけど、エーアイ氏なら読み解いてくれて実装してくれて便利。叩けるAPI自体は便利なものが幅広く実装されていて、ドキュメントはとりあえず公開されているだけで十分とも感じる。</p>
<ul>
<li><a href="https://github.com/hotchpotch/pixoo-spotify">https://github.com/hotchpotch/pixoo-spotify</a></li>
</ul>
<p>こんな感じで表示される👇</p>
<img src="https://storage.googleapis.com/secons-site-images/other/blog_images/20260810-pixoo-spotify-example.gif" width="128" height="128" />
<p>64x64 ピクセルしかないので、ピクセルアートっぽくなって満足。kawaii。曲タイル取るなどは、美咲ゴシック8pt をオーバーレイで重ね、gif を作り、それを表示している感じ。小さなピクセルフォント様々(ありがたや〜)。プログラムは余っている raspi で動かしている。spotify API は pooling なので反応が若干遅い。イベントで受け取れるといいんだけどねぇ。</p>]]></description>
            <link>https://secon.dev/entry/2026/08/10/200000-pixoo-spotify-release</link>
            <guid isPermaLink="false">/entry/2026/08/10/200000-pixoo-spotify-release</guid>
            <dc:creator><![CDATA[secondlife / @hotchpotch / Yuichi Tateno]]></dc:creator>
            <pubDate>Mon, 10 Aug 2026 11:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[あるいちにち]]></title>
            <description><![CDATA[<p><img src="https://storage.googleapis.com/secons-site-images/other/blog_images/20260806-a-day-with-ai-agent.webp" alt="ある夜"></p>
<p>つい、やらなくてもいいようなことを、たくさんやってしまった一日。AI Agent により、以前ははやればできるが時間かかるのでやらない・やるべきでないと判断していた開発が雑指示で出来てしまう。それらは本来優先度が高くないのだけど、10分ぐらいで終わるなら、とついやってしまう。設計・実装的には無駄なコードが増えがち・チーム共有の他人への認知負荷も発生するのでなので、マイナスですらある。</p>
<p>今までは数時間〜数日かかった開発が物の数分〜数十分出てきちゃうので、成果が出たと勘違いしてしまうが、むしろマイナス。本末転倒である。もっと考えを広げたり深めたりする時間に使う分だが、AI Agent は毎度ガチャが発生して射倖心を煽る(短時間で良いものが作れるかどうかはギャンブルみがある)からなぁ。issue, PR をこなすと成果が出た気になれてしまうのも良くない。</p>
<hr>
<p>以前某社にソフトウェアエンジニアとして入社した時、目標設定の際に、開発はしなくて良いから、目標を徹底的に考えて。この目標は小さな積み重ねではなく、到達が非常に難しいが、達成した時に大きな価値につながるものね、というお題をこなしていた時期が1ヶ月ぐらいあった。</p>
<p>目標承認も、上司の部長承認、その後社長承認を経て、初めて開発に取り掛かれる、というものだった。とりわけ社長承認が「うーん、本当？なんか違うんじゃないかなー」という禅問答のような内容で、まぁ解も特になかった(と思う)のだけど、エンジニアだけど手を止めて開発せずに、徹底的に考える、みたいなプロセスには非常に価値があった。何も価値を出せていない焦り（何かを開発すると、とりあえずは価値が出せている感じなり安心できる。新参者は新しい組織で居場所が作れてないから尚更）はあって、入社早々転職を考えたりもしたけど、今振り返るとありがたい思考プロセスであった。サラリーマンなので給料はもらえてたしね、ラッキー。</p>
<hr>
<p>個人的には、今世に出ている AI を使ったプロダクトの成功は非常に難しいのでは、と思っている。技術進化が速く、あっという間に時代遅れになるから、プロダクトリリースし、そこから進化し続けない限りは失敗する。ほとんどのプロダクトはスタートが今見えているゴールであるし、ユーザが定着するとそれはそれで破壊的変更を入れることが難しい(裏側の見えない部分を徹底的に良くする、みたいな方向になる)ので、AI Agent でガット作っても、ガットの作り直しはリリースしてからは出来にくい。</p>
<p>またAIを使わないプロダクトは、AIによって代替されるなら、今作っても意味がないので、プロダクトを成功させる難易度が、プロダクト実装は簡単になったが、むしろ世の中の流れ的には、非常に難しくなっている。</p>
<hr>
<p>AI における開発生産性向上も、結局 AI を使ったベストな開発手法なんてしょっちゅう変わっていっているので、あんまり追いかけてもなーと思っている。プロダクトを作るのが難しい今、開発生産性が上がっても事業価値は上がらないから、なら別に組織としては上げなくても良いのでは、とも思っている。時間が経てば、ある程度汎用的なAIとの協調開発手法が生み出されていくわけだし。</p>
<p>例えば今流行りのハーネスも、AIと協調開発しやすい環境を整えましょうやっていき〜〜という感じで、今今AIにおける開発生産性を上げたいならやりましょう、となるのだが、将来 AI ready cloud みたいな完成系が出たタイミングで移行する、でも良いのでは。</p>
<p>流行りのループなんかも、プロダクトにおけるループゴールの設定を考えるには、結果組織が何をゴールにするべきか、そのゴールを提供するための判断材料は、そのためにはコンテキストが必要だからさまざまな方法、例えば Claude Tag を用いて slack でのフロー情報を集めたりして、組織最高のコンテキストメモリを作ってくぞ、みたいな話になったりしがちだが、そのコンテキストメモリの作り方も今後変わっていくだろうし、いやいやそんなみんながデジタルな場所に情報は出さないでしょ、もっと別のところから変えていくべきでは、などとも思ったりする。</p>
<p>組織の価値提供・向上のボトルネックは開発やデジタル作業から別のところに移るのは間違いないので、ではそのボトルネックは自分の組織ではどこになって、どういうふうに変えていくと良いのでは、といった解を考え、変えていくことに時間をかけるべきなんじゃないかなぁ。言うが易しだけどね。</p>
<hr>
<p>あれこれと無駄なことをやり過ぎてしまった1日を自省しつつ、なにもやらないこと自体が価値になったりもするんじゃないかなー、となにもしなかった1ヶ月間を思い出したりしていたのでした。</p>]]></description>
            <link>https://secon.dev/entry/2026/08/06/200000-a-day-with-ai-agent</link>
            <guid isPermaLink="false">/entry/2026/08/06/200000-a-day-with-ai-agent</guid>
            <dc:creator><![CDATA[secondlife / @hotchpotch / Yuichi Tateno]]></dc:creator>
            <pubDate>Thu, 06 Aug 2026 11:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[超小型な多言語ベクトル検索モデル Bekko Embedding を公開]]></title>
            <description><![CDATA[<p>昨今、ベクトル(文章埋め込み)モデルは性能向上とともにサイズも巨大になってきました。総パラメータ数が100M〜600Mの多言語モデルでは、<a href="https://huggingface.co/google/embeddinggemma-300m">EmbeddingGemma</a>、<a href="https://huggingface.co/ibm-granite/granite-embedding-311m-multilingual-r2">Granite Embedding R2 311M</a>、<a href="https://huggingface.co/Alibaba-NLP/gte-multilingual-base">gte-multilingual-base</a>、<a href="https://huggingface.co/BAAI/bge-m3">BGE-M3</a>、<a href="https://huggingface.co/Snowflake/snowflake-arctic-embed-l-v2.0">Arctic Embed</a> などがあります。さらに大きなモデルとしてLLMを基盤にした <a href="https://huggingface.co/nvidia/Nemotron-3-Embed-8B-BF16">Nemotron-3-Embed-8B</a>、<a href="https://huggingface.co/Qwen/Qwen3-Embedding-8B">Qwen3-Embedding-8B</a>、<a href="https://huggingface.co/perplexity-ai/pplx-embed-v1-4b">pplx-embed-v1-4b</a> など、数Bのモデルも出てきました。十分な速度で動かせるGPU環境があるなら、こうした大きな高性能モデルを使うと良いですね。</p>
<p>ただ、自分が興味を持ったのは巨大な高性能化とは反対の、どこまで小型にできるかというアプローチです。実際の検索に使える性能を残したまま、どこまで小さくできるのか。そこで作ってみたのが Bekko Embedding です。 <a href="https://huggingface.co/hotchpotch/bekko-embedding-v1-a8m">bekko-embedding-v1-a8m</a> と <a href="https://huggingface.co/hotchpotch/bekko-embedding-v1-a25m">bekko-embedding-v1-a25m</a> の2モデルでMITライセンスで公開しています。以下では短く bekko-a8m、bekko-a25m と表記します。</p>
<p>小さい方(a8m)のモデルは、<strong>Active Parameters（AP）がわずか 7.67M</strong>です。APとはトークン埋め込み参照テーブルを除いた、Transformer演算で使う重みの部分のパラメータです。検索性能も公式の <a href="https://huggingface.co/spaces/mteb/leaderboard">MMTEB Multilingual v2</a> に含まれる18の検索タスクでは平均スコアをa8m では56.2を記録し、APが約3〜40倍ある <a href="https://huggingface.co/intfloat/multilingual-e5-small">multilingual-e5</a> 系の全モデルと BGE-M3 を上回りました。またよりパラメータが大きい bekko-a25m はより良いスコアを出しています。</p>
<p><img src="https://storage.googleapis.com/secons-site-images/other/huggingface/bekko/blog/01_frontier.webp?v=2" alt="Active Parametersあたりの検索性能"></p>
<table>
<thead>
<tr>
<th></th>
<th align="right"><a href="https://huggingface.co/hotchpotch/bekko-embedding-v1-a8m">bekko-embedding-v1-a8m</a></th>
<th align="right"><a href="https://huggingface.co/hotchpotch/bekko-embedding-v1-a25m">bekko-embedding-v1-a25m</a></th>
</tr>
</thead>
<tbody>
<tr>
<td>Active Parameters</td>
<td align="right">7.67M</td>
<td align="right">24.93M</td>
</tr>
<tr>
<td>総パラメータ数</td>
<td align="right">106M</td>
<td align="right">123M</td>
</tr>
<tr>
<td>出力次元</td>
<td align="right">384 (→ 256 / 128 / 64)</td>
<td align="right">384 (→ 256 / 128 / 64)</td>
</tr>
<tr>
<td>最大入力長</td>
<td align="right">8,192トークン</td>
<td align="right">8,192トークン</td>
</tr>
<tr>
<td>MMTEB Multilingual v2、検索18タスク</td>
<td align="right">56.2</td>
<td align="right">57.5</td>
</tr>
<tr>
<td>MMTEB Multilingual v2、全131タスク</td>
<td align="right">56.7</td>
<td align="right">58.3</td>
</tr>
<tr>
<td>CPUスループット (Ryzen 9 7950X、OpenVINO)</td>
<td align="right">364 docs/s</td>
<td align="right">134 docs/s</td>
</tr>
<tr>
<td>軽量 ONNX ファイル</td>
<td align="right">124 MiB</td>
<td align="right">190 MiB</td>
</tr>
<tr>
<td>query / document prefix</td>
<td align="right">なし</td>
<td align="right">なし</td>
</tr>
</tbody>
</table>
<p>インストールせずに試すこともできます。<a href="https://huggingface.co/spaces/hotchpotch/bekko-embedding-web">bekko-embedding-web</a> のデモはモデルをブラウザに読み込み、そのままブラウザ上で実行します。</p>
<h2>小型モデルを作った理由</h2>
<p>コーディング・AIエージェントの台頭により、PCの使い方が変わりました。LLMの推論はAPIの先にあるフロンティアモデルが行うため、その部分においては手元のマシン性能は以前ほど気になりません。一方、エージェントが情報を探すための処理は、今も手元のマシンで動かします。ドキュメントの埋め込み(ベクトルに変換)、インデクス作成、コンテキストの探索等々です。</p>
<p>手元のマシンにGPUがないことも多く、低スペックなマシン(Raspberry Piなど)で動かすこともあります。その際 multilingual-e5-large で1万件の文書を埋め込むと、高速なデスクトップCPUでも約8分、Raspberry Pi 5 では2時間近くかかります。しかもクエリの埋め込みはインデックス作成時に一度計算すれば終わりではなく、検索のたびにも推論が必要です。</p>
<p>小さな埋め込みモデル、たとえばAPが30M未満のモデルの選択肢はかなり少ないです。自分が調べた範囲では、オープンなライセンスで利用でき、文脈を考慮する多言語埋め込みモデルのうち、Bekko以外で30M未満かつ検索に使える性能だったのは2つだけでした。2020年に蒸留された MiniLM を初期値にした <a href="https://huggingface.co/intfloat/multilingual-e5-small">multilingual-e5-small</a> と、2026年に公開されたAP 28.3Mの <a href="https://huggingface.co/ibm-granite/granite-embedding-97m-multilingual-r2">granite-embedding-97m-r2</a> です。</p>
<p>なおModel2Vec などの <a href="https://huggingface.co/blog/static-embeddings">静的埋め込み Static Embeddings</a> はさらに小さくできます。ただし、Transformers のような文脈を理解するモデルではなく、性能も低くなります。</p>
<h2>モデルパラメータと演算量</h2>
<p>多言語埋め込みモデルの演算量は、総パラメータ数だけでは見積もれません。モデルが118Mパラメータと書かれていると、そのパラメータすべてを使って計算するように思えます。しかし、多言語エンコーダでは、その大半が多言語のためのトークン埋め込みテーブルです。Bekkoの場合はこの埋め込みテーブルが256,000トークンありますが、推論時にはこのテーブルを参照するだけです。トークンごとに1つを取り出すため行列積はなく、このルックアップテーブルから読み込むだけです。</p>
<p>各トークンで実際に行列積を行うのは、Transformerブロックに含まれるパラメータです。<a href="https://arxiv.org/abs/2001.08361">スケーリング則で用いられるパラメータの数え方</a>にならい、ここではこれらを <strong>Active Parameters</strong>(AP) と呼びます。総パラメータ数よりもより推論コストを考える際に重要な指標となります。</p>
<p>この Active Parameters (AP) という言葉は別の意味でも使われるため、補足します。ここでいう AP は、ルータがトークンごとに異なるエキスパートを選び、全重みの一部だけを動かす Mixture-of-Experts(MoE) の文脈のAPではありません。Bekko は MoE ではない通常のエンコーダで、7.67Mのパラメータすべてを推論時に使います。パラメータ数から除いているのは、埋め込みのルックアップだけです。</p>
<p>たとえば、multilingual-e5-small は総パラメータ数118Mのうち、APが21.6Mです。bekko-a8m は総パラメータ数106M、AP 7.67Mです。この差が推論時間に表れます。なおこのAPだけで速度が決まるわけではありませんが、小さいほど基本的に推論が高速です。</p>
<h2>Bekko Embedding</h2>
<p>Bekko は、22層の <a href="https://huggingface.co/jhu-clsp/mmBERT-small">mmBERT-small</a> エンコーダを4層(a8m)と13層(a25m)にそれぞれ pruning し、これらの2モデルを約11億の多言語ペアで学習しています。</p>
<ul>
<li>100以上の言語を含むデータで、言語横断検索ができるように学習しました。翻訳を挟まず、日本語のクエリから英語の文書を検索できます。後述する言語別評価では、そのうち14言語を扱います。</li>
<li>どちらのモデルも8,192トークンまで入力できます。</li>
<li>出力は384次元です。Matryoshka学習により、256 / 128 / 64次元へ切り詰めて使えます。bekko-a25m を256次元にすると、検索性能は HAKARI-Bench Overall が相対で約1.3%、128次元では約6.2%低下します。</li>
<li>モデルの重みはMITライセンスです。</li>
<li>学習データも、<a href="https://huggingface.co/datasets/hotchpotch/bekko-embedding-v1-unsupervised">第一段階のコーパス</a>と<a href="https://huggingface.co/datasets/hotchpotch/bekko-embedding-v1-hard-negatives">マイニングしたhard negatives</a>を公開しています。</li>
</ul>
<h2>ベンチマーク結果</h2>
<p>下の図には6つの列があります。最初の2列は、同じ <a href="https://huggingface.co/spaces/mteb/leaderboard">MMTEB Multilingual v2</a> 評価を異なる切り口で集計したものです。ALLは全131タスクの平均、Retはそのうち18の検索タスクだけの平均です。比較モデルのスコアには公式に公開されているスナップショットを使い、Bekkoも同じタスク集合と集計方法で評価しました。</p>
<p>残る4列は、すべて検索タスクのベンチマーク評価です。<a href="https://huggingface.co/collections/zeta-alpha-ai/nanobeir-66e1a0af21dfd93e620cd9f6">Multilingual NanoBEIR</a> は、英語版のオリジナル NanoBEIR に、コミュニティが公開した13の翻訳版を加えたものです。これらの翻訳版は私が作ったものではありませんが、他の Nano-set は後述の HAKARI-Bench 用に私が作った物です。NanoRTEB は、実運用に近い検索データセットを集めた <a href="https://huggingface.co/blog/rteb">RTEB</a> の小型版です。NanoCoIR は<a href="https://huggingface.co/CoIR-Retrieval">コード検索</a>、NanoLongEmbed は<a href="https://huggingface.co/datasets/dwzhu/LongEmbed">長文入力</a>を扱います。この4つは、私が作った <a href="https://huggingface.co/spaces/hakari-bench/leaderboard">HAKARI-Bench</a>（<a href="https://arxiv.org/abs/2606.22778">arXiv</a>）で同じ設定を使って評価しました。語彙一致のベースラインとして、BM25も含めています。</p>
<p><img src="https://storage.googleapis.com/secons-site-images/other/huggingface/bekko/blog/02_benchmarks.webp?v=2" alt="12モデルとBM25を6つのベンチマークで比較"></p>
<p>MMTEBの2列を並べると、順位がかなり違います。特に分かりやすいのが granite-embedding-97m-r2 で、18の検索タスクでは60.3と比較中4位ですが、全131タスクでは51.9と最下位です。検索タスクを集中して学習すると、そのほかのタスクで性能を落とすことがあります。Bekkoも検索向けに学習したモデルですが、全タスクの平均も悪くはありません。</p>
<p>bekko-a8m は6つの列すべてで multilingual-e5-small を上回り、multilingual-e5-small のAPは2.8倍と約3倍の大きさです。bekko-a25m は、APが約12分の1でありながら、MMTEBの検索18タスクでは multilingual-e5-large と BGE-M3 を上回ります。ただしMMTEB全131タスクでは、どちらのモデルも bekko-a25m より高いスコアです。</p>
<p>18の検索タスクでは、5モデルが bekko-a25m を上回ります。<a href="https://huggingface.co/microsoft/harrier-oss-v1-270m">harrier-oss-v1-270m</a>、granite-embedding-311m-r2、EmbeddingGemma-300M、granite-embedding-97m-r2、snowflake-arctic-embed-l-v2.0 です。全131タスクでは4モデルが上回ります。harrier-oss-v1-270m と EmbeddingGemma-300M に加え、BGE-M3 と <a href="https://huggingface.co/intfloat/multilingual-e5-large">multilingual-e5-large</a> です。gte-multilingual-base は同点でした。</p>
<p>ここで bekko-a25m を上回ったモデルは、granite-embedding-97m-r2 を除き、bekko-a25m の4〜13倍のAPを持ちます。検索精度を最優先し、十分な計算資源があるなら、どれも優れたモデルと言えるでしょう。</p>
<p>コード検索では、bekko-a25m は78.6で、multilingual-e5-large と BGE-M3 を上回る一方、84.7の EmbeddingGemma-300M と81.4の granite-embedding-311m-r2 には届きません。長文入力の結果は、もう少し意外でした。長い文書の中から1つの箇所を探す場合、語彙一致は強く、BM25が82.2で全モデルを上回ります。しかし12の密ベクトルモデルの中では、bekko-a25m が70.6で1位、bekko-a8m が3位でした。</p>
<h2>言語別の結果</h2>
<p>平均値だけを見ると、特定の言語でモデルの性能が崩れていても気づけません。以下は、Multilingual NanoBEIR の14言語を個別に見た結果です。</p>
<p><img src="https://storage.googleapis.com/secons-site-images/other/huggingface/bekko/blog/03_languages.webp?v=2" alt="Multilingual NanoBEIR 14言語の言語別評価結果"></p>
<p>bekko-a25m は、14言語すべてで multilingual-e5-small と BM25 を上回りました。BGE-M3 との差が最も大きい言語でも2.7ポイントです。14言語の中ではタイ語、アラビア語、セルビア語が弱く、まだ改善の余地があります。</p>
<h2>推論速度</h2>
<p>APはスループットを大まかに見積もる目安になります。Raspberry Pi 5 から RTX 5090 まで、4つの環境で6モデルを同じ条件で測定しました。</p>
<p><img src="https://storage.googleapis.com/secons-site-images/other/huggingface/bekko/blog/04_speed_devices.webp" alt="4つの環境すべてで最も高速"></p>
<p>bekko-a8m は、どの環境でも6モデル中もっとも高速でした。実際のインデックス作成で、Ryzen 9 7590X CPUで10万文書を埋め込みベクトルに変換すると、bekko-a8m なら約5分ですが、multilingual-e5-large なら約80分かかります。</p>
<p>自分がより面白いと思ったのは、Raspberry Pi 5 の結果です。1秒あたり33文書はGPUに比べれば圧倒的に遅いですが、1万文書のインデックスなら約5分で作成可能です。これぐらいの速度なら、用途によっては実用的でしょう。同じ Raspberry Pi 5 で multilingual-e5-large を使うと、2時間近くかかります。</p>
<p>図の2つのCPUパネルでは、それぞれのモデルが公開している PyTorch のバックエンドに OpenVINO を使う版を使っています。6モデルとも、CPUでは OpenVINO が最速だったためです。一部のモデルだけOpenVINO を使わずに動かすと公平な比較になりません。同等の OpenVINO 版がないモデルに、ここでの数値をそのまま当てはめることはできません。Bekko は両サイズとも OpenVINO 版を公開しています。</p>
<p>APだけですべての速度差を説明できるわけではありません。multilingual-e5-small のAPは bekko-a25m の87%ですが、CPUでは1.7倍高速です。granite-embedding-97m-r2 はAPが14%多いものの、速度はほぼ変わりません。</p>
<p>自分は、アーキテクチャの違いが効いているのではないかと思っています。<a href="https://arxiv.org/abs/2412.13663">ModernBERT</a> のアーキテクチャでは、unpadding、可変長 FlashAttention カーネル、global attention と local attention の相互配置など、GPUカーネルを意識した高速化を行っています。一方、素直な XLM-R 系エンコーダアーキテクチャは、CPUバックエンドに載せやすそうです。原因を切り分けるところまではできていないので、ここは実際の実装を真に確認した結果ではなく自分の解釈です。ただこうした違いがあっても、bekko-a8m は十分に小さく、今回の比較では最速でした。</p>
<h2>124 MiB の配布サイズとブラウザ実行</h2>
<p>総パラメータ数を大きくしている語彙埋め込みテーブルは、ダウンロードサイズも大きくします。このテーブルは静的なルックアップなので、ONNX 版と OpenVINO 版では行ごとの int8 量子化で保存し、Transformer の重みは fp32 のままにしました。リリース時の検証では、PyTorch 版とのコサイン類似度は最小でも0.9994でした。</p>
<p>これにより bekko-a8m は124 MiB、bekko-a25m は190 MiBになり、ブラウザへ配れるサイズになりました。なおTransformer の重み自体をさらに小さくfloatから int8 にしサイズ削減もできるのですが、精度劣化が激しいため行なっておりません。</p>
<table>
<thead>
<tr>
<th></th>
<th align="right">bekko-a8m</th>
<th align="right">bekko-a25m</th>
</tr>
</thead>
<tbody>
<tr>
<td>ブラウザ、WebGPU</td>
<td align="right">187 docs/s</td>
<td align="right">89 docs/s</td>
</tr>
<tr>
<td>ブラウザ、WASM (CPU)</td>
<td align="right">51 docs/s</td>
<td align="right">16 docs/s</td>
</tr>
<tr>
<td>ネイティブ、Apple GPU (MPS)</td>
<td align="right">592 docs/s</td>
<td align="right">351 docs/s</td>
</tr>
</tbody>
</table>
<p>上の速度図と同じ Natural Questions の入力を使っています。最後の行はブラウザでの結果ではなく、比較用に同じモデルをネイティブ実行した値です。</p>
<p>ブラウザデモは <a href="https://huggingface.co/spaces/hotchpotch/bekko-embedding-web">huggingface.co/spaces/hotchpotch/bekko-embedding-web</a> で試せます。埋め込みの計算はブラウザ内で行うため、入力した文章をサーバーへ送ることはありません。</p>
<h2>ほかのモデルを選んだ方がよい場合</h2>
<ul>
<li>日本語のみを扱いたい場合、ruri-v3 シリーズは小さく Bekko より高性能です。<a href="https://huggingface.co/cl-nagoya/ruri-v3-30m">ruri-v3-30m</a>は AP 10M、出力次元が 256 と小型ながら必要十分な性能のことも多いでしょう</li>
<li>計算資源に余裕があり、この比較で最も高い検索精度を求める場合は、harrier-oss-v1-270m、granite-embedding-311m-r2、EmbeddingGemma-300M の方が高いスコアです。</li>
<li>検索以外にも広く使える文章埋め込みモデルが必要な場合、Bekko の分類とクラスタリング性能はは中位から下位です。検索ではない目的なら、他のモデルの方が適していることも多いでしょう。</li>
</ul>
<h2>Bekko Embedding の使い方</h2>
<p>どちらのモデルを試すか迷ったら、CPUでのインデックス作成やブラウザ検索には a8m、Apple MPS やGPUが使え速度より検索性能を優先するなら a25m がよいでしょう。</p>
<p>PyTorchでそのまま動かすほか、CPUでは OpenVINO、ブラウザでは Transformers.js を使えます。3つとも同じモデルIDで動き、prefixも不要です。実行環境ごとにAPIが異なります。</p>
<pre><code class="hljs language-bash">pip install -U <span class="hljs-string">"sentence-transformers>=5.0"</span> <span class="hljs-string">"transformers>=5.12"</span></code></pre>
<pre><code class="hljs language-python"><span class="hljs-keyword">from</span> sentence_transformers <span class="hljs-keyword">import</span> SentenceTransformer, util

model = SentenceTransformer(<span class="hljs-string">"hotchpotch/bekko-embedding-v1-a8m"</span>)

query = <span class="hljs-string">"What are the characteristics of sushi?"</span>
docs = [
    <span class="hljs-string">"A warm noodle soup served in broth with sliced toppings."</span>,
    <span class="hljs-string">"天ぷらは魚や野菜に衣をつけて揚げた料理です。"</span>,
    <span class="hljs-string">"Une fine crepe garnie de sucre, de beurre ou de fruits."</span>,
    <span class="hljs-string">"A Japanese dish made with vinegared rice, often shaped with seafood, vegetables, or egg."</span>,
]

scores = util.cos_sim(
    model.encode(query, normalize_embeddings=<span class="hljs-literal">True</span>),
    model.encode(docs, normalize_embeddings=<span class="hljs-literal">True</span>),
)[<span class="hljs-number">0</span>]
<span class="hljs-built_in">print</span>(<span class="hljs-string">"best doc:"</span>, docs[<span class="hljs-built_in">int</span>(scores.argmax())])</code></pre>
<p>prefix やタスク指示は不要で、クエリと文書はどちらも同じ <code>encode</code> 呼び出しで処理します。上の条件では、a8m の OpenVINO 実装は PyTorch より x86 で約2.8倍、Raspberry Pi 5 で約1.7倍高速です。</p>
<details>
<summary><strong>CPU で OpenVINO を使う</strong></summary>
<pre><code class="hljs language-bash">pip install -U \
  <span class="hljs-string">"sentence-transformers[openvino]>=5.0"</span> \
  <span class="hljs-string">"transformers>=4.57,&#x3C;5"</span></code></pre>
<pre><code class="hljs language-python"><span class="hljs-keyword">from</span> sentence_transformers <span class="hljs-keyword">import</span> SentenceTransformer, util

model = SentenceTransformer(
    <span class="hljs-string">"hotchpotch/bekko-embedding-v1-a8m"</span>,
    backend=<span class="hljs-string">"openvino"</span>,
    device=<span class="hljs-string">"cpu"</span>,
    model_kwargs={<span class="hljs-string">"file_name"</span>: <span class="hljs-string">"openvino/openvino_model.xml"</span>, <span class="hljs-string">"device"</span>: <span class="hljs-string">"CPU"</span>},
)

query = <span class="hljs-string">"What are the characteristics of sushi?"</span>
docs = [
    <span class="hljs-string">"A warm noodle soup served in broth with sliced toppings."</span>,
    <span class="hljs-string">"A Japanese dish made with vinegared rice, often shaped with seafood, vegetables, or egg."</span>,
]

scores = util.cos_sim(
    model.encode(query, normalize_embeddings=<span class="hljs-literal">True</span>),
    model.encode(docs, normalize_embeddings=<span class="hljs-literal">True</span>),
)[<span class="hljs-number">0</span>]
<span class="hljs-built_in">print</span>(<span class="hljs-string">"best doc:"</span>, docs[<span class="hljs-built_in">int</span>(scores.argmax())])</code></pre>
<p>OpenVINO 連携は Transformers を5.1未満に固定するため、先ほどの <code>transformers>=5.12</code> と同じ環境には入れられません。別環境を用意するか、両方とも Transformers 4.57 を使ってください。通常の PyTorch の例も4.57で動きます。</p>
</details>
<p>Transformers.js でも、同じモデルをブラウザ内で動かせます。対応しているブラウザでは WebGPU を使います。</p>
<details>
<summary><strong>ブラウザで Transformers.js を使う</strong></summary>
<pre><code class="hljs language-bash">npm install @huggingface/transformers</code></pre>
<pre><code class="hljs language-js"><span class="hljs-keyword">import</span> { pipeline } <span class="hljs-keyword">from</span> <span class="hljs-string">"@huggingface/transformers"</span>;

<span class="hljs-comment">// Browser: use WebGPU when available, otherwise fall back to WASM.</span>
<span class="hljs-comment">// Node.js: replace this line with `const device = "cpu";`.</span>
<span class="hljs-keyword">const</span> device = navigator.gpu ? <span class="hljs-string">"webgpu"</span> : <span class="hljs-string">"wasm"</span>;

<span class="hljs-keyword">const</span> extractor = <span class="hljs-keyword">await</span> pipeline(
  <span class="hljs-string">"feature-extraction"</span>,
  <span class="hljs-string">"hotchpotch/bekko-embedding-v1-a8m"</span>,
  { device, <span class="hljs-attr">dtype</span>: <span class="hljs-string">"fp32"</span> },
);

<span class="hljs-keyword">const</span> embedding = <span class="hljs-keyword">await</span> extractor(<span class="hljs-string">"What are the characteristics of sushi?"</span>, {
  <span class="hljs-attr">pooling</span>: <span class="hljs-string">"mean"</span>,
  <span class="hljs-attr">normalize</span>: <span class="hljs-literal">true</span>,
});

<span class="hljs-built_in">console</span>.log(embedding.dims); <span class="hljs-comment">// [1, 384]</span></code></pre>
</details>
<h2>リソースへのリンク</h2>
<ul>
<li>モデル：<a href="https://huggingface.co/hotchpotch/bekko-embedding-v1-a8m">bekko-embedding-v1-a8m</a> と <a href="https://huggingface.co/hotchpotch/bekko-embedding-v1-a25m">bekko-embedding-v1-a25m</a></li>
<li>ブラウザデモ：<a href="https://huggingface.co/spaces/hotchpotch/bekko-embedding-web">bekko-embedding-web</a></li>
<li>学習データ：<a href="https://huggingface.co/datasets/hotchpotch/bekko-embedding-v1-unsupervised">第一段階のコーパス</a> と <a href="https://huggingface.co/datasets/hotchpotch/bekko-embedding-v1-hard-negatives">hard negatives</a></li>
</ul>
<h2>モデルの学習方法</h2>
<p>使い方を中心にした記事なので、学習については簡単に。mmBERT-small の22層を4層と13層に削り、先頭側の層と、深い位置にある global attention の層を1つ残しました。削った後のチェックポイントを、そのまま基盤モデルとして使っています。</p>
<p>そこから2段階の対照学習を行いました。第一段階では、公開しているコーパスの約11億多言語ペア(合成データセットなども多様して作成)を使っています。性質の異なる2系統の LLM 合成クエリも含まれます。続いて、8,192トークンの長文も含む hard negative を使ってファインチューニングしました。どちらの段階でも教師モデルや蒸留は使っていません。</p>
<p>両モデルとも、RTX PRO 6000 Blackwell Max-Q 1枚のみで学習しました。所要時間は a8m が約3日、a25m が約8日です。一般的な規模の多言語埋め込みモデルは GPU クラスターで学習され、BGE-M3 の論文では最大96基の GPU を使ったと報告されています。APを小さくすると推論コストが下がり、学習もワークステーション GPU 1枚で行えます。RTX5090でも学習時間は増えますが、学習可能です。大量のGPUが必要ないことも、自分がこのサイズのモデルに取り組む大きな理由の1つです。</p>
<p>今回のモデルは、かなり多くの研究や実装を参考にしています。基盤モデルには mmBERT と ModernBERT、学習方法には E5、GTE、BGE-M3、Qwen3 Embedding、Ruri、実装には sentence-transformers を使いました。これだけ小さなモデルで、どうやって多言語検索の性能を保ったのか。残す層を選ぶ実験、損失、約11億ペアの収集・合成方法、詳しい評価結果をまとめた野良論文は以下で公開しています。</p>
<ul>
<li>arXiv: <a href="https://arxiv.org/abs/2607.25180">Bekko Embedding: Parameter-Efficient Multilingual Retrieval with Ultra-Compact Encoders</a></li>
<li>日本語版: <a href="https://storage.googleapis.com/secons-site-images/other/huggingface/bekko/blog/bekko_embedding_paper_ja.pdf">Bekko Embedding: 超小型エンコーダによるパラメータ効率の高い多言語検索</a></li>
</ul>
<p>小さな多言語検索モデルを探している方に、Bekko Embedding が一つの選択肢になれば幸いです。</p>]]></description>
            <link>https://secon.dev/entry/2026/07/29/080000-bekko-embedding</link>
            <guid isPermaLink="false">/entry/2026/07/29/080000-bekko-embedding</guid>
            <dc:creator><![CDATA[secondlife / @hotchpotch / Yuichi Tateno]]></dc:creator>
            <pubDate>Tue, 28 Jul 2026 23:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[herdr で cdd]]></title>
            <description><![CDATA[<p>screen, tmux 時代から、<a href="https://secon.dev/entry/20080218/1203303528/">cdd というコマンドを作り</a>愛用してきた。cdd とは、例えば <code>window:3</code> で <code>~/foo/bar</code> のディレクトリで作業している時に <code>cdd 3</code> とすると <code>cd ~/foo/bar</code> される、というだけのものなのだが、しょっちゅう使っているぐらい重宝してきた。<code>cdd</code> というコマンド名も打ちやすくて好き。というわけで、cdd も herdr で動くように実装した。</p>
<ul>
<li><a href="https://gist.github.com/hotchpotch/8fbca5605af16c386acb34bc74f8c1ae">https://gist.github.com/hotchpotch/8fbca5605af16c386acb34bc74f8c1ae</a></li>
</ul>
<p>herdr は以下の三つの状態を検討する必要がある。</p>
<ul>
<li>現在の workspace の tab, pane の dir</li>
<li>別の workspace の tab, pane の dir</li>
<li>agent が作業している dir</li>
</ul>
<p>これらを考慮し、zsh 決め打ちで、以下のような仕様で作った。bash その他用もエーアイに伝えれば同様な実装はすぐ作れると思う。</p>
<ul>
<li><code>cdd</code> のみを実行すると、 すべての作業ディレクトリ一覧を fzf でフィルターし移動が可能</li>
<li><code>cdd 3</code> などで、現在の workspace の tab id 3 に移動</li>
<li><code>cdd a3</code> で、agent list の3番目の agent の cwd に移動</li>
<li><code>cdd w3:p2</code> などで、workspace id 3 の pane id 2 に移動。<code>w3:p2</code> などは herdr オフィシャルでの表記と一緒。</li>
<li><code>cdd w3:t2</code> など(w3, tab 2)も。</li>
<li>適当に tab を打つと補完リストが出てきて選択も可能</li>
<li>なお <code>jq</code> と <code>fzf</code> に依存しているので、これらのコマンドが必要</li>
</ul>]]></description>
            <link>https://secon.dev/entry/2026/07/10/080000-herdr-cdd</link>
            <guid isPermaLink="false">/entry/2026/07/10/080000-herdr-cdd</guid>
            <dc:creator><![CDATA[secondlife / @hotchpotch / Yuichi Tateno]]></dc:creator>
            <pubDate>Thu, 09 Jul 2026 23:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[herdr で tmux-fingers のようなことができる plugin を作った]]></title>
            <description><![CDATA[<p>最近話題のターミナルマルチプレクサ herdr、使ってみたらあっという間に手に馴染む。センスがいいね。</p>
<p>今まで使っていた tmux では、<a href="https://github.com/Morantron/tmux-fingers">tmux-fingers</a>という、画面上に表示されているコピーしたくなるような文字列(url, SHAs, UUID などなど)を短いキーでコピーできるものが便利でよく使っていたのだけど、これがなかったので、herdr pluginとして実装してみた。</p>
<ul>
<li><a href="https://github.com/hotchpotch/herdr-tiny-fingers">https://github.com/hotchpotch/herdr-tiny-fingers</a></li>
</ul>
<pre><code>herdr plugin install hotchpotch/herdr-tiny-fingers
</code></pre>
<pre><code>[[keys.command]]
key = "prefix+f"
type = "plugin_action"
command = "hotchpotch.herdr-tiny-fingers.open"
description = "fingers mode"
</code></pre>
<p>などすれば使えるので、tmux-fingers 使いの方はどうぞ。</p>
<hr>
<p>例によってエーアイに herdr の repos を見せて実装してもらったんだけど、herdr は plugin 開発もめちゃ楽な感じであった。エーアイによって上手く開発されているプロジェクトは、エーアイが開発・デバッグしやすいように作られていているのだなぁ、と改めて感じる。</p>]]></description>
            <link>https://secon.dev/entry/2026/07/09/080000-herdr-tiny-fingers</link>
            <guid isPermaLink="false">/entry/2026/07/09/080000-herdr-tiny-fingers</guid>
            <dc:creator><![CDATA[secondlife / @hotchpotch / Yuichi Tateno]]></dc:creator>
            <pubDate>Wed, 08 Jul 2026 23:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[macOS Tahoe で動くネイティブAPI経由での翻訳 cli を作った]]></title>
            <description><![CDATA[<p>macOS ちょっと前から、そういえば Apple インテリジェンスなるものが使えるなぁ、ただなんかただ邪魔なUIが出るだけだが（自分のユースケースでは全く使わない）、程度に思っていたのだけど、macOS のネイティブAPIとして呼び出せるようなので、それを使って翻訳 cli アプリを作ってみた。</p>
<ul>
<li><a href="https://github.com/hotchpotch/mac-translate-cli">https://github.com/hotchpotch/mac-translate-cli</a></li>
</ul>
<pre><code>brew tap hotchpotch/mac-translate-cli https://github.com/hotchpotch/mac-translate-cli
brew install hotchpotch/mac-translate-cli/trn
</code></pre>
<p>で入れて</p>
<pre><code>trn --to ja "Hello world!"
#=> こんにちは、世界！
echo "Hello world!" | trn --to ja
#=> こんにちは、世界！
trn --to ja -q low "Hello world!" # デフォルト
trn --to ja -q high "Hello world!" # ニューラルネットワーク翻訳ぽい、高品質…？
</code></pre>
<p>みたいに使える。なお macOS Tahoe 26.4 以降に対応。最初、Apple Intelligence models(ニューラルネットワークを使った翻訳なのか?) API をデフォルトとして使っていたんだけど、<a href="https://github.com/hotchpotch/mac-translate-cli/blob/main/translation-quality-check.md">これが遅い割に、あんまり品質が高くない</a>。長文ならコンテキストの空気を読むのかな、と思いきや en &#x3C;-> ja に関しては試した感じ別に良くない。今までの統計確率ベース翻訳モデルの方が、10倍以上速くてLLMから見たクオリティはあまり変わらず。high は自然な文章、な気もするが、場合によってはうまく翻訳ができてないケースもありそう。なのでデフォルト品質は low (今までの翻訳API)とした。</p>
<p>音声をテキストに変換する STT は <a href="https://kanary.download/ja">kanary.app</a> 経由で使った限り、変換品質そこそこで1時間の音声を1分で文字起こしできて爆走だったため、翻訳(highのApple Intelligence model)でも爆速を期待したんだけど、翻訳の方は次のモデルに期待かな。</p>]]></description>
            <link>https://secon.dev/entry/2026/06/08/080000-mac-translate-cli-trn</link>
            <guid isPermaLink="false">/entry/2026/06/08/080000-mac-translate-cli-trn</guid>
            <dc:creator><![CDATA[secondlife / @hotchpotch / Yuichi Tateno]]></dc:creator>
            <pubDate>Sun, 07 Jun 2026 23:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Codex 認証を使った OpenAI API 互換サーバーの実装と利用]]></title>
            <description><![CDATA[<p>ローカル環境の Codex の認証情報を使い、OpenAI API の Responses API や Chat Completions API として叩ける互換サーバーを実装してみました。Codex の利用方法の一つである、ChatGPT サブスクリプションでの定額利用範囲でも使えるのが嬉しいですね。Codex で認証済みの環境なら、<code>uvx</code> コマンド1つで互換サーバを起動できます。</p>
<ul>
<li><a href="https://github.com/hotchpotch/openai-api-server-via-codex">https://github.com/hotchpotch/openai-api-server-via-codex</a></li>
</ul>
<pre><code class="hljs language-bash">uvx openai-api-server-via-codex</code></pre>
<p>これでローカルにサーバーが立ち上がります。デフォルトでは <code>http://127.0.0.1:18080</code> で待ち受け、OpenAI API を叩けるクライアントから、<code>/v1/responses</code> や <code>/v1/chat/completions</code> のエンドポイントが利用できるようになります。ライブラリ経由で API を叩きたいときに便利ですね。</p>
<p>例えば、起動した環境に適当な OpenAI API に対応している GUI クライアントを使ってみるとこんな感じです。ChatGTP Pro サブスクリプションでは Codex から今現在(2026年5月7日)、<code>gpt-5.3-codex-spark</code> が使えるので、以下のスクリーンショットでは試しに使ってみています。</p>
<img src="https://storage.googleapis.com/secons-site-images/other/blog_images/20260506-openai-api-server-via-codex.webp" style="max-width: 640px" />
<hr>
<h2>どのように実現しているの?</h2>
<p>この方法は、OpenClaw が Codex を経由で処理するときに利用しているエージェント実行エンジンの一つ、<a href="https://github.com/badlogic/pi-mono">Pi</a>でも行われている方法で、認証は Codex の情報を利用しつつ、<code>https://chatgpt.com/backend-api/codex</code> の Codex 用 API エンドポイントを叩いています。</p>
<p>この API エンドポイントを勝手に使って良いかは不明だったのですが、Simon Willison 氏の記事 <a href="https://simonwillison.net/2026/Apr/23/gpt-5-5/">A pelican for GPT-5.5 via the semi-official Codex backdoor API</a> を読むと、どうやら利用してもよさそう(semi-official とは言い得て妙ですね)な雰囲気なので作ってみました。</p>
<h2>注意事項</h2>
<p>このプロジェクトは OpenAI 公式のAPI ではありません。あくまで、自身が利用権限を持つ Codex の認証情報を使い、ローカルなどの開発環境で OpenAI API 互換の形に変換するものです。次のような用途に利用すると、OpenAI の利用規約に抵触する場合があります。</p>
<ul>
<li>ChatGPT / Codex の利用制限を回避する目的で使う</li>
<li>自分以外の人に API として提供する</li>
<li>サブスクリプションを再販・共有する</li>
<li>公開 API や第三者向けサービスのバックエンドとして使う</li>
<li>Codex の認証情報やトークンを他人と共有する</li>
</ul>
<p>また、Codex backend の仕様は予告なく変更される可能性があります。動作していたリクエスト形式やモデル名が突然使えなくなることもあり得ます。</p>
<h2>Codex, ClaudeCode サブスクの2社のスタンスの違い</h2>
<p><a href="https://www.theverge.com/ai-artificial-intelligence/907074/anthropic-openclaw-claude-subscription-ban">ClaudeCode が、OpenClaw などでのサブスクション契約での利用禁止</a>が、2026年4月に通達されましたが、反対に Codex では、<a href="https://developers.openai.com/codex/app-server">Codex App Server</a>や<a href="https://developers.openai.com/codex/sdk">Codex SDK</a>が公開されるなど、少なくとも今今はサブスクでも幅広く使ってもらうための仕組みを提供し始めており、両者のスタンスが反対で興味深いですね。</p>
<p>Anthropic 社はClaude向けの推論リソースが現状カツカツな感じがするので厳しく制限していることに対し、OpenAI 社はリソースが余っているのか、割と大盤振る舞いな雰囲気を感じています。ただ、OpenAI 社もリソースが厳しくなる・競争が無くなると将来的には厳しくなる・サブスクが無くなる可能性も十分にあり得ると思うので、今後どうなることやら、未来は読めませんね。</p>]]></description>
            <link>https://secon.dev/entry/2026/05/07/080000-openai-api-server-via-codex</link>
            <guid isPermaLink="false">/entry/2026/05/07/080000-openai-api-server-via-codex</guid>
            <dc:creator><![CDATA[secondlife / @hotchpotch / Yuichi Tateno]]></dc:creator>
            <pubDate>Wed, 06 May 2026 23:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[SQLiteやDuckDBで日本語全文検索をVaporettoを組み込んで実現する]]></title>
            <description><![CDATA[<p>各種エージェントの台頭により、サーバレスに動作しローカルファイルとして保存でき、永続化可能な組み込みデータベースのSQLiteやDuckDBへの注目を感じる昨今ですね。これらDBでの全文検索(FTS)の日本語対応ってどんなものなのだろうかと調べると、<a href="https://www.sqlite.org/fts5.html">trigram での検索</a>はできるものの、日本語語彙に特化した検索は標準できないようでした。</p>
<p><a href="https://github.com/lindera/lindera">Lindera</a>を使うアプローチもあるようですが、今回は Rust で実装されている軽量高速なトークナイザの <a href="https://github.com/daac-tools/vaporetto">Vaporetto</a> を組み込んで動く拡張機能を作ってみました。</p>
<ul>
<li>SQLite + Vaporetto
<ul>
<li><a href="https://github.com/hotchpotch/sqlite-vaporetto">https://github.com/hotchpotch/sqlite-vaporetto</a></li>
</ul>
</li>
<li>DuckDB + Vaporetto
<ul>
<li><a href="https://github.com/hotchpotch/duckdb-vaporetto">https://github.com/hotchpotch/duckdb-vaporetto</a></li>
</ul>
</li>
</ul>
<p>Vaporetto は、<a href="https://www.anlp.jp/proceedings/annual_meeting/2022/pdf_dir/D2-5.pdf">点予測法</a>で文字境界を線形分類モデルで判定するため、辞書なしモデル(辞書ありモデルもある)で利用可能なため、サイズを小さく保つこともできるので用途によっては便利そうですね。ので、Web ブラウザー上で完結する、DuckDB + Vaporetto の組み合わせで bm25 関連度スコアでソートする全文検索を行える技術デモを作ってみました。ただ対象テキストの件数が少ないと、全文検索(件数が増えても高速に検索が可能)やbm25(単語の出現回数や文章長を加味)の嬉しさが少ないのですが…。</p>
<ul>
<li><a href="https://duckdb-vaporetto-wasm-demo.surge.sh/">https://duckdb-vaporetto-wasm-demo.surge.sh/</a></li>
</ul>
<p>また例えば、この blog(secon.dev) の記事検索を SQLite + FTS5 + vaporetto の組み合わせで試しに作ってみたところ、約2700記事の bm25 検索で、大体3ms前後の速度で検索が可能になりました。</p>
<p><img src="https://storage.googleapis.com/secons-site-images/other/blog_images/20260427-secon-dev-sqlite-search.webp" alt="secon. dev検索例"></p>
<p>SQLite, DuckDB などでカジュアルに日本語全文検索ができるようになるので、使い所がハマれば便利そうな気がしています。</p>
<hr>
<p>追記: 形態素解析の第一人者である、Kudo さんよりコメントをいただく、ありがたい。全文検索では点予測による単語分割は、一貫性の無さが不向きと。なるほど〜。</p>
<blockquote>
<p>点予測の単語分割は全文検索には不向きです。特に辞書なしだと、文脈依存分割が避けられず検索漏れのリスクが増えます。拙書の形態素解析本に解説あります。</p>
</blockquote>
<ul>
<li><a href="https://x.com/taku910/status/2048676651517768163">https://x.com/taku910/status/2048676651517768163</a></li>
</ul>
<blockquote>
<p>文脈依存性とは、例えば「形態素解析」というフレーズの分割が、その前後文脈に左右されず、一意に決まることを指します。クエリの分割が文書中で再現されることが重要であり、Unigram言語モデルはこの条件を満たします。精度は犠牲になるものの、一貫性が保証されます。</p>
</blockquote>
<ul>
<li><a href="https://x.com/taku910/status/2048695518176665637">https://x.com/taku910/status/2048695518176665637</a></li>
</ul>]]></description>
            <link>https://secon.dev/entry/2026/04/27/080000-sqlite-duckdb-vaporetto</link>
            <guid isPermaLink="false">/entry/2026/04/27/080000-sqlite-duckdb-vaporetto</guid>
            <dc:creator><![CDATA[secondlife / @hotchpotch / Yuichi Tateno]]></dc:creator>
            <pubDate>Sun, 26 Apr 2026 23:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[RTX5090 2台構成の機械学習用PCを自作する]]></title>
            <description><![CDATA[<p>私は小さな、パラメータサイズが100M以下ぐらいのtransformerモデルの学習が好きで、しょっちゅう学習を回している。今までも RTX3090,4090,5090 の自作PCを作成し、利用してきた。</p>
<p>ただ、もうちょっと学習速度が欲しいことがあったり、また複数GPU環境での学習の知見を得たい為、今回 RTX5090 x2 構成の自作PCを作ってみた。その際、最近はコンシューマ向けGPUからNVLinkが廃止され、かつ電力消費も上がったため意外と RTX5090 2枚を使った事例がなく少々調べるのに苦労したため、まとめてみた。なおこの自作例は2025年末時点の例である。</p>
<div class="photos photos-small"><span itemscope="" itemtype="http://schema.org/Photograph"><a href="https://storage.googleapis.com/secons-site-images/photo/large/20260118_L1001763.webp"><img src="https://storage.googleapis.com/secons-site-images/photo/medium/20260118_L1001763.webp" class="photo" itemprop="image" /></a></span></div>
<h2>電源</h2>
<p>RTX5090 x2 で苦労する点といえば、まず電源である。RTX5090のTBPは最大575Wで、それが2機。CPUその他諸々の消費電力を考えると、最低1600W電源以上は欲しい。しかしながら、日本のご家庭用コンセントの100Vでは最大1500Wとなっているし、調べる限り一般的なPC用電源は100Vでは1300Wまでしか販売されていない。</p>
<p>なので、1300W電源までは多彩なラインナップがあるのだが、それ以上の電源になると極端に少なくなる。それ以上の電源は、電源の入力コネクタの口が一般的なPC電源のC13ではなく、C19という形状に変わる。そこに200V電源を供給することで1300W以上の出力を得ることができる。</p>
<p>というわけで、電源を繋げるべくNEMA規格の20A250V対応の壁コンセント(パナソニックのWF2520Bを選んだ)を工事して設置し、そこから200V20A供給(最大4000W)を可能とした。電源ケーブルはNEMA L6-20P → IEC 60320 C19のものが必要になるので、Schneider Electric AP8753J Power Cord, Locking C19 to L6‑20P を利用。なお、このコンセントにはブレーカーから単独で給電している。</p>
<p>また電源は評判が良さそうな1650WのASRockのTaichi TC-1650Tを選択した。GPUに大きな電力を供給する12V-2x6コネクタの安全性を考慮したATX3.1に対応している。またこの電源は、標準で100V用の電源ケーブル（C19-C20）に挿せる電源ケーブルがついてくる。これを使うと1300Wまでだが、このケーブル自体が市場にほぼ出回っていないので、テスト起動などで活用できて好感度高し。</p>
<p><ins>追記:電源 x2 が設置できるケースを使い、1300W電源x2を各々100V電源に繋ぐ、という方法もあるようだ</ins></p>
<h2>GPU</h2>
<p>RTX5090は膨大な発熱処理のため、空冷モデルではPCIスロット3〜4個分を占める厚さのものがほとんどだ。この厚さのGPUを2枚使う場合は、ライザーケーブルを使って物理的に離して設置しないと、ケースやマザーボードでぶつかって装着できないという問題が起きることが多いだろう。</p>
<p>このため選択肢として</p>
<ul>
<li>3スロット以下の空冷モデルを使う（隙間なくみっちり挿すことになり熱が心配だが）</li>
<li>2枚のGPUとも簡易水冷にする</li>
<li>1枚を空冷、1枚を簡易水冷にする</li>
<li>ライザーケーブルを使ってどうにかする</li>
</ul>
<p>あたりが考えられる。すでに自分は厚さ約3.5スロットのRTX5090を保持していたため、1枚を簡易水冷、もう1枚を空冷とし、以下の2つのGPUの選択となった。なお、もしRTX5090を1枚も持っていなければ、価格が少々高くなるが、GPUを2枚とも簡易水冷とし、CPUを空冷としたほうが、ケース内部の配置に余裕が出て楽になるし、GPU温度もさらに下げることが可能なので、そちらにしたと思う。</p>
<p>なお今回使ったGPUは以下。</p>
<ul>
<li>MSI GeForce RTX 5090 32G VENTUS 3X OC
<ul>
<li>約3.5スロットの厚みがある空冷（元々持っていた）</li>
</ul>
</li>
<li>MSI GeForce RTX 5090 32G SUPRIM LIQUID SOC
<ul>
<li>厚さ2スロット強の空冷 + 120x360の水冷ラジエータ</li>
</ul>
</li>
</ul>
<p>また、お金に余裕があれば、RTX 6000 Pro (RTX5090と同じBlackwellアーキテクチャでメモリが96GB)や、性能は少々落ちるが消費電力がかなり下がって300WのRTX PRO 6000 Blackwell Max-Q を選ぶという手もある。Max-Qは排熱の考慮もだいぶ減りそうなので、設置が楽そうだ。</p>
<h2>マザーボード</h2>
<p>マザーボードに求める要件は、PCIe 5.0 x8 の速度で二枚刺さること、上部に刺すGPU1(水冷)と、下部にさすGPU2(空冷)の間が2レーンあって問題ないことである。実際に海外で RTX5090x2 の組み立て済みPCとして販売されている実績を評価し、Ryzen が乗るASUS ProArt X870E-CREATOR WiFi AMD AM5 X870E ATXを選択した。</p>
<p>なおオンボードWiFi 7チップが載っているが、Linuxのカーネルドライバーが現状無さそうなので、オンボードWiFi で繋ごうと思ってる人は注意が必要かもしれない。自分の用途では無線は使わず有線LAN接続なので特に困っていない。</p>
<h2>ケース</h2>
<p>ケースは、下部に3.5レーン分の厚さがあるGPUを差した時、問題なくある程度の空間があり、簡易水冷のラジエータを2機(CPUとGPU1)を問題なく設置できるもので検討した結果、CORSAIR 7000D AIRFLOWとなった。通常のケースより一回り大きいが、ケース内空間が大きいことも冷却においてはメリットが大きい。PC内部が見れるガラスパネルは不要なのだが、いざ作ってみたら結構かっこ良くて満足。</p>
<h2>エアフロー（空気の流れ）</h2>
<p>ケース内で最大1650W程度の電力消費が発生し、その時発生する熱は相当なものなので、良い形で空気を循環させねばならない。</p>
<p>簡易水冷はCPUとGPU1、空冷はGPU2で使うので、どのように外気を取り込み・排出すると良いのかを考える必要がある。PCの冷却ファンは、表裏をひっくり返すことで、吸気・排気を簡単に変更することができる。AIに壁打ちしながらベストを考えた結果、以下のエアフローになった。ただこの辺は素人なので、もっと良い配置があるかもしれない。</p>
<ul>
<li>フロント・吸気
<ul>
<li>140mm ファンx2(ケース付属、本当は140mmをもう一つ追加したほうが良い)</li>
<li>GPU2(空冷)に当たる位置に配置</li>
</ul>
</li>
<li>サイド（ケース横）・吸気
<ul>
<li>GPU1の水冷・120mm x3</li>
</ul>
</li>
<li>トップ・排気
<ul>
<li>CPUの水冷・120mm x3</li>
</ul>
</li>
<li>リア・排気
<ul>
<li>ケース付属・140mm x1</li>
</ul>
</li>
</ul>
<p>この辺までが、組み立てる上であまり情報がなかったので苦労したところだ。続いて以下は好みで選べば良いと思うが、機械学習マシン視点からコメント入りで組み立てたパーツを紹介する。</p>
<h2>CPU</h2>
<p>16コア32スレッドのAMD Ryzen9 9950X。9950X3Dも出ていたが、ゲームをしない環境では誤差程度の性能差であり、差額も2万円ほど9950Xの方が安かったので9950Xを。データ加工などの処理は並列で行うことがほとんどなため、CPUコアはあればあるほど良いが、これ以上のコア数になるとThreadripperになってしまうため、16コアで。</p>
<h2>RAM</h2>
<p>せっかくなので上限の192GBを、と思っていたが、AI関連データセンタによるメモリ需要急増のため、2025年9月と比べると4-5倍ぐらいの値段で高止まりしていて、いくらなんでも高すぎるので DDR5-5600 32x2=64GBで。本当はECCにしたかったがこちらも高すぎるので…。自分の使い方の場合、容量は64GBだと時々swapにアクセスが発生する程度・かつswapがNVMe書き込み読み込みともに結構速いものを使っていることもあり、RAM はもっとあったら嬉しいが、64GBでも困ったことがほとんどない。</p>
<p>今回、中国のAcclamatorというブランドのメモリが、他のブランドの同容量のメモリの60%ぐらいの価格で売っていた(今はそこそこ高くなってしまったようだが)ので、DDR5 5600MHz 32GBx2 を購入。5600MHzでmemtest86やstresstest-cliで12時間ほど負荷をかけてみたが、とりわけエラーなく使えている。長期の耐久性や暑さ本番の夏(現在は冬で寒い)はわからない。GPU学習時にRAM速度の影響はほとんどないので、さらに安定すべく4800Mhzにクロックを落とし使っている。推論時にCPUオフロードする場合など、RAM速度も重要になるケースもあるのだけど、自分はやる予定がないので。</p>
<p><ins>追記: 結局メモリ不足を感じ、もう32GBx2を増やして合計128GBへ。</sin></p>
<h2>ストレージ・NVMe</h2>
<p>学習に使うデータは、雑にやるとデータがシャッフルされしてランダムアクセスが発生するため(たとえばHuggingFace Transformers も標準では学習時必ず shuffle する)。そのため容量が巨大なNVMe(SSD)を。容量はあるだけ良い。</p>
<ul>
<li>Sandisk SN850X NVMe SSD WDS800T2X0E 8TB
<ul>
<li>PCIe のCPU直結レーン。8TB でも足りない（データを削除しながら使っている）ので本当はもっと容量が欲しい。</li>
</ul>
</li>
<li>Samsung 980 Pro 2TB
<ul>
<li>これは余っていたので追加</li>
<li>チップセット共有レーン</li>
</ul>
</li>
</ul>
<h2>ストレージ・HDD</h2>
<p>生ダウンロードデータの一時的なファイル置き場として 14TB のHDDを使っている。ランダムアクセスが発生する用途には遅すぎて使えないのだけど、たとえば実運用面では、 HuggingFace datasets ライブラリはまず環境変数 <code>HF_HUB_CACHE</code> にデータをダウンロードするのだが、実際にライブラリがロードする際は、parquet ファイルから arrow 形式に変換されるため、後者の方が NVMe でアクセスできれば良いので、<code>HF_HUB_CACHE</code> のディレクトリだけHDDに指定することで、切り分けて使えている。</p>
<ul>
<li>TOSHIBA MG07ACA14TE 14TB</li>
</ul>
<h2>CPUクーラー</h2>
<p>120x3 のラジエータの簡易水冷モデルなら特にこだわりがなかったので、CORSAIR NAUTILUS 360 RS LCDを利用。CPUクーラーの表面に液晶があるモデルで、液晶にCPU温度表示できるのいいじゃん、と購入してからこの制御はUSB経由で行われるため、Linuxからだと制御が難しい(OSSでできるが、サクッと温度表示などは難しそう)ことの気づく。ので、今ならLCD無しモデルを買ったかな…。</p>
<h2>組み立て</h2>
<p>ケースや電源や空冷が重い(筋肉痛)、自分のミスでしょっちゅうファンの前後ろを間違える、ラジエータの上下を間違える、など以外は特に困らず組み立てられ、一発で起動し問題無く動いている。</p>
<h2>OS</h2>
<p>使い慣れている Ubuntu Server 24 LTS で。ssh で繋ぐだけなので、GUIは一切使っていない。</p>
<h1>RTX5090 x2 PCを作ってみての感想</h1>
<p>実際に作ってから1ヶ月ほど経ったが、冬場だからかもしれないが、GPU二枚をフルで使っても特に問題なく安定して動いている。良かったところとしては、PCIe がボトルネックにならない場合、例えばMLMでのbi-encoderモデルの学習速度が RTX5090x1 に比べ x1.8程度の速度になり、だいぶ速くなった。また、推論も水平処理ができる場合、例えば vLLM に Qwen3-8B モデルを載せて1000万件処理する、みたいな処理もほぼ2倍速で処理できるので便利だ。</p>
<p>CUDAは環境変数 CUDA_VISIBLE_DEVICES でプログラムから見えるGPUを簡単に切り替えできるので、たとえばGPU2を使いたい場合は CUDA_VISIBLE_DEVICES=1 とするだけで、プログラムには一切手を入れずに1枚のGPUとして認識させることできるのも便利。簡単にGPUを切り替えつつ使うことができている。</p>
<p>また、マルチGPU周りの知見を得るという点でも、今までずっと1GPUしか使ってこなかったため、複数GPU環境で学習・推論の方法や考え方を知ることができて勉強になり、こちらの点でも良かった。</p>
<p>ただ、PCIe 5.0 x8 の速度がボトルネックに感じることが割とあって、例えば PyTorch DDP では学習stepごとに GPU間のデータを同期する All-Reduce が発生するが、学習方法によっては非常に時間がかかる。巨大バッチでのコントラスト学習とかね。すると GPU SMの idle 時間がグッと増えて、速度向上がせいぜい1.2倍程度、場合によっては1 GPUの方が速いみたいなケースすらある。</p>
<p>B200、H200 などのデータセンター向けGPUではNVLinkを使うと、構成によっては GPU間で 数百GB/s〜TB/sの速度が出るため、高速な転送速度が確保できるが、PCIe 5.0 x8 では実効速度は 約20-30GB/s ほどのため、NVLink に比べると圧倒的に遅かったりする。高いGPUはよくできているなぁ(B200 x8 なマシン1つで8000万円程度かな…)。</p>
<p>というわけで、作ってみての満足度は高い。パーツを購入したタイミングも、メモリは高くなっていたが、2026年1月中旬はさらにストレージもメモリもGPU(RTX5090)も高くなってしまったので、まだマシだったタイミングであった。AI需要・そして円安もあり色々と高くなってしまったなぁ…。</p>]]></description>
            <link>https://secon.dev/entry/2026/01/19/100000-rtx5090x2-pc</link>
            <guid isPermaLink="false">/entry/2026/01/19/100000-rtx5090x2-pc</guid>
            <dc:creator><![CDATA[secondlife / @hotchpotch / Yuichi Tateno]]></dc:creator>
            <pubDate>Mon, 19 Jan 2026 01:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[振り返り2025年]]></title>
            <description><![CDATA[<h1>生活</h1>
<h2>子供</h2>
<p>子供がうまれた。人生で一番大きな変化は子供が生まれた時、とはよく聞くが、当事者になってみると全くその通りだと思う。何もかも子供主体な考え方に変わる。それにしても子供はかわいい。かわいすぎる。子供を育てられる幸せを噛み締める。リモートワークで、しょっちゅう子の顔を見れる、ありがたさもある。</p>
<p>産まれる前は妻が持病関連で体を悪くし、長期入院になったり、出産後もどうなるかわからずだいぶ不安だったが、その後の回復は良好で、問題無く日常生活を過ごせている。健康のありがたさよ。私は(四|五)十肩、以外はだいたい元気。</p>
<div class="photos photos-small"><span itemscope="" itemtype="http://schema.org/Photograph"><a href="https://storage.googleapis.com/secons-site-images/photo/large/20251231_L1001845.webp"><img src="https://storage.googleapis.com/secons-site-images/photo/medium/20251231_L1001845.webp" class="photo" itemprop="image" /></a></span></div>
<h2>家</h2>
<p>昨年建てて、昨年末から新しく住み出した家、すこぶる快適。冬はそれなりに寒いし、周りが農地なので夏は虫が多いが、それらをさっ引いても大変暮らしやすい。子も増えたことだし、建てて良かった。</p>
<h2>車</h2>
<p>テスラのモデルY ジュニパー ロングレンジをお迎え入れした。BEVのエンジンがない快適さ(静か、あっという間に速度が上がる)もさることながら、ソフトウェア・UX周辺、ほんとよくできている。ほとんどの車が、過去の車の延長線上なUXだが、新興の会社は過去を踏襲する必要がないので、新しい体験設計ができ、それをひしひしと感じる。車移動（というのは田舎において移動手段のほぼ全てある）が非常に楽に・快適になった。</p>
<p>現在のオートパイロット運転アシストでさえもかなり快適なのに、将来はFSD(完全自動運転、という名の、いい感じの自動運転支援)が日本でも使えるようになるだろうから、そちらもとても楽しみである。</p>
<h1>技術</h1>
<p>引き続き、情報検索周りを主に、技術的なあれこれやプロダクトづくりをやっていた。コーディングエージェントが台頭した年で、ほぼ全ての技術作業はエーアイさんにやってもらっているが、打ち手が増えて、できることが大きく広がったと感じる。通常のソフトウェア開発に限らず、例えば情報検索モデル開発関連も、エーアイが全部やってくれ、今までだったら手を動かす時間がかかりすぎていて大変だったことも、エーアイYOLO、ですんで最高だ。</p>
<p>エーアイが代替できない・代替しない技術をちゃんとやる、というのが正解プロダクト不定の時代の仕込みとしては大事だと思っているのだけど、その技術的なところを色々やれているので、楽しいね。バイアスがかかってるので、自分がそう思ってるだけで、簡単に代替される可能性はもちろんあるのだけど。</p>
<p>仕事周りでも今年はメインで作っていたエーアイプロダクトが世に出て、世の中的にも会社的にも一定の評価をいただけたようで、ありがたい限り。チーム開発のやりやすさの賜物でもあるので、関係者各位ありがとうございます。来年もまたチーム、エーアイさんの手を大いに借りて、技術的なことをやりつつも、新しいプロダクトを作っていきたい。</p>
<hr>
<p>2025年はいろいろあったが、子が産まれたに尽きる。毎度のことだが、さまざまなことをサポートしてくれる妻に感謝だ。というわけで、皆様2026年もよろしくお願いいたします。</p>
<div class="photos photos-small"><span itemscope="" itemtype="http://schema.org/Photograph"><a href="https://storage.googleapis.com/secons-site-images/photo/large/20251231_L1001851.webp"><img src="https://storage.googleapis.com/secons-site-images/photo/medium/20251231_L1001851.webp" class="photo" itemprop="image" /></a></span></div>
<hr>
<ul>
<li><a href="https://secon.dev/entry/2024/12/31/100000-furikaeri-2024/">振り返り2024年</a></li>
<li><a href="https://secon.dev/entry/2024/01/08/070000/">振り返り2023年</a></li>
<li><a href="https://secon.dev/entry/2022/12/31/070000/">振り返り2022年</a></li>
<li><a href="https://secon.dev/entry/2021/12/31/070000/">振り返り2021年</a></li>
<li><a href="https://secon.dev/entry/2020/12/31/080000-hurikaeri-2020/">2020年の振り返り</a></li>
</ul>]]></description>
            <link>https://secon.dev/entry/2025/12/31/100000-furikaeri-2025</link>
            <guid isPermaLink="false">/entry/2025/12/31/100000-furikaeri-2025</guid>
            <dc:creator><![CDATA[secondlife / @hotchpotch / Yuichi Tateno]]></dc:creator>
            <pubDate>Wed, 31 Dec 2025 01:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[LLMに渡す前に関連しない文を削除するモデル OpenProvence を公開]]></title>
            <description><![CDATA[<p>昨今、LLMが回答するための「良い知識」を作るために、検索を行い情報を集め、さらに足りない知識を補うために多方面のさまざまな検索クエリを作り検索結果から必要な情報だけを抽出したり…といったことを、再起的に行っています。AI Agent、DeepResearch、Context Engineering と 2025年の流行の技術では、このような検索を裏側で行うことがしばしばあり、筋が良い情報をいかに検索で取得できるかが鍵になることも多いでしょう。</p>
<p>しかしながら、大量に検索を行うと「検索結果」の情報も同時に増加していきます。そのため、本当に必要な情報の抽出をLLMが間違えたり、ハルシネーションが起きたり、入力情報の増加により処理が遅くなったり、LLM利用費用が増加したりと、大量の検索が難しかったりもします。</p>
<p>そこで、検索結果をLLMに渡す前に、関連しない情報は削除しちゃおう、ついでに関連度スコアもつけちゃおう、というアプローチが <a href="https://arxiv.org/abs/2501.16214">Provence</a> です。このアプローチでは、検索でヒットした文章のうち、関連しない部分を削除することが可能です。実際にデルの性能を測定したところ、長文の質問・回答データセットを用いた評価(MLDR + LLM eval)では、80-95%ほど文章を削除できました。10000文字の文章なら500-2000字程度にLLMに渡す前に減らせる、ということですね。かなりの入力データの削減が期待できますね。短い文章に分割されたような短文が多いデータセットでも、ドメインによりますが30〜70%の文の削除が行われています。</p>
<p><img src="https://storage.googleapis.com/secons-site-images/other/open_provence/carbon_xsmall_ja.png" alt="短文での削除例"></p>
<p>ただ研究開発として公開されている Provence 実装やモデルは非商用で、日本語のデータセットも公開されていなかったので、今回 <a href="https://github.com/hotchpotch/open_provence/">OpenProvence</a> というプロジェクトを作成し、で学習推論などのソースコードやモデルの重みなどを "オープン" なライセンスで公開しました。日本語データセットも作成して公開しています(データセットは大元のライセンスがあるため、オープンなライセンスではないものが多いですが)。</p>
<hr>
<h2>OpenProvence の試し方</h2>
<p>以下の URL に huggingface spaces (CPU) 環境で動くデモを用意したのでお試しください。デモのサンプルにあるWikipediaの情報検索のページ情報をもとに「ベクトル検索は？」をクエリに文削除を実行すると、約5000文字の記事が400文字に削減され、かつベクトル検索についての情報のみが残った形で出力さると思います。</p>
<ul>
<li>🤗 <a href="https://huggingface.co/spaces/hotchpotch/open_provence_demo">https://huggingface.co/spaces/hotchpotch/open_provence_demo</a></li>
</ul>
<p>またデモは以下の手順でローカルマシンでも手軽に動かせます。最近の MacBook でしたら、かなり高速に推論することも可能でしょう。</p>
<pre><code class="hljs language-bash">git <span class="hljs-built_in">clone</span> https://huggingface.co/spaces/hotchpotch/open_provence_demo
<span class="hljs-built_in">cd</span> open_provence_demo
uv sync
uv run python app.py</code></pre>
<h3>python からの利用方法</h3>
<p>python からは以下の感じで利用できます。小型のxsmallモデルならCPU環境でも推論可能です。また GPU 環境(NVIDIA + flash attention2)では、即座にで推論が完了し、文章の削除が行われるでしょう。本番検索環境に組み込んでも、問題ない速度で処理できると思っています。</p>
<pre><code class="hljs language-python"><span class="hljs-keyword">from</span> transformers <span class="hljs-keyword">import</span> AutoModel

<span class="hljs-comment"># 利用モデルに合わせて変更</span>
model_name = <span class="hljs-string">"hotchpotch/open-provence-reranker-xsmall-v1"</span>
provence = AutoModel.from_pretrained(model_name, trust_remote_code=<span class="hljs-literal">True</span>)

question:<span class="hljs-built_in">str</span> = <span class="hljs-string">"日本の首都について"</span>
context:<span class="hljs-built_in">str</span> = <span class="hljs-string">"""
今日は学校に行き、さまざまなことを学んだり、友達と学食でたらふく食べた。
日本の首都は東京で、東京は日本の政治、経済、文化の中心地らしい。この都市は約1,400万人の人口を抱える世界有数の大都市らしい。
夜は飲み会に誘われたが、参加せずに帰宅した、今月そんなにお金が残ってないからなぁ、残念だ。
"""</span>

result = provence.process(question, context, threshold=<span class="hljs-number">0.1</span>)
<span class="hljs-built_in">print</span>(<span class="hljs-string">f"Reranking Score: <span class="hljs-subst">{result[<span class="hljs-string">'reranking_score'</span>]:<span class="hljs-number">.4</span>f}</span>"</span>)
<span class="hljs-built_in">print</span>(<span class="hljs-string">f"Compression Rate: <span class="hljs-subst">{result[<span class="hljs-string">'compression_rate'</span>]:<span class="hljs-number">.1</span>f}</span>%"</span>)
<span class="hljs-built_in">print</span>(<span class="hljs-string">f"Pruned Context:\n<span class="hljs-subst">{result[<span class="hljs-string">'pruned_context'</span>]}</span>"</span>)

<span class="hljs-comment"># 出力例:</span>
<span class="hljs-comment"># Reranking Score: 0.7043</span>
<span class="hljs-comment"># Compression Rate: 62.5%</span>
<span class="hljs-comment"># Pruned Context:</span>
<span class="hljs-comment"># 日本の首都は東京で、東京は日本の政治、経済、文化の中心地らしい。</span>
<span class="hljs-comment"># この都市は約1,400万人の人口を抱える世界有数の大都市らしい。</span></code></pre>
<h2>コーディングエージェントの活用</h2>
<p>OpenProvence は、推論・学習モデル実装、評価実装、データセット作成実装など、私は一行もコードを書かない縛りで、全ての実装はコーディングエージェント(Claude Code, Codex) によって行いました。かなり修正の指示は必要でしたが、隙間時間に進めたプロジェクトとしてはなかなかのものが、コーディングエージェントを活用することで出来上がったのかな、と思っています。出来上がった成果物のコードを見ると、もっとシンプルなコードにすることはできそうですが、現状のLLMが理解しやすい形・LLMが修正しやすい形だと、これぐらいの冗長なコードが丁度良いのかもしれません。</p>
<p>適切な指示と開発指針、AIが自身で開発、改善し続けられる環境等を作り続けることで、プロダクションレベルの品質のソフトウェアをAIと協調しながら作成する、<a href="https://simonwillison.net/2025/Oct/7/vibe-engineering/">Vibe engineering</a> という言葉も生まれました。</p>
<p>開発指針やユニットテスト、CI、コードレビュー環境といった通常のコーディングエージェントを用いたソフトウェア開発に加え、モデル学習時の学習を短時間で行える最小ベースラインと評価データの用意(これが意図せず変化するとバグ)、データセットについての詳細な説明等々を用意することで、ある程度の規模の機械学習モデル・プロジェクトも開発できることを実感しています。</p>
<h2>おわりに</h2>
<p>OpenProvence のような、質問と関連しない文章を削除するアプローチは、とりわけ巨大な文章を処理するようなプロダクトととても相性が良いでしょう。</p>
<p>2024年はRAGが話題でしたが、2025年のAI Agent、DeepResearch、Context Engineering のような流行を先取りし、技術的に重要なポイントを研究開発した Naver Labs Europe の Provence チームの先見の明(Provenceは2025年1月公開!)に驚きと感謝を。</p>
<p>昨今、LLMを活用するプロダクトでは、裏側で情報検索を活用することで価値を高められ、情報検索技術は引き続きとても面白いです。このプロジェクトが少しでもプロダクトや研究で活用していただけたら幸いです。</p>
<ul>
<li><a href="https://github.com/hotchpotch/open_provence/">https://github.com/hotchpotch/open_provence/</a></li>
<li><a href="https://huggingface.co/collections/hotchpotch/openprovence">https://huggingface.co/collections/hotchpotch/openprovence</a></li>
</ul>]]></description>
            <link>https://secon.dev/entry/2025/10/31/100000-open-provence-release</link>
            <guid isPermaLink="false">/entry/2025/10/31/100000-open-provence-release</guid>
            <dc:creator><![CDATA[secondlife / @hotchpotch / Yuichi Tateno]]></dc:creator>
            <pubDate>Fri, 31 Oct 2025 01:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Embedding Gemma 300M 文章ベクトルの日本語性能を JMTEB で測る]]></title>
            <description><![CDATA[<p>Google が先日 EmbeddingGemma <a href="https://huggingface.co/google/embeddinggemma-300m">google/embeddinggemma-300m</a> という文章ベクトルモデルをリリースしましたね。MTEB(Multilingual v2)においては、かなりの成績、というわけで日本語性能もちゃんと測るべく、JMTEB(v1)でベンチマークを取ってみました。</p>
<p>結論から言うと日本語においては、EmbeddingGemma はとても性能が低かったです。</p>
<h2>JMTEB v1 ベンチマーク評価</h2>
<table>
<thead>
<tr>
<th>モデル</th>
<th>params</th>
<th>avg</th>
<th>Retrieval</th>
<th>STS</th>
<th>Classification</th>
<th>Reranking</th>
<th>Clustering</th>
<th>PairClass</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="https://huggingface.co/google/embeddinggemma-300m">google/embeddinggemma-300m</a></td>
<td>308M</td>
<td><strong>58.10</strong></td>
<td>42.18</td>
<td>73.36</td>
<td>63.23</td>
<td>91.55</td>
<td>45.87</td>
<td>62.42</td>
</tr>
<tr>
<td><a href="https://huggingface.co/intfloat/multilingual-e5-small">intfloat/multilingual-e5-small</a></td>
<td>118M</td>
<td><strong>69.52</strong></td>
<td>67.27</td>
<td>80.07</td>
<td>67.62</td>
<td>93.03</td>
<td>46.91</td>
<td>62.19</td>
</tr>
<tr>
<td><a href="https://huggingface.co/intfloat/multilingual-e5-large">intfloat/multilingual-e5-large</a></td>
<td>560M</td>
<td><strong>71.65</strong></td>
<td>70.98</td>
<td>79.70</td>
<td>72.89</td>
<td>92.96</td>
<td>51.24</td>
<td>62.15</td>
</tr>
<tr>
<td><a href="https://huggingface.co/cl-nagoya/ruri-v3-30m">cl-nagoya/ruri-v3-30m</a></td>
<td>37M</td>
<td><strong>74.51</strong></td>
<td>78.08</td>
<td>82.48</td>
<td>74.80</td>
<td>93.00</td>
<td>52.12</td>
<td>62.40</td>
</tr>
<tr>
<td><a href="https://huggingface.co/cl-nagoya/ruri-v3-310m">cl-nagoya/ruri-v3-310m</a></td>
<td>315M</td>
<td><strong>77.24</strong></td>
<td>81.89</td>
<td>81.22</td>
<td>78.66</td>
<td>93.43</td>
<td>55.69</td>
<td>62.60</td>
</tr>
</tbody>
</table>
<p><em>注：MTEB v1の16の日本語タスクのマイクロ平均（単純平均）で算出</em></p>
<p>なお、JMTEBの設定は<a href="https://github.com/hotchpotch/JMTEB/compare/e152a7a351d0550466a...f23d9a737f70c57f8#diff-7c452491cda037603553f833680a105d21981861f8bd037a91779d824f641e45">こちら</a>で、各種 prefix などはつけているはずです。また結果の json である <a href="https://gist.github.com/hotchpotch/62eb81698b66e3fea5a15816521f695d">summary.json はこちら(gist)</a>。再現方法も gist に記載してます。私の測定結果がおかしかったら教えてください。</p>
<p><ins>2025/10/03追記: <a href="https://huggingface.co/google/embeddinggemma-300m/discussions/3#68baf8490495f751dd1a654b">transformersのバグの影響</a>で、最新版だと ruri-base 並に性能が向上するとのこと。LM8(@ShengzheLi) さん、情報ありがとうございます!</ins></p>
<h2>JQaRA / JaCWIR</h2>
<p>JMTEB v1 でのスコアが低すぎるので、別途 <a href="https://github.com/hotchpotch/JQaRA">JQaRA</a> / <a href="https://github.com/hotchpotch/JaCWIR">JaCWIR</a> でも評価してみましたが、やはりかなり低い結果となりました。</p>
<table>
<thead>
<tr>
<th>モデル</th>
<th>JQaRA (nDCG@10)</th>
<th>JQaRA (MRR@10)</th>
<th>JaCWIR (MAP@10)</th>
<th>JaCWIR (HIT_RATE@10)</th>
</tr>
</thead>
<tbody>
<tr>
<td>google/embeddinggemma-300m</td>
<td>0.261</td>
<td>0.457</td>
<td>0.730</td>
<td>0.904</td>
</tr>
<tr>
<td>intfloat/multilingual-e5-small</td>
<td>0.492</td>
<td>0.729</td>
<td>0.869</td>
<td>0.970</td>
</tr>
<tr>
<td>intfloat/multilingual-e5-large</td>
<td>0.554</td>
<td>0.799</td>
<td>0.876</td>
<td>0.973</td>
</tr>
</tbody>
</table>
<h1>MTEB 高性能 ≠ 日本語高性能</h1>
<p>先日評価した Qwen3 Embedding (<a href="https://secon.dev/entry/2025/06/11/100000-qwen3-embedding-jmteb/">Qwen3 Embedding 文章ベクトルの日本語性能を JMTEB で測る</a>)もですが、最近の MTEB 高評価マルチリンガル embedding モデルは、日本語性能が低いことが多いですね。なんでだろうと、MTEB Leaderboard の <code>Language-specific</code> の <code>Japanese</code> を見ると、Qwen3 Embeddings, Embedding Gemma 共に Pair Classification しか日本語結果では載っていないので、ほぼ参考になりません。マルチリンガル性能とは…。</p>
<p>またこの Qwen3 Embedding, Embedding Gemma の2モデルは decoder モデルベースのアーキテクチャです。embeddinggemma-300m の中身を見ると、<a href="https://huggingface.co/google/embeddinggemma-300m/tree/main">埋め込み用の HEAD (pooling + 2層dense) を mean pooling して使っています</a>ね。</p>
<p>decoder + 小さなパラメータサイズの場合、少なくとも日本語における性能は他の encoder マルチリンガルモデルよりだいぶ低い結果でした。この辺は、そもそも日本語を embeddings タスクでほとんど学習させてないからなのか、それとも大元の小さな decoder の時点で日本語汎化性能が低いのか…。</p>]]></description>
            <link>https://secon.dev/entry/2025/09/18/100000-embedding-gemma300m</link>
            <guid isPermaLink="false">/entry/2025/09/18/100000-embedding-gemma300m</guid>
            <dc:creator><![CDATA[secondlife / @hotchpotch / Yuichi Tateno]]></dc:creator>
            <pubDate>Thu, 18 Sep 2025 01:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[JFWIR - Japanese FineWeb Information Retrieval: 日本語FineWebを用いた巨大な情報検索用データセットを公開]]></title>
            <description><![CDATA[<p>日本語の情報検索（Information Retrieval, IR）分野において、これまで多くのデータセットがWikipediaを中心に構築されてきました。しかし、実際のWebにはWikipediaのような「綺麗に整形された文章」だけでなく、ブログ、ニュース、フォーラムなど、多様な文体やノイズを含む文章が存在します。</p>
<p>今回公開した <strong>JFWIR (Japanese FineWeb Information Retrieval)</strong> は、この課題に取り組むために作成した約6,400万件の大規模な日本語情報検索に活用できるデータセットです。このデータセットは、高品質な教育的コンテンツを含むWebクロールデータ「<a href="https://huggingface.co/datasets/hotchpotch/fineweb-2-edu-japanese">fineweb-2-edu-japanese</a>」を基に構築されています。</p>
<ul>
<li><a href="https://huggingface.co/datasets/hotchpotch/JFWIR">https://huggingface.co/datasets/hotchpotch/JFWIR</a></li>
</ul>
<h2>JFWIRの特徴</h2>
<h3>1. 大規模かつ多様性の高いデータセット</h3>
<p>JFWIRは以下の特徴を持つデータセットです：</p>
<ul>
<li><strong>6,400万件以上の文書-クエリペア</strong>: 各文書に対して7種類の異なるタイプのクエリ（keywords, synonym_keywords, query, alt_query, title, faq, summary）を生成</li>
<li><strong>実際のWeb文章</strong>: Wikipedia以外の教育的価値の高いWebコンテンツを収録</li>
<li><strong>ハードネガティブ付き</strong>: 効果的な学習のための類似しているネガティブ文書</li>
</ul>
<h3>2. ベンチマーク評価結果</h3>
<p>JFWIRを使用して学習させたリランキングモデルの性能を、主要な日本語情報検索ベンチマークで評価しました。以下の4つのベンチマークで比較を行いました：</p>
<table>
<thead>
<tr>
<th>ベンチマーク</th>
<th>JFWIRなし</th>
<th>JFWIR 1000万件利用</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="https://huggingface.co/datasets/SkelterLabsInc/JQaRA">JQaRA</a></td>
<td>0.7621</td>
<td>0.7633</td>
</tr>
<tr>
<td><a href="https://huggingface.co/datasets/miracl/miracl">MIRACL(ja)</a></td>
<td>0.8332</td>
<td>0.8385</td>
</tr>
<tr>
<td><a href="https://techblog.yahoo.co.jp/entry/2022122030379907/">jsquad</a></td>
<td>0.9801</td>
<td>0.9821</td>
</tr>
<tr>
<td><a href="https://huggingface.co/datasets/hotchpotch/JaCWIR">JaCWIR</a></td>
<td>0.9339</td>
<td><strong>0.9586</strong></td>
</tr>
</tbody>
</table>
<p>特に、Web文章を対象とするJaCWIRでは0.9339から0.9586への改善が見られました。</p>
<h2>使い方</h2>
<p>JFWIRはHugging Face Datasetsから簡単に利用できます。以下に基本的な使用例を示します：</p>
<pre><code class="hljs language-python"><span class="hljs-keyword">from</span> datasets <span class="hljs-keyword">import</span> load_dataset

<span class="hljs-comment"># メインデータセットの読み込み</span>
train_ds = load_dataset(<span class="hljs-string">"hotchpotch/JFWIR"</span>, split=<span class="hljs-string">"train"</span>, name=<span class="hljs-string">"small_tokens_cleaned"</span>)

<span class="hljs-comment"># サンプルデータの確認</span>
<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">3</span>):
    sample = train_ds[i]
    <span class="hljs-built_in">print</span>(<span class="hljs-string">f"Query: <span class="hljs-subst">{sample[<span class="hljs-string">'query'</span>]}</span>"</span>)
    <span class="hljs-built_in">print</span>(<span class="hljs-string">f"Document: <span class="hljs-subst">{sample[<span class="hljs-string">'text'</span>][:<span class="hljs-number">100</span>]}</span>..."</span>)

<span class="hljs-comment"># ハードネガティブ付きデータセットの読み込み</span>
hard_negatives_ds = load_dataset(<span class="hljs-string">"hotchpotch/JFWIR"</span>, split=<span class="hljs-string">"train"</span>, name=<span class="hljs-string">"hard_negatives"</span>)

<span class="hljs-comment"># ハードネガティブの使用例</span>
<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">3</span>):
    hn_sample = hard_negatives_ds[i]
    pos_id = hn_sample[<span class="hljs-string">'pos_id'</span>]
    pos_doc = train_ds[pos_id]
    
    <span class="hljs-built_in">print</span>(<span class="hljs-string">f"Query: <span class="hljs-subst">{pos_doc[<span class="hljs-string">'query'</span>]}</span>"</span>)
    <span class="hljs-built_in">print</span>(<span class="hljs-string">f"Positive (score: <span class="hljs-subst">{hn_sample[<span class="hljs-string">'pos_score'</span>]:<span class="hljs-number">.3</span>f}</span>): <span class="hljs-subst">{pos_doc[<span class="hljs-string">'text'</span>][:<span class="hljs-number">100</span>]}</span>..."</span>)
    
    <span class="hljs-comment"># ネガティブ文書をスコア順にソート</span>
    neg_pairs = <span class="hljs-built_in">list</span>(<span class="hljs-built_in">zip</span>(hn_sample[<span class="hljs-string">'neg_ids'</span>], hn_sample[<span class="hljs-string">'neg_scores'</span>]))
    neg_pairs.sort(key=<span class="hljs-keyword">lambda</span> x: x[<span class="hljs-number">1</span>])
    
    <span class="hljs-built_in">print</span>(<span class="hljs-string">"Negatives (lowest scores):"</span>)
    <span class="hljs-keyword">for</span> neg_id, score <span class="hljs-keyword">in</span> neg_pairs[:<span class="hljs-number">2</span>]:
        <span class="hljs-built_in">print</span>(<span class="hljs-string">f"  Score <span class="hljs-subst">{score:<span class="hljs-number">.3</span>f}</span>: <span class="hljs-subst">{train_ds[neg_id][<span class="hljs-string">'text'</span>][:<span class="hljs-number">80</span>]}</span>..."</span>)</code></pre>
<h2>データセットの作成プロセス</h2>
<h3>1. 高品質な日本語Web文章の収集</h3>
<p>まず、大規模なWebクロールデータセット「<a href="https://huggingface.co/datasets/HuggingFaceFW/fineweb-2">FineWeb-2</a>」から、教育的価値の高い日本語コンテンツを抽出して「<a href="https://huggingface.co/datasets/hotchpotch/fineweb-2-edu-japanese">fineweb-2-edu-japanese</a>」を作成しました。さらに、Web文章特有のノイズを除去し、適切な文章長に調整した「small_tokens_cleaned」サブセットを作成しました。</p>
<h3>2. 多様なクエリの生成</h3>
<p>6,400万件のデータセットに対してクエリを生成するため、軽量なクエリ生成モデル「<a href="https://secon.dev/entry/2025/05/07/100000-query-crafter-japanese/">query-crafter-japanese</a>」を使用しました。多様性を確保するため、以下の3つのモデルを組み合わせて使用しています：</p>
<ul>
<li><a href="https://huggingface.co/hotchpotch/query-crafter-japanese-Qwen3-1.7B">hotchpotch/query-crafter-japanese-Qwen3-1.7B</a></li>
<li><a href="https://huggingface.co/hotchpotch/query-crafter-japanese-Qwen3-4B">hotchpotch/query-crafter-japanese-Qwen3-4B</a></li>
<li><a href="https://huggingface.co/hotchpotch/query-crafter-japanese-sarashina2.2-3b-instruct-v0.1">hotchpotch/query-crafter-japanese-sarashina2.2-3b-instruct-v0.1</a></li>
</ul>
<p>各文書に対して7種類のクエリタイプ（keywords, synonym_keywords, query, alt_query, title, faq, summary）を生成することで、多角的な検索ニーズに対応できるデータセットを構築しました。</p>
<h3>3. ハードネガティブの作成</h3>
<p>情報検索モデルの性能を向上させるため、ハードネガティブ（クエリに類似しているが正解ではない文書）を含むデータセットも作成しました：</p>
<ol>
<li><strong>埋め込みモデルによる類似文書検索</strong>: <a href="https://huggingface.co/cl-nagoya/ruri-v3-30m">ruri-v3-30m</a>モデルを使用して6,400万件の文書をベクトル化し、各文書に対して類似度の高い文書を検索</li>
<li><strong>適切なネガティブの選定</strong>: 類似度top10-50とtop50-200からランダムサンプリング</li>
<li><strong>リランカースコアの付与</strong>: <a href="https://huggingface.co/hotchpotch/japanese-reranker-xsmall-v2">japanese-reranker-xsmall-v2</a>を使用してスコアリングしています。たとえば正例として不適切なもの（スコア&#x3C;0.6など）や負例として不適切なもの（スコア>0.4など）を除外して利用することで、より適切な正例・負例を選択できます。</li>
</ol>
<h2>今後の展望</h2>
<p>JFWIRは、日本語情報検索分野の発展に貢献することを目的として公開されました。しかしながら、<a href="https://secon.dev/entry/2025/05/07/100000-query-crafter-japanese/">query-crafter-japanese</a> は文章からのある程度単純なクエリ生成にとどまり、もっと多様な価値のある質問文を作成することで、より様々な情報検索精度の向上が可能になると思っております。</p>
<h2>まとめ</h2>
<p>JFWIRは、Wikipediaに偏重していた従来の日本語IRデータセットとは異なるアプローチとして、実際のWeb文章を対象とした情報検索データセットです。約6,400万件のデータ、7種類のクエリタイプ、対照学習用のハードネガティブなど、情報検索システムの開発に活用いただける要素を含んでおります。</p>
<p>データセットはHugging Faceで公開されており、ODC-byライセンスの下で自由に利用できます。日本語情報検索分野の発展に、このデータセットが少しでも貢献できれば幸いです。</p>
<hr>
<h2>関連リンク</h2>
<h3>データセット</h3>
<ul>
<li><strong>JFWIRデータセット</strong>: <code>hotchpotch/JFWIR</code> (Hugging Face Datasets)</li>
<li><strong>fineweb-2-edu-japanese</strong>: <a href="https://huggingface.co/datasets/hotchpotch/fineweb-2-edu-japanese">https://huggingface.co/datasets/hotchpotch/fineweb-2-edu-japanese</a></li>
<li><strong>FineWeb-2</strong>: <a href="https://huggingface.co/datasets/HuggingFaceFW/fineweb-2">https://huggingface.co/datasets/HuggingFaceFW/fineweb-2</a></li>
</ul>
<h3>モデル</h3>
<ul>
<li><strong>ruri-v3-30m（埋め込みモデル）</strong>: <a href="https://huggingface.co/cl-nagoya/ruri-v3-30m">https://huggingface.co/cl-nagoya/ruri-v3-30m</a></li>
<li><strong>ruri-v3-pt-70m（事前学習モデル）</strong>: <a href="https://huggingface.co/cl-nagoya/ruri-v3-pt-70m">https://huggingface.co/cl-nagoya/ruri-v3-pt-70m</a></li>
<li><strong>japanese-reranker-xsmall-v2</strong>: <a href="https://huggingface.co/hotchpotch/japanese-reranker-xsmall-v2">https://huggingface.co/hotchpotch/japanese-reranker-xsmall-v2</a></li>
<li><strong>query-crafter-japanese（クエリ生成モデル）</strong>:
<ul>
<li><a href="https://huggingface.co/hotchpotch/query-crafter-japanese-Qwen3-1.7B">hotchpotch/query-crafter-japanese-Qwen3-1.7B</a></li>
<li><a href="https://huggingface.co/hotchpotch/query-crafter-japanese-Qwen3-4B">hotchpotch/query-crafter-japanese-Qwen3-4B</a></li>
<li><a href="https://huggingface.co/hotchpotch/query-crafter-japanese-sarashina2.2-3b-instruct-v0.1">hotchpotch/query-crafter-japanese-sarashina2.2-3b-instruct-v0.1</a></li>
</ul>
</li>
</ul>
<h3>記事・論文</h3>
<ul>
<li><a href="https://secon.dev/entry/2025/05/07/100000-query-crafter-japanese/">query-crafter-japanese記事</a></li>
<li><a href="https://techblog.yahoo.co.jp/entry/2022122030379907/">日本語言語理解ベンチマークJGLUEの構築 〜 自然言語処理モデルの評価用データセットを公開しました</a></li>
<li><a href="https://arxiv.org/abs/2210.09984">MIRACL: A Multilingual Retrieval Dataset Covering 18 Diverse Languages</a></li>
<li><a href="https://arxiv.org/abs/2406.17557">FineWeb-Edu: The Finest Collection of Educational Content the Web Has to Offer</a></li>
<li><a href="https://arxiv.org/abs/2409.07737">Ruri: Japanese General Text Embeddings</a></li>
</ul>
<p><strong>作者</strong>: <a href="https://secon.dev/">Yuichi Tateno (@hotchpotch)</a></p>
<h2>ライセンス</h2>
<p>本データセットは、元の FineWeb2 と同様に <strong>Open Data Commons Attribution License (ODC-By) v1.0</strong> の下で公開します。また、使用にあたっては <a href="https://commoncrawl.org/terms-of-use">CommonCrawlの利用規約</a> も適用されます</p>
<h2>Citation Information</h2>
<p>JFWIRデータセットを研究や開発に使用される場合は、以下の引用情報をご利用ください</p>
<pre><code>@misc{tateno2025jfwir,
  author = {Yuichi Tateno},
  title = {JFWIR: Japanese FineWeb Information Retrieval Dataset},
  year = {2025},
  url = {https://huggingface.co/datasets/hotchpotch/JFWIR},
  note = {A large-scale Japanese information retrieval dataset with 60+ million document-query pairs}
}
</code></pre>]]></description>
            <link>https://secon.dev/entry/2025/06/19/100000-jfwir-japanese-fineweb-ir</link>
            <guid isPermaLink="false">/entry/2025/06/19/100000-jfwir-japanese-fineweb-ir</guid>
            <dc:creator><![CDATA[secondlife / @hotchpotch / Yuichi Tateno]]></dc:creator>
            <pubDate>Thu, 19 Jun 2025 01:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Qwen3 Embedding 文章ベクトルの日本語性能を JMTEB で測る]]></title>
            <description><![CDATA[<p>オープンウェイトな高性能マルチリンガル embedding, reranker モデル、<a href="https://qwenlm.github.io/blog/qwen3-embedding/">Qwen3 Embedding</a> シリーズがリリースされましたね。モデルサイズも 8B, 4B, 0.6B とあり文章ベクトルの作成・リランキングで高性能で、<a href="https://huggingface.co/spaces/mteb/leaderboard">Multilingual MTEB leaderboard</a>ではトップの性能となっています。</p>
<p>ただ、マルチリンガルモデルはあまり日本語が重視されない傾向にあるので、<a href="https://github.com/sbintuitions/JMTEB">JMTEB: Japanese Massive Text Embedding Benchmark</a>で Qwen3-Embedding-0.6B の性能を計測してみました。なお、jsick, jsts がエラーになったため、STSタスクは除いてあります。</p>
<h2>JMTEB 計測結果</h2>
<table>
<thead>
<tr>
<th align="left">Model</th>
<th align="center">Retrieval</th>
<th align="center">STS</th>
<th align="center">Classification</th>
<th align="center">Reranking</th>
<th align="center">Clustering</th>
<th align="left">PairClassification</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left"><strong>Qwen3-Embedding-0.6B</strong></td>
<td align="center">72.81</td>
<td align="center">--</td>
<td align="center">66.09</td>
<td align="center">93.10</td>
<td align="center">48.84</td>
<td align="left">62.42</td>
</tr>
<tr>
<td align="left">ruri-v3-310m</td>
<td align="center"><strong>81.89</strong></td>
<td align="center">81.22</td>
<td align="center"><strong>78.66</strong></td>
<td align="center">93.43</td>
<td align="center"><strong>55.69</strong></td>
<td align="left"><strong>62.60</strong></td>
</tr>
<tr>
<td align="left">ruri-v3-130m</td>
<td align="center"><strong>81.89</strong></td>
<td align="center">79.25</td>
<td align="center">77.16</td>
<td align="center">93.31</td>
<td align="center">55.36</td>
<td align="left">62.26</td>
</tr>
<tr>
<td align="left">ruri-v3-70m</td>
<td align="center">79.96</td>
<td align="center">79.82</td>
<td align="center">76.97</td>
<td align="center">93.27</td>
<td align="center">52.70</td>
<td align="left">61.75</td>
</tr>
<tr>
<td align="left">PLaMo-Embedding-1B</td>
<td align="center">79.94</td>
<td align="center"><strong>83.14</strong></td>
<td align="center">77.20</td>
<td align="center">93.57</td>
<td align="center">53.47</td>
<td align="left">62.37</td>
</tr>
<tr>
<td align="left">ruri-v3-30m</td>
<td align="center">78.08</td>
<td align="center">82.48</td>
<td align="center">74.80</td>
<td align="center">93.00</td>
<td align="center">52.12</td>
<td align="left">62.40</td>
</tr>
<tr>
<td align="left">sbintuitions/sarashina-embedding-v1-1b</td>
<td align="center">77.61</td>
<td align="center">82.71</td>
<td align="center">78.37</td>
<td align="center"><strong>93.74</strong></td>
<td align="center">53.86</td>
<td align="left">62.00</td>
</tr>
<tr>
<td align="left">jinaai/jina-embeddings-v3</td>
<td align="center">75.22</td>
<td align="center">80.05</td>
<td align="center">76.39</td>
<td align="center">92.71</td>
<td align="center">51.46</td>
<td align="left">62.37</td>
</tr>
<tr>
<td align="left">OpenAI/text-embedding-3-large</td>
<td align="center">74.48</td>
<td align="center">82.52</td>
<td align="center">77.58</td>
<td align="center">93.58</td>
<td align="center">53.32</td>
<td align="left">62.35</td>
</tr>
<tr>
<td align="left">pkshatech/GLuCoSE-base-ja-v2</td>
<td align="center">73.36</td>
<td align="center">82.96</td>
<td align="center">74.21</td>
<td align="center">93.01</td>
<td align="center">48.65</td>
<td align="left">62.37</td>
</tr>
<tr>
<td align="left">pkshatech/RoSEtta-base-ja</td>
<td align="center">73.21</td>
<td align="center">81.39</td>
<td align="center">72.41</td>
<td align="center">92.69</td>
<td align="center">53.23</td>
<td align="left">61.74</td>
</tr>
<tr>
<td align="left">intfloat/multilingual-e5-large</td>
<td align="center">70.98</td>
<td align="center">79.70</td>
<td align="center">72.89</td>
<td align="center">92.96</td>
<td align="center">51.24</td>
<td align="left">62.15</td>
</tr>
<tr>
<td align="left">OpenAI/text-embedding-3-small</td>
<td align="center">66.39</td>
<td align="center">79.46</td>
<td align="center">73.06</td>
<td align="center">92.92</td>
<td align="center">51.06</td>
<td align="left">62.27</td>
</tr>
</tbody>
</table>
<p>結果はこちらです。日本語のタスクがあまり学習されていないからなのか、日本語の結果は振るわない結果でした。ruri-v3 シリーズはモデルサイズも小さく、かつ日本語では圧倒的に高性能ですね。</p>
<p>なお Retrieval, Reranking タスクでは、Query の prefix に <code>Instruct: Given a web search query, retrieve relevant passages that answer the query\nQuery:</code> を追加しています。</p>
<p>また計測に使った、JMTEB用の設定(jsonnet)や結果の summary.json、実行コマンドは以下においてあります。Qwen3-Embedding-0.6B の性能が低すぎる気もするので、何か間違っていたら教えてください。</p>
<ul>
<li><a href="https://gist.github.com/hotchpotch/f6be186010e70d6eb6e46447cea258f9">https://gist.github.com/hotchpotch/f6be186010e70d6eb6e46447cea258f9</a></li>
</ul>
<h2>おまけ: Qwen3 Embedding 論文を読む</h2>
<p><a href="https://arxiv.org/abs/2506.05176">Qwen3 Embedding: Advancing Text Embedding and Reranking Through Foundation Models</a>が公開されたのでざっくり読んでみました。とりわけ合成データセット作成あたりが個人的に面白かったです。</p>
<p>以下は私の興味範囲のメモ書きです。</p>
<ul>
<li>LLM2Vec のような decoder → encoder ではなく、casual attention をそのまま利用</li>
<li>Embedding モデルは最終層の<code>[EOS]</code> トークンの hidden state から最終埋め込みを取得
<ul>
<li>Query は Instruction + Query で作成。Doc はそのまま。</li>
<li>InfoNCE を改良したスコア(単純な対照学習ではなく、ハードネガティブを複数含めたり、類似度のポジネガを調整した偽陰性の調整など)</li>
</ul>
</li>
<li>Reranking は chat template をそのまま使って、"yes", "no" トークンの確率で、関連性スコアとして計算
<ul>
<li>decoder model のラベル分類の解き方(該当ラベルトークンの確率を見る)のアプローチをママ適用</li>
<li>SFT で学習できる</li>
</ul>
</li>
<li>1st stage で Qwen3-32B で作った合成データセットをもとに学習
<ul>
<li>情報検索, 対訳マイニング(Bitext Mining), 意味的類似性, 分類 の4つのタイプを作成</li>
<li>情報検索の合成データセットの場合、詳細な設定を作り、それをもとにQwen3の事前訓練コーパスの文章からクエリを生成</li>
</ul>
</li>
<li>2nd stage で 700万の既存データセット(MS Marco, MIRACLなどなど)と、1st stage のコサイン類似度でフィルタリングした1200万件のデータをもとに学習</li>
<li>最後に多様性考慮のモデルマージ
<ul>
<li>詳細は記されてないので推察だが、2nd stage の複数のチェックポイントは、タスク特化学習させたもの、特定言語にフォーカスして学習させたもの、などが考えられそう</li>
<li>モデルマージは適当にマージして、ベンチマーク走らせると結果が向上することを、少ないコンピューティングリソースで観測できるので、たくさんチェックポイントがあるならいろいろ試した方が良さそう。</li>
</ul>
</li>
</ul>]]></description>
            <link>https://secon.dev/entry/2025/06/11/100000-qwen3-embedding-jmteb</link>
            <guid isPermaLink="false">/entry/2025/06/11/100000-qwen3-embedding-jmteb</guid>
            <dc:creator><![CDATA[secondlife / @hotchpotch / Yuichi Tateno]]></dc:creator>
            <pubDate>Wed, 11 Jun 2025 01:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[とても小さく速く実用的な日本語リランカー japanese-reranker-tiny,xsmall,small,base の v2 を公開]]></title>
            <description><![CDATA[<p>とても小さな日本語のリランカーモデル <a href="https://huggingface.co/hotchpotch/japanese-reranker-tiny-v2">japanese-reranker-tiny-v2</a> と <a href="https://huggingface.co/hotchpotch/japanese-reranker-xsmall-v2">japanese-reranker-xsmall-v2</a> を公開しました。情報検索システムにおいて、リランカーは検索結果の精度を高める役割を担いますが、モデルサイズと計算コストが実用における課題でした。</p>
<p>🆕 2025-07-10 まぁまぁ小さなリランカー <a href="https://huggingface.co/hotchpotch/japanese-reranker-small-v2">japanese-reranker-small-v2</a> と <a href="https://huggingface.co/hotchpotch/japanese-reranker-base-v2">japanese-reranker-base-v2</a> も追加しました。</p>
<p>本モデルは最小限のレイヤー数とパラメータ数で作成されており、CPUやAppleシリコン環境でも実用的な速度で動作します。これにより、高価なGPUリソースなしでもRAGシステムの精度向上が可能になり、エッジデバイスでの展開や低レイテンシが要求される本番環境で活用できるでしょう。性能評価では、大型モデルと比較しても競争力のあるスコアを出しています。</p>
<ul>
<li><a href="https://huggingface.co/hotchpotch/japanese-reranker-tiny-v2">https://huggingface.co/hotchpotch/japanese-reranker-tiny-v2</a></li>
<li><a href="https://huggingface.co/hotchpotch/japanese-reranker-xsmall-v2">https://huggingface.co/hotchpotch/japanese-reranker-xsmall-v2</a></li>
<li><a href="https://huggingface.co/hotchpotch/japanese-reranker-small-v2">https://huggingface.co/hotchpotch/japanese-reranker-small-v2</a></li>
<li><a href="https://huggingface.co/hotchpotch/japanese-reranker-base-v2">https://huggingface.co/hotchpotch/japanese-reranker-base-v2</a></li>
</ul>
<p><img src="https://storage.googleapis.com/secons-site-images/other/blog_images/20250508-japanese-reranker-v2-scores.png" alt="Reranker Benchmark"></p>
<h1>リランカーとは何か、そして小さなリランカーの重要性</h1>
<p>リランカーとは、検索システムにおいて、質問（クエリ）と文書の関連性を評価し、最も関連性の高い順に並べ替える（ランキング）するモデルです。従来の文ベクトル（埋め込み）検索だけでは捉えきれない複雑な関連性を評価できる点が強みです。特にCrossEncoderと呼ばれるアーキテクチャを用いることで、質問と文書を一つのペアとして入力し、より細かなニュアンスや文脈的理解を実現します。</p>
<ul>
<li><a href="https://secon.dev/entry/2024/04/02/070000-japanese-reranker-release/">日本語最高性能のRerankerをリリース / そもそも Reranker とは?</a></li>
</ul>
<p>小さなリランカーモデルが重要な理由はいくつかあります。まず、リランカーは質問と候補文書のすべての組み合わせを評価する必要があるため、計算量が非常に多くなります。例えば100件の候補文書をリランクする場合、100回のモデル推論が必要です。そのため、モデルが小さいほど処理速度が向上し、レイテンシが低減します。</p>
<p>また、小型モデルは限られたリソース環境での実行も可能です。CPUのみの環境やエッジデバイス、モバイルデバイスでも現実的な速度で動作でき、RAG（検索拡張生成）システムの実用性を大きく高めます。同時に、クラウド等のサーバ環境ではGPUメモリ使用量の削減により、GPUリソースの共有が可能となりコスト効率が大幅に向上します。</p>
<ul>
<li><a href="https://speakerdeck.com/hotchpotch/ask-nikkei-ragjian-suo-ji-shu-noshen-ceng">Ask! NIKKEI RAG検索技術の深層</a></li>
</ul>
<p>このように、小型リランカーは速度、コスト、リソース効率の面で大きなメリットをもたらし、実用的なRAGシステム構築において大切な役割を果たすでしょう。</p>
<h2>ベンチマーク性能</h2>
<p>ベンチマーク結果は以下です。小さなな tiny, xsmall v2 の性能はモデルサイズを考えるとかなり高く、大きいモデルとしては <a href="https://huggingface.co/cl-nagoya/ruri-v3-reranker-310m">ruri-v3-reranker-310m</a> が圧倒的ですね。これらの高性能なモデルは、ベースがどれも高性能な ModernBert になったことも、性能向上に寄与しているでしょう。</p>
<p>なお、日本語モデルはどれもJQaRA(クイズ形式)の傾向を学んでおり、bge-reranker-v2-m3 は不利になります。これはリランカーが適切にドメイン課題を学習すれば、だいぶスコアが上がることの例でもあります。</p>
<table>
<thead>
<tr>
<th>モデル名</th>
<th>avg</th>
<th>JQaRA</th>
<th>JaCWIR</th>
<th>MIRACL</th>
<th>JSQuAD</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="https://huggingface.co/hotchpotch/japanese-reranker-tiny-v2">japanese-reranker-tiny-v2</a></td>
<td>0.8138</td>
<td>0.6455</td>
<td>0.9287</td>
<td>0.7201</td>
<td>0.9608</td>
</tr>
<tr>
<td><a href="https://huggingface.co/hotchpotch/japanese-reranker-xsmall-v2">japanese-reranker-xsmall-v2</a></td>
<td>0.8699</td>
<td>0.7403</td>
<td>0.9409</td>
<td>0.8206</td>
<td>0.9776</td>
</tr>
<tr>
<td><a href="https://huggingface.co/hotchpotch/japanese-reranker-small-v2">japanese-reranker-small-v2</a></td>
<td>0.8856</td>
<td>0.7633</td>
<td>0.9586</td>
<td>0.8385</td>
<td>0.9821</td>
</tr>
<tr>
<td><a href="https://huggingface.co/hotchpotch/japanese-reranker-base-v2">japanese-reranker-base-v2</a></td>
<td>0.8930</td>
<td>0.7845</td>
<td>0.9603</td>
<td>0.8425</td>
<td>0.9845</td>
</tr>
<tr>
<td><a href="https://huggingface.co/hotchpotch/japanese-reranker-cross-encoder-xsmall-v1">japanese-reranker-cross-encoder-xsmall-v1</a></td>
<td>0.8131</td>
<td>0.6136</td>
<td>0.9376</td>
<td>0.7411</td>
<td>0.9602</td>
</tr>
<tr>
<td><a href="https://huggingface.co/hotchpotch/japanese-reranker-cross-encoder-small-v1">japanese-reranker-cross-encoder-small-v1</a></td>
<td>0.8254</td>
<td>0.6247</td>
<td>0.9390</td>
<td>0.7776</td>
<td>0.9604</td>
</tr>
<tr>
<td><a href="https://huggingface.co/hotchpotch/japanese-reranker-cross-encoder-base-v1">japanese-reranker-cross-encoder-base-v1</a></td>
<td>0.8484</td>
<td>0.6711</td>
<td>0.9337</td>
<td>0.8180</td>
<td>0.9708</td>
</tr>
<tr>
<td><a href="https://huggingface.co/hotchpotch/japanese-reranker-cross-encoder-large-v1">japanese-reranker-cross-encoder-large-v1</a></td>
<td>0.8661</td>
<td>0.7099</td>
<td>0.9364</td>
<td>0.8406</td>
<td>0.9773</td>
</tr>
<tr>
<td><a href="https://huggingface.co/hotchpotch/japanese-bge-reranker-v2-m3-v1">japanese-bge-reranker-v2-m3-v1</a></td>
<td>0.8584</td>
<td>0.6918</td>
<td>0.9372</td>
<td>0.8423</td>
<td>0.9624</td>
</tr>
<tr>
<td><a href="https://huggingface.co/BAAI/bge-reranker-v2-m3">bge-reranker-v2-m3</a></td>
<td>0.8512</td>
<td>0.6730</td>
<td>0.9343</td>
<td>0.8374</td>
<td>0.9599</td>
</tr>
<tr>
<td><a href="https://huggingface.co/cl-nagoya/ruri-v3-reranker-310m">ruri-v3-reranker-310m</a></td>
<td>0.9171</td>
<td>0.8688</td>
<td>0.9506</td>
<td>0.8670</td>
<td>0.9820</td>
</tr>
</tbody>
</table>
<h2>推論速度</h2>
<p>こちらは、HuggingFace transformers ライブラリを使った、約15万ペアをリランキングした推論速度結果(トークナイズ時間は除いていて、純粋なモデルでの推論時間)です。MPS(Appleシリコン),CPUの計測にはM4 Maxを、GPUにはRTX5090を用い、かつ ModernBert 系列モデルでは GPU 処理時に flash-attention2 を使っています。</p>
<p>japanese-reranker-tiny-v2, xsmall-v2 は速度面で圧倒的ですね。ruri-v3-reranker-310m もモデルサイズを考えるとかなり速く、これらは flash-attention2 が効いているからでしょう。なお、<a href="https://github.com/huggingface/text-embeddings-inference/">text-embeddings-inference</a>等を使うことで、他のモデルも flash-attention2 を使うことができ、その場合はこの評価以上の速度が出ると思います。</p>
<table>
<thead>
<tr>
<th>モデル名</th>
<th>レイヤー数</th>
<th>隠れ層サイズ</th>
<th>速度(GPU)</th>
<th>速度(MPS)</th>
<th>速度(CPU)</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="https://huggingface.co/hotchpotch/japanese-reranker-tiny-v2">japanese-reranker-tiny-v2</a></td>
<td>3</td>
<td>256</td>
<td>2.1s</td>
<td>82s</td>
<td>702s</td>
</tr>
<tr>
<td><a href="https://huggingface.co/hotchpotch/japanese-reranker-xsmall-v2">japanese-reranker-xsmall-v2</a></td>
<td>10</td>
<td>256</td>
<td>6.5s</td>
<td>303s</td>
<td>2300s</td>
</tr>
<tr>
<td><a href="https://huggingface.co/hotchpotch/japanese-reranker-small-v2">japanese-reranker-small-v2</a></td>
<td>13</td>
<td>384</td>
<td>15.2s</td>
<td></td>
<td></td>
</tr>
<tr>
<td><a href="https://huggingface.co/hotchpotch/japanese-reranker-base-v2">japanese-reranker-base-v2</a></td>
<td>19</td>
<td>512</td>
<td>32.5s</td>
<td></td>
<td></td>
</tr>
<tr>
<td><a href="https://huggingface.co/hotchpotch/japanese-reranker-cross-encoder-xsmall-v1">japanese-reranker-cross-encoder-xsmall-v1</a></td>
<td>6</td>
<td>384</td>
<td>20.5s</td>
<td></td>
<td></td>
</tr>
<tr>
<td><a href="https://huggingface.co/hotchpotch/japanese-reranker-cross-encoder-small-v1">japanese-reranker-cross-encoder-small-v1</a></td>
<td>12</td>
<td>384</td>
<td>40.3s</td>
<td></td>
<td></td>
</tr>
<tr>
<td><a href="https://huggingface.co/hotchpotch/japanese-reranker-cross-encoder-base-v1">japanese-reranker-cross-encoder-base-v1</a></td>
<td>12</td>
<td>768</td>
<td>96.8s</td>
<td></td>
<td></td>
</tr>
<tr>
<td><a href="https://huggingface.co/hotchpotch/japanese-reranker-cross-encoder-large-v1">japanese-reranker-cross-encoder-large-v1</a></td>
<td>24</td>
<td>1024</td>
<td>312.2s</td>
<td></td>
<td></td>
</tr>
<tr>
<td><a href="https://huggingface.co/hotchpotch/japanese-bge-reranker-v2-m3-v1">japanese-bge-reranker-v2-m3-v1</a></td>
<td>24</td>
<td>1024</td>
<td>310.6s</td>
<td></td>
<td></td>
</tr>
<tr>
<td><a href="https://huggingface.co/BAAI/bge-reranker-v2-m3">bge-reranker-v2-m3</a></td>
<td>24</td>
<td>1024</td>
<td>310.7s</td>
<td></td>
<td></td>
</tr>
<tr>
<td><a href="https://huggingface.co/cl-nagoya/ruri-v3-reranker-310m">ruri-v3-reranker-310m</a></td>
<td>25</td>
<td>768</td>
<td>81.4s</td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<p>なお、推論速度のベンチマークに用いた<a href="https://gist.github.com/hotchpotch/bab03c7d4399aa13beb2702600ad9371">スクリプトはこちら</a>です。</p>
<p>また CPU用に onnx に変換したモデルも公開しているため、例えばラズパイ環境などで、onnx + arm向け量子化モデルを使うことで、実際にエッジ環境でも動くでしょう。</p>
<h1>モデル作成の簡易テクニカルレポート</h1>
<p>japanese-reranker-tiny-v2, xsmall-v2, small-v2, base-v2 の学習データ元として、<a href="https://huggingface.co/hotchpotch/japanese-splade-v2">hotchpotch/japanese-splade-v2</a> 学習で用いたデータセット + ハードネガティブ + 若干の独自データを用いて学習させています。v1と比べて大幅に性能が上がったのは、ModernBert ベースで事前対象学習を行った <a href="https://huggingface.co/cl-nagoya/ruri-v3-pt-30m">ruri-v3-pt-30m</a>を用いてることと、v1よりも数倍のデータセットを用いたこと、またハードネガティブでの良質なデータの抽出(各種rerankerのスコアを用い、正しい・正しくないでフィルタリング)を行ったことも大きいでしょう。</p>
<p>また、Tiny モデルのモデルパラメータ抽出元として、<a href="https://huggingface.co/sbintuitions/modernbert-ja-30m">sbintuitions/modernbert-ja-30m</a>と<a href="https://huggingface.co/cl-nagoya/ruri-v3-pt-30m">cl-nagoya/ruri-v3-pt-30m</a>を利用・評価しました。ModernBert アーキテクチャは、グローバルアテンションとローカルアテンションのレイヤーを交互に含みます。例えば modernbert-ja-30m モデルは10層のレイヤーで、<code>[0,3,6,9]</code>層がグローバルアテンションで、それ以外がローカルアテンションとなっています。</p>
<p>最初は全てグローバルアテンションの方が良いだろうと思ったのですが、3,6,9層を含むと基本悪くなり、また出力層に近い層を含むと、こちらも結果が悪くなりました。以下のグラフは同じデータセットで学習したrerankerのrerank評価結果です。出力層に近い6,9などを含むとだいぶ悪くなり学習早期で止めたので、以下の結果には含めてません。また、layer 0 のみは流石に全く性能が出ませんでした。</p>
<table>
<thead>
<tr>
<th>name</th>
<th>JQaRA</th>
<th>miracl</th>
<th>jsquad</th>
<th>JaCWIR</th>
</tr>
</thead>
<tbody>
<tr>
<td>modernbert-ja-30m + full layers</td>
<td>0.7261</td>
<td>0.8095</td>
<td>0.9752</td>
<td>0.9420</td>
</tr>
<tr>
<td>modernbert-ja-30m + layer 0,2,4</td>
<td>0.6455</td>
<td>0.7185</td>
<td>0.9588</td>
<td>0.9265</td>
</tr>
<tr>
<td>modernbert-ja-30m + layer 0,2</td>
<td>0.6171</td>
<td>0.6784</td>
<td>0.9516</td>
<td>0.9155</td>
</tr>
<tr>
<td>modernbert-ja-30m + layer 0</td>
<td>0.2515</td>
<td>0.4416</td>
<td>0.3172</td>
<td>0.0738</td>
</tr>
<tr>
<td>ruri-v3-pt-30m + full layers (= xsmall-v2)</td>
<td>0.7403</td>
<td>0.8206</td>
<td>0.9776</td>
<td>0.9409</td>
</tr>
<tr>
<td>ruri-v3-pt-30m + layer 0,2,4  (= tiny-v2)</td>
<td>0.6455</td>
<td>0.7201</td>
<td>0.9608</td>
<td>0.9287</td>
</tr>
<tr>
<td>ruri-v3-pt-30m + layer 0,1,3</td>
<td>0.6405</td>
<td>0.7124</td>
<td>0.9552</td>
<td>0.9211</td>
</tr>
<tr>
<td>ruri-v3-pt-30m + layer 0,3</td>
<td>0.6177</td>
<td>0.6619</td>
<td>0.9482</td>
<td>0.9076</td>
</tr>
</tbody>
</table>
<p>この中から、最も良質な結果になった <code>ruri-v3-pt-30m</code> を xsmall として、tiny モデルとしては <code>ruri-v3-pt-30m + layer 0,2,4</code> を公開しました。また、small-v2 と base-v2 は <a href="https://huggingface.co/cl-nagoya/ruri-v3-pt-70m">ruri-v3-pt-70m</a> と <a href="https://huggingface.co/cl-nagoya/ruri-v3-pt-130m">ruri-v3-pt-130m</a> をベースにそれぞれ作成されています。なお、モデルマージすると性能は少々上がりますが、今回は行っていません。</p>
<h1>おわりに</h1>
<p>本エントリーでは、非常に小型軽量で実用的な日本語リランカーモデル<a href="https://huggingface.co/hotchpotch/japanese-reranker-tiny-v2">japanese-reranker-tiny-v2</a>、<a href="https://huggingface.co/hotchpotch/japanese-reranker-xsmall-v2">japanese-reranker-xsmall-v2</a>、<a href="https://huggingface.co/hotchpotch/japanese-reranker-small-v2">japanese-reranker-small-v2</a>、<a href="https://huggingface.co/hotchpotch/japanese-reranker-base-v2">japanese-reranker-base-v2</a> についての紹介をしました。これらのモデルのうちtinyやxsmallは、CPUやAppleシリコンといった環境でも実用的な速度で動作し、高価なGPUリソースを必要とせずにとも、とりわけローカルなRAGシステムなどの検索精度の向上に寄与します。またGPU上で動かすことで、高速なレスポンスも実現可能です。</p>
<p>近年の高性能な ModernBert 等の Encoder モデルの登場により、より高性能な実用的な性能を持つモデルの開発を後押ししています。本記事が、日本語処理技術のさらなる発展に貢献できれば幸いです。</p>]]></description>
            <link>https://secon.dev/entry/2025/05/08/100000-japanese-reranker-v2</link>
            <guid isPermaLink="false">/entry/2025/05/08/100000-japanese-reranker-v2</guid>
            <dc:creator><![CDATA[secondlife / @hotchpotch / Yuichi Tateno]]></dc:creator>
            <pubDate>Thu, 08 May 2025 01:00:00 GMT</pubDate>
        </item>
    </channel>
</rss>