最近ニューラルネットやってみてる
理屈を学ぼうと思って、まずはオブジェクト的に作ってみてる
(ベクトル化とかは後回しで)
sigmoid, tanh, ReLU
MSE, cross entorpy
あたりを小規模にいじってみてます
でも今 soft max の逆伝搬ができなくて困ってる
ネットの説明みても数式がわからない感じ
数学は興味はあるけど、実際やろうとすると拒否感がすごい
分かると楽しいのではないかと思うんだけど、
記号の意味わからなさ(コードと違って識別子が説明的じゃないし)と
学校教育の初期でドロップアウトしたことで
どうもだめです
それでもなんとか3Dやるのに困らない感じには
(ベクトルとか行列とかテンソルとかイナーシャとか…)
カンを頼りにコードに起こしてるけど
苦手意識がはんぱない
ニューラルネットはものすごい昔に本とか読んだ
当時、なんというか脳内のホルモン的なものによる
感情的なものの簡易的なエミュレートとかやってみたいなと思ってた
んで今やってみようと
逆伝搬は個人的にあまり興味がないので、別の方法とかないかなと思ってて
最近金子勇氏の講演動画にいきあたったりして
すごい興味あるんだけども、もうこの世にはいない 残念だ
学習に浮動小数点数を使用するのも、もっとこう簡易的に byte とかで
済ませらんないのかな?とか
ごく簡単な方法とかないのかなとか 探してみたい
なんとなく俯瞰的に見て、ニューロンであるかないかはあまり関係なくて、
単体が非線形で、他の単体との関係性があるモデルであることが重要なのかなとか
思うのが、バードイドとか
あの辺、単体には簡単なルールしかないのに全体として面白い動きをするあたり、
ちょっと似た感じをうける
ライフゲームとかもそうだろうか
そのうち、この辺を一般化した考え方みたいなのが出てくるんじゃないだろうか
動物と生態系とか人間と都市社会とか
そのネスト関係とか
話がおかしくなったけど、
当面やりたいのは、ゲーム的な環境の中に自律したキャラクターを置いて、
仮想ペットみたいなのにしたりとか
そいういのがしたいかんじ
2019年4月1日月曜日
2018年12月9日日曜日
コンピューとシェーダー覚え
めも 時々書き換える
概要
http://neareal.com/2601/
長所短所、効率等
https://wlog.flatlib.jp/item/1425
DirectCompute だとどうなってるか
https://wlog.flatlib.jp/item/1411
構成要素
シェーダー
バッファ
カーネル カーネルID
スレッド スレッドグループ
定数バッファ
実行はグループ数を指定 (x,y,z)
1グループにつき (x,y,z) スレッドを実行
バッファは普通にランダムアクセスする
実行中のスレッドIDを得ることが可能、バッファアクセスに利用できる
グループIDも取得可能
定数バッファは他のシェーダと同じ
コンピュートバッファは1次元、テクスチャバッファは2次元、という感じ
RW は書き込み可能
StructuredBuffer
AppendStructuredBuffer/ConsumeStructuredBuffer
バッファタイプ
Default structured buffer
Raw byte address buffer
Append AppendStructuredBuffer/ConsumeStructuredBuffer
Counter よくわかんない、カウンタ付きの structured buffer
IndirectArguments DrawIndirect 系に渡すための引数バッファ(dword*5)
DX11では
リソースとその使用方法としてのビューという概念があるみたい
同じリソースを複数のビューから扱えるもよう
リソースはバッファとテクスチャに分けられるみたい
--------
リソース
Texture/RWTexture
Buffer/RWBuffer
ByteAdddressBuffer/RWByteAddressBuffer
StructuredBuffer/RWSturcturedBuffer
ConsumeStructuredBuffer/AppendSturctutedBuffer
ビュー
ShaderResourceView (SRV) R
UnorderedAccessView (UAV) R/W
RenderTargetView (RTV) W
DepthStencilView (DSV) W
この辺は Unity では隠されているかんじ?
-------
バッファ
CopyCount() バッファ間でカウントをコピーできる
・おそらくCPUを介せずにGPU内で可能なんだと思う
SetCounterValue()
・カウンタをセットできる 定数バッファの SetXxxx() と同じ感じなんじゃないかな
・よくわからないが、たぶん内部がどうなってるとかは考えずに使用していける感じか?
・要素の追加/取得と現在状態(カウンタ)だけ管理すればいいみたいな
SetData( nativeArray, arrayStart, bufferStart, elementCount )
・任意の位置へのアクセス
・帯域も節約できるんだろうか
・複数個所に細かく SetData() した場合の転送効率はどうなんだろう
概要
http://neareal.com/2601/
長所短所、効率等
https://wlog.flatlib.jp/item/1425
DirectCompute だとどうなってるか
https://wlog.flatlib.jp/item/1411
構成要素
シェーダー
バッファ
カーネル カーネルID
スレッド スレッドグループ
定数バッファ
実行はグループ数を指定 (x,y,z)
1グループにつき (x,y,z) スレッドを実行
バッファは普通にランダムアクセスする
実行中のスレッドIDを得ることが可能、バッファアクセスに利用できる
グループIDも取得可能
定数バッファは他のシェーダと同じ
コンピュートバッファは1次元、テクスチャバッファは2次元、という感じ
RW は書き込み可能
StructuredBuffer
AppendStructuredBuffer/ConsumeStructuredBuffer
バッファタイプ
Default structured buffer
Raw byte address buffer
Append AppendStructuredBuffer/ConsumeStructuredBuffer
Counter よくわかんない、カウンタ付きの structured buffer
IndirectArguments DrawIndirect 系に渡すための引数バッファ(dword*5)
DX11では
リソースとその使用方法としてのビューという概念があるみたい
同じリソースを複数のビューから扱えるもよう
リソースはバッファとテクスチャに分けられるみたい
--------
リソース
Texture/RWTexture
Buffer/RWBuffer
ByteAdddressBuffer/RWByteAddressBuffer
StructuredBuffer/RWSturcturedBuffer
ConsumeStructuredBuffer/AppendSturctutedBuffer
ビュー
ShaderResourceView (SRV) R
UnorderedAccessView (UAV) R/W
RenderTargetView (RTV) W
DepthStencilView (DSV) W
この辺は Unity では隠されているかんじ?
-------
バッファ
CopyCount() バッファ間でカウントをコピーできる
・おそらくCPUを介せずにGPU内で可能なんだと思う
SetCounterValue()
・カウンタをセットできる 定数バッファの SetXxxx() と同じ感じなんじゃないかな
・よくわからないが、たぶん内部がどうなってるとかは考えずに使用していける感じか?
・要素の追加/取得と現在状態(カウンタ)だけ管理すればいいみたいな
SetData( nativeArray, arrayStart, bufferStart, elementCount )
・任意の位置へのアクセス
・帯域も節約できるんだろうか
・複数個所に細かく SetData() した場合の転送効率はどうなんだろう
Linq を毎フレーム使うには
Linq で、オペレータのオブジェクトは全部クラスなわけで、Unity でフレーム内で使用するにはGC的にヤダなぁ、というのがあると思うんです(速度的な面はいいとして)
オペレータってのは遅延実行できて、使いまわすことができるのですが、
そうすると列挙ソースだけ変更したいなっていう要望が発生すると思います。
(もしくはもっといいやり方があるかもしれませんが)
そういう場合のために、ソースを差し替えできるようなクラスを作成してみました。
https://github.com/abarabone/EnumerableCache/blob/master/ConsoleApp1/EnumerableCache.cs?ts=4
絶賛試行錯誤中なんですが。
つうてもまぁ、なんか微妙なかんじです。
一番微妙なのが、struct enumerator ですよね。
Linq オペレータって、内部で foreach() yield return やってるじゃないですか。
そこで生成される enumerator は、class enumerator になりますよね?
んじゃあ結局、毎フレーム列挙する度にオペレータの深さだけGCゴミがたまっていくのは変わらないということなんじゃないかと。
まだ実際に Unity で試してないのであれなんですけど
(テストとかデバッグとかの機能をよく知らないので二の足を踏んでしまいます…)
ところで
Linq のオペレータとかイテレータのシグネチャ?を、
static IEnumerable<TResult> SelectIterator<TSource, TResult>
(IEnumerable<TSource> source, Func<TSource, int, TResult> selector)
から
static IEnumerable<TResult> SelectIterator<TSource, TResult, TEnumerable>
(TEnumerable source, Func<TSource, int, TResult> selector)
where TEnumerable : IEnumerable<TSource>
みたいな感じに変えれば、内部の foreach() で専用の GetEnumerator() を呼ぶ感じになったりしますかね?
(あ、無意味…だって専用の struct enumerator を書かないとだめだし、そうすると foreach() yield return が使用できなくなって、選択的に struct enumerator を呼ぶことができなくなる…よね?)
selector ラムダとかはどうなんだろ、キャッシュされると思うんですけど。
あ、いや、Linq のソース全書き換えとかはさすがにやらないですが…
オペレータってのは遅延実行できて、使いまわすことができるのですが、
そうすると列挙ソースだけ変更したいなっていう要望が発生すると思います。
(もしくはもっといいやり方があるかもしれませんが)
そういう場合のために、ソースを差し替えできるようなクラスを作成してみました。
https://github.com/abarabone/EnumerableCache/blob/master/ConsoleApp1/EnumerableCache.cs?ts=4
絶賛試行錯誤中なんですが。
つうてもまぁ、なんか微妙なかんじです。
一番微妙なのが、struct enumerator ですよね。
Linq オペレータって、内部で foreach() yield return やってるじゃないですか。
そこで生成される enumerator は、class enumerator になりますよね?
んじゃあ結局、毎フレーム列挙する度にオペレータの深さだけGCゴミがたまっていくのは変わらないということなんじゃないかと。
まだ実際に Unity で試してないのであれなんですけど
(テストとかデバッグとかの機能をよく知らないので二の足を踏んでしまいます…)
ところで
Linq のオペレータとかイテレータのシグネチャ?を、
static IEnumerable<TResult> SelectIterator<TSource, TResult>
(IEnumerable<TSource> source, Func<TSource, int, TResult> selector)
から
static IEnumerable<TResult> SelectIterator<TSource, TResult, TEnumerable>
(TEnumerable source, Func<TSource, int, TResult> selector)
where TEnumerable : IEnumerable<TSource>
みたいな感じに変えれば、内部の foreach() で専用の GetEnumerator() を呼ぶ感じになったりしますかね?
(あ、無意味…だって専用の struct enumerator を書かないとだめだし、そうすると foreach() yield return が使用できなくなって、選択的に struct enumerator を呼ぶことができなくなる…よね?)
selector ラムダとかはどうなんだろ、キャッシュされると思うんですけど。
あ、いや、Linq のソース全書き換えとかはさすがにやらないですが…
2018年11月14日水曜日
OneFrameEntityComponentChunk みたいの欲しくないですか
エンティティのコンポーネントデータを処理して、その中から選別されたデータを次の段階の処理へ進めたいとき、なんかのコンテナに詰め替えて処理していくけど、なんかECSっぽくないていうか。
なんかこう、一時的なチャンクみたいな仕組みみたいのが欲しい。
フレームが終われば破棄される、一時的に作成できるエンティティみたいの。
チャンク移動や削除みたいのはしない前提の、作られるだけのタイプ。
そういうのならエンティティ編集にかかる制限は緩くなりそうだけど、ならんかな。
そんで job process component 的なジョブにも対応してるようなやつ。
2018年11月13日火曜日
NativeQueue の Defer な Job を作れないかな
NativeQueue の Defer な Schedule() があるとうれしんだけど、なさそう
つくれないかな
Job の作り方
https://jacksondunstan.com/articles/4857https://github.com/Unity-Technologies/UnityCsReference/blob/54dd67f09e090b1ad5ba1f55886f327106406b0c/Runtime/Jobs/Managed/IJobParallelFor.cs
https://docs.unity3d.com/2018.3/Documentation/ScriptReference/Unity.Jobs.LowLevel.Unsafe.JobsUtility.html
じょぶは、おおまかにこんな感じでつくるっぽい
・基本となるインターフェースの定義( IJobXxx とかいうやつ)
・JobScheduleParameters と、ジョブの Execute() を実行しつづける関数の準備
・そいつを JobsUtility.ScheduleXxx() 系の関数に渡して、スケジュールしてやる
ユーザーがこさえるジョブのひな型たるインターフェースの定義は、こんな感じ
[JobProducerType(typeof(IJobParallelForExtensions.ParallelForJobStruct < >))]
public interface IJobParallelFor
{
void Execute(int index);
}
JobScheduleParameters の準備として重要なのは、ReflectionData をセットすること
で、ReflectionData ってのは、JobsUtility.CreateJobReflectionData() で作成するみたい
その時、ジョブを制御するメソッドを渡してやる(ExecuteJobFunction みたいなデリゲートを定義してそいつにキャストして渡してるもよう)
そのジョブ制御メソッドの中では、基本てきにはループで「ユーザーがこさえたジョブ」の Execute() を実行し続けるんだけど、JobsUtility.GetWorkStealingRange() なるもので中断/終了判定をとっているみたいな気配
…と、そんな感じでじょぶ自体は作れそうなかんじなんだけど、肝心のスケジュールが
JobsUtility.Schedule()
JobsUtility.ScheduleParallelFor()
JobsUtility.ScheduleParallelForDeferArraySize() ←これが個数を後回しにできるやつ
JobsUtility.ScheduleParallelForTransform()
くらいしかない
そのうえ個数遅延は NativeList に対して行うものしか用意されていないっぽい
そういうわけで、なんか目論見は無理そう
あと残された手は NativeList 互換的なコンテナ(個数遅延に渡せるもの)の作成なんだけど、なんか難しそうでヤダな…
そういえば、IJobProcessComponent なんとかってのもあったな、あれもソースみてみるか
追記:キューの内部ブロックかスレッドIDに関する情報を詰めた NativeList を軽く作って Defer に渡し、それをもとにデキューしていく…みたいのってできないかな(やる気はない)
そういえば、IJobProcessComponent なんとかってのもあったな、あれもソースみてみるか
追記:キューの内部ブロックかスレッドIDに関する情報を詰めた NativeList を軽く作って Defer に渡し、それをもとにデキューしていく…みたいのってできないかな(やる気はない)
パラレルな読み書きができるネイティブコンテナはないの?
んーーーーーと、
NativeQueue は Concurrent によってパラレル書き込みができるけど、パラレル読み出しができない
NativeList はパラレル書き込みができないけど、JobsUtility.ScheduleParallelForDeferArraySize() を使用するとパラレル読み出しができる
なぜ、パラレル書き込みができてパラレル読み出しができるコンテナがないのか?
理由があるんだろうか?
それともそういうシチュエーションになることがそもそもおかしいのだろうか
そんなこんなで、では NativeList の Concurrent な構造体でも用意してやろうかと、
バッファ実体と長さフィールドへのポインタを格納して、Add() するとインターロックでカウントアップするようなものを作った。
そいつでパラレル書き込みを一応クリアとして、こんどは Defer な Schedule() を使用すると、
InvalidOperationException: The previously scheduled job MotionProgressJob reads from the NativeArray MotionProgressJob.srcEntities. You must call JobHandle.Complete() on the job MotionProgressJob, before you can write to the NativeArray safely.
NativeQueue は Concurrent によってパラレル書き込みができるけど、パラレル読み出しができない
NativeList はパラレル書き込みができないけど、JobsUtility.ScheduleParallelForDeferArraySize() を使用するとパラレル読み出しができる
なぜ、パラレル書き込みができてパラレル読み出しができるコンテナがないのか?
理由があるんだろうか?
それともそういうシチュエーションになることがそもそもおかしいのだろうか
そんなこんなで、では NativeList の Concurrent な構造体でも用意してやろうかと、
バッファ実体と長さフィールドへのポインタを格納して、Add() するとインターロックでカウントアップするようなものを作った。
そいつでパラレル書き込みを一応クリアとして、こんどは Defer な Schedule() を使用すると、
InvalidOperationException: The previously scheduled job MotionProgressJob reads from the NativeArray MotionProgressJob.srcEntities. You must call JobHandle.Complete() on the job MotionProgressJob, before you can write to the NativeArray safely.
って言われて、Complete() で待たないとエラー消えない
そんでもって、それを回避できるかなと考えて TempJob で NativeList を作りたいんだけど、
InvalidOperationException: DisposeJob.list uses [DeallocateOnJobCompletion] but the native container does not support deallocation of the memory from a job.
がでてしまう
自分でコンテナを作らないとダメなんだろうか…
そんでもって、それを回避できるかなと考えて TempJob で NativeList を作りたいんだけど、
InvalidOperationException: DisposeJob.list uses [DeallocateOnJobCompletion] but the native container does not support deallocation of the memory from a job.
がでてしまう
自分でコンテナを作らないとダメなんだろうか…
2018年11月6日火曜日
Complete() は嫌だなぁ
ああーしまった
Job でカウントアップするなどした結果カウントを取得して、
そいつを .Schedule() の全長として渡したいなんてときは
Job の完了を待たないとだめなんだなぁ そりゃそうだー
OnUpdate( JobHandle inputDeps )
で渡される inputDeps はスケジュールのためのハンドルに過ぎないから、当然 Complete() 待ちはしないといけないんだ
以前のコードにも苦し紛れに Complete() 挟んであった
システムを分けるわけない関係ないな
でもメインスレッド上で待たせるのは嫌だなぁ
これブロックするんでしょ?
どうしたもんかな
Job でカウントアップするなどした結果カウントを取得して、
そいつを .Schedule() の全長として渡したいなんてときは
Job の完了を待たないとだめなんだなぁ そりゃそうだー
OnUpdate( JobHandle inputDeps )
で渡される inputDeps はスケジュールのためのハンドルに過ぎないから、当然 Complete() 待ちはしないといけないんだ
以前のコードにも苦し紛れに Complete() 挟んであった
システムを分けるわけない関係ないな
でもメインスレッド上で待たせるのは嫌だなぁ
これブロックするんでしょ?
どうしたもんかな
2018年11月5日月曜日
ECS
Unity ECS をやっています
現状を書きなぐります すみませんが推敲しません
ところで「Unity ECS 完全に理解した」という勉強会に行きたかったのだけど、いけなかった。
キャンセルをぎりぎりまでやきもきしながら見守ったのだけども、地方からの移動時間を考えてあきらめて補欠キャンセルした。(が、もしキャンセルしなかったら最終的にギリピッタリで行けたみたいだった。なんてこった。)
内容自体はネットで目にする記事を改めて整理、という感じだったけど、懇親会がおすしとても有意義そうだった。
それはさておき。
今まで Q6600+gf8600GTという環境で満足していました。
しかしメッシュ描画関連で ComputeShader を使用しないと定数バッファの数が切なくなってきたので、居間の安いノートで試してました(新しいマシンなのでCSサポートしてる)。
が、スペックが心元ないのでグラフィックボードでも買おうかなぁといろいろ見てたら Ryzen 2400G というのが欲しくなってきて、ちょうど amazon がCEDEC(じゃなかったか?)でゲーム関係のタイムセールやっててどうにも安くて異常な心理状態に。買ってしまった。でもなんか今メモリ高い時期だそうで、そこは残念だった…。
スペック的には今までの構成でも不自由なかったんだけど。
結果的に Ryzen2400G + マザボ + メモリ16GB を購入した。
(でもいまだにメモリ使用8G超えたことないんだけど)
本題、最近思ったこと
・System の意義に懐疑的な気持ちが芽生えてきた。
というのも、結局処理は全部JOBで行うので、System が単なるJOBの起動を行う存在になってる。そんならモノビの Update() でもいいんじゃないの?という感じ。
・構造体メインになってGCをガチで減らそうとしてるな…と好印象だったんだけど、結局ラムダとかいろんな利便性を犠牲にする。じゃあC#じゃなくてC++のほうがSIMDイントリンシックも使い放題だし、最近ラムダだの型推論だの追加されてるらしいし(Cは触らなくなって久しいので勉強しないと…)言語機能なんでも自由に使えてそっちのほうがむしろ便利だったりしないんかね?とか思ったり。
・ある程度 System を細分化してたんだけども、それだとほかの System とデータ受け渡すとき(結果を NativeArray に詰めて渡すとか)、TempJob の NativeArray が System をまたいでしまうのがなんかなぁとか思った。どっちに NativeArray 置いていいかとかも悩む。あと、[Inject] とかでほかの System を参照するようにしたときに System のコンストラクタが使えなかったり、依存関係とかめんどくさいなと思った。ので、System あんまり分割しないほうがよくない?とか思って一つにしようとしたら、NativeArray に詰め終わったときに何個詰めたのよって話で Complete() で待たないといけなかったりしたわけで、OnUpdate() に Complete 待ちの Yield あればいいのになぁって思った。ちなみに Await 的な感じでまたせるとしたら、別スレッドでは IsComplete() だっけ?とかで確認しつづけないといけないんだろうか?
・ComponentData を IJobProcessComponentData で処理するのがすごく楽しい。のだけど、あんまりそれでデータを処理していくことも少ないのかな…?と思えてきた。例えば索敵するぞってなってまず ComponentData をECSのしくみに抽出してもらって条件判定するけど、その結果対象となったものは結局別のネイティブコンテナに詰めて(いろいろ考えると NativeArray に詰めることになる?)いくのだろうから、そっからはチャンクとかどうでもよくなってくる。こういうときECSではメンバのない IComponentData を付けて識別させるんでしょ?っておもっていたのだけど、チャンク移動だのエンティティコマンドバッファだの NativeArray が一番効率いいだの、そういう話を聞くとどうもだめなのかなと思えてくる。個人的にはECSの考え方は刺激があって楽しいので、多少効率悪くても分かりやすく書ければECS的なやりかたでやりたい。そもそも効率とかあまり気にしないようにしたいんだけど、どうもだめだ…(そういのからの逃避で Unity 使い始めたので)。
・NativeArray に対して、あれだけ複雑に組み上げられているエンティティとコンポーネントの存在意義は何なのか。それはチャンク移動だと思う。つまり「抽出作業を効率的に行うために事前に分類する」ことと「削除しても歯抜けにならない」ことかと(キャッシュ効率は使う側の問題)。そんならその利点を感じられなければ、ECSいらない、NativeArray とJOBあればいい、ってなる。でもECS事態はすごく楽しい。なんていうかデータ抽出と処理分割がすごく気持ちいい。好き。活かせるようにしたい。でもなんかEとCとSの全部に懐疑心ちょっとだけでてきた。
・ていうか、System 間で NativeArray 渡すってのはそもそもECSからすると逸れてるのでは。そもそもECでぜんぶやれるべきなのでは。流れるデータはECであって、システムはその軌道を左右する程度のデータしか持たないべきなのでは。
試したいこと
・キャッシュヒット率のためにはデータを細分化したほうがいいという話を聞く。
でもJOBなんかだとおそらく、ある程度の処理を一塊にしたほうがよさそうな気もする(スケジュールのコストとか?)。どっちがいいのか試したい。
・上と似たような話。今まで(ECSで)モデルアニメーションさせるのにキャラクター、ボーン、キーストリーム、の単位でそれぞれエンティティにしてたんだけど、Dynamic Buffers もできたことだし、キャラクター単位でJOB化したほうがいいんかな?とか思ったり。まぁ、エンティティ化したほうが、ECS使ってる感あって楽しいんだけど。エンティティってJOBから作るのが面倒なんだよな。ラベル的な ComponentData 張り替える作業もめんどくさいし(メインスレッド負荷とチャンク移動的な)コストかさみそうなイメージあるし。
・JOBで NativeArray にデータを追加していくときなどの、個数のカウントアップ。インターロックとスレッドごとに領域をつくって書き込む方法、どっちが総合的によいだろう。また後者では、結果を受け取った先でJOBで回すとき、一つに結合したと考えてJOBで回す方法と各スレッドごとに領域をただループで回す方法とがあると思うけど、どちらがいいのか。
気づいたこと(疑問とかも)
・Temp で確保した NativeArray って、フレームまたいで Dispose() すると逆に怒られるね…。これってむしろ Dispose() しなくてよくなったってこと?
・Malloc() は Temp とか TempJob とかは対応しないの?
現状を書きなぐります すみませんが推敲しません
ところで「Unity ECS 完全に理解した」という勉強会に行きたかったのだけど、いけなかった。
キャンセルをぎりぎりまでやきもきしながら見守ったのだけども、地方からの移動時間を考えてあきらめて補欠キャンセルした。(が、もしキャンセルしなかったら最終的にギリピッタリで行けたみたいだった。なんてこった。)
内容自体はネットで目にする記事を改めて整理、という感じだったけど、懇親会が
それはさておき。
今まで Q6600+gf8600GTという環境で満足していました。
しかしメッシュ描画関連で ComputeShader を使用しないと定数バッファの数が切なくなってきたので、居間の安いノートで試してました(新しいマシンなのでCSサポートしてる)。
が、スペックが心元ないのでグラフィックボードでも買おうかなぁといろいろ見てたら Ryzen 2400G というのが欲しくなってきて、ちょうど amazon がCEDEC(じゃなかったか?)でゲーム関係のタイムセールやっててどうにも安くて異常な心理状態に。買ってしまった。でもなんか今メモリ高い時期だそうで、そこは残念だった…。
スペック的には今までの構成でも不自由なかったんだけど。
結果的に Ryzen2400G + マザボ + メモリ16GB を購入した。
(でもいまだにメモリ使用8G超えたことないんだけど)
本題、最近思ったこと
・System の意義に懐疑的な気持ちが芽生えてきた。
というのも、結局処理は全部JOBで行うので、System が単なるJOBの起動を行う存在になってる。そんならモノビの Update() でもいいんじゃないの?という感じ。
・構造体メインになってGCをガチで減らそうとしてるな…と好印象だったんだけど、結局ラムダとかいろんな利便性を犠牲にする。じゃあC#じゃなくてC++のほうがSIMDイントリンシックも使い放題だし、最近ラムダだの型推論だの追加されてるらしいし(Cは触らなくなって久しいので勉強しないと…)言語機能なんでも自由に使えてそっちのほうがむしろ便利だったりしないんかね?とか思ったり。
・ある程度 System を細分化してたんだけども、それだとほかの System とデータ受け渡すとき(結果を NativeArray に詰めて渡すとか)、TempJob の NativeArray が System をまたいでしまうのがなんかなぁとか思った。どっちに NativeArray 置いていいかとかも悩む。あと、[Inject] とかでほかの System を参照するようにしたときに System のコンストラクタが使えなかったり、依存関係とかめんどくさいなと思った。ので、System あんまり分割しないほうがよくない?とか思って一つにしようとしたら、NativeArray に詰め終わったときに何個詰めたのよって話で Complete() で待たないといけなかったりしたわけで、OnUpdate() に Complete 待ちの Yield あればいいのになぁって思った。ちなみに Await 的な感じでまたせるとしたら、別スレッドでは IsComplete() だっけ?とかで確認しつづけないといけないんだろうか?
・ComponentData を IJobProcessComponentData で処理するのがすごく楽しい。のだけど、あんまりそれでデータを処理していくことも少ないのかな…?と思えてきた。例えば索敵するぞってなってまず ComponentData をECSのしくみに抽出してもらって条件判定するけど、その結果対象となったものは結局別のネイティブコンテナに詰めて(いろいろ考えると NativeArray に詰めることになる?)いくのだろうから、そっからはチャンクとかどうでもよくなってくる。こういうときECSではメンバのない IComponentData を付けて識別させるんでしょ?っておもっていたのだけど、チャンク移動だのエンティティコマンドバッファだの NativeArray が一番効率いいだの、そういう話を聞くとどうもだめなのかなと思えてくる。個人的にはECSの考え方は刺激があって楽しいので、多少効率悪くても分かりやすく書ければECS的なやりかたでやりたい。そもそも効率とかあまり気にしないようにしたいんだけど、どうもだめだ…(そういのからの逃避で Unity 使い始めたので)。
・NativeArray に対して、あれだけ複雑に組み上げられているエンティティとコンポーネントの存在意義は何なのか。それはチャンク移動だと思う。つまり「抽出作業を効率的に行うために事前に分類する」ことと「削除しても歯抜けにならない」ことかと(キャッシュ効率は使う側の問題)。そんならその利点を感じられなければ、ECSいらない、NativeArray とJOBあればいい、ってなる。でもECS事態はすごく楽しい。なんていうかデータ抽出と処理分割がすごく気持ちいい。好き。活かせるようにしたい。でもなんかEとCとSの全部に懐疑心ちょっとだけでてきた。
・ていうか、System 間で NativeArray 渡すってのはそもそもECSからすると逸れてるのでは。そもそもECでぜんぶやれるべきなのでは。流れるデータはECであって、システムはその軌道を左右する程度のデータしか持たないべきなのでは。
試したいこと
・キャッシュヒット率のためにはデータを細分化したほうがいいという話を聞く。
でもJOBなんかだとおそらく、ある程度の処理を一塊にしたほうがよさそうな気もする(スケジュールのコストとか?)。どっちがいいのか試したい。
・上と似たような話。今まで(ECSで)モデルアニメーションさせるのにキャラクター、ボーン、キーストリーム、の単位でそれぞれエンティティにしてたんだけど、Dynamic Buffers もできたことだし、キャラクター単位でJOB化したほうがいいんかな?とか思ったり。まぁ、エンティティ化したほうが、ECS使ってる感あって楽しいんだけど。エンティティってJOBから作るのが面倒なんだよな。ラベル的な ComponentData 張り替える作業もめんどくさいし(メインスレッド負荷とチャンク移動的な)コストかさみそうなイメージあるし。
・JOBで NativeArray にデータを追加していくときなどの、個数のカウントアップ。インターロックとスレッドごとに領域をつくって書き込む方法、どっちが総合的によいだろう。また後者では、結果を受け取った先でJOBで回すとき、一つに結合したと考えてJOBで回す方法と各スレッドごとに領域をただループで回す方法とがあると思うけど、どちらがいいのか。
気づいたこと(疑問とかも)
・Temp で確保した NativeArray って、フレームまたいで Dispose() すると逆に怒られるね…。これってむしろ Dispose() しなくてよくなったってこと?
・Malloc() は Temp とか TempJob とかは対応しないの?
2018年9月16日日曜日
Unity再燃
昔Unityで作っていたゲームを置いていた場所
ECSでまた作り直したい
とりあえずECS でボーンアニメーションさせてみた
https://github.com/abarabone/ecs_motion
2017年11月12日日曜日
SafeArray でユーザー定義型を使いたい
SafeArray の要素をVBAのユーザー定義型にするにはどうしたらいいんだろうか
https://msdn.microsoft.com/ja-jp/library/windows/desktop/ms221482(v=vs.85).aspx
SAFEARRAY 構造体の fFeatures を FADF_RECORD にすればいいのか?
とあるから IRecordInfo をセットするんだな、ユーザー定義型の情報なんだろう
でもこれどうやって調達すればいいんだろう
自前で作るとかはやりたくない
SafeArrayGetRecordInfo() でとれるかなと思ったんだけど失敗する
dim arr()
redim arr(1) as ユーザー定義型
の SafeArray 構造体がどうなってるか確認したら、arr の fFeatures には FADF_RECORD が格納されていない
ユーザー定義型を示すGUIDから取得できたりもするっぽい?
でもGUIDの取得方法わからない
んーーー
ユーザー定義型の配列を variant に突っ込もうとしたときに
「パブリックモジュールで定義されたなんとかかんとか」
みたいなエラーメッセージが表示されたりするのと関係があるんだろうか
そういうの以外は実はCOM的な意味でのユーザー定義型になっていなくて、
要素長だけかんりしてるとか
でもVBEでインテリセンスみたいなメンバ表示が出るあたり、
IRecordInfo とか持ってそうな感じするんだけどなぁ
https://msdn.microsoft.com/ja-jp/library/windows/desktop/ms221482(v=vs.85).aspx
SAFEARRAY 構造体の fFeatures を FADF_RECORD にすればいいのか?
An array that contains records. When set, there will be a pointer to the IRecordInfo interface at negative offset 4 in the array descriptor.
とあるから IRecordInfo をセットするんだな、ユーザー定義型の情報なんだろう
でもこれどうやって調達すればいいんだろう
自前で作るとかはやりたくない
SafeArrayGetRecordInfo() でとれるかなと思ったんだけど失敗する
dim arr()
redim arr(1) as ユーザー定義型
の SafeArray 構造体がどうなってるか確認したら、arr の fFeatures には FADF_RECORD が格納されていない
ユーザー定義型を示すGUIDから取得できたりもするっぽい?
でもGUIDの取得方法わからない
んーーー
ユーザー定義型の配列を variant に突っ込もうとしたときに
「パブリックモジュールで定義されたなんとかかんとか」
みたいなエラーメッセージが表示されたりするのと関係があるんだろうか
そういうの以外は実はCOM的な意味でのユーザー定義型になっていなくて、
要素長だけかんりしてるとか
でもVBEでインテリセンスみたいなメンバ表示が出るあたり、
IRecordInfo とか持ってそうな感じするんだけどなぁ
2017年11月11日土曜日
AddRef() で落ちる 続き
variant 型に IEnumVariant をセットしようとしたときにエクセルが落ちることがある件の続き。
いろいろ試してみると、set variant = a.NewEnum() の時 queryInterface() でGUID B196B283-BAB4-101A-B69C-00AA00341D07 を要求しくることに気づいた。
これは IprovideClassInfo インターフェースというものらしく、唯一?のメソッド GetClassInfo() から ItypeInfo インターフェースを得るためのもの(っぽい)。
これをちゃんと実装するとたぶん落ちなくなるんだと思うが、かなり大変そうなのでやめとく。代わりに E_NOINTERFACE を返すようにした。
とりあえず「型が一致しません」エラーが出て、エクセルが落ちることはなくなった。
2017年10月31日火曜日
AddRef() が落ちる
制作中の VBAEnumration の話
For Each で列挙できるようにするため、EnumVariat をVBAから CoTaskMemAlloc() でメモリ確保して作っています。
そこに標準モジュール関数を登録した vtable をセットして仮想関数持ちのオブジェクトを再現しているんですが、なんか AddRef() で時々落ちてしまいます。エクセルが。
dim a as IEnumVariant
set a = q.NewEnum
だと落ちないっぽいのに、
dim a as variant
set a = q.NewEnum
だと、set a = したところで addref() に飛んで、そこを抜けると落ちる。気がする。
原因がわかんないなぁー
こういう悩み中みたいな話を GitHub のどこかにのせていってもいいんだろうか
Readme とか Issue?は違うのかな目的が
For Each で列挙できるようにするため、EnumVariat をVBAから CoTaskMemAlloc() でメモリ確保して作っています。
そこに標準モジュール関数を登録した vtable をセットして仮想関数持ちのオブジェクトを再現しているんですが、なんか AddRef() で時々落ちてしまいます。エクセルが。
dim a as IEnumVariant
set a = q.NewEnum
だと落ちないっぽいのに、
dim a as variant
set a = q.NewEnum
だと、set a = したところで addref() に飛んで、そこを抜けると落ちる。気がする。
原因がわかんないなぁー
こういう悩み中みたいな話を GitHub のどこかにのせていってもいいんだろうか
Readme とか Issue?は違うのかな目的が
2017年10月25日水曜日
VBAでLINQみたいなことができるクラス群
意味ないものですが作成中
https://github.com/abarabone/vbaEnumeration
GitHub にアップしてるんだけど Git も GitHub もよくわかりませぬ…
とりあえず一通りのオペレータができるまでは黙々とやっていきます
実用性はないでしょうけど
https://github.com/abarabone/vbaEnumeration
GitHub にアップしてるんだけど Git も GitHub もよくわかりませぬ…
とりあえず一通りのオペレータができるまでは黙々とやっていきます
実用性はないでしょうけど
2017年7月5日水曜日
クソVBAをやってる話
VBAでラムダのようなものを使いたくて試行錯誤中
まずは引数として渡せる関数の再現
試行錯誤の履歴
・Application.Run() … 名前文字列で指定する 重め
参照引数が使えない
Application ってどうなの
・CallByName() … 名前文字列で指定する 重め
参照引数は使える
オブジェクトのメソッドしか呼べない
・イベント … 汎用的に呼べるイベントを作ってやることで再現 軽め!
戻り値はない エラーを呼び出し元に Raise できない
withEvents のメンバにセットした値を外部に持ち出せば、
対応したイベントを呼び出すことができる
イベントに光を見出して、文字列コードをラムダにして動的モジュールを生成していくようにした。
LINQのオペレータ的なものを、Skip, Take, Select, Where, SelectMany, くらいまで作成した。
しかし for each に対応させられずに、Do Loop で回す感じになっていて、不満があった。
IEnumVariant を V-table ごとメモリ上に構築してしまえばよいことを知る。
APIを使用することをなぜか拒んでいたが、解禁する。つまらないこだわりだったと思う。
VBAのオブジェクトはCOM関係そのものということに気づく。
で、ついでにここでこれに気づいてしまう…
・DispCallFunc() … AddressOf で関数ポインタを得て、使用できる。
参照引数も使用できる。型も使用できる。
が、引数指定のクセが強く、たやすくハングアップする。これは問題。
なやむ。
また、オブジェクトのメソッドを V-table のオフセットで指定実行できる。
そこからVBAのクラスは IDispatch を継承しているということに気づく。
ITypeInfo を作成すればいろいろいじれる。
ただ、本当に DispCallFunc() の引数はセンシティブで、試行錯誤しまくった。情報もないし…。
また、クラスメソッドを呼ぼうとしたときに、第一引数が戻り値になってしまうという謎の現象に遭遇。
回避できない。
同じことで悩んでる外人さんもいた。
どうしたものか
そこで今、このページを発見。
https://msdn.microsoft.com/en-us/library/ms221141(v=vs.85).aspx
うおぅ!!
今までやってた煩雑なことが、APIでできそう???
と興奮すると同時に徒労感が。
いまここ。
まずは引数として渡せる関数の再現
試行錯誤の履歴
・Application.Run() … 名前文字列で指定する 重め
参照引数が使えない
Application ってどうなの
・CallByName() … 名前文字列で指定する 重め
参照引数は使える
オブジェクトのメソッドしか呼べない
・イベント … 汎用的に呼べるイベントを作ってやることで再現 軽め!
戻り値はない エラーを呼び出し元に Raise できない
withEvents のメンバにセットした値を外部に持ち出せば、
対応したイベントを呼び出すことができる
イベントに光を見出して、文字列コードをラムダにして動的モジュールを生成していくようにした。
LINQのオペレータ的なものを、Skip, Take, Select, Where, SelectMany, くらいまで作成した。
しかし for each に対応させられずに、Do Loop で回す感じになっていて、不満があった。
IEnumVariant を V-table ごとメモリ上に構築してしまえばよいことを知る。
APIを使用することをなぜか拒んでいたが、解禁する。つまらないこだわりだったと思う。
VBAのオブジェクトはCOM関係そのものということに気づく。
で、ついでにここでこれに気づいてしまう…
・DispCallFunc() … AddressOf で関数ポインタを得て、使用できる。
参照引数も使用できる。型も使用できる。
が、引数指定のクセが強く、たやすくハングアップする。これは問題。
なやむ。
また、オブジェクトのメソッドを V-table のオフセットで指定実行できる。
そこからVBAのクラスは IDispatch を継承しているということに気づく。
ITypeInfo を作成すればいろいろいじれる。
ただ、本当に DispCallFunc() の引数はセンシティブで、試行錯誤しまくった。情報もないし…。
また、クラスメソッドを呼ぼうとしたときに、第一引数が戻り値になってしまうという謎の現象に遭遇。
回避できない。
同じことで悩んでる外人さんもいた。
どうしたものか
そこで今、このページを発見。
https://msdn.microsoft.com/en-us/library/ms221141(v=vs.85).aspx
うおぅ!!
今までやってた煩雑なことが、APIでできそう???
と興奮すると同時に徒労感が。
いまここ。
2017年6月4日日曜日
async/await について
async/await
await XxxxAsync();
と記述した時、XxxxAsync() が終了するまで制御をOSに返し、
それ以降の実行を待機する仕組み
async 関数を await で実行
void を返す ... fire & forget
Task<int> を返す ... 非同期処理完了後に同期して int を返す
Task を返す ... 非同期処理完了後に同期して void を返す
fire & forget とは
await XxxxAsync(); と、その下に続くコードが並列実行される
(ノンブロッキング関数的なイメージ)
await
await XxxxAsync(); の下に続くコードは、
XxxxAsync() から戻ってきた後に実行されるコールバックとしてコンパイルされる。
コールバックが実行されるスレッドを決定するのが同期コンテキスト。
同期コンテキスト(synchronization context)
Task オブジェクトがタスク実行後に戻る文脈を保持する。
await 呼び出し側の SynchronizationContext.Current に戻ってくるように設定される。
デフォルトでは task.ConfigureAwait( true ) となっており、同期コンテキストが適用される。
実行環境による同期コンテキストの違い
WPF等GUI … UIスレッド
ASP.NET … リクエストとレスポンスが同一スレッド
コンソール … null(同期コンテキストが存在しない)
※同期コンテキストが存在しない
= 戻るべきスレッドを規定しない
= スレッドプールの任意のスレッドに戻る(というか移行)
同期コンテキストを無視したいとき
await XxxAsync().ConfigureAwait( false );
コンソールと同じ動作となる
単に、何かの処理を別スレッドで実行したい場合について
await/async で、せっかくコールバックをインデントのネストから解放できたのに、
任意の処理を別スレッドでさせたいときなんかに Task.Run() で処理を書かざるを得ないのはダサく感じる。
平坦に書きたいです。
平坦に書きたいです。
同期コンテキストがなければ await Task.Yield() でそれ以降を別スレッドに移せるぽいが、
そうでない場合は await Task.Run( () => {} ).ConfigureAwait( false ); などと書かないとダメかも。
でも無意味なタスクオブジェクトが発生したりしそう。
そもそも、async/await は非同期タスクを待ち受けるための構文であって、
スレッド実行を平坦に記述するという汎用的な目的で使うべきものではない、ということか。
同期させるスレッドを自由に切り替えできればいいのにと思うけど、そういう思想のものじゃない、のか…。
そもそも、async/await は非同期タスクを待ち受けるための構文であって、
スレッド実行を平坦に記述するという汎用的な目的で使うべきものではない、ということか。
同期させるスレッドを自由に切り替えできればいいのにと思うけど、そういう思想のものじゃない、のか…。
登録:
投稿 (Atom)
ニューラルネットやってみてる
最近ニューラルネットやってみてる 理屈を学ぼうと思って、まずはオブジェクト的に作ってみてる (ベクトル化とかは後回しで) sigmoid, tanh, ReLU MSE, cross entorpy あたりを小規模にいじってみてます でも今 soft max の逆伝...
-
VBAでラムダのようなものを使いたくて試行錯誤中 まずは引数として渡せる関数の再現 試行錯誤の履歴 ・Application.Run() … 名前文字列で指定する 重め 参照引数が使えない Appli...
-
Unity ECS をやっています 現状を書きなぐります すみませんが推敲しません ところで「Unity ECS 完全に理解した」という勉強会に行きたかったのだけど、いけなかった。 キャンセルをぎりぎりまでやきもきしながら見守ったのだけども、地方からの移動時間を考えてあき...
-
variant 型に IEnumVariant をセットしようとしたときにエクセルが落ちることがある件の続き。 いろいろ試してみると、set variant = a.NewEnum() の時 queryInterface() でGUID B196B283-BAB4-101A-B...