2024-12-16
- AttentionWeightPlayer
- AttentionWeightLayer
いやまだ、組めない。- ParamsPlayer
あれ、さっき作ったの改良しよう。最初のインデックスだけで良いでは無いか。
ということでpublic int ResultIndexOfParamsSave( int PositionIndex, // 自身のポジションIndex int LayerIndex, // EmbeddingLayerから数えて自分が何層目のLayerなのか。 int LayerSize, // 全てのレイヤ数(Embedding以降において) int LayerParamsSize // LayerがParamsに保持してよい行数 ) // 戻値:このポジションが保存すべきParamsのIndexsの最初の数値 // ▶︎今回1レイヤ当たり3行の空データを提供している。その3つのインデックスの内の最初のインデックスを返す。 { return (PositionIndex * LayerSize) + (LayerParamsSize + LayerIndex); }
- ParamsPlayer
- AttentionWeightLayer
2024-12-17
なんだっけ、、
自身のパラメータを保存するべき行の最初のインデックスを返すメソッドを作ったんだ。
- AttentionWeight
- hsを取得するコード作ろう
自分の自分を含め、過去の自分の全てのポジションのhをとるから、自分のポジション数をforで回せばいいよね。
AttentionWeightPlayerでは、自分のParamsの場所3つのうちIndex2行目は、hにしよう。Index0行目にはWのフラットデータ.Index1はバイアスにしよう(AttentionWeightには重みとかないけど共通ルールとして。)。- hはPlayerでのメンバ保持実装
- WはParamsPlayerで全てのレイヤー分実装(ハードコーディング)
- hsを取得するコード作ろう
2024-12-20
なんだっけ。
-
AttentionWeightPlayer
AttentionWeightLayerの方のhsとdhsについて…これ、ForwardとBackwardで hsとdhsのインデックスに相当するベクトル関係は等しいかしら? 管理としては、hsのインデックスがポジション数と等しくしたいの。 Forwardのほうは確認したよ。なので、あとはBackwardのdhsとhsのベクトル関係においてインデックスが等しければ、そのままカレントポジションより前のLayersに振り分けられるんだけど、、
…みらい、リコに質問してきた。
問題なく一致していて良かった↓インデックスの一致: cacheHs[i] はForwardの入力であるhs[i]と同じデータを保持しています。 Backward内で計算されたdhs[i]は、cacheHs[i]を使って計算されるため、インデックスは一致しています。 みらい:「やったね、りな!dhs[i]はhs[i]と完全に対応しているよ!つまり、ポジション数もインデックスもそのまま扱えるね!」 リコ:「ええ、Forwardのhsのインデックスが、Backwardのdhsに正しく反映されていることが確認できたわ。これなら現在の設計で、カレントポジションより前のLayersにも問題なく振り分けられるわね。」
そしたら改めて、
順伝播入力:x,hs
順伝播出力:a
逆伝播入力:da
逆伝播出力:dx,dhs- 順伝
- hsの呼び出し
ポジションをforで回し、
それまでの全てのポジションの
自身のhを取得し、
this.hs += [h]として保持 - Forwardを実行
a = this.Forward(x,hs)
- hsの呼び出し
- 逆伝
- Backwardを実行
dx, dhs = this.Backward(dout) - dhsの振り分け
ポジションをforで回し、
それ以前の全てのポジションの
自身のdhsに
this.dhs[i] += [dhs[i]]
- Backwardを実行
って思って実装したんだけど、AttentionWeightLayer内でそれが既に実装してあったんだけど。さすがみらいとリコ。
なので…4時間くらいいらない実装をしてたのですが、こうだ!↓
さて、再度あらためもう一度組み立てよう。順伝播入力:x,hs
順伝播出力:a,hs
逆伝播入力:da,dhs
逆伝播出力:dx,dhs- 順伝
- hsの呼び出し
ポジションをforで回し、
それまでの全てのポジションの
自身のhを取得し、
this.hs += [h]として保持 - Forwardを実行
a,hs = this.Forward(x,hs)
- hsの呼び出し
- 逆伝
- Backwardを実行
dx, dhs = this.Backward(da, dhs) - dhsの振り分け
ポジションをforで回し、
それ以前の全てのポジションの
自身のdhsに
this.dhs[i] += [dhs[i]]
- Backwardを実行
ん?
つまり、Layerの方で
各ポジションのdhに微分を加算実装済み
だったから、これで良い。
従って、逆伝播では- 加算処理は不要
- DParamsに戻す際は上書きして良い
という理解で。良いのか!?もう一度Layerを観てこよう。
- 順伝
朗報がある。
なんと、スーパークラスは継承し放題らしい。
出来ないという謝った情報を、信じてきてしまった。
2024-12-23
はい。
AttentionWeightPlayerかな?
あー、、重みの、、、hsの、、
あー、
hsを丸ごとLayer.Forwardに持っていき、
hsを
Layer見ながら確認するか。
hsを丸ごとLayer.Forwardに持っていき、
学習したいパラメータを、
Params、DParamsに保存する訳じゃないですか。
でもでも、AttentionWeightPlayerでは、
・ほかのポジションの値も参照したいから
という理由で、h(== 入力x)を保持するわけですね。
なので、更新時hを飛ばす処理が必要(まぁForward時上書きするから計算的には問題ないのですが。)ですね。
2024-12-25
問題だ。今までほとんどのベクトル、テンソルは
参照渡しだ。
多分…AttentionWeightできた。あとは実行しないと分からない。
も、戻りましょうか。
最初のLayerから確認し、参照渡しの部分を全て値渡しにしなくてはならない。
とくに、
レイヤーLayerは問題なさそうだけど、
レイヤーPlayerは
各ポジションと干渉するので、
参照渡しは絶対にだめだ。
最後に結局確認するから、
今はとりあえず形として完成させる方が先かもしれない…
2024-12-25
- NormalizationPlayer
機能や確認が増えたので、
1度テンプレートを作ろう。
using UdonSharp;
using UnityEngine;
public class プレイヤー : SuperPlayer
{
public string myName;
public Layer layer;
public AiFlagsPlayer aiFlagsPlayer;
public AiSettingsPlayer aiSettingsPlayer;
public RinaNumpy rinaNumpy;
public float[] x; // 順入力
public float[] y; // 順出力
public float[] dout; // 逆入力
public float[] dx; // 逆出力
public int MyPositionNum;
public int MysLayerNum;
// 初期化メソッド (Pythonの__init__に相当)
public bool layerReset()
{
myName = "Layer";
return true;
}
// プレイヤーの名前を返すメソッド
public override string ReturnMyName()
{
return "Layer";
}
public float[] Forward(float[] x)
{
// Paramsから自身のベータ値をとってくる。
//// 自身のParamsのindexを取得
//// このポジションのデータ場所の最初のindex
int PositionDataIndex = paramsPlayer.ResultIndexOfParamsSave(
MyPositionNum,
MyLayerNum
);
//// ベータガンマ重みバイアス等
float[] beta = rNp.Copy_FloatArray(paramsPlayer.AllParams[PositionDataIndex]);
float[] gamma = rNp.Copy_FloatArray(paramsPlayer.AllParams[PositionDataIndex + 1]);
y = rNp.Copy_FloatArray(layer.Forward(x, beta, gamma));
return rNp.Copy_FloatArray(y);
}
public float[] Backward(float[] dout)
{
float[][][] result = layer.Backward(dx)
this.dx = rNp.Copy_FloatArray(result[0][0]);
this.beta = rNp.Copy_FloatArray(result[1][0]);
this.dbeta = rNp.Copy_FloatArray(result[2][0]);
this.gamma = rNp.Copy_FloatArray(result[3][0]);
this.dgamma = rNp.Copy_FloatArray(result[4][0]);
// Params,DParamsに保存
paramsPlayer.AllParams[MyPositionNum] = rNp.Copy_FloatArray(this.beta);
paramsPlayer.AllParams[MyPositionNum + 1] = rNp.Copy_FloatArray(this.gamma);
return rNp.Copy_FloatArray(dx);
}
// メイン処理を行うメソッド
public override string ExecuteMain()
{
if (aiFlagsPlayer.TravelMode == "Forward")
{
// 1つ前のレイヤのyをxとする。
this.x = swishPlayer.y
// Forward処理
this.y = layer.Forward(this.x)
}
else if (aiFlagsPlayer.TravelMode == "Backward")
{
// ひとつ先のLayerのdxをdoutとする。
this.dout = attentionWeightPlayer.dx
// backward
this.dx = layer.Backward(this.dout)
}
return "Completed";
}
}
- NormalizationPlayer0~3を4と同じように改良
- あ、前のレイヤー、あとのレイヤーの関係保持するの忘れた。改良。
つまり、今各レイヤに実装できていないのは(するべきなのは)、
- Params,DParamsのやり取りコード
- 値渡し実装
です。
以下、それらをAffinePlayerから確認していく。
2024-12-26
- AffinePlayer
🌙- AffineLayer
- NormalizationPlayer2
- SwishPlayer
- NormalizationPlayer4
- WeightSumPlayer(ああ、、ようやくここまで来た、、)
2024-12-30
…俺はもう、可愛くなれないのか…