CoolFace
Datasetpublic

qleap/Opening_dataset_by_NAGISA_V4

Opening dataset by NAGISA_V4 平手から 15手目までを方策ネット b15c256 で広げ、NNUE エンジン attic-gensfen が NAGISA_V4 (HalfKA-2304) を読んで depth 9・MultiPV 5 で採点した序盤局面集。 manaka-teacher が MPK1 ストリームに落とし、manaka-pack が同一局面を 1 行に 畳み込んで、この parquet を書いた。学習側がそのまま読む形である。 自己対局のコーパスではない。 対局は 1 局も指していない。木を広げて採点しただけで、 局面同士に前後関係は無い。勝敗を持つデータが要るなら qleap/Knowledge_distilled_dataset_by_NAGISA_V4 のほう。あちらと同じスキーマ・同じ変換規約なので、混ぜて読める。 行数: 19,896,088 (畳み込み前のレコード数: 19,898,611) シャード数: 4 (data/teacher-00000.parquet …) 合計: 1,137… See the full description on the dataset page: https://huggingface.co/datasets/qleap/Opening_dataset_by_NAGISA_V4.

sourceHugging Facemitupdated 19d agoView on Hugging Face
0likes141downloads
Dataset Card

Opening dataset by NAGISA_V4

平手から 15手目までを方策ネット b15c256 で広げ、NNUE エンジン attic-gensfen が NAGISA_V4 (HalfKA-2304) を読んで depth 9・MultiPV 5 で採点した序盤局面集。 manaka-teacher が MPK1 ストリームに落とし、manaka-pack が同一局面を 1 行に 畳み込んで、この parquet を書いた。学習側がそのまま読む形である。

自己対局のコーパスではない。 対局は 1 局も指していない。木を広げて採点しただけで、 局面同士に前後関係は無い。勝敗を持つデータが要るなら qleap/Knowledge_distilled_dataset_by_NAGISA_V4 のほう。あちらと同じスキーマ・同じ変換規約なので、混ぜて読める。

  • —行数: 19,896,088 (畳み込み前のレコード数: 19,898,611)
  • —シャード数: 4 (data/teacher-00000.parquet …)
  • —合計: 1,137,896,896 B

先頭 3 つが 5,000,000 行、最後が残りの 4,896,088 行。zstd 圧縮、row group は 8192 行。

python
from datasets import load_dataset

ds = load_dataset("qleap/Opening_dataset_by_NAGISA_V4", split="train")

生成のしかた

設定を知る手立てはこの節しかない。 parquet のフッタが述べているのは変換側が 適用した規約であって、探索を回した条件ではない。

局面を選んだ側

出発点は平手 1 局面のみ。そこから 1 手ずつ 15手目まで、次を繰り返して広げた。

  1. 1.提案 — 方策ネット b15c256 (ONNX) が top-p 0.90、親 1 つにつき最大 16 手
  2. 2.採点 — attic-gensfen が --depth 16 --multipv 1 --eval-tolerance 0
  3. 3.親にするかどうか — その局面の評価値を先手視点に直したものが、平手の 評価値 54cp から ±50 センチポーン以内なら次の手数の親にする

2 と 3 の評価値はこのデータに入っていない。 ここに並んでいるラベルは、 局面集合を据え置いたまま depth 9 / MultiPV 5 で付け直したものである。したがって:

  • —ここの cp で「互角なら採用」をやり直しても、木を作ったときと同じ集合にはならない。
  • —木の形(どの局面が存在するか)には depth 16 の採点が効いているが、その採点はこのデータに無い。

局面の存在理由とラベルが別の探索から来ている、というのはこのデータの性質なので、 選抜の再現が要る用途には向かない。ラベルとして使うぶんには問題ない。

採点を通った候補は 3 で落ちたものも含めて全て入っている。 基準にした評価値が 無いので、いまある cp で絞り直しても当時と同じ集合にはならない。新しい基準に よる別の選抜として扱うこと:

