DJProject_備忘録_7

## 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);
            }
            ```
## 2024-12-17
なんだっけ、、
自身のパラメータを保存するべき行の最初のインデックスを返すメソッドを作ったんだ。
- AttentionWeight
    - hsを取得するコード作ろう
        自分の自分を含め、過去の自分の全てのポジションのhをとるから、自分のポジション数をforで回せばいいよね。
        AttentionWeightPlayerでは、自分のParamsの場所3つのうちIndex2行目は、hにしよう。Index0行目にはWのフラットデータ.Index1はバイアスにしよう(AttentionWeightには重みとかないけど共通ルールとして。)。
        - hはPlayerでのメンバ保持実装
        - WはParamsPlayerで全てのレイヤー分実装(ハードコーディング)
        


## 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)
    - 逆伝
        - Backwardを実行
            dx, dhs = this.Backward(dout)
        - dhsの振り分け
            ポジションをforで回し、
            それ以前の全てのポジションの
            自身のdhsに
            this.dhs[i] += [dhs[i]]
            
    って思って実装したんだけど、AttentionWeightLayer内でそれが既に実装してあったんだけど。さすがみらいとリコ。
    なので…4時間くらいいらない実装をしてたのですが、こうだ！↓
    ![IMG_0250.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3910368/9483156c-2312-37f1-1345-0e770e265afd.jpeg)
    さて、再度あらためもう一度組み立てよう。
    
    順伝播入力:x,hs
    順伝播出力:a,hs
    逆伝播入力:da,dhs
    逆伝播出力:dx,dhs

    - 順伝
        - hsの呼び出し
            ポジションをforで回し、
            それまでの全てのポジションの
            自身のhを取得し、
            this.hs += [h]として保持
        - Forwardを実行
            a,hs = this.Forward(x,hs)
    - 逆伝
        - Backwardを実行
            dx, dhs = this.Backward(da, dhs)
        - dhsの振り分け
            ポジションをforで回し、
            それ以前の全てのポジションの
            自身のdhsに
            this.dhs[i] += [dhs[i]]

    ん？
    つまり、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は
各ポジションと干渉するので、
参照渡しは絶対にだめだ。

最後に結局確認するから、
今はとりあえず形として完成させる方が先かもしれない…
![IMG_0274.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3910368/613442c9-3327-993f-177e-f9b5cb83d59c.png)


## 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から確認していく。

この順番で確認しなきゃ↓
![IMG_0277.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3910368/88c0c90e-1ded-bbcc-cf01-37e52ac4eb89.jpeg)


## 2024-12-26
- AffinePlayer
    🌙
    - AffineLayer
- NormalizationPlayer2
- SwishPlayer
- NormalizationPlayer4
- WeightSumPlayer(ああ、、ようやくここまで来た、、)
    - AttentionWeightでhsは作成済みなので、AttentionWeightからhsは取得する。
    - dhsについては、AttentionWeightの方に、WeightSum用に、変数「DhsByWeightSum」を用意し、逆伝播時にWeightSumPlayerのdhsはここに保存することになる。
    - そして、AttentionWeightは、backwardでdhsを、算出したら、dhsを各ポジションに振り分ける前に、「dhs += DhsByWeightSum」とす。![IMG_0279.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3910368/769588cc-90cc-6bb7-9c99-5f6ab91f527e.jpeg)
    - 

## 2024-12-30
…俺はもう、可愛くなれないのか…


AffineAddPlayer
![IMG_0309.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3910368/399e5dbd-4bb0-7b3b-617c-fd5c6b2561c1.png)
の、🌙の部分まで実装済


あとはSoftmaxWithLossPlayer
![IMG_0310.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3910368/7d105710-0ab3-ffaa-31a8-6f62e2c738cc.jpeg)

## 2025-01-10
ことよろ

何してたんだっけ…
とりあえず、作ってたんだね（そりゃそうか）

そうだ、スケジュール順にLayerを直して（正して、作って）たんだ。

#### 回想
- スケジュール順にLayerを正してた
- 最後の備忘録がSoftmaxWithLossなので、
一先ずSoftmaxWithLossを観て、正す箇所があれば正そう
- 正す場所分からなければ、備忘録をさらに黙読しよう
- いや、1つ前の層のNormalizationLayerを先に見よう。感覚を掴んでから、SoftmaxWithLossを見よう。

大丈夫そんぁちがう！あれだ！思い出した！
ほとんどが参照渡しだったから値渡しに変換してるんだった！RinaNumpyで！
それが、「あとSoftmaxWithLossだけ！」の意味だ！

後もうひとつ思い出した！
paramsとdParamsの振り分けだよ！
しっかり、データを取得、代入しなきゃ。
確かにSoftmaxWithLossPlayerはparams,dParamsが未実装だ。

```
        int PositionDataIndex = paramsPlayer.ResultIndexOfParamsSave(
                                        MyPositionNum,
                                        MyLayerNum
                                    );
```
これで自身の場所取得して、、
SoftmaxWithLossで使うベータ値なんてあったっけーって、考えるんだったね。そうだったそうだった。
…x,doutは引数で伝播させてるからParamsに登録は不要、、？
いやいや、最初のLayerで取得、代入するんだ。最初のLayerのForwardとBackwardでそれそれ、その時処理するポジションのxを取得、doutを代入させるんだね。

なので、、

# あとやることは
・SoftmaxWithLossPlayerのParamsの受け渡し
→ 保持するデータがないため、実装不要だね。
・ポジション振り分け直後のLayer（1番最初のレイヤー）にxの取得、doutの移植を実装（もうしてある？）
→ 
・ループしてPositionずつxを渡す機能の実装

## 2025-01-14
おおお、ちょっと逆算意識しすぎじゃない？
ここは、せっかくLayerが準備できたので、
InitAiTypesPlayer から組み立てていこう。
#### あとやることは…
・ballスケジュール「make_x」を仮定
・InitAiTypesPlayerの実装（🔺）
・InitAiTypesPlayerをmake_xに追加（✅）
・ChangeAiModePlayerの実装
・ChangeAiModePlayerをmake_xに追加
・ChangeTravelModePlayerの実装
・ChangeTravelModePlayerをmake_xに追加
・AiSettingsPlayerの実装
・AiSettingsPlayerをmake_xに追加
・EmbeddingPlayerの実装
・EmbeddingPlayerをmake_xに追加