2024-11-28
次はTransformerを作るために、Affine,LeLU,Softmax,Normalization(逆伝播難しいんだよね…),AttentionWeight,WeightSum,CrossEntropyLoss
、、ぐらいかな。作っていこう。
えっと、前に書いた簡易Transformerの写真、写真、、、あった
あったけど、これAttentionLayerに1つ前のポジションのhs渡す矢印が足りない
ここで言う、FeedforwardLayerはAffineLayerとやってる事全く一緒らしい。
…ほんとに?
でもとりあえず、xW + bで良いってさ。
SigmoidLayerはReLULayerに置き換えよう。
そして、全てのLayerの手前にNormalizationLayerを挟み、爆発消失避けよう。
ちよっとまって、SwishLayerを過去の自分がUdonSharpで用意してくれてる。
ここのディレクトリ素敵、、。これ、今回使おう。
中身が少し特殊だったので、それを訂正する形で、バージョンをアップさせよう。
ここまで
用意できた。
CrossEntropyLossはSoftmaxWithLossとしてまとめた。
そしたら、、サーバー側のPythonにも同じレイヤーを作りましょうか…。
Pythonの方もできた。
2024-11-29
-
LiONにスケールダウン機能を加える。
勾配爆発、消失した場合に、重み、バイアス全体のスケールダウンをすることで、限りなく勾配爆発、消失を教える試み。 -
スケジュールを作ろう
2024-11-30
スケジュールをつくろうと思ったけど、Layerを作っただけなので、各全てほLayerのPlayerを作ろう。
…土曜12時間出勤だるい今日、、、
とりあえずテンプレ…
using UdonSharp;
using UnityEngine;
public class AffinePlayer : SuperPlayer
{
public string myName;
public AffineLayer affineLayer;
public InitAiTypesPlayer initAiTypesPlayer;
// 初期化メソッド (Pythonの__init__に相当)
public bool AffinePlayerReset()
{
myName = "AffinePlayer";
return true;
}
// プレイヤーの名前を返すメソッド
public override string ReturnMyName()
{
return "AffinePlayer";
}
public float[] Forward(float[] x)
{
float[] y = affineLayer.Forward(x);
return y;
}
public float[] Backward(float[] dx)
{
float[] dout = affineLayer.Backward(dx)
return dout;
}
// メイン処理を行うメソッド
public override string ExecuteMain()
{
// ForwardPlayerでライブラリ的に使用するので
// 実装今のところ不要
return "Completed";
}
}
レイヤーすべてにPlayerを用意した。LiON、もっと早い処理になるように改良できないかな、、
もう電池無くなる、、さよなら
2024-12-02
レイヤーのオブジェクト数は
UdonSharpの処理力的に、
各レイヤ1つずつとするため、
重み、バイアス、ベータ値
そして、それぞれの微分値は、
各ポジション分用意する必要がある。
- レイヤーの作成
- Params,DParamsLayerの作成
- Xs,DXsLayerの作成
2024-12-05,2024-12-06
日付けが空いた。
なにしてたんだっけ、、
ああ、前回の画像みて思い出した。
- レイヤーの作成
- Params,DParamsLayerの作成
さて、必要としてるのは…
・4次元arrayを持ったparams
・4次元arrayを持ったdparams
ね。
- Params,DParamsLayerの作成
…これじゃダメだ。C#知識不足の私に組み込めない。
パラメータ群は、ひとつの行列に収めることにした。
3行をひとつのLayer分の情報とし、
各重み、バイアス、ベータ値はフラットに…って、
あ、フラットにするのは重みだけで良いのか。
Layerでパラメータを呼び出す時は、reshapeして使うことにした。
これなら4次元データにならず、2次元行列で済む!
なので、えっと、次することは、、
- Paramsプレイヤーは2次元ジャグ配列をもつオブジェクトとして作り直す。
- DParamsプレイヤーも同様に。
その後で、どのようにForwardPlayerでの処理をするか、考えよう。流れは大まかに出来てる…
…ので、後で考えても大丈夫。
- AiSettingsPlayer の作成
このプレイヤーに、HiddenSizeやXSizeのパラメータ設定をメンバ変数として持たせよう。
2024-12-09
- ParamsPlayer を作らなきゃ
2024-12-11
まってまず、EmbeddingLayerの改良から始めよう。
なので、
- EmbeddingPlayerの改良
あ、Tokenizerクラス作らなきゃ
EmbeddingLayerの重み定義できないや。
あいや、設定パラメータは全てAiSettingsPlayerから取得するようにしよう。仮定義としてEmbeddingLayerを先に作ろう。- RinaNumpyに
- Append_FloatArray()
- Append_StringArray()
を追加。 - …あと色々追加。
- RinaNumpyに
2024-12-12
EmbeddingLayerあとBackwardだけ
えっとEmbeddingLayerの次のレイヤーは、レイヤー群になる。
なので、レイヤー群の最初のレイヤー(LayerNormalizationPlayer)は、
なので、次のレイヤーはEmbeddingのthis.SampleIdVerをforで回して取得することになる。
そのため、AiFlagsPlayerを作成し、その時学習中のポジションのインデックスをこのプレイヤーに保持させることにした。
ほか、ほかの処理でフラグが必要になった場合、このプレイヤーに書き込み使用していく。
EmbeddingPlayerできた。
ついでに、「予定スケジュール.md」も作成した。中身は次の通り。
# Forward
## Xのフロートベクトル化まで
- InitAiTypesPlayer # モード変数の初期化
- ChangeAiModePlayer # TrainまたはPredictのトグルスイッチ
- ChangeTravelModePlayer # ForwardまたはBackwardのトグルスイッチ
- AiSettingsPlayer # 入力データ、隠れ層等の設定
- EmbeddingPlayer # Xを1次元ベクトル化
## フロートベクトルをlossに変換するまで
- PositionsParamsPlayer # このポジションのパラメータを、各レイヤーにペーストする
- NormalizationPlayer # 各ポジション毎回、EmbeddingPlayerのSampleVecVerから取り出してくる。
- SkipAddPlayer
- AffinPlayer
- NormalizationPlayer
- SwishPlayer
- NormalizationPlayer
- AttentionWeightPlayer
- NormalizationPlayer
- WeightSumPlayer
- NormalizationPlayer
- AffinPlayer
- NormalizationPlayer
- SoftmaxWithLossPlayer
---
# Backward
## Backwardモードに移行
- ChangeTravelModePlayer # ForwardまたはBackwardのトグルスイッチ
## EmbeddingPlayer直前まで逆伝播
- SoftmaxWithLossPlayer
- NormalizationPlayer
- AffinPlayer
- NormalizationPlayer
- WeightSumPlayer
- NormalizationPlayer
- AttentionWeightPlayer
- NormalizationPlayer
- SwishPlayer
- NormalizationPlayer
- AffinPlayer
- SkipAddPlayer
- NormalizationPlayer # 各ポジション毎回、EmbeddingPlayerのdSampleVecVerに入れ込んでいく。
- PositionsParamsPlayer # Layerのパラメータを、自身の変数に保持
## EmbeddingPlayerのbackwardで、dWの完成
- EmbeddingPlayer
プレイヤーの実行順番が記載されている。新しいプレイヤーも定義した。
各レイヤーの中に、またプレイヤーとしてまとめていないもの、さらにレイヤーとして未完成なものがほとんどなので、1プレイヤー1プレイヤー、完成させていこう
- NormalizationPlayer,NormalizationLayer
んー、、LayerとPlayerを交互に見て疲れる…しんどい…パソコンでやりたい…
NormalizationPlayerは(NormalizationPlayerに限らず)何度か使用してるので、NormalizationPlayer2とか作ってかなきゃね。
あ、、githubだと
みたいに左しか見えないから
2_Normalizationとかにしなきゃ、、。
うーん、基本的にプレイヤーのExecuteMainは1つ前のプレイヤーから取って来る感じでいいかな、、。// メイン処理を行うメソッド public override string ExecuteMain() { if (initAiTypesPlayer. TravelMode == "Forward") { // 1つ前のレイヤから、xを取ってくる this.x = embeddingPlayer.SampleVecVer[aiFlagsPlayer.NowPositionIndex] // Forward処理 this.y = normalizationLayer.Forward(this.x) } else if (initAiTypesPlayer. TravelMode == "Backward") { // ひとつ先のLayerから、doutを取ってくる this.dout = skipAddPlayer.dx // backward this.dx = normalizationLayer.Backward(this.dout) // このポジション終了したので+=1 aiFlagsPlayer.NowPositionIndex += 1; }
Pythonみたいにインスタンスをリストで管理できないから、if分岐で実行する処置をとった。U#はオブジェクト指向プログラミングがやりにくいですね…。
2024-12-13
- SkipAddPlayer, SkipAddLayer
- Player
- ExecuteMain
ifでForward分岐
- ExecuteMain
- Layer
ForwardとBackwardの機能がなんか逆だったから訂正。
Skip先はAffineLayer2とし、AffineLayer2自身でSkipAddPlayerにアクセスしてyを取得して加算させることにする。
- Player
- AffinePlayer(1つ目)
- プレイヤー
はい。
あ、PlayerのPlayerResetメソッドで
Layerの初期化してないや。
やろう。
(邪心発散:上京アフロ田中の次のシリーズってあるのかな…見たい)
(邪心発散:ぁぁ、、UdonSharpはふたつ先のスーパーレイヤ取れないっていう噂だし、、とりあえずハードコーディングするしかないよね…全部で10超過位のレイヤ数だし、すぐだよ、すぐ。)
…なんだっけ
ああ、初期かね。
いいや。
- NormalizationPlayer2
- SwishPlayer
- NormalizationPlayer3
2024-12-16
- NormalizationPlayer3
- AttentionWeightPlayer
- AttentionLayer
さて。そうですね、Forwardで、1つ前のポジションと、自身のhをまとめhsにしなければならない。
ポジションの順伝逆伝が1つ終わると、レイヤのパラメータはParamsPlayerの2次元ベクトルに
わー、、
- AttentionLayer
入力は、int型。
出力は、
って、、ああ、なんか出来ちゃったよ、笑
ちょっとベクトルの書き方が数学的にやったことないから(園芸科学科の専門高校だったから…線形代数習わなかったの…悔しい)あれだけど、
[y1,y2,y3] = 3x + [0,1,2]
で出来そうね。
y=ax+bで考えてみたよ。バイアスが個々のインデックスのズレだとすれば、あとは3かけるだけでいけるよね。傾きが3なのね、この式は。
だから、、
def result_index_of_paramssave(x=None):
y = []
bs = [0, 1, 2]
a = self.LayersParamSize * self.LayerSize
for b in bs:
y.append(a * x + b)
return y
として保存しよう
chatGPTに変換させて、さらに細かいところの修正、ほかプレイヤーからの引き継ぎ
public int[] ResultIndexOfParamsSave(int x)
// 引数:処理中のposition数
// 戻値:このポジションが保存すべきParamsのIndexs
{
// 結果を格納する配列を初期化
int[] y = new int[3];
int[] bs = { 0, 1, 2 };
int[] a = aiSettingsPlayer.LayerParamsSize * aiSettingsPlayer.LayerSize
// bsの各要素に3 * xを加算してyに格納
for (int bi = 0; bi < bs.Length;bi++)
{
y = rinaNumpy.Append_FloatArray(y, bs[bi] + 3 * x);
}
return y;
}
じゃぁAttentionWeightPlayerでは、、
・現在のPositionをforで回す
・ResultIndexOfParamsSaveにiを入れて保存すべき