Keras のサンプル

Github Keras Examples
https://github.com/keras-team/keras/tree/master/examples

公式のサンプルプログラム

MNIST の CNN

サンプルコードはここにある。
https://github.com/keras-team/keras/blob/master/examples/mnist_cnn.py

Summary を出力するとこのようになる。

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1 (Conv2D)            (None, 26, 26, 32)        320       
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 24, 24, 64)        18496     
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 12, 12, 64)        0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 12, 12, 64)        0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 9216)              0         
_________________________________________________________________
dense_1 (Dense)              (None, 128)               1179776   
_________________________________________________________________
dropout_2 (Dropout)          (None, 128)               0         
_________________________________________________________________
dense_2 (Dense)              (None, 10)                1290      
=================================================================
Total params: 1,199,882
Trainable params: 1,199,882
Non-trainable params: 0
_________________________________________________________________

Conv2D() で畳み込みレイヤーの追加。
Conv2D filters 32, kernel size (3, 3) -> ReLU
Conv2D filters 64, kernel size (3, 3) -> ReLU
MaxPooling (2, 2)

(28, 28, 1) の input を、32 filters, size(3, 3) の Conv2D に入力すると、(26, 26, 32) になる。(26, 26, 32) を 64 filters, size(3, 3) に入れれば、(24, 24, 64) になる。

KerasのConv2Dの行列式演算
https://qiita.com/nishiha/items/bfd5dfcd7fffd3c529bc

Keras の Flatten の実装

How flatten layer works in keras?
https://stackoverflow.com/questions/44176982/how-flatten-layer-works-in-keras

どのように展開されるか疑問だったので、凄く分かりやすかった。

Conv2DTranspose

KerasのConv2DTransposeの動作について
https://qiita.com/takurooo/items/9a9f387390f5fcf5a516

An Introduction to different Types of Convolutions in Deep Learning
https://towardsdatascience.com/types-of-convolutions-in-deep-learning-717013397f4d

How to use the UpSampling2D and Conv2DTranspose Layers in Keras
https://machinelearningmastery.com/upsampling-and-transpose-convolution-layers-for-generative-adversarial-networks/

分かりやすい記事に感謝。

Skip Connection U-Net

オートエンコーダーとしてのU-Net
https://qiita.com/koshian2/items/603106c228ac6b7d8356

Affine 変換の Backpropagation メモ

    def backward(self, dout): # dout (3x10)
        dx = np.dot(dout, self.W.T) # W (50x10) W.T (10x50)
        self.dW = np.dot(self.x.T, dout) # x (3x50) x.T (50x3)
        self.db = np.sum(dout, axis=0)
        
        dx = dx.reshape(*self.original_x_shape)
        return dx

self.x は affine 変換する前のレイヤーに入力される値。

全然関係無いですが、ニューラルネットワークをレイヤーの概念図で表すと、入力する値の位置とアフィン変換する位置が、コードと一階層(半階層)ズレてる感覚を受ける。コードで記述する時は、レイヤーの層を表す図から左側の接続の線までを含んでいるイメージを持つようにする。

自身のレイヤーの重みの勾配は np.dot(self.x.T, dout) で求まり、バイアスは np.sum(dout) で総和を取る。

参照コード
ゼロから作る Deep Learningn から

HLSL ByteAddressBuffer の使い方

ByteAddressBuffer は引数にバイト数を指定する。

ByteAddressBuffer byteBuffer : register(t0);
uint value = byteBuffer.Load(0);

4 Byte 単位でメモリーにアクセスしてデータを取得出来るバッファータイプ。戻り値は uint (4 Byte) になる。Load 関数の引数は 4 の倍数でなければいけない。Load2(0) で指定すれば uint2 型で 8 Byte の連続した領域を取得できる。Load3(0) で指定すれば uint3 型で 12 Byte の連続したメモリー。

uint4 value = byteBuffer.Load4(4);
という指定をすれば、アドレスの開始位置が先頭から 4 Byte 目から、16 Byte の連続した領域を取得出来る。

DirectX12 HLSL Texture2D.Load にはまる

Texture2D の Load 命令は引数として int3 を受け取るため、texture.Load(int3(0, 0, 0)); のような形式で呼び出す。この時 x, y には UV ではなくて テクスチャの width -1, height -1 の値を指定する。当たり前だが、-1 に注意。そして z は mipmap を指定できる。

Texture サイズが 256×256 だとして、Load(int3(256, 256, 0)); とサイズを超えてしまった場合は 0 が返るようになっている。この時に大切なのが存在しない mipmap にアクセスした場合も 0 が返るという事。

int3 を指定せずに Load(0) とやるのは特に問題無いが、テストで Load(1) としてしまったとき、Load(int3(1, 1, 1)); になるため、もし mipmap が存在しないテクスチャに対してこれをした場合は 0 が返ってしまう。ちょっとしたテストで Load(1) をやった結果、原因を突き止めるのに時間がかかった。

Texture2D.Load は int3 でテクスチャ座標とミップマップ値に気をつけて使用する。

DirectX12 Misc

ID3D12Resource::GetGPUVirtualAddress

D3DResource は GetGPUVirtualAddress メソッドを持っており、Vertex Buffer を作るときなど View 構造体に対してアドレスを渡すときに使う。このメソッドは Buffer Resource のみで使用可能で、Texture Resource の時は使用できないため 0 が返る。

Root Parameter の並び順

アクセス頻度の高いものをインデックス 0 から並べた方が、パフォーマンスが良い? (未検証)

DirectX12 Root Signature

Root Signature を覚えるのは大変だ。これは抽象的な図や分かりやすい言葉で表すのは困難で (少なくとも自分には)、C言語を最初に学んだ時のポインタのように、苦しんで覚えるしかない類の物だと思ってる。

MS のドキュメントやこんなブログの内容を見るよりも、D3D12 のサンプルプログラムを実行し、修正しながら動作を確認するのが一番の近道な気がします。

自分は Root Signature を理解するのに最も大切な概念って Descriptor Table だと勝手に思い込んでいたのですが (いや重要なんですけどね…)、CD3DX12_ROOT_PARAMETER1 が大切で、この定義と、CommandList->SetGraphicsRootDescriptorTable() との関連性が理解出来れば、Root Signature って大体分かるんだと思う。

DirectX12 Compute Shader

Compute Shader の実行は D3D12ExecuteIndirect の Sample を参考に。

Graphics Task 用と Compute Task 用で Command Allocator と Command List の分割。D3D12_COMMAND_LIST_TYPE_COMPUTE を指定して作成。

Root Signature

Graphics と Compute で使うリソースが異なるため、当然 Root Signature も分けて作成される。

Resource Binding

このサンプルの Compute Shader で使われるリソースは b0, t0, t1, u0 の4つ。

cbuffer RootConstants : register(b0) {…}
StructuredBuffer cbv : register(t0);
StructuredBuffer inputCommands : register(t1);
AppendStructuredBuffer outputCommands : register(u0);

HLSL Structured Buffer へのアクセス

Shader から Structured Buffer にアクセスする場合は、

StructuredBuffer Buffer0 : register(t0);

このように Shader 上で定義を行い Buffer0[0] や Buffer0[16] のように Array of Structure の形でアクセス出来る。注意が必要なのが、データ定義時は[] でのサイズ指定は必要ないということ。

仮にもし [] でサイズ指定をしてしまうと、それは複数のリソースを連続定義したことになる。

StructuredBuffer Buffer0[10] : register(t0);

この指定は t0 – t9 まで、複数の SRV を使うという指定になる。

アクセスする場合は Buffer0[2][16] という形になる。