# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. """Relax script for attention module.""" import tvm from tvm.script import relax as R from tvm.script import tirx as T from tvm.script.ir_builder import IRBuilder from tvm.script.ir_builder import relax as relax_builder def get_relax_attention_module( q_shape, k_shape, v_shape, *, dtype, bias_shape=None, qk_scale=None, causal_mask=None, window_size=None, ): # pylint: disable=too-many-arguments, too-many-locals, invalid-name """Get a relax module for attention.""" if qk_scale is not None: qk_scale = T.FloatImm("float32", qk_scale) if window_size is not None: window_size = T.IntImm("int32", window_size) with IRBuilder() as builder: with relax_builder.function(): R.func_name("main") q = R.arg("q", R.Tensor(q_shape, dtype)) k = R.arg("k", R.Tensor(k_shape, dtype)) v = R.arg("v", R.Tensor(v_shape, dtype)) bias = None if bias_shape is not None and bias_shape != "none": bias = R.arg("bias", R.Tensor(bias_shape, dtype)) with R.dataflow() as frame: result = R.emit(R.nn.attention(q, k, v, bias, qk_scale, causal_mask, window_size)) R.output(result) R.func_ret_value(frame.output_vars[0]) func = builder.get() return tvm.IRModule({"main": func}) def get_relax_stacked_attention_module( qkv, b, s, n, h, h_v, op, bias=None, qk_scale=None, single_shape=False, layout="BS3NH", ): # pylint: disable=too-many-arguments, too-many-locals, too-many-branches, invalid-name # pylint: disable=too-many-statements """Get a relax module for stacked attention.""" dtype = str(qkv.dtype) assert layout in ["BS3NH", "SBN3H"] if qk_scale is not None: qk_scale = T.FloatImm("float32", qk_scale) if single_shape: if layout == "BS3NH": qk_shape = R.shape([b, s, n, h]) elif layout == "SBN3H": qk_shape = R.shape([b, s, n, h]) v_shape = qk_shape else: if layout == "BS3NH": qk_shape = [b, s, n, h] v_shape = [b, s, n, h_v] elif layout == "SBN3H": qk_shape = [s, b, n, h] v_shape = [s, b, n, h_v] if layout == "BS3NH": split_axis = 2 split_sections = [n * h, n * h * 2] elif layout == "SBN3H": split_axis = 3 split_sections = [h, h * 2] with IRBuilder() as builder: with relax_builder.function(): R.func_name("main") qkv = R.arg("qkv", R.Tensor(qkv.shape, dtype)) if bias is not None: bias = R.arg("bias", R.Tensor(bias.shape, dtype)) with R.dataflow() as frame: if op == "split": qkv_tuple = R.split(qkv, split_sections, axis=split_axis) q = qkv_tuple[0] k = qkv_tuple[1] v = qkv_tuple[2] elif op == "strided_slice": q = R.strided_slice(qkv, [split_axis], [0], [split_sections[0]], [1]) k = R.strided_slice( qkv, [split_axis], [split_sections[0]], [split_sections[1]], [1] ) v = R.strided_slice( qkv, [split_axis], [split_sections[1]], [int(qkv.ty.shape[split_axis])], [1], ) else: raise NotImplementedError() if layout == "BS3NH": q = R.reshape(q, qk_shape) k = R.reshape(k, qk_shape) v = R.reshape(v, v_shape) elif layout == "SBN3H": q = R.permute_dims(q, [1, 0, 2, 3]) k = R.permute_dims(k, [1, 0, 2, 3]) v = R.permute_dims(v, [1, 0, 2, 3]) result = R.emit(R.nn.attention(q, k, v, bias, qk_scale)) if layout == "SBN3H": result = R.emit(R.permute_dims(result, [1, 0, 2, 3])) R.output(result) R.func_ret_value(frame.output_vars[0]) func = builder.get() return tvm.IRModule({"main": func})