0
メタルフレームワーク(および一般的にはGPGPU)の初心者であり、何が起こっているのかをよりよく知るためにコードを使いこなそうとしています。メタルを配列内に出力する
次のコードは、単に入力配列の要素を出力し、5.0を追加するだけです。何らかの理由で、しかし、出力配列にデータをコピー、それだけで以下
[6.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
を出力し、最後のステップで私の小さなプログラムされています
import Foundation
import Metal
//Metal Setup
var device = MTLCreateSystemDefaultDevice()!
var commandQueue = device.makeCommandQueue()!
var library = device.makeDefaultLibrary()!
var commandBuffer = commandQueue.makeCommandBuffer()!
var commandEncoder = commandBuffer.makeComputeCommandEncoder()!
//Prepare Inputs/Outputs
var input = [Float](repeating: 1, count: 10)
var output = [Float](repeating: 0, count: 10)
//Setup Pipeline
let kernel = library.makeFunction(name: "sigmoid")!
var pipelineState = try device.makeComputePipelineState(function: kernel)
commandEncoder.setComputePipelineState(pipelineState)
//Create GPU Buffers for input/output
let bytelength = input.count * MemoryLayout<Float>.size
var inputBuffer = device.makeBuffer(bytes: &input, length: bytelength, options: [])
var outputBuffer = device.makeBuffer(bytes: &output, length: bytelength, options: [])
commandEncoder.setBuffer(inputBuffer, offset: 0, index: 0)
commandEncoder.setBuffer(outputBuffer, offset: 0, index: 1)
//Setup threads
var threadsPerGroup = MTLSize(width: 32, height: 1, depth: 1)
var numThreadGroups = MTLSize(width: (input.count + 31)/32, height: 1, depth: 1)
commandEncoder.dispatchThreads(numThreadGroups, threadsPerThreadgroup: threadsPerGroup)
//Start the program on the GPU, wait until finished.
commandEncoder.endEncoding()
commandBuffer.commit()
commandBuffer.waitUntilCompleted()
//Get result from GPU to CPU data.
var result = [Float](repeating: 0, count: input.count)
var data = NSData(bytesNoCopy: (outputBuffer?.contents())!, length: bytelength, freeWhenDone: false)
data.getBytes(&result, length: bytelength)
print(result)
カーネルコードはかなり愚かです:
#include <metal_stdlib>
using namespace metal;
kernel void sigmoid(const device float *inVector [[ buffer(0) ]],
device float *outVector [[buffer(1) ]],
uint id [[ thread_position_in_grid ]]) {
outVector[id] = inVector[id] + 5.0;
}
これは私が読んできたチュートリアルと一貫しているようです。私もSwift 4のちょっと新しくなったので、私が書いたコードがこれについての最良の方法かどうかは分かりません。すべての助けがありがたいです。
計算機能のスレッド/呼び出しの数はいくらですか? 32(シングルスレッドグループ)、そうですか? 'id'の値が10以上の人はどうなりますか?ええ、わからない。 ;)関数の先頭に 'if(id> = 10)return;'を入れてみてください。 (実際のコードでは、ハードコーディングするのではなく、バッファを使用してカウントを渡したいと思っています) –
ありがとう、これは本当です。私が使用していないスレッドを使用することには意味がありません。しかし、これは私のベクトルの最初のエントリだけに私の出力コンピューティングの私の全体的な問題で私を助けません。 –
GPUカーネルをデバッグするのは難しいです。私が試みる一つの方法は 'outVector [id] =(float)id;'で、どのスレッドIDがバッファ内のどの位置に書き込まれているのか調べます。また、入力バッファと出力バッファを異なる値で埋めることで、正確に何が起こっているのかをよりよく理解することができます。 –