python
import numpy as np, pyarrow.parquet as pq, pyarrow.compute as pc

t = pq.read_table("data/teacher-00000.parquet", columns=["ply", "candidates"])
c = t["candidates"].combine_chunks()
off = np.asarray(c.offsets)
cp = c.flatten().field("cp").to_numpy(zero_copy_only=False).astype(np.int64)
best = np.maximum.reduceat(cp, off[:-1])          # 最善手の cp。候補は cp 順ではない
ply = t["ply"].to_numpy().astype(np.int64)
pov = np.where(ply % 2 == 1, best, -best)         # 先手視点に直す
balanced = np.abs(pov - 54) <= 50                 # 全 4 シャードで 9,866,539 行

木の形そのものには 3 が効いている。 採用された局面だけを次の手数の親にしたので、 「互角から外れた局面の、さらに先」はこの中に無い。

採点した側

探索エンジンattic-gensfen
評価関数NAGISA_V4 (NNUE, HalfKA-2304)
FV_SCALE28
探索depth 9、MultiPV 5、--hash 16 --eval-tolerance 0
手の選択無し。対局していないので指した手が無い

全段を一律 depth 9 で付けている。 手数による探索深さの差は無い。

`FV_SCALE` が centipawn を centipawn たらしめている。 NNUE が積み上げた内部の値は この数で割られて初めて評価値になる。同じネットをエンジン既定の 16 で読めば、ここに 並んでいる cp はすべて 1.75 倍の値になっていた。他所のデータと混ぜるなら、まずこの数が 一致しているかを見ること。二つの尺度をまたいで混ぜた教師データは、どちらのものでもない 数字で学習することになる。

MultiPV 1 と MultiPV 5 では同じ局面でも root value が変わる。 5 本ぶんの探索が 1 本目の枝刈りを緩めるためで、非決定性ではない (depth 9 / MultiPV 1 を 2 回走らせると バイト単位で一致することは確認してある)。同じ 1500 局面 (15手目) を depth 9 で測った実測:

root value の差局面数
0〜287
3〜10248
11〜30493
31〜50293
51 以上379

1500 局面中 1478 局面で値が動き、平均 |差| は 36.5cp、最大 346cp だった。同じ 1500 局面を depth 16 で測ると平均 |差| 30.2cp、最大 241cp で、浅いほうが MultiPV の影響を強く 受ける。他所の MultiPV 1 のデータと直接比べないこと。

変換で落ちた行は無い

manaka-teacher は 19,898,611 行を読んで 19,898,611 レコードを書いた。拒否 0 行 (move_not_candidate 0、malformed_record 0)。

自己対局のコーパスが 3% ほど落とすのは、わざと混ぜたランダム手が MultiPV の外にあって 「指した手に対応する評価値が無い」ためである。ここは指した手そのものが無いので、 その拒否は起こりようがない。

スキーマ

列型内容
packedfixed binary (96)局面。手番は最終バイト
plyuint16手数。1〜15
value_qfloat32探索価値の教師信号。手番側視点
weightuint32畳み込まれた探索の数
candidateslist<struct<mv uint16, prob float32, cp int16>>方策

合法手の一覧も合法手マスクも入っていない。要るなら packed から作り直す。

勝敗の列は無い

このデータは局面と評価値である。対局していないので勝敗は存在しない。0 を入れれば 引き分けと読まれ、NaN は (1 − ratio)·z + ratio·q のような混ぜ方を突き抜けてしまう。 列が無ければ「述べられていない」と読める。参照実装の学習側は None / Option::None を 返し、価値の教師信号は value_q 一本になる。

評価値と勝敗を混ぜる lambda を既定で持つ学習設定にこのデータを渡すなら、 明示的に評価値のみ (lambda = 1) にすること。

packed の中身

