いま自社で動かせるオープンウェイトのLLMは、ほぼ例外なくRoPE(Rotary Position Embedding、回転位置埋め込み)で位置情報を持っています。ところが、この方式が実装者の前に姿を見せるのは、たいてい「学習時より長い入力を投げたら出力が崩れた」「設定ファイルの rope_scaling を書き換えたのに効かない」といった不具合の側からです。本記事では、RoPEが何を回転させて何を解いているのかを処理単位まで分解し、手元で走らせて内積の値を確かめる最小スクリプト、設定キーの実体、コンテキスト長を伸ばす4方式の選び分け、推論エンジン側の指定手順、そして拡張に手を出してよい条件までを2026年9月時点の一次情報で整理します。QKの内積そのもの、つまりTransformerの自己注意の仕組みは別記事で扱っているため、本記事は位置情報の与え方に絞ります。
まとめ:RoPEの仕組みとコンテキスト長拡張・採用判断の結論
RoPEは、トークンの位置を「ベクトルに足す値」ではなく「ベクトルを回す角度」として与える位置エンコーディングです。クエリとキーの各ヘッド次元を2つずつペアにし、位置mのトークンならペアごとに角度 m·θ を掛けて回す。それだけの操作です。
この形にした見返りが、内積の性質に出ます。位置mのクエリと位置nのキーの内積を展開すると、回転角の差 (m−n)·θ だけが残り、mとnの絶対値は消える。絶対位置を入力しているのに、注意スコアには相対距離しか効かないという明快な構造を取ります。RoFormer論文(arXiv:2104.09864)が示したのがこの点で、同論文は2021年4月に公開され、Neurocomputing 568巻に2024年掲載されています。後述の最小スクリプトを走らせれば、距離が同じペアの内積が位置をずらしても同一値になることを数分で確認可能です。
実装上の触りどころは3か所しかありません。回転の細かさを決める base(設定キーは rope_theta、既定は10,000)、回転を掛ける対象(クエリとキーのみ、値ベクトルには掛けない)、そして学習長を超えて使うときの拡張方式(rope_type)です。Hugging Face transformers では設定が rope_parameters という辞書に統合され、従来の rope_scaling は非推奨エイリアスとして読み替えられます。PyPIの配布ページで確認できる最新版は 5.16.1(2026年8月26日公開)で、本記事の記述はこの5.16系を基準にしています。
判断の起点は、伸ばしたい倍率と精度の許容幅の2つ。2倍前後までなら学習なしの dynamic(NTK-aware)で足り、8倍を超えるなら YaRN のように短時間の追加学習を伴う方式でなければ品質が保てません。そして、どの方式でもコンテキスト長に比例してKVキャッシュが膨らむため、伸ばした長さを本当に使うのかをメモリ側から先に確かめるのが安全な順序です。
RoPEが解く問題|位置情報を加算する方式から回転方式へ移った理由
まず、この方式が何を置き換えたのかを確定させます。
絶対位置を足し込む方式が長い文脈で崩れてしまう仕組み上の理由
初期のTransformerは、トークン埋め込みに位置ベクトルを加算していました。正弦波で作る方式(Sinusoidal PE)でも、位置ごとに学習する方式(Learned PE)でも、入り口で足すという点は共通です。この設計には2つの弱点があります。
1つは、位置情報が入力層で1度だけ注入され、層を重ねるうちに他の特徴と混ざって薄まること。もう1つは、学習した位置までしかベクトルが存在しないことです。学習を2,048トークンで行えば2,049番目の位置ベクトルは未定義で、学習型なら参照そのものができません。正弦波型は数式上いくらでも伸ばせますが、その領域は学習で1度も見ていない値であり、注意スコアが不安定になります。
相対位置を直接埋め込む方式(Relative PE)はこの弱点に対処しましたが、注意スコアの計算にトークン対ごとの項が加わり、実装と計算コストが重くなりました。RoPEはこの2系統の間を通します。入力に足すのをやめ、注意を計算する直前のクエリとキーに対して、位置に応じた回転を掛ける。それだけで相対位置の性質が手に入る、という筋です。
2次元ペアの回転で内積に相対距離だけが残る中核の性質を数式で確認
回転の対象はヘッド次元(head_dim)です。仮に128次元なら、これを (0,1)(2,3)…(126,127) のように2つずつのペアに分け、各ペアを2次元平面上のベクトルとみなします。位置mのトークンなら、i番目のペアを角度 m·θ_i だけ回す。回転行列の適用そのものです。
ここで効いてくるのが、回転行列の積の性質です。角度αの回転の転置と角度βの回転を掛けると、角度 β−α の回転になる。クエリ(位置m)とキー(位置n)の内積を取ると、この差だけが残ります。
score(m, n) = q_m · k_n
= (R(m·θ) q) · (R(n·θ) k)
= q · R((n − m)·θ) k # 絶対位置 m, n は消える
結果として、モデルは「50番目と55番目」ではなく「5つ離れている」という情報だけを見ることになります。同じ距離のペアなら文書のどこにあっても同じ扱いになり、位置ベクトルを別途学習する必要もありません。この性質が、パラメータを1つも増やさずに得られる点がRoPEの効率です。
もう1つ、距離が開くほど内積の期待値が下がるという副次的な性質もあります。ペアごとに回転速度が違うため、遠いトークン同士では位相がばらけて打ち消し合う。この減衰は後述のスクリプトで実数として確認できます。LLMという枠組み全体での位置づけや企業導入の判断軸はLLM(大規模言語モデル)の仕組みと導入判断で扱っています。
波長を決める base(rope_theta)と次元ごとの周波数の割り当て
ペアごとの回転角 θ_i は、次の式で決まります。base は既定で10,000です。この既定値は transformers の modeling_rope_utils.py に default_theta = 10_000.0 として書かれています。
inv_freq = 1.0 / (base ** (arange(0, head_dim, 2) / head_dim))
freqs = position_ids * inv_freq # 形状 [系列長, head_dim ÷ 2]
cos, sin = freqs.cos(), freqs.sin()
先頭のペアほど θ が大きく、1トークン進むだけで大きく回ります。末尾のペアは θ が極端に小さく、数千トークン進んでようやく1周する。つまり、低次元側が「隣接語の並び」を、高次元側が「文書内の大まかな位置」を担う周波数分解になっています。
base を上げるとすべての周波数が下がり、波長が伸びます。長い文脈を扱うモデルが base を大きく取るのはこのためで、Llama 3 は事前学習の段階で base を10,000から500,000へ引き上げました。低周波側のペアが1周し切らないまま長い系列を表現できるようになり、後付けの拡張に頼らずに長さを稼げます。
実装で実際に触る場所|QとKへの適用位置と設定キーの対応関係
数式より先に、コードのどこに現れるかを押さえておくほうが実務では早く済みます。
rotate_half と cos・sin の掛け方=Vには適用しないという原則
実装は回転行列を組み立てず、要素ごとの積と符号反転で済ませます。Hugging Face 実装の骨格は次の通りです。
def rotate_half(x):
x1, x2 = x.chunk(2, dim=-1)
return cat((-x2, x1), dim=-1)
q = q * cos + rotate_half(q) * sin
k = k * cos + rotate_half(k) * sin
# v には掛けない
押さえる点は2つあります。第一に、回転を掛けるのはクエリとキーだけで、値ベクトル(V)には掛けません。位置に依存させたいのは「どこを見るか」であって「何を運ぶか」ではないためです。ここを取り違えた自作実装は、短文では動くのに長文で急に壊れるという分かりにくい壊れ方をします。
第二に、ペアの取り方が原論文と実装で異なります。原論文とGPT-J系は隣接する次元 (0,1)(2,3) を組にしますが、Hugging Face のこの書き方は前半と後半を組にする(0と64、1と65…)GPT-NeoX系です。回転としては次元の並べ替えを挟めば等価ですが、別実装から重みを移植するときは、この並べ替えを入れないと出力が壊れます。変換スクリプトが permute 処理を持っているのは、この差を吸収するためです。
5系transformersのrope_parametersと旧rope_scaling
設定の置き場所は移行の途中にあります。transformers 5.16系の modeling_rope_utils.py を読むと、RoPE関連の設定は rope_parameters という1つの辞書に統合済みで、base も rope_theta としてこの辞書の中に入ります。従来トップレベルに置いていた rope_scaling は convert_rope_params_to_dict によって rope_parameters へ読み替えられる非推奨エイリアスという扱いです(辞書内の旧 type フィールドも rope_type と等価に処理されます)。
"rope_parameters": {
"rope_type": "yarn",
"rope_theta": 10000.0,
"factor": 8.0,
"original_max_position_embeddings": 4096
}
実務上の注意はここです。4系の記事やスクリプトをそのまま持ち込み、config.json のトップレベルに rope_scaling を書いた場合、読み替えは効いても、コード側で config.rope_scaling を直接参照している自作の前処理は空を掴みます。「設定を書き換えたのに挙動が変わらない」という症状の多くは、読み替え後の rope_parameters を見ていないことが原因です。確かめ方は次章の設定確認スニペットで示します。
partial_rotary_factorの部分適用とhead_dimの対応関係
すべての次元を回す必要はありません。partial_rotary_factor は、head_dim のうち何割にRoPEを適用するかを 0 から 1 の範囲で指定するパラメータで、既定値は 1.0(全次元に適用)です。GPT-NeoX系やPhi系のモデルは 0.25 や 0.4 といった値を採ります。残りの次元は回転を受けず、位置に依存しない特徴としてそのまま通ります。
この設計の狙いは、位置に縛られない意味的な特徴を確保しておくことにあります。一方で、拡張方式の計算式は適用対象の次元数を前提に組まれているため、partial_rotary_factor を設定したまま factor だけを触ると、意図した波長にならないことがあります。既存モデルの設定を書き換えるときは、この値が1未満かどうかを最初に確認するのが確実です。
手元で回す最小コード|内積に相対距離だけが残ることを確かめる手順
数式を追うより、実際に値を出したほうが早く腑に落ちます。ここで示す2本は追加ライブラリなしで走ります。
inv_freqから回転を組み立て内積の差分だけが残るか確かめる
標準ライブラリの math と random だけで、RoPEの中核はそのまま再現できます。head_dim を8に落とし、原論文と同じ隣接ペア方式で回転を掛け、距離が等しい組み合わせの内積を並べます。
import math
import random
head_dim = 8
base = 10000.0
inv_freq = [1.0 / (base ** (i / head_dim)) for i in range(0, head_dim, 2)]
def rope(x, pos):
out = list(x)
for i, w in enumerate(inv_freq):
a = pos * w
c, s = math.cos(a), math.sin(a)
x0, x1 = x[2 * i], x[2 * i + 1]
out[2 * i] = x0 * c - x1 * s
out[2 * i + 1] = x1 * c + x0 * s
return out
def dot(a, b):
return sum(p * q for p, q in zip(a, b))
random.seed(0)
q = [random.gauss(0, 1) for _ in range(head_dim)]
k = [random.gauss(0, 1) for _ in range(head_dim)]
for m, n in [(5, 10), (100, 105), (1000, 1005), (5, 30), (5, 200)]:
print(m, n, round(dot(rope(q, m), rope(k, n)), 6))
Python 3.14 で実行すると、距離5の3組(5と10、100と105、1000と1005)はいずれも −2.206829 という同一の値を返します。位置を200倍ずらしても内積が動かない、これが「絶対位置が消える」の実体です。距離を25に開くと −0.043805、195まで開くと 0.046099 まで落ち、絶対値が2桁縮みます。減衰項を書いていないのに遠距離の結びつきが弱まる様子が、この3行の出力に出ます。
base を500,000に変えて同じ距離の内積がどう動くかを見る実験も、この数値を1行差し替えるだけで試せます。
読み替え後のrope_parametersをconfigから出力して確かめる手順
設定が意図通りに読まれているかは、推論を回す前に確定させます。transformers を入れた環境で対象モデルの設定を読み、rope_parameters と rope_scaling の両方を出力すれば、どちらに値が入っているかが一目で分かります。
from transformers import AutoConfig
cfg = AutoConfig.from_pretrained("Qwen/Qwen3-0.6B")
print("rope_parameters:", getattr(cfg, "rope_parameters", None))
print("rope_scaling :", getattr(cfg, "rope_scaling", None))
print("max_pos :", cfg.max_position_embeddings)
print("partial :", getattr(cfg, "partial_rotary_factor", 1.0))
見るべきは3点です。rope_parameters に rope_type と factor が入っているか、rope_theta が期待した base になっているか、そして partial_rotary_factor が 1.0 以外なら拡張の計算対象が全次元ではないこと。ここで factor が None のまま長い入力を通していたなら、拡張は一切効いていません。
コンテキスト長を伸ばす方式の違い|PI・NTK・YaRN・LongRoPEの整理
学習長を超えた入力をどう扱うかが、RoPEを実務で触る最大の理由になります。
事前学習の段階で base を上げる方法とLlama 3の500,000という選択
後付けの拡張より先に押さえるべきは、そもそも base を大きくして長い文書で学習してしまう手です。Llama 3 の技術報告(arXiv:2407.21783)には「We increase the RoPE base frequency hyperparameter to 500,000」と明記されており、同報告は405Bの事前学習で 8K から 128K まで6段階に分けて長さを伸ばしたとも書いています。低周波側の波長が最初から長いため、モデルは長距離の位置差を学習の中で直接見ることになります。
この方法が使えるのは、自前で事前学習または大規模な継続学習を回せる場合に限られます。段階を踏んだ長文学習に投じたトークン量は約800Bと報告されており、規模の桁が違う。学習済みモデルを配布物として受け取る立場なら、選べるのは次に挙げる後付けの4系統です。
後付け拡張の4系統と rope_type 指定値の対応を一覧で整理する
transformers 5.16系の ROPE_INIT_FUNCTIONS に登録されている値は、linear・dynamic・yarn・longrope・llama3・proportional で、無指定なら拡張なしの既定動作になります。主要な4系統の性格は次のように分かれます。
| rope_type | 元になる手法 | 追加学習 | 向く倍率 |
|---|---|---|---|
| linear | Position Interpolation | 短時間の追加学習が前提 | 2〜4倍 |
| dynamic | NTK-aware 動的スケール | 不要(そのまま推論) | 2倍前後まで |
| yarn | YaRN | 短時間の追加学習で効く | 8〜32倍 |
| longrope | LongRoPE | 探索と追加学習が必要 | 数十倍以上 |
linear は位置インデックスを factor で割って既存の範囲に押し込む素直な補間で、原論文はPosition Interpolation(arXiv:2306.15595)です。隣接トークンの分解能まで一律に潰れるため、無学習では近距離の精度が落ちます。dynamic は割るのではなく、入力長に応じて base を動的に持ち上げる方式で、学習なしで使える代わりに倍率を上げると崩れます。
YaRN(arXiv:2309.00071)は、周波数帯ごとに扱いを変えるのが要点です。高周波側は隣接語の分解能を守るため補間せず、低周波側だけを補間し、その中間は beta_fast と beta_slow で決まる区間でなだらかに切り替える。加えて attention_factor で注意ロジットの温度を補正します。高倍率でも品質が落ちにくいのはこの作り分けによるもので、その分パラメータの指定項目が増えます。
LongRoPE(arXiv:2402.13753)は、次元ごとに別々のスケール係数を探索で決める方式で、短い入力用の short_factor と長い入力用の long_factor を持ちます。200万トークン級まで伸ばした報告があるのはこの系統です。llama3 は low_freq_factor と high_freq_factor で低周波側だけを補間する専用式で、Llama 3.1系の配布設定に現れます。
推論エンジン側の設定手順|vLLMのhf-overridesとKVキャッシュ試算
config.json を直したあと、同じ値を推論エンジンにも伝える工程が残ります。ここを飛ばすと、設定は正しいのに長文で壊れるという状態になります。
vLLMでrope-scalingが廃止されhf-overridesへ移った指定手順
vLLM公式のコンテキスト拡張ドキュメントは、旧来の --rope-scaling 引数がサポート対象外になり、--hf-overrides に rope_parameters を渡す形へ移ったと明記しています。公式が載せている YaRN の起動例がそのまま雛形になります。
vllm serve Qwen/Qwen3-0.6B \
--hf-overrides '{"rope_parameters": {"factor": 4.0,
"original_max_position_embeddings": 32768,
"rope_theta": 1000000, "rope_type": "yarn"}}' \
--max-model-len 131072
注意すべき対象は max-model-len の意味にあります。公式は「拡張後の新しい最大シーケンス長(元の値 × 係数)」と説明しており、KVキャッシュの事前割り当てと提供時のリクエスト上限にも使われる値です。上の例では、32,768 に factor 4.0 を掛けた 131,072 を指定しています。original_max_position_embeddings と factor と max-model-len の3つが噛み合っていないと、起動を拒否されるか、噛み合わない位置で推論が進む原因です。起動オプション全体の決め方はvLLMの仕組みと使い方・起動オプションの決め方にまとめてあります。
KVキャッシュの増加量を実数で見積もり同時実行数と突き合わせる
伸ばした長さは丸ごとメモリ請求書として返ってきます。KVキャッシュはコンテキスト長に比例して増えるため、4kから32kへ8倍にすれば、1リクエストあたりのキャッシュも8倍です。計算式は次の形で、桁を掴むだけなら暗算の範囲に収まります。
KV bytes = 2 × layers × kv_heads × head_dim × seq_len × dtype_bytes
例: 32層 × kv_heads 8 × head_dim 128 × 32,768トークン × fp16(2byte)
= 4,294,967,296 byte = 4.0 GiB / リクエスト
GQAで kv_heads を8まで削った構成でも、32kを1本通すだけで4GiBが消えます。80GiBのGPU1枚なら、重みを載せた残りで同時に何本さばけるかがここで決まる。同時実行数を保ったまま長さだけ伸ばすと、バッチが組めなくなって実効スループットが落ちます。見積もりの手順と削減の打ち手はKVキャッシュの仕組みとメモリ削減の考え方で扱っています。
拡張後の精度回帰をneedle形式と実務プロンプトで測る検証手順
拡張を入れたら、必ず前後で同じ条件の評価を回します。長文の中に1文だけ手がかりを埋めて回収させる形式の評価(needle-in-a-haystack)を、目標長の25%・50%・75%・100%の位置で当て、あわせて実務のプロンプト20〜50件を回帰セットとして通す。この2本立てで足ります。
困るのは、短い入力では差が出ないのに、想定した長さの8割あたりから静かに精度が落ちるという壊れ方をする点です。短文のスモークテストだけでは検出できません。合格基準は拡張前の正答率を基準線にして、許容できる低下幅を数値で決めておくのが実務的です。
RoPE拡張を採用してよい3条件と、見送るべき場面の判断基準
ここからは判断の話です。設定を1行足せば動いてしまうため、採否の線引きを先に決めておかないと、壊れているのに気づかないまま本番へ出ます。
拡張採用の第1条件は必要なコンテキスト長の要求が実測に基づくこと
1つ目の条件は、必要な長さが実測で決まっていることです。「念のため128kまで」ではなく、実際の入力トークン分布の95パーセンタイルを測り、その値の少し上に置く。分布を測らずに上限を取ると、使わない長さのためにKVキャッシュとGPU台数を払い続けることになります。
2つ目は、長さを使う目的が検索・要約・参照といった「広く浅く読む」処理であること。文書横断の参照や長い議事録の要約は、拡張後の精度低下が許容範囲に収まりやすい用途です。逆に、長文の隅にある1つの数値を厳密に取り出して判断に使う処理は、拡張の劣化がそのまま業務の誤りになります。
3つ目は、拡張前後を比べる評価セットを自前で持てること。公開ベンチマークの数値ではなく、自社の実データで作った20〜50件程度の回帰セットがあれば十分です。これを持てない体制なら、倍率を上げる判断を下す根拠がありません。
拡張を見送るべき3場面=精度保証・低レイテンシ・短文中心の用途
1つ目は、出力の正しさを契約や規程で保証する必要がある場面。拡張は学習時に見ていない位置での外挿であり、品質が保たれる保証は原理的にありません。この場合は、長文をそのまま投げるのではなく分割して処理する設計か、初めから長いコンテキストで学習されたモデルを選ぶほうが筋が通ります。
2つ目は、応答時間の上限が厳しい場面。長いコンテキストは入力処理(プリフィル)の時間を押し上げ、KVキャッシュの増加でバッチも組みにくくなります。P99レイテンシを守る用途では、長さを伸ばすより入力側を絞り込む設計のほうが確実に効きます。
3つ目は、入力の大半が数千トークン以内で収まっている場面です。長い入力が全体の数パーセントなら、その数パーセントのために全リクエストのメモリ設計を犠牲にする理由はありません。ここで比較すべき相手は、コンテキストを伸ばす工事ではなく、必要な断片だけを検索して渡す構成です。判断材料が足りないなら、RAG構築支援で入力分布の実測と検索側の設計を先に固め、そのうえで拡張が要るかを決める順序を採ってください。拡張は、いわば全員分の座席を広げる工事であって、たまに来る大柄な来客のための対応としては割高です。
長文対応の実装を外部へ委託するとき見積書で確認すべき5項目の基準
委託時に見積もりの精度を左右するのは、次の5点です。第一に、対象モデルの学習時コンテキスト長と base(rope_theta)の実値、そして目標長と倍率が明記されているか。倍率が書かれていない見積書は、方式の選定が済んでいない可能性があります。
第二に、採用する rope_type と、追加学習の有無・データ量・計算資源。yarn や longrope を選ぶなら追加学習の工数が乗るはずで、そこが空欄なら無学習の dynamic を想定している見積もりです。第三に、KVキャッシュを含めたVRAM試算と、想定同時実行数での必要GPU台数。第四に、拡張前後の回帰評価の設計(評価セットの件数・作成主体・合格基準)。第五に、推論エンジン側の設定変更とデプロイ手順が範囲に含まれるか。
この5点が曖昧なまま進むと、構築後に「長さは通るのに、長い入力での精度が業務水準に届かない」という形で表面化します。委託先を選ぶ際は、機械学習モデル開発のようにモデル構造の選定と基盤実装を一体で扱える体制かを確認してください。
よくある質問
RoPEの検討時に問い合わせが多い論点を5つ挙げます。
RoPEと従来の位置エンコーディングは何が違うのですか?
足すか、回すかの違いです。従来方式はトークン埋め込みに位置ベクトルを加算し、入力層で1度だけ位置情報を注入していました。RoPEは注意計算の直前にクエリとキーを回転させるため、層ごとに位置情報が作用し、内積には相対距離だけが残ります。学習可能なパラメータを増やさない点と、系列長を後から伸ばす余地がある点も差になります。
RoPEを使えば学習した長さを超えても動くのですか?
形式上は動きますが、品質は保たれません。位置インデックス自体は上限なく計算できるので、学習長の10倍を投げてもエラーにはならず、出力だけが崩れます。この「静かに壊れる」性質が実装者にとっての落とし穴で、拡張方式を指定せずに長い入力を通していないかは、本番投入前に確認しておく価値があります。
rope_scaling を後から書き換えるだけで長文に対応できますか?
倍率次第です。2倍前後までなら dynamic の無学習指定で実用に足りることが多い一方、8倍を超える拡張では yarn などの方式と短時間の追加学習を伴わないと精度が落ちます。加えて transformers 5系では設定が rope_parameters に統合されているため、書き換えた値が読み込み後の config に反映されているかを、本記事のコード例で先に確かめてください。
RoPEはKVキャッシュとどのように関係しますか?
Hugging Face の一般的な実装では、回転を適用した後のキーをキャッシュします。したがってキャッシュ済みの内容は特定の絶対位置に紐づいており、プロンプトの前方を差し替えると位置がずれて再利用できません。拡張の設定を変えた場合も、以前の設定で作られたキャッシュは無効になると考えて扱ってください。
画像や音声を扱うモデルにもRoPEを適用できますか?
利用可能です。テキストの1次元の位置を複数の軸へ分解して割り当てる多次元の派生が公表されており、Qwen2-VL の技術報告(arXiv:2409.12191)は M-RoPE(Multimodal Rotary Position Embedding)を導入し、テキスト・画像・動画にまたがる位置情報を統合すると述べています。基本の考え方は同じで、軸ごとに次元のブロックを割り当て、それぞれの位置に応じて回転させる形になります。
関連記事
- LLM推論とは?仕組みと高速化の手法・推論基盤の選び方を実装視点で解説【2026年】:RoPE拡張を載せる推論基盤側の全体像
- LoRA(低ランク適応)とは?仕組み・使い方・QLoRAなど派生手法を解説:YaRNなどで必要になる短時間の追加学習の手段
- LLM量子化とは?仕組みとGPTQ・AWQ・GGUFの違い・企業の採用判断を解説【2026年版】:長文化で膨らむメモリを別方向から抑える手法
- DeepSeek V4とは|CSA・HCAの仕組みとPro/Flashの性能・料金・移行期限を解説:長文アテンションを構造側から軽くする実例
- ニューラルネットワークとは?仕組み・種類・学習方法を実装目線で解説:回転を掛ける対象である埋め込み表現の基礎