def _pack_batch_channel(data, dshape, bfactor, cfactor): """Pack the data channel dimension. """ assert int(dshape[0]) % bfactor == 0 assert int(dshape[1]) % cfactor == 0 data = op.reshape(data, newshape=(int(dshape[0]) // bfactor, bfactor, int(dshape[1]) // cfactor, cfactor, int(dshape[2]), int(dshape[3]))) data = op.transpose(data, axes=(0, 2, 4, 5, 1, 3)) return data
def _pack_weight(data, dshape, cfactor): """Pack the weight into packed format. """ assert len(dshape) == 4 assert int(dshape[0]) % cfactor == 0 assert int(dshape[1]) % cfactor == 0 data = op.reshape(data, newshape=(int(dshape[0]) // cfactor, cfactor, int(dshape[1]) // cfactor, cfactor, int(dshape[2]), int(dshape[3]))) data = op.transpose(data, axes=(0, 2, 4, 5, 1, 3)) return data
def _pack_weight_conv2d_transpose(data, dshape, cfactor): """Pack the weight into packed format. """ dshape = _to_shape(dshape) assert len(dshape) == 4 assert dshape[0] % cfactor == 0 assert dshape[1] % cfactor == 0 data = op.reshape(data, newshape=(dshape[0] // cfactor, cfactor, dshape[1] // cfactor, cfactor, dshape[2], dshape[3])) data = op.transpose(data, axes=(2, 0, 4, 5, 3, 1)) return data
def _pack_const(data, dshape, dtype, bfactor, cfactor): """Pack a constant parameter.""" dshape = _to_shape(dshape) assert len(dshape) == 3 assert dshape[0] % cfactor == 0 data = op.reshape(data, newshape=(dshape[0] // cfactor, cfactor, dshape[1], dshape[2], 1)) data = op.transpose(data, axes=(0, 2, 3, 4, 1)) # broadcast batch dimension to bfactor data = op.broadcast_to( data, shape=(dshape[0] // cfactor, dshape[1], dshape[2], bfactor, cfactor) ) return data
def _impl(inputs, _): weight = inputs[1][0] weight_scale = inputs[1][1] weight_zero_point = inputs[1][2] inp = inputs[0] input_scale, input_zero_point = _calculate_qparam(inp) qinp = relay.qnn.op.quantize(inp, input_scale, input_zero_point, out_dtype="uint8") data_shape = infer_shape(inp) if len(data_shape) > 2: qinp = _op.reverse_reshape(qinp, [-1, 0]) weight_shape = infer_shape(weight) units = weight_shape[0] dense = relay.qnn.op.dense( qinp, weight, input_zero_point, weight_zero_point, input_scale, weight_scale, units=units, ) bias_var = inputs[1][3] dequant_scale = input_scale * weight_scale dense_out = relay.qnn.op.dequantize(dense, dequant_scale, input_zero_point=relay.const( 0, "int32"), axis=1) if len(data_shape) > 2: new_shape = list(data_shape[:-1]) new_shape.append(units) dense_out = _op.reshape(dense_out, new_shape) if bias_var is not None: return dense_out + bias_var return dense_out
def aten_view(inputs, attributes, scope): assert len(inputs) == 2 ctx = current_context() net = current_context().network if ctx.is_tensorrt and has_trt_tensor(inputs): shape = inputs[1][1:] # trt tensor shape don't include batch axis # TODO add batch size check if len(shape) == 1: shape += [1, 1] # elif len(shape) == 2: # shape += [1] layer = net.add_shuffle(inputs[0]) layer.reshape_dims = shape output = layer.get_output(0) layer.name = scope output.name = scope return [output] elif ctx.is_tvm and has_tvm_tensor(inputs): return [_op.reshape(inputs[0], newshape=inputs[1])] return [inputs[0].view(*inputs[1])]
def _reshape(children, attrs, odtype='float32'): data = children[0] shape = attrs.get_int_list('shape') return op.reshape(data, shape)
def _unpack_batch_channel(data, old_shape): """Unpack the data channel dimension. """ data = op.transpose(data, axes=(0, 4, 1, 5, 2, 3)) data = op.reshape(data, newshape=old_shape) return data
def visit_call(self, call): """ Visit the children. """ # First visit the children. oshape = _get_tensor_shape(call) odtype = _get_tensor_type(call) input_types = [arg.checked_type for arg in call.args] args = [self.visit(arg) for arg in call.args] # Start and stop cases. if call.op == self.bitpack_start: assert not self.start_pack self.start_pack = True return _pack_batch_channel(args[0], oshape, self.bfactor, self.cfactor) if call.op == self.bitpack_end: if self.start_pack: self.start_pack = False data = args[0] data_shape = _get_tensor_shape(call.args[0]) return _unpack_batch_channel(data, data_shape) if self.start_pack: # Operator cases if call.op == self.conv2d and odtype == 'int32': self.number_of_conv2d += 1 assert 8 % self.weight_bits == 0 w_lanes = 8 // self.weight_bits data_layout = "NCHW%dn%dc" % (self.bfactor, self.cfactor) kernel_layout = "OIHW%do%di" % (self.cfactor, self.cfactor) data, weight = args data_shape = _to_shape(input_types[0].shape) kernel_shape = _to_shape(input_types[1].shape) channels = call.attrs.channels weight, kernel_shape, channels = _weight_shape_match( weight, kernel_shape, channels, self.cfactor) kernel = _pack_weight(weight, kernel_shape, self.cfactor) # insert bit packing when necessary if w_lanes != 1: assert 8 % w_lanes == 0 kernel = op.bitpack(kernel, lanes=w_lanes) conv2d = op.nn.conv2d(data, kernel, strides=call.attrs.strides, padding=call.attrs.padding, dilation=call.attrs.dilation, groups=call.attrs.groups, channels=channels, kernel_size=call.attrs.kernel_size, data_layout=data_layout, kernel_layout=kernel_layout, out_dtype=call.attrs.out_dtype) return conv2d if call.op == self.conv2d_transpose and odtype == 'int32': self.number_of_conv2d += 1 assert 8 % self.weight_bits == 0 w_lanes = 8 // self.weight_bits if self.start_pack: data_layout = "NCHW%dn%dc" % (self.bfactor, self.cfactor) kernel_layout = "IOHW%di%do" % (self.cfactor, self.cfactor) data, weight = args data_shape = _to_shape(input_types[0].shape) kernel_shape = _to_shape(input_types[1].shape) channels = call.attrs.channels weight, kernel_shape, channels = _weight_shape_match_transpose( weight, kernel_shape, channels, self.cfactor) kernel = _pack_weight_conv2d_transpose( weight, kernel_shape, self.cfactor) conv2d = op.nn.conv2d_transpose( data, kernel, strides=call.attrs.strides, padding=call.attrs.padding, dilation=call.attrs.dilation, groups=call.attrs.groups, channels=call.attrs.channels, kernel_size=call.attrs.kernel_size, data_layout=data_layout, kernel_layout=kernel_layout, output_padding=call.attrs.output_padding, out_dtype=call.attrs.out_dtype) return conv2d if call.op == self.add and \ tuple(input_types[0].shape) == tuple(input_types[1].shape): pass elif call.op == self.add and len(input_types[1].shape) == 3: data, const = args const, input_shape = _const_shape_match( const, input_types[1].shape, self.cfactor) const = _pack_const(const, _to_shape(input_shape), input_types[1].dtype, self.bfactor, self.cfactor) return relay.Call(self.add, [data, const]) elif call.op == self.multiply and \ tuple(input_types[0].shape) == tuple(input_types[1].shape): pass elif call.op == self.multiply and len(input_types[1].shape) == 3: data, const = args const = _pack_const(const, _to_shape(input_types[1].shape), input_types[1].dtype, self.bfactor, self.cfactor) return relay.Call(self.multiply, [data, const]) elif self.start_pack and call.op == self.bias_add: data, bias = args bias = _pack_const(bias, _to_shape(input_types[1].shape), input_types[1].dtype, self.bfactor, self.cfactor) return relay.Call(self.add, [data, bias]) elif self.start_pack and call.op == op.op.get('cast') and \ input_types[0].dtype == 'int32': cast = relay.Call(op.op.get('cast'), [args[0]], call.attrs) return relay.Call(op.op.get('copy'), [cast]) elif call.op == self.pad: pad_width = call.attrs.pad_width if len(pad_width) == 6: pass elif len(pad_width) == 4: data, = args new_pad_width = [] new_pad_width.extend(pad_width) for _ in range(2): new_pad_width.append([0, 0]) return op.nn.pad(data, pad_value=call.attrs.pad_value, pad_width=new_pad_width) elif call.op == self.upsampling: data, = args scale_h = call.attrs.scale_h scale_w = call.attrs.scale_w data_layout = "NCHW%dn%dc" % (self.bfactor, self.cfactor) method = call.attrs.method align_corners = call.attrs.align_corners return op.nn.upsampling(data, scale_h, scale_w, data_layout, method, align_corners) elif call.op == self.reshape and len(input_types[0].shape) == 4: data, _ = args data = op.transpose(data, axes=(0, 4, 1, 5, 2, 3)) return op.reshape(data, [int(x) for x in input_types[0].shape]) return relay.Call(self.visit(call.op), args, call.attrs)
def _tvm_reshape(inp, shape, name): return _op.reshape(inp, newshape=shape)
def _tvm_unsqueeze(inp, dim, name): inp_shape = infer_shape(inp) inp_shape = list(inp_shape) inp_shape.insert(dim, 1) return _op.reshape(inp, newshape=inp_shape)