Я пытаюсь позволить нейронной сети работать на металле.
Основная идея заключается в дублировании данных. Каждый поток GPU запускает одну версию сети для случайных точек данных.
Я написал другие шейдеры, которые отлично работают.
Я также попробовал свой код в приложении командной строки c ++. Там нет ошибок.
Также нет ошибки компиляции.
Я использовал документацию apple, чтобы конвертировать в металл с ++, так как не все из с ++ 11 поддерживается.
Вылетает после загрузки функции ядра и при попытке назначить newComputePipelineStateWithFunction
к металлическому устройству. Это означает, что есть проблема с кодом, который не перехватывается во время компиляции.
MCVE:
kernel void net(const device float *inputsVector [[ buffer(0) ]], // layout of net *
uint id [[ thread_position_in_grid ]]) {
uint floatSize = sizeof(tempFloat);
uint inputsVectorSize = sizeof(inputsVector) / floatSize;
float newArray[inputsVectorSize];float test = inputsVector[id];
newArray[id] = test;
}
Обновить
Это связано с динамическими массивами.
Поскольку он не может создать состояние конвейера и не приводит к сбою при запуске реального шейдера, это должно быть проблемой кодирования. Не проблема ввода.
Назначение значений из динамического массива в буфер приводит к сбою.
Настоящая проблема:
Это проблема памяти!
Чтобы все люди говорили, что это проблема памяти, вы были правы!
Вот некоторый псевдокод, чтобы проиллюстрировать это. Извините, что это в «Свифте», но легче читать. Металлические шейдеры имеют причудливый способ ожить. Сначала они инициализируются без значений, чтобы получить память. Этот шаг не удался, потому что он опирался на более поздний шаг: настройку буфера.
Все сводится к тому, какие значения доступны, когда. Мое понимание newComputePipelineStateWithFunction
был неправ. Это не просто получение функции шейдера. Это также маленький шаг в процессе инициализации.
class MetalShader {
// buffers
var aBuffer : [Float]
var aBufferCount : Int
// step One : newComputePipelineStateWithFunction
memory init() {
// assign shader memory
// create memory for one int
let aStaticValue : Int
// create memory for one int
var aNotSoStaticValue : Int // this wil succeed, assigns memory for one int
// create memory for 10 floats
var aStaticArray : [Float] = [Float](count: aStaticValue, repeatedValue: y) // this will succeed
// create memory for x floats
var aDynamicArray : [Float] = [Float](count: aBuffer.count, repeatedValue: y) // this will fail
var aDynamicArray : [Float] = [Float](count: aBufferCount, repeatedValue: y) // this will fail
let tempValue : Float // one float from a loop
}
// step Two : commandEncoder.setBuffer()
assign buffers (buffers) {
aBuffer = cpuMemoryBuffer
}
// step Three : commandEncoder.endEncoding()
actual init() {
// set shader values
let aStaticValue : Int = 0
var aNotSoStaticValue : Int = aBuffer.count
var aDynamicArray : [Float] = [Float](count: aBuffer.count, repeatedValue: 1) // this could work, but the app already crashed before getting to this point.
}
// step Four : commandBuffer.commit()
func shaderFunction() {
// do stuff
for i in 0..<aBuffer.count {
let tempValue = aBuffer[i]
}
}
}
Fix:
Я наконец понял, что буферы — это технически динамические массивы, и вместо создания массивов внутри шейдера я мог бы просто добавить больше буферов. Это очевидно работает.
Я думаю, что ваша проблема с этой строкой:
uint schemeVectorSize = sizeof(schemeVector) / uintSize;
Вот schemeVector
является динамический так как в классическом C ++ вы не можете использовать sizeof
на динамическом массиве, чтобы получить количество элементов. sizeof
будет работать только с массивами, которые вы определили бы локально / статически в коде шейдера металла.
Только представьте, как это работает внутри: во время компиляции компилятор Metal должен преобразовывать sizeof
позвонить в константу … но он не может, так как schemeVector
является параметром вашего шейдера и поэтому может иметь любой размер …
Так что для меня решение было бы вычислить schemeVectorSize
в части кода C ++ / ObjectiveC / Swift и передайте ее в качестве параметра шейдеру (как униформу в терминологии OpenGLES …).