96 バイト、manaka_core::pack。どちらのエンジンの入力層でもない。Manaka の accumulator も DLManaka の入力面も、読み込み時にここから組み立てる。

text
バイト
 0..81   盤面。1 マス 1 バイト、マス番号順
81..88   先手の持ち駒。駒種ごとに 1 バイト
88..95   後手の持ち駒。同じ順
    95   手番。0 = 先手 / 1 = 後手

マス 0 が 9a、マス 80 が 1i。square = (9 − file) × 9 + (rank − 1)。空マスは 0xFF。 持ち駒は歩・香・桂・銀・金・角・飛の順に 1 バイトずつ。

`packed` の手番は `ply` の偶奇と必ず一致する (19,896,088 行すべてで確認)。奇数手数が 先手番、偶数手数が後手番である。

候補手は手であってラベルではない

mv は move16 — chisaki の手の表現そのまま。

text
 bit  15 │ 14 │ 13 ──────── 7 │ 6 ──────── 0
      ✗  │ 成 │ from または 81+駒種 │     to

to が bit 0–6、移動元が bit 7–13、成りが bit 14。打つ手は移動元の欄に 81 + 持ち駒の 番号が入るので、打った駒種は手のビットだけから読める。方策ラベルも動かした駒も ビット演算だけで出るので、将棋のライブラリは要らない。

`candidates` は `cp` 順ではない。`mv` の昇順である。 全 79,569,273 個の隣接ペアが 昇順で、candidates[0] が最善手なのは 19,896,088 行中 4,616,729 行しかない。 最善手が要るなら `cp` の最大を取ること。先頭を最善手と決め打ちにした読み方は 4 分の 3 の行で別の手を拾う。

prob は行内で合計 1 になる (実測 0.9999997〜1.0000002、float32 の丸めのぶん)。

候補手の数は MultiPV の幅であって、数えれば分かる。 実測:

候補手行数
519,881,89599.93%
413,5630.07%
33660.002%
22620.001%
62—

5 に満たないのは合法手が MultiPV の幅より少ない局面、すなわち王手を受けている局面 である。6 は畳み込みで、同じ盤面を指した二つの探索が別の手を挙げ、和集合が両方を 残したもの。長さ 5 を決め打ちにした読み方は落ちる。

これは方策ネットの分布ではない。 木を広げるときに使った b15c256 の確率はこの データに入っていない。ここにあるのは NNUE の探索が付けた評価値から作った分布である。

畳み込み

同一局面は 1 行。 鍵は packed の 96 バイトだけで、(packed, ply) ではない。 13手目で現れた盤面と 15手目で現れた同じ盤面は、探索から見れば同じ 1 局面である。

  • —value_q — 畳み込んだレコードの平均
  • —candidates — mv で突き合わせた和集合。cp はその手を挙げたレコードの平均
  • —ply — 最小
  • —weight — レコード数。1 はその局面が 1 回だけ現れたということ

畳み込みで消えたのは 2,523 レコード、全体の 0.0127%。

`weight`行数
119,893,565
22,523

最大が 2 である。自己対局のコーパスでは平手が 20 万回以上畳み込まれるが、ここでは 木が同じ盤面を二度作らないので、転置で 2 回出会うのが上限だった。畳み込み後の packed は 19,896,088 行すべてで一意である (重複 0 件)。

packed に手数は入らないので、13手目の盤面と 15手目の同じ盤面は同じ行に畳まれる。 2,523 組がこれにあたる。

prob は畳み込みの後に一度だけ計算する。平均した cp に対する温度 100 センチ ポーンの softmax である。

手数の内訳 (畳み込みで ply は最小を取る):

`ply`行数
11
28
350
4185
5627
62,022
75,962
817,271
946,559
10130,915
11330,919
12875,053
132,058,208
145,097,635
1511,330,673

1手目から 15手目まで揃っているが、量は 15手目に集中している (全体の 57%)。 手数が奇数の段は全て先手番、偶数の段は全て後手番なので、片方の段だけ使うと手番が 偏る。

