代码之家  ›  专栏  ›  技术社区  ›  mrplants

苹果金属元素矩阵乘法(阿达玛积)

  •  2
  • mrplants  · 技术社区  · 7 年前

    是否可以使用苹果的金属性能遮影器来制作哈达玛产品?我看到一个正常的矩阵乘法可以用 this 但是我特别想找一个元素乘法,或者一个聪明的方法来构造一个。(例如,是否可以将mpsmatrix转换为mpsvector,然后使用向量执行产品?)

    更新: 感谢您推荐使用遮影器!我正在研究一个实现,这看起来很有希望!我会在我有工作的时候发布解决方案。

    1 回复  |  直到 7 年前
        1
  •  0
  •   mrplants    7 年前

    好吧,在这里根据评论者的建议回答我自己的问题-尝试编写我自己的着色器!

    这是明暗器代码:

    #include <metal_stdlib>
    using namespace metal;
    
    /*
     hadamardProduct:
     Perform an element-wise multiplication (hadamard product) of the two input matrices A and B, store the result in C
     */
    kernel void hadamardProductKernel(
    texture_buffer<float, access::read> A [[texture(0)]],
    texture_buffer<float, access::read> B [[texture(1)]],
    texture_buffer<float, access::write> C [[texture(2)]],
    uint gid [[thread_position_in_grid]]) {
        // C[i,j] = A[i,j] * B[i,j]
        C.write(A.read(gid) * B.read(gid), gid);
    }
    

    以及在两个4x4矩阵上执行明暗器的swift:

    import Foundation
    import Metal
    import MetalKit
    
    guard
        let gpu = MTLCreateSystemDefaultDevice(),
        let commandQueue = gpu.makeCommandQueue(),
        let commandBuffer = commandQueue.makeCommandBuffer(),
        let defaultLibrary = gpu.makeDefaultLibrary(),
        let kernelFunction = defaultLibrary.makeFunction(name: "hadamardProductKernel")
    else {exit(1)}
    
    // Create the matrices to multiply (as row-major matrices)
    var A:[Float] = [2,0,0,0,
                     0,2,0,0,
                     0,0,2,0,
                     0,0,0,2]
    
    var B:[Float] = [1,0,0,0,
                     0,2,0,0,
                     0,0,3,0,
                     0,0,0,4]
    
    let A_buffer = gpu.makeTexture(descriptor: MTLTextureDescriptor.textureBufferDescriptor(with: .r32Float,
                                                                                                                                                                                    width: 16,
                                                                                                                                                                                    resourceOptions: .storageModeManaged,
                                                                                                                                                                                    usage: .shaderRead))
    let B_buffer = gpu.makeTexture(descriptor: MTLTextureDescriptor.textureBufferDescriptor(with: .r32Float,
                                                                                                                                                                                    width: 16,
                                                                                                                                                                                    resourceOptions: .storageModeManaged,
                                                                                                                                                                                    usage: .shaderRead))
    let C_buffer = gpu.makeTexture(descriptor: MTLTextureDescriptor.textureBufferDescriptor(with: .r32Float,
                                                                                                                                                                                    width: 16,
                                                                                                                                                                                    resourceOptions: .storageModeManaged,
                                                                                                                                                                                    usage: .shaderWrite))
    A_buffer?.replace(region: MTLRegionMake1D(0, 16),
                      mipmapLevel: 0,
                      withBytes: UnsafeRawPointer(A),
                      bytesPerRow: 64)
    B_buffer?.replace(region: MTLRegionMake1D(0, 16),
                      mipmapLevel: 0,
                      withBytes: UnsafeRawPointer(B),
                      bytesPerRow: 64)
    
    let computePipelineState = try gpu.makeComputePipelineState(function: kernelFunction)
    let computeEncoder = commandBuffer.makeComputeCommandEncoder()
    computeEncoder?.setComputePipelineState(computePipelineState)
    computeEncoder?.setTexture(A_buffer, index: 0)
    computeEncoder?.setTexture(B_buffer, index: 1)
    computeEncoder?.setTexture(C_buffer, index: 2)
    let threadGroupSize = MTLSize(width: 16, height: 1, depth: 1)
    let threadGroupCount = MTLSize(width: 1, height: 1, depth: 1)
    computeEncoder?.dispatchThreadgroups(threadGroupCount, threadsPerThreadgroup: threadGroupSize)
    computeEncoder?.endEncoding()
    commandBuffer.commit()
    commandBuffer.waitUntilCompleted()
    
    print("done")
    

    感谢任何链接到参考资料的评论,以便进一步了解这类事情。