diff --git a/metal/paddle-mobile-unit-test/paddle-mobile-unit-test/ViewController.swift b/metal/paddle-mobile-unit-test/paddle-mobile-unit-test/ViewController.swift index 8d173d6bcc546916ceb1c011110340e6ebf2e95a..80d818a0b54f4159aa4b5c8b61a6c8781782ad96 100644 --- a/metal/paddle-mobile-unit-test/paddle-mobile-unit-test/ViewController.swift +++ b/metal/paddle-mobile-unit-test/paddle-mobile-unit-test/ViewController.swift @@ -20,7 +20,8 @@ class ViewController: UIViewController { inDevice: device, inQueue: queue ) - test.testReshape() + test.testConcat() +// test.testReshape() // test.testTranspose() print(" done ") } diff --git a/metal/paddle-mobile/paddle-mobile/Common/PaddleMobileUnitTest.swift b/metal/paddle-mobile/paddle-mobile/Common/PaddleMobileUnitTest.swift index f4bd21452e2a011c7dd0ab09479df94d4b1f17a6..0d1fd39a346f220e4afa5b2bc2e5a711e57e7c14 100644 --- a/metal/paddle-mobile/paddle-mobile/Common/PaddleMobileUnitTest.swift +++ b/metal/paddle-mobile/paddle-mobile/Common/PaddleMobileUnitTest.swift @@ -82,6 +82,37 @@ public class PaddleMobileUnitTest { indentPrintTensor(tensor: tensor, dim: ndim, ix: dim.map { $0 * 0 }, indentLevel: 0) } + public func testConcat() { + let buffer = queue.makeCommandBuffer() ?! "buffer is nil" + var it: [[Float32]] = [] + for _ in 0..<7 { + it.append((0..<12).map { Float32($0) }) + } + let input = it.map { device.tensor2texture(value: $0, dim: [3, 4]) } + let output = device.tensor2texture(value: [Float32](), dim: [3, 28]) + + let param = ConcatTestParam.init( + input: input, + output: output, + dims: [[3, 4], [3, 4], [3, 4], [3, 4], [3, 4], [3, 4], [3, 4]], + axis: 1, + odim: [3, 28] + ) + let concatKernel = ConcatKernel.init(device: device, testParam: param) + concatKernel.test(cmdBuffer: buffer, param: param) + buffer.addCompletedHandler { (buffer) in + for i in 0..: OpParam { class ConcatOp: Operator, ConcatParam