詰みは候補手にだけ、しかも全て負で入っている

詰みは ±(32000 − 詰みまでの手数) で表される。`value_q` に ±1 は 1 行も無い (実測範囲 -0.8351〜0.9999987)。root は 1 局面も詰んでいない。

`cand` の側には 3,917 個入っている (3,917 行に 1 個ずつ、全体の 0.02%)。値は -31998 が 3,850 個、-31994 が 67 個で、全て負である。手数の内訳は 11手目 9 / 12手目 6 / 13手目 323 / 14手目 267 / 15手目 3,312。

つまり root は詰んでいないが、候補手の下位に「指すと詰まされる手」が入っている 局面がある。符号が負なのはそのため (手番側視点)。

出所は王手を受けた局面である。 角交換から角を打ち込んで成る筋が 15手以内に成立 するので、馬に王手をかけられた局面がこの中にある。合法手が数手しか無く、そのうち玉が 逃げる手が持ち駒の角で詰む、という形。方策ネットが詰みを探した結果ではない。

この 3,917 手の `prob` は全て 0 である。 温度 100 の softmax が exp((-31998 − top)/100) を float32 の 0 に落とすためで、方策としては候補から外れる。 詰みが最善手の側にある行 (one-hot に切り替わる行) は 0 行だった。

`cp` を回帰の目標にするなら、この 3,917 個は -32000 付近の外れ値として効く。 value_q だけ見て「詰みは入っていない」と判断すると取り逃がす。

key-value メタデータ

シャードのフッタが、変換側の適用した規約を述べている。読む前に確認すること。

キー値
povside_to_move
policy_sourcesoftmax_cp
softmax_temp_cp100
mate_scale32000
mate_slack100
eval_coef1512.173
fv_scale28
packedmailbox position, side to move in the last byte
writermanaka-pack 0.2.0

詰みの閾値は ±(mate_scale − mate_slack)、value_q は eval_coef を係数とする tanh である。1512.173 は dlshogi の 756.0865 を倍にした値。あちらは [0, 1] の sigmoid 用に較正されていて、同じ勝率曲線を tanh で [-1, 1] に通すと係数が倍になる。

value_q が tanh(最善手の cp / 1512.173) と一致することは、畳み込みが起きていない 19,893,565 行すべてで確認した (最大差 9.9e-08、float32 の丸めのぶん)。

`mate_scale` は V3 のシャードでは 30000 である。二つは互換ではない。片方の尺度の 詰みは、もう片方では単に大きな評価値になる。他所のシャードと畳み込む前にこのキーを 見ること。

行の並び

全体を 1 回シャッフルしてある。畳み込みのあと、コーパス全体に対して固定 seed の Fisher–Yates を 1 回かける (manaka-pack の --buckets 1 経路)。決定的なので同じ ストリームからは同じシャードが出るが、順序としての意味は無い。

手数の並びは残っていない。 ply のラグ 1 自己相関は 0.000237、行番号との相関は 0.000340 だった。

train/val の分け方

行をランダムに切ってよい。 盤面は一意で、ラベルは局面ごとに決まる探索の評価値 なので、切り方に条件は無い。対局単位で切る必要は無い — 対局が無いので、そのための `game_id` のような列も無い。

使いどころ

序盤の局面の広さを稼ぐためのもの。 自己対局のコーパスは開始局面が少ないと同じ 手順を何度も踏むので、それを散らす目的で作った。

SPRT の自己対局の開始局面には使わないこと。 採点を通った候補を全部含んでいるので、 互角から大きく外れた局面が入っている。開始局面が要るなら上の balanced で絞ってから 使うこと。ただしその balanced は木を作ったときの選抜とは別物である (上記)。

出所とライセンス

平手から自前の方策ネットと評価関数だけで生成したもので、外部の局面集は使っていない。