2016-11-10 28 views
6

Metal Performance Shaderフレームワークは、独自の畳み込みニューラルネットを構築するためのサポートを提供します。例えばMSPCNNConvolutionを作成する場合、1D浮動小数点ポインタとして表されるinitパラメータの4Dのテンソルが必要です。MPSCNN重み付け順序

init(device: MTLDevice, 
    convolutionDescriptor: MPSCNNConvolutionDescriptor, 
    kernelWeights: UnsafePointer<Float>, 
    biasTerms: UnsafePointer<Float>?, 
    flags: MPSCNNConvolutionFlags) 

ドキュメントは、 4Dテンソル(配列) 重量[outputChannels]として再解釈することができるように、フィルタ重みのレイアウトが配置される4Dテンソル

について言うためにこれを持っています[kernelHeight] [kernelWidth] [入力チャネルに/グループ]

残念ながら、その情報は本当に次元の1に4D配列を配置する方法を教えていません0ポインタ。

私はBNNSのような重量を注文しようとしましたが、運が必要です。

4Dテンソル(配列)を1D Floatポインタ(配列)として正しく表現するにはどうすればよいですか?

PS:C配列のように配列して、フラット配列へのポインタを取得しようとしましたが、動作しませんでした。

UPDATE

@RhythmicFistman:それは私が私がUsafePointer<Float>に変換することができます(ただし、動作しません)、プレーンアレー、それを保存された方法は次のとおりです。

var output = Array<Float>(repeating: 0, count: weights.count) 

for o in 0..<outputChannels { 
    for ky in 0..<kernelHeight { 
     for kx in 0..<kernelWidth { 
      for i in 0..<inputChannels { 
       let offset = ((o * kernelHeight + ky) * kernelWidth + kx) * inputChannels + i 
       output[offset] = ... 
      } 
     } 
    } 
} 
+0

4Dを1Dにしようとした方法を示すことができますか?間違ったポインタを使用しない限り、間違っている可能性がある唯一のものはインデックスの順序です。 –

+0

@RhythmicFistman質問を更新しました.Apples OWNのサンプルプロジェクト(独自の訓練されたウェイトあり)は正しく動作しません。だから私はどういうことが間違っているかを知っているはずです...自分のデータやその実装。 –

+0

どのAppleサンプルを参考にしていますか? MetalImageRecognitionとMPSCNNHelloWorldの両方が、Xcode 8.2ベータとiOS 10.2ベータ版で私にとってうまくいくようです。 – warrenm

答えて

1

[OK]をので、私理解した。ここでは2つのpython私は私の畳み込みを改革するために使用する関数と完全に接続された行列

# shape required for MPSCNN [oC kH kW iC] 
# tensorflow order is [kH kW iC oC] 
def convshape(a): 
    a = np.swapaxes(a, 2, 3) 
    a = np.swapaxes(a, 1, 2) 
    a = np.swapaxes(a, 0, 1) 
    return a 

# fully connected only requires a x/y swap 
def fullshape(a): 
    a = np.swapaxes(a, 0, 1) 
    return a 
1

があるこれは私が最近、カフェの重みのためにしなければならなかったものですので、私は、私は、これらの並べ替え方法についてスウィフト実装を提供することができます。次の関数は、[c_o] [c_i] [h] [w]順の畳み込みのためのCaffeウェイトのFloat配列を取り込み、Metalが期待するもの([c_o] [h] [w] [c_i] ):

public func convertCaffeWeightsToMPS(_ weights:[Float], kernelSize:(width:Int, height:Int), inputChannels:Int, outputChannels:Int, groups:Int) -> [Float] { 

    var weightArray:[Float] = Array(repeating:0.0, count:weights.count) 
    var outputIndex = 0 

    let groupedInputChannels = inputChannels/groups 
    let outputChannelWidth = groupedInputChannels * kernelSize.width * kernelSize.height 

    // MPS ordering: [c_o][h][w][c_i] 
    for outputChannel in 0..<outputChannels { 
     for heightInKernel in 0..<kernelSize.height { 
      for widthInKernel in 0..<kernelSize.width { 
       for inputChannel in 0..<groupedInputChannels { 
        // Caffe ordering: [c_o][c_i][h][w] 
        let calculatedIndex = outputChannel * outputChannelWidth + inputChannel * kernelSize.width * kernelSize.height + heightInKernel * kernelSize.width + widthInKernel 
        weightArray[outputIndex] = weights[calculatedIndex] 
        outputIndex += 1 
       } 
      } 
     } 
    } 

    return weightArray 
} 

私のレイヤの視覚化に基づいて、これは正しい畳み込み結果(Caffeによって生成されたものと一致する)を生成するようです。グループ分けも適切に考慮していると思いますが、そのことを確認する必要があります。

TensorflowはCaffeとは異なる順序付けをしていますが、ループの内側の数値を変更してそれを考慮する必要があります。

1

ここでは、x、y、zがコンパイル時に既知の定数である場合、a [x] [y] [z]は通常1次元配列に崩壊します。これが起こると、z成分は最も速く変化し、次にyが続き、x - outsideが続きます。

[2] [2] [2]があると、1Dに畳み込まれて

{ a[0][0][0], a[0][0][1], a[0][1][0], a[0][1][1], 
    a[1][0][0], a[1][0][1], a[1][1][0], a[1][1][1] } 
関連する問題