Vraag newComputePipelineStateWithFunction mislukt


Ik probeer een neuraal net op metaal te laten lopen. Het basisidee is dataduplicatie. Elke gpu-thread voert één versie van het net uit voor willekeurige gegevenspunten.

Ik heb andere shaders geschreven die goed werken.

Ik probeerde ook mijn code in een c ++ opdrachtregel app. Geen fouten daar. Er is ook geen compileerfout.

Ik heb de Apple-documentatie gebruikt om te zetten in metal c ++, omdat niet alles van C ++ 11 wordt ondersteund.

Het crasht nadat het de kernelfunctie laadt en wanneer het probeert toe te wijzen newComputePipelineStateWithFunction naar het metalen apparaat. Dit betekent dat er een probleem is met de code die niet wordt vastgehouden tijdens het compileren.

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;

}

Bijwerken

Het heeft alles te maken met dynamische arrays.

Aangezien het er niet in slaagt de pijplijnstatus te maken en niet crasht met het uitvoeren van de eigenlijke arcering, moet dit een coderingsprobleem zijn. Geen probleem met de invoer.

Het toewijzen van waarden uit een dynamische array aan een buffer zorgt ervoor dat deze mislukt.


11
2017-08-25 00:24


oorsprong


antwoorden:


Het echte probleem: Het is een geheugenprobleem!

Aan alle mensen die zeiden dat het een geheugenprobleem was, had je gelijk! Hier is wat pseudo-code om dit te illustreren. Sorry dat het in "Swift" staat maar makkelijker te lezen is. Metal Shaders hebben een funky manier om tot leven te komen. Ze worden eerst geïnitialiseerd zonder waarden om het geheugen te krijgen. Het was deze stap die mislukte omdat hij was gebaseerd op een latere stap: het instellen van de buffer.

Het komt allemaal neer op welke waarden beschikbaar zijn wanneer. Mijn begrip van newComputePipelineStateWithFunction was verkeerd. Het krijgt niet alleen de arceringsfunctie. Het is ook een kleine stap in het initialisatieproces.

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:

Ik realiseerde me eindelijk dat buffers technisch dynamische arrays zijn en in plaats van arrays in de arcering te maken, zou ik ook gewoon meer buffers kunnen toevoegen. Dit werkt duidelijk.


4
2017-09-02 22:51



Ik denk dat je probleem met deze regel zit:

uint schemeVectorSize = sizeof(schemeVector) / uintSize;

Hier schemeVector is dynamisch zo zoals in klassieke C ++ je kunt niet gebruiken sizeof op een dynamische array om het aantal elementen te krijgen. sizeof zou alleen werken op arrays die u lokaal / statisch in de metal shader-code zou hebben gedefinieerd.

Stelt u zich eens voor hoe het intern werkt: tijdens compilatie zou de Metal-compiler het sizeof roep in een constante ... maar hij kan niet sindsdien schemeVector is een parameter van je arcering en kan dus elke grootte hebben ...

Dus voor mij zou de oplossing zijn om te berekenen schemeVectorSize in het C ++ / ObjectiveC / Swift-gedeelte van uw code, en geef dit door als parameter aan de arcering (als uniform in OpenGLES-terminologie ...).


-1
2017-09-01 12:08