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() した場合の転送効率はどうなんだろう








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 のソース全書き換えとかはさすがにやらないですが…


ニューラルネットやってみてる

最近ニューラルネットやってみてる 理屈を学ぼうと思って、まずはオブジェクト的に作ってみてる (ベクトル化とかは後回しで) sigmoid, tanh, ReLU MSE, cross entorpy あたりを小規模にいじってみてます でも今 soft max の逆伝...