2016-11-10 13 views
6

Struktury Metal Shader zapewnia wsparcie dla budowy własnych konwolucyjnych sieci neuronowych. Podczas tworzenia na przykład MSPCNNConvolution wymaga tensora 4D jako parametru init, który jest reprezentowany jako wskaźnik pływający 1D.MPSCNN Ciężar Zamawianie

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

Dokumentacja ma to znaczy o tensora 4D

Rozkład ciężaru filtra jest umieszczony tak, że może być zinterpretowane jako 4D tensora (array) ciężar [outputChannels] [kernelHeight] [kernelWidth] [inputChannels/grupy]

Niestety te informacje nie bardzo mi powiedzieć jak zorganizować tablicy 4D w jeden trójwymiarowy Float wskaźnik.

Próbowałem zamówić wagi, takie jak odpowiednik BNNS, ale bez powodzenia.

Jak prawidłowo reprezentować tensor 4D (tablicę) jako wskaźnik 1D Float?

PS: Próbowałem zorganizować go jak tablicę C i otrzymując wskaźnik do płaskiej tablicy, ale to nie zadziałało.

UPDATE

@RhythmicFistman: To jak ja przechowywać go w zwykłej tablicy, które można przekonwertować do UsafePointer<Float> (ale nie działa):

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

czy możesz pokazać, w jaki sposób podjąłeś próbę 4D do 1D?obawiając się użycia niewłaściwego wskaźnika, myślę, że jedyną rzeczą, która może pójść źle, jest kolejność indeksów. –

+0

@RhythmicFistman Zaktualizowano pytanie, problem nie jest nawet projekt przykładowy Jabłka WŁASNE (z własnymi wyszkolonych wag) działa poprawnie. Więc skąd mam wiedzieć, co jest nie tak ... moje dane lub ich implementacja. –

+0

Do jakiej próbki Apple się odwołujesz? Zarówno MetalImageRecognition, jak i MPSCNNHelloWorld wydają się działać dla mnie z Xcode 8.2 beta i iOS 10.2 beta. – warrenm

Odpowiedz

1

Ok więc ja domyśliłam się. Oto 2 funkcje Python używam zreformować swoje zwoje i pełni połączone macierze

# 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

To jest coś Niedawno miałem zrobić dla ciężarów cafe, więc mogę zapewnić szybkie wdrożenie do tych jak ja zreorganizowane. Następująca funkcja przyjmuje spłaszczoną tablicę wagi Caffe dla splotu (w [c_o] [c_i] [h] [w] celu) i zmienia kolejność na to, czego oczekuje Metal ([c_o] [h] [w] [c_i] zamówienie):

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 
} 

Na podstawie mojej wizualizacji warstwy wydaje się, że generuje prawidłowe wyniki splotu (odpowiadające wynikom produkowanym przez Caffe). Uważam, że również poprawnie uwzględnia to grupowanie, ale muszę to sprawdzić.

Tensorflow ma inną kolejność niż Caffe, ale powinieneś być w stanie zmienić matematykę w wewnętrznej części pętli, aby to uwzględnić.

1

Dokumentacja tutaj zakłada pewną wiedzę w C. W tym kontekście, [x] [y] [z] jest zazwyczaj zwinięte w tablicę 1-d, gdy x, y i z są stałymi znanymi podczas kompilacji. Gdy to się stanie, składowa z zmienia się najszybciej, a następnie przez Y, a następnie x - poza

Jeśli mamy [2], [2], [2], to jest zwinięta do 1d jako:.

{ 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] }