2017-02-02 3 views

Répondre

0

MPS fournit maintenant MPSCNNConvolutionTranspose dans macOS X.13 et tvOS/iOS 11.

5

Vous pouvez écrire vos propres noyaux de calcul Metal et les exécuter entre les opérations MPS.

Par exemple:

let commandBuffer = commandQueue.makeCommandBuffer() 

. . . 

// Do something with an MPSCNN layer: 
layer1.encode(commandBuffer: commandBuffer, sourceImage: img1, destinationImage: img2) 

// Perform your own compute kernel: 
let encoder = commandBuffer.makeComputeCommandEncoder() 
encoder.setComputePipelineState(yourOwnComputePipeline) 
encoder.setTexture(img2.texture, at: 0) 
encoder.setTexture(img3.texture, at: 1) 
let threadGroupSize = MTLSizeMake(. . .) 
let threadGroups = MTLSizeMake(img2.texture.width/threadGroupSize.width, 
           img2.texture.height/threadGroupSize.height, 1) 
encoder.dispatchThreadgroups(threadGroups, threadsPerThreadgroup: threadGroupSize) 
encoder.endEncoding() 

// Do something with another MPSCNN layer: 
layer2.encode(commandBuffer: commandBuffer, sourceImage: img3, destinationImage: img4) 

. . . 

commandBuffer.commit() 

Vous devez écrire votre propre noyau compute dans le métal Shading Language et charger ce dans l'objet yourOwnComputePipeline. Ensuite, vous pouvez l'encoder dans le tampon de commande actuel quand vous le voulez.

+0

Oui, je le sais. Avez-vous des exemples sur comment passer 'MPSImage' comme paramètre et travailler avec lui dans la fonction' kernel'? – s1ddok

+0

Vous ne transmettez pas 'MPSImage' directement. Au lieu de cela, vous utilisez 'image.texture', comme je l'ai fait dans l'exemple de code. Si vous avez <= 4 canaux alors la texture est juste un objet de texture unique; avec> 4 canaux c'est en fait un tableau de textures. –

1

[J'ajoute cela comme une nouvelle réponse, car il est une autre solution.]

Notez que déconvolution dans l'apprentissage en profondeur est également connu comme « convolution transposée », ce qui signifie que c'est la même chose que faire une convolution régulière mais avec les noyaux horizontalement et verticalement retournés. Vous devriez donc être en mesure d'utiliser une couche MPSCNNConvolution qui prend le MPSImage que vous souhaitez déconvoluer en entrée, et qui utilise les mêmes noyaux que l'étape de convolution «forward», mais inversée horizontalement et verticalement. L'avantage de faire cela en écrivant votre propre noyau de calcul est que vous pouvez utiliser les noyaux très rapides de MPS.

Édition: Un exemple. Disons que votre poids du noyau de conv ressemblent à ceci:

1, 2, 3 
4, 5, 6 
7, 8, 9 

Puis, après retournement du noyau, les poids se présentent comme suit:

9, 8, 7 
6, 5, 4 
3, 2, 1 

En d'autres termes, vous devez faire une copie de votre tableau de poids et inversez-le. En mémoire les premiers poids ressemblent à ceci:

1, 2, 3, 4, 5, 6, 7, 8, 9 

Le noyau basculée ressemble à ceci en mémoire, il est tout simplement le noyau d'origine, mais dans l'ordre inverse:

9, 8, 7, 6, 5, 4, 3, 2, 1 

Ensuite, vous faites une nouvelle couche de convolution en utilisant ce tableau inversé. C'est maintenant votre couche de déconv.

Je n'ai pas d'exemple de code Metal pour vous montrer, mais ce n'est vraiment pas différent de créer un calque MPSCNNConvolution. Vous avez juste à inverser les poids pour la couche.

+0

Je tuerais pour un exemple – s1ddok

+0

Ajout d'un exemple. –

+0

Je suppose que ce n'est pas entièrement correct. Tout d'abord, nous avons 3 poids dimensionnels. Et la déconvolution supposée est censée rendre la largeur et la hauteur de l'image plus grandes, n'est-ce pas? – s1ddok