_callGPU(inputs) {
    inputs.forEach(input => {
      if (!input.glTexture && !input.glTextureFragments) {
        input.createGLTexture({ type: '2d', format: 'float', supportsTextureFragments: true })
      }
    })

    // create output textures if doesn't already exist
    if (!this.output) {
      this.output = new Tensor([], inputs[0].glTextureShape)
      this.output.createGLTexture({ type: '2d', format: 'float', supportsTextureFragments: true })
      if (inputs[0].is1D) {
        this.output.is1D = inputs[0].is1D
      } else if (inputs[0].is2DReshaped || inputs[0].is2DSquareReshaped) {
        if (inputs[0].is2DReshaped) {
          this.output.is2DReshaped = inputs[0].is2DReshaped
        } else if (inputs[0].is2DSquareReshaped) {
          this.output.is2DSquareReshaped = inputs[0].is2DSquareReshaped
        }
        this.output.originalShape = inputs[0].originalShape.slice()
        this.output.indicesForReshaped = inputs[0].indicesForReshaped
      }
    }

    webgl2.runProgram({
      program: this.mergeProgram,
      output: this.output,
      inputs: inputs.map((input, i) => ({ input, name: `inputs[${i}]` })),
      supportsTextureFragments: true
    })

    // GPU -> CPU data transfer
    if (this.outbound.length === 0) {
      this.output.transferFromGLTexture()
      if (this.output.is2DReshaped) {
        this.output.reshapeFrom2D()
      } else if (this.output.is2DSquareReshaped) {
        this.output.reshapeFrom2DSquare()
      }
    }
  }
GPU call

mode: sum, diff, mul, ave, max, min

method for mode concat/dot implemented in child class

@param {Tensor[]} inputs