首页 > 解决方案 > 在不同形状的金属纹理之间复制数据

问题描述

我正在将两个训练有素的 Keras 模型转换为金属性能着色器。我必须重塑第一个图的输出并将其用作第二个图的输入。第一个图的输出是一个具有“形状”(1,1,8192) 的 MPSImage,第二个图的输入是一个“形状”(4,4,512) 的 MPSImage。

我将 graph1 的输出 image.texture 转换为 float16 数组,并将其传递给以下函数以将数据复制到“midImage”,即 4x4x512 MPSImage:

func reshapeTexture(imageArray:[Float16]) -> MPSImage{

    let image = imageArray
    image.withUnsafeBufferPointer { ptr in
        let width = midImage.texture.width
        let height = midImage.texture.height
        for slice in 0..<128{
            for w in 0..<width{
                for h in 0..<height{
                    let region = MTLRegion(origin: MTLOriginMake(w, h, 0),
                                           size: MTLSizeMake(1, 1, 1))
                    midImage.texture.replace(region: region, mipmapLevel: 0, slice: slice, withBytes: ptr.baseAddress!.advanced(by: ((slice * 4 * width * height) + ((w + h) * 4)), bytesPerRow: MemoryLayout<Float16>.stride * 4, bytesPerImage: 0)
                }
            }
        }
    }
    return midImage
}

当我将 midImage 传递给 graph2 时,图形的输出是一个正方形,有 3/4 的乱码噪声,右下角有 1/4 的黑色。我想我不了解用于存储额外通道的 MPSImage 切片属性。谢谢!

标签: swiftkerasmetalmetal-performance-shaders

解决方案


金属二维纹理数组几乎总是以某种莫顿或“Z”顺序存储。当然 MPS 总是以这种方式分配它们,尽管我认为在 MacOS 上可能有一种方法可以制作线性 2D 纹理数组并在其周围包裹 MPSImage。因此,如果不小心,直接访问 2d 纹理数组后备存储将导致悲伤和混乱。

正确的做法是编写一个简单的 Metal 拷贝内核。这为您提供了存储顺序独立性,您不必等待命令缓冲区完成即可执行操作。

Radar 中的功能请求也可能是有保证的。另请查看最新的 macOS / iOS 种子,看看 Apple 最近是否为您添加了重塑过滤器。


推荐阅读