使用 Metal Performance Shaders 反卷积
Deconvolution with Metal Performance Shaders
原来MPS
里面没有deconvolution
这样的操作。 tensorflow
中最接近的类似物是 conv2d_transpose
。
是否可以在 MPS
默认操作之间对插件自定义操作进行排序?
您可以编写自己的 Metal 计算内核并在 MPS 操作之间执行它们。
例如:
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()
您必须使用金属着色语言编写自己的计算内核并将其加载到 yourOwnComputePipeline
对象中。然后你可以随时将它编码到当前命令缓冲区中。
[我将其添加为新答案,因为它是不同的解决方案。]
请注意,深度学习中的反卷积也称为 "transposed convolution",这意味着它与进行常规卷积相同,但内核水平和垂直翻转。
因此您应该能够使用常规 MPSCNNConvolution
层,该层将您希望反卷积的 MPSImage
作为输入,并且使用与 "forward" 卷积相同的内核一步,但水平和垂直翻转。
与编写您自己的计算内核相比,这样做的优势在于您可以使用 MPS 中速度非常快的内核。
编辑:一个例子。假设您的转换内核权重如下所示:
1, 2, 3
4, 5, 6
7, 8, 9
然后翻转内核后,权重如下所示:
9, 8, 7
6, 5, 4
3, 2, 1
换句话说,您需要复制权重数组并将其反转。在内存中,第一个权重如下所示:
1, 2, 3, 4, 5, 6, 7, 8, 9
翻转后的内核在内存中看起来像这样,所以它只是原始内核,但顺序相反:
9, 8, 7, 6, 5, 4, 3, 2, 1
然后你使用那个反向数组创建一个新的卷积层。现在这是你的 deconv 层。
我没有 Metal 示例代码可以向您展示,但这与制作常规 MPSCNNConvolution
层确实没有什么不同。您只需反转层的权重。
MPS 现在在 macOS X.13 和 tvOS/iOS11 中提供 MPSCNNConvolutionTranspose。
原来MPS
里面没有deconvolution
这样的操作。 tensorflow
中最接近的类似物是 conv2d_transpose
。
是否可以在 MPS
默认操作之间对插件自定义操作进行排序?
您可以编写自己的 Metal 计算内核并在 MPS 操作之间执行它们。
例如:
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()
您必须使用金属着色语言编写自己的计算内核并将其加载到 yourOwnComputePipeline
对象中。然后你可以随时将它编码到当前命令缓冲区中。
[我将其添加为新答案,因为它是不同的解决方案。]
请注意,深度学习中的反卷积也称为 "transposed convolution",这意味着它与进行常规卷积相同,但内核水平和垂直翻转。
因此您应该能够使用常规 MPSCNNConvolution
层,该层将您希望反卷积的 MPSImage
作为输入,并且使用与 "forward" 卷积相同的内核一步,但水平和垂直翻转。
与编写您自己的计算内核相比,这样做的优势在于您可以使用 MPS 中速度非常快的内核。
编辑:一个例子。假设您的转换内核权重如下所示:
1, 2, 3
4, 5, 6
7, 8, 9
然后翻转内核后,权重如下所示:
9, 8, 7
6, 5, 4
3, 2, 1
换句话说,您需要复制权重数组并将其反转。在内存中,第一个权重如下所示:
1, 2, 3, 4, 5, 6, 7, 8, 9
翻转后的内核在内存中看起来像这样,所以它只是原始内核,但顺序相反:
9, 8, 7, 6, 5, 4, 3, 2, 1
然后你使用那个反向数组创建一个新的卷积层。现在这是你的 deconv 层。
我没有 Metal 示例代码可以向您展示,但这与制作常规 MPSCNNConvolution
层确实没有什么不同。您只需反转层的权重。
MPS 现在在 macOS X.13 和 tvOS/iOS11 中提供 MPSCNNConvolutionTranspose。