def Affine(self, opset, func):
        """
        Affine is decomposed as 3 steps:
            Reshape inputs
            Gemm
            Reshape
        """
        nl = []
        out_a = fork_name(func.input[0])
        base_axis = func.affine_param.base_axis

        x_shape = list(self._var_dict[func.input[0]].dim[:])
        x_shape_dims = [np.prod(x_shape[:base_axis]),
                        np.prod(x_shape[base_axis:])]
        x_shape_dims_name = fork_name('x_shape_dims')
        x_shape_dims_raw = np.array(x_shape_dims).astype(np.int64)
        self._add_param(x_shape_dims_name, TensorProto.INT64, list(
            x_shape_dims_raw.shape), x_shape_dims_raw.tostring())

        n = onnx.helper.make_node(
            "Reshape",
            [func.input[0], x_shape_dims_name],
            [out_a]
        )
        nl.append(n)

        # To support SNPE, default set to `transB=1`
        if func.input[1] not in self._parameters:
            raise ValueError(
                "{} is not in network's parameters.".format(func.input[1]))

        transB = 0
        if opset == '9x':
            state = self._parameters_state.get(func.input[1], 0)
            if not state & ParameterState.TRANSPOSED:
                # make it to `transB=1`
                w_shape = list(self._var_dict[func.input[1]].dim[:])
                w_shape_dims = [int(np.prod(w_shape) / w_shape[0]), w_shape[0]]
                proto_w_shape = self._var_dict[func.input[1]]
                del proto_w_shape.dim[:]
                proto_w_shape.dim.extend(w_shape_dims)
                param = self._parameters[func.input[1]]
                w_data = np.array(param.data).reshape(
                    w_shape[0], int(np.prod(w_shape) / w_shape[0]))
                d = list(np.transpose(w_data).astype(np.float32).flatten())
                del param.data[:]
                param.data.extend(d)
                self._parameters_state[func.input[1]
                                       ] = state | ParameterState.TRANSPOSED
            transB = 1
        else:
            w_shape = list(self._var_dict[func.input[1]].dim[:])
            w_shape_dims = [w_shape[0], int(np.prod(w_shape) / w_shape[0])]
            proto_w_shape = self._var_dict[func.input[1]]
            del proto_w_shape.dim[:]
            proto_w_shape.dim.extend(w_shape_dims)

        if len(func.input) <= 2:
            out_c = fork_name("affine_bias")
            shape = (1, )
            raw_data = np.zeros(shape).astype(np.float32).tostring()
            self._add_param(out_c, TensorProto.FLOAT, shape, raw_data)
        else:
            bias_shape = list(self._var_dict[func.input[2]].dim[:])
            new_bias_shape = [np.prod(bias_shape)]
            proto_bias_shape = nnabla_pb2.Shape()
            proto_bias_shape.dim.extend(new_bias_shape)
            self._var_dict[func.input[2]] = proto_bias_shape
            out_c = func.input[2]

        out = fork_name(func.output[0])

        if opset == '6':
            # broadcast is needed.
            n = onnx.helper.make_node(
                "Gemm",
                [out_a, func.input[1], out_c],
                [out],
                alpha=1.0,
                beta=1.0,
                transA=0,
                transB=transB,
                broadcast=1,
                name='Gemm' + func.input[0])
        else:
            # broadcast cannot appear for opset > 6
            n = onnx.helper.make_node(
                "Gemm",
                [out_a, func.input[1], out_c],
                [out],
                alpha=1.0,
                beta=1.0,
                transA=0,
                transB=transB,
                name='Gemm' + func.input[0])
        nl.append(n)

        param_name = func.output[0] + '_shape'
        n = onnx.helper.make_node(
            "Reshape",
            [out, param_name],
            func.output,
            name='Reshape' + func.input[0])
        nl.append(n)

        output_shape = np.array(
            self._var_dict[func.output[0]].dim).astype(np.int64)
        self._add_param(param_name, TensorProto.INT64, list(
            output_shape.shape), output_shape.tostring())

        return nl