>, Runable, Creator, InferShaperable{ func inferShape() { - let dim = para.input.reduce([0, 0]) {[$0[0] + $1.dim[0], $1.dim[1]]} - para.output.dim = Dim.init(inDim: dim) +// let dim = para.input.reduce([0, 0]) {[$0[0] + $1.dim[0], $1.dim[1]]} +// para.output.dim = Dim.init(inDim: dim) } typealias OpType = ConcatOp

diff --git a/metal/paddle-mobile/paddle-mobile/Operators/Kernels/ConcatKernel.swift b/metal/paddle-mobile/paddle-mobile/Operators/Kernels/ConcatKernel.swift index f5a16141fa77a1a03eedbdb5748bd321f667d226..9e6e0c368f4f745fc6b2e7ef8d7bef802eb20b41 100644 --- a/metal/paddle-mobile/paddle-mobile/Operators/Kernels/ConcatKernel.swift +++ b/metal/paddle-mobile/paddle-mobile/Operators/Kernels/ConcatKernel.swift @@ -14,18 +14,114 @@ import Foundation +struct ConcatTestParam: TestParam { + var input: [MTLTexture] + var output: MTLTexture + var dims: [[Int]] + var axis: Int + var odim: [Int] +} + +struct ConcatMetalParam { + var odim: (Int32, Int32, Int32, Int32) = (1, 1, 1, 1) + var axis: Int32 = 0 + var offset: Int32 = 0 + var vdim: (Int32, Int32, Int32, Int32, Int32, Int32) = (0, 0, 0, 0, 0, 0) +} + class ConcatKernel: Kernel, Computable{ - func compute(commandBuffer: MTLCommandBuffer, param: ConcatParam

) throws { - guard let encoder = commandBuffer.makeComputeCommandEncoder() else { + + func encodeTest(_ cmdBuffer: MTLCommandBuffer, _ param: ConcatTestParam, _ istart: Int, _ iend: Int) { + let encoder = cmdBuffer.makeComputeCommandEncoder()! + var p = ConcatMetalParam.init() + var odim: [Int32] = [1, 1, 1, 1] + for i in 0...size, index: 0) + encoder.dispatch(computePipline: pipline, outTexture: param.output) + encoder.endEncoding() + } + + func encode(_ cmdBuffer: MTLCommandBuffer, _ param: ConcatParam

, _ istart: Int, _ iend: Int) throws { + guard let encoder = cmdBuffer.makeComputeCommandEncoder() else { throw PaddleMobileError.predictError(message: " encode is nil") } -// encoder.setTexture(param.input.metalTexture, index: 0) -// encoder.setTexture(param.output.metalTexture, index: 1) + var p = ConcatMetalParam.init() + let odim = (0..<4).map { Int32(param.output.dim[$0]) } + p.odim = (odim[0], odim[1], odim[2], odim[3]) + p.axis = Int32(4 - param.output.tensorDim.cout() + param.axis) + for i in 0...size, index: 0) encoder.dispatch(computePipline: pipline, outTexture: param.output.metalTexture) encoder.endEncoding() } + func compute(commandBuffer: MTLCommandBuffer, param: ConcatParam

) throws { + for i in 0.. 0 { + try self.encode(commandBuffer, param, 6 * group, param.input.count) + } + } + + func test(cmdBuffer: MTLCommandBuffer, param: ConcatTestParam) { + let group = param.input.count / 6 + let remain = param.input.count % 6 + for i in 0.. 0 { + try self.encodeTest(cmdBuffer, param, 6 * group, param.input.count) + } + } + required init(device: MTLDevice, param: ConcatParam

) { + param.output.initTexture(device: device) + super.init(device: device, inFunctionName: "concat") + } + + required init(device: MTLDevice, testParam: ConcatTestParam) { super.init(device: device, inFunctionName: "concat") } } diff --git a/metal/paddle-mobile/paddle-mobile/Operators/Kernels/Kernels.metal b/metal/paddle-mobile/paddle-mobile/Operators/Kernels/Kernels.metal index f8c9099415b3675c5f583d2905a1fa52e46b05a3..234fbd0fd61fed4def08a3526a4b5fe17aae80fc 100644 --- a/metal/paddle-mobile/paddle-mobile/Operators/Kernels/Kernels.metal +++ b/metal/paddle-mobile/paddle-mobile/Operators/Kernels/Kernels.metal @@ -425,3 +425,55 @@ kernel void reshape(texture2d_array inTexture [[texture(0)] // half4 r = inTexture.read(uint2(0, 0), gid.x); // outTexture.write(r, gid.xy, gid.z); //} + +struct ConcatParam { + int32_t odim[4]; + int32_t axis; + int32_t offset; + int32_t vdim[6]; +}; + +kernel void concat(texture2d_array in0 [[texture(0)]], + texture2d_array in1 [[texture(1)]], + texture2d_array in2 [[texture(2)]], + texture2d_array in3 [[texture(3)]], + texture2d_array in4 [[texture(4)]], + texture2d_array in5 [[texture(5)]], + texture2d_array inx [[texture(6)]], + texture2d_array out [[texture(7)]], + constant ConcatParam & pm [[buffer(0)]], + uint3 gid [[thread_position_in_grid]]) { + ConcatParam cp = pm; + int xyzn[4] = {int(gid.x), int(gid.y), int(gid.z), 0}, abcd[4], oxyzn[4]; + float4 r; + for (int i = 0; i < 4; i++) { + xyzn[3] = i; + xyzn2abcd(cp.odim[3], xyzn, abcd); + int k = abcd[cp.axis] - cp.offset; + int j = 0; + if (k < 0) { + r[i] = inx.read(gid.xy, gid.z)[i]; + } else { + for (; j < 6; j++) { + if (k < cp.vdim[j]) { + break; + } + k -= cp.vdim[j]; + } + int ta = cp.odim[cp.axis]; + abcd[cp.axis] = k; + cp.odim[cp.axis] = cp.vdim[j]; + abcd2xyzn(cp.odim[3], abcd, oxyzn); + cp.odim[cp.axis] = ta; + switch (j) { + case 0: r[i] = in0.read(uint2(oxyzn[0], oxyzn[1]), oxyzn[2])[oxyzn[3]]; break; + case 1: r[i] = in1.read(uint2(oxyzn[0], oxyzn[1]), oxyzn[2])[oxyzn[3]]; break; + case 2: r[i] = in2.read(uint2(oxyzn[0], oxyzn[1]), oxyzn[2])[oxyzn[3]]; break; + case 3: r[i] = in3.read(uint2(oxyzn[0], oxyzn[1]), oxyzn[2])[oxyzn[3]]; break; + case 4: r[i] = in4.read(uint2(oxyzn[0], oxyzn[1]), oxyzn[2])[oxyzn[3]]; break; + case 5: r[i] = in5.read(uint2(oxyzn[0], oxyzn[1]), oxyzn[2])[oxyzn[3]]; break; + } + } + } + out.write(r, gid.xy, gid.z); +} diff --git a/metal/paddle-mobile/paddle-mobile/framework/Texture.swift b/metal/paddle-mobile/paddle-mobile/framework/Texture.swift index f34cebbfc9bf344fe52b3a5c77a9ab20288516c8..04e48c7b08ab3165175bb37aeb6e9a2568794a47 100644 --- a/metal/paddle-mobile/paddle-mobile/framework/Texture.swift +++ b/metal/paddle-mobile/paddle-mobile/framework/Texture.swift @@ -40,6 +40,7 @@ extension InputTexture { public class Texture: Tensorial { var dim: Dim + var tensorDim: Dim private(set) var originDim: Dim private var textureDesc: MTLTextureDescriptor! var metalTexture: MTLTexture! @@ -89,7 +90,7 @@ public class Texture: Tensorial { } else { fatalError(" not support ") } - + tensorDim = inDim dim = fourDim originDim = fourDim layout = DataLayout.init([(.N, fourDim[0]), (.C, fourDim[1]), (.H, fourDim[2]), (.W, fourDim[3])])