chore: import upstream snapshot with attribution
Lint / lint (push) Has been cancelled
CI / MacOS (push) Has been cancelled
CI / Windows (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:36:25 +08:00
commit 26446540fa
3151 changed files with 974126 additions and 0 deletions
@@ -0,0 +1,842 @@
# 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.
# ruff: noqa: E501, F401, F841
"""CLML integration operator tests."""
import json
import numpy as np
import pytest
import tvm
import tvm.testing
from tvm import relax, rpc
from tvm.relax.backend.adreno import clml
from tvm.script import ir as I
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_conv2d_mod(
data_shape,
weight_shape,
stride,
dilation,
padding,
weight_layout="OIHW",
groups=1,
dtype="float32",
has_bias=False,
has_bn=False,
has_activation=False,
has_pad=False,
is_depthwise=False,
):
with IRBuilder() as builder:
with relax_builder.function():
R.func_name("main")
if has_pad:
p = (0, 0, 0, 0, padding[0], padding[0], padding[1], padding[1])
orig_data = R.arg("data", R.Tensor(data_shape, dtype))
data = R.nn.pad(orig_data, pad_width=p, pad_value=0.0)
padding = (0, 0, 0, 0)
else:
data = R.arg("data", R.Tensor(data_shape, dtype))
weight = R.arg("weight", R.Tensor(weight_shape, dtype))
if has_bias:
bias = R.arg("bias", R.Tensor((1, weight_shape[0], 1, 1), dtype))
is_depthwise = data_shape[1] == weight_shape[0] == groups
with R.dataflow() as frame:
output = R.emit(
R.nn.conv2d(
data,
weight,
out_dtype=dtype,
strides=stride,
dilation=dilation,
padding=padding,
data_layout="NCHW",
kernel_layout=weight_layout,
groups=groups,
)
)
if has_bias:
output = R.emit(output + bias)
if has_bn:
gamma = R.arg("gamma", R.Tensor((weight_shape[0],), dtype))
beta = R.arg("beta", R.Tensor((weight_shape[0],), dtype))
mean = R.arg("mean", R.Tensor((weight_shape[0],), dtype))
variance = R.arg("variance", R.Tensor((weight_shape[0],), dtype))
output = R.emit(
R.nn.batch_norm(output, gamma, beta, mean, variance, axis=1, epsilon=1e-5)[
0
]
)
if has_activation:
output = R.emit(R.nn.relu(output))
R.output(output)
R.func_ret_value(frame.output_vars[0])
func = builder.get()
return tvm.IRModule({"main": func})
def get_clml_conv2d_codegen(
data_shape,
weight_shape,
stride,
dilation,
padding,
weight_layout="OIHW",
groups=1,
dtype="float32",
has_bias=False,
has_bn=False,
has_activation=False,
has_pad=False,
is_depthwise=False,
):
kernel_h, kernel_w = weight_shape[2], weight_shape[3]
channels = weight_shape[0]
if len(padding) == 2:
padding = (padding[0], padding[1], padding[0], padding[1])
output_height = ((data_shape[2] - kernel_h + padding[0] + padding[2]) / stride[0]) + 1
output_width = ((data_shape[3] - kernel_w + padding[1] + padding[3]) / stride[1]) + 1
output_shape = (1, channels, int(output_height), int(output_width))
out_dtype = dtype
is_depthwise = data_shape[1] == channels == groups
weight_layout = "IOHW" if is_depthwise else "OIHW"
if weight_layout == "OIHW":
weight_shape = (channels, data_shape[1] // groups, kernel_h, kernel_w)
else:
weight_shape = (data_shape[1] // groups, channels, kernel_h, kernel_w)
if is_depthwise:
name = "openclml.nn.depthwise_conv2d"
else:
name = "openclml.nn.conv2d"
node = {
"op": "kernel",
"name": "",
"inputs": [],
"attrs": {
"groups": groups,
"num_outputs": 1,
"data_layout": "NCHW",
"kernel_layout": weight_layout,
"dilation": dilation,
"out_layout": "NCHW",
"out_dtype": out_dtype,
"shape": [list(output_shape)],
"dtype": [dtype],
"padding": padding,
"strides": stride,
},
}
if has_activation:
node["attrs"]["activation_type"] = "relu"
nodes = [
{
"op": "input",
"name": "",
"attrs": {"shape": [list(data_shape)], "dtype": [str(dtype)]},
},
]
nodes.append(
{
"op": "const",
"name": "",
"attrs": {"shape": [list(weight_shape)], "dtype": [str(dtype)]},
}
)
if has_bias:
bias_dtype = dtype
nodes.append(
{
"op": "const",
"name": "",
"attrs": {
"shape": [[1, weight_shape[1] if is_depthwise else weight_shape[0], 1, 1]],
"dtype": [bias_dtype],
},
}
)
if has_bn:
bn_shape = [1, weight_shape[0], 1, 1]
# conv2d + bn --> conv2d + Add due to OptimizeBatchNorm transformation Pass
nodes.append(
{
"name": "",
"op": "const",
"attrs": {"dtype": [dtype], "shape": [[1, weight_shape[0], 1, 1]]},
},
)
input_idx = 0
for _ in range(len(nodes)):
node["inputs"].append([input_idx, 0, 0])
input_idx += 1
node["attrs"]["num_inputs"] = len(nodes)
nodes.append(node)
return nodes
def get_relax_conv2d_transpose_mod(
data_shape,
weight_shape,
channels,
stride,
padding,
dtype="float32",
):
with IRBuilder() as builder:
with relax_builder.function():
R.func_name("main")
data = R.arg("data", R.Tensor(data_shape, dtype))
weight = R.arg("weight", R.Tensor(weight_shape, dtype))
with R.dataflow() as frame:
output = R.emit(
R.nn.conv2d_transpose(
data,
weight,
groups=1,
strides=stride,
padding=padding,
kernel_layout="OIHW",
data_layout="NCHW",
)
)
R.output(output)
R.func_ret_value(frame.output_vars[0])
func = builder.get()
return tvm.IRModule({"main": func})
def get_conv2d_transpose_expected_codegen(
dshape, kshape, channels, kernel_size, strides, padding, dilation, dtype, output_shape
):
attrs = {
"data_layout": "NCHW",
"kernel_layout": "OIHW",
"groups": 1,
"dilation": dilation,
"num_inputs": 2,
"num_outputs": 1,
"padding": padding,
"shape": [list(output_shape)],
"dtype": [dtype],
"strides": strides,
"out_dtype": "",
"out_layout": "NCHW",
"output_padding": [0, 0],
}
exp_codegen = [
{
"op": "input",
"name": "",
"attrs": {"shape": [list(dshape)], "dtype": [str(dtype)]},
},
{
"op": "const",
"name": "",
"attrs": {"shape": [list(kshape)], "dtype": [str(dtype)]},
},
{
"op": "kernel",
"name": "",
"inputs": [[0, 0, 0], [1, 0, 0]],
"attrs": attrs,
},
]
return exp_codegen
def get_batchnorm_mod(data_shape, channels, axis, epsilon, dtype):
with IRBuilder() as builder:
with relax_builder.function():
R.func_name("main")
data = R.arg("data", R.Tensor(data_shape, dtype))
gamma = R.arg("gamma", R.Tensor((channels,), dtype))
beta = R.arg("beta", R.Tensor((channels,), dtype))
mean = R.arg("moving_mean", R.Tensor((channels,), dtype))
variance = R.arg("moving_var", R.Tensor((channels,), dtype))
with R.dataflow() as frame:
output = R.emit(
R.nn.batch_norm(data, gamma, beta, mean, variance, axis, epsilon)[0]
)
R.output(output)
R.func_ret_value(frame.output_vars[0])
func = builder.get()
return tvm.IRModule({"main": func})
def get_binary_op_mod(a_shape, b_shape, op, dtype):
with IRBuilder() as builder:
with relax_builder.function():
R.func_name("main")
a = R.arg("a", R.Tensor(a_shape, dtype))
b = R.arg("b", R.Tensor(b_shape, dtype))
with R.dataflow() as frame:
output = R.emit(op(a, b))
R.output(output)
R.func_ret_value(frame.output_vars[0])
func = builder.get()
low, high = 0, 1
a_data = np.random.uniform(low, high, size=(a_shape)).astype(dtype)
b_data = np.random.uniform(low, high, size=(b_shape)).astype(dtype)
return (tvm.IRModule({"main": func}), (a_data, b_data))
def get_unary_op_mod(a_shape, op, dtype):
with IRBuilder() as builder:
with relax_builder.function():
R.func_name("main")
a = R.arg("a", R.Tensor(a_shape, dtype))
with R.dataflow() as frame:
output = R.emit(op(a))
R.output(output)
R.func_ret_value(frame.output_vars[0])
func = builder.get()
low, high = 0, 1
a_data = np.random.uniform(low, high, size=(a_shape)).astype(dtype)
return (tvm.IRModule({"main": func}), (a_data,))
def get_relax_maxpool_mod(
data_shape, dtype, pool_size, stride=None, dilation=(1, 1), padding=(0, 0), has_pad=False
):
"""
Args:
data_shape (tuple): Input tensor shape
pool_size (tuple): Pooling window size (height, width)
stride (tuple, optional): Stride of pooling operation. Defaults to pool_size.
dilation (tuple, optional): Dilation rate. Defaults to (1, 1).
padding (tuple, optional): Padding for the input tensor. Defaults to (0, 0).
dtype (str, optional): Data type. Defaults to "float32".
has_pad (bool, optional): Whether to apply explicit padding. Defaults to False.
Returns:
tvm.IRModule: Relax MaxPool module
"""
with IRBuilder() as builder:
with relax_builder.function():
R.func_name("main")
if has_pad:
p = (0, 0, 0, 0, padding[0], padding[1], padding[0], padding[1])
orig_data = R.arg("data", R.Tensor(data_shape, dtype))
data = R.nn.pad(orig_data, pad_width=p, pad_value=float("-inf"))
padding = (0, 0)
else:
data = R.arg("data", R.Tensor(data_shape, dtype))
with R.dataflow() as frame:
output = R.emit(
R.nn.max_pool2d(
data,
pool_size=pool_size,
strides=stride,
dilation=dilation,
padding=padding,
layout="NCHW",
)
)
R.output(output)
R.func_ret_value(frame.output_vars[0])
func = builder.get()
return tvm.IRModule({"main": func})
def get_maxpool_expected_codegen(input_shape, pool_size, stride, padding, pool_type, dtype):
import math
adjusted_input_shape = [
input_shape[0],
input_shape[1],
input_shape[2] + padding[0] + padding[1],
input_shape[3] + padding[2] + padding[3],
]
pool_height = math.floor(((adjusted_input_shape[2] - pool_size[0]) / stride[0]) + 1)
pool_width = math.floor(((adjusted_input_shape[3] - pool_size[1]) / stride[1]) + 1)
output_shape = [adjusted_input_shape[0], adjusted_input_shape[1], pool_height, pool_width]
attrs = {
"ceil_mode": 0,
"dilation": [1, 1],
"layout": "NCHW",
"num_inputs": 1,
"num_outputs": 1,
"out_layout": "NCHW",
"padding": list(padding),
"pool_size": pool_size,
"shape": [list(output_shape)],
"dtype": [dtype],
"strides": stride,
"count_include_pad": 0,
}
if sum(padding):
attrs["count_include_pad"] = 0
exp_codegen = [
{
"op": "input",
"name": "",
"attrs": {"shape": [list(adjusted_input_shape)], "dtype": [str(dtype)]},
},
{
"op": "kernel",
"name": "",
"inputs": [[0, 0, 0]],
"attrs": attrs,
},
]
return exp_codegen
def get_relax_avgpool_mod(data_shape, dtype, pool_size, stride, dilation, padding, has_pad):
"""
Args:
data_shape (tuple): Input tensor shape
pool_size (tuple): Pooling window size (height, width)
stride (tuple, optional): Stride of pooling operation. Defaults to pool_size.
dilation (tuple, optional): Dilation rate. Defaults to (1, 1).
padding (tuple, optional): Padding for the input tensor. Defaults to (0, 0).
dtype (str, optional): Data type. Defaults to "float32".
has_pad (bool, optional): Whether to apply explicit padding. Defaults to False.
count_include_pad (bool, optional): Whether to include padding in averaging. Defaults to True.
Returns:
tvm.IRModule: Relax AvgPool module
"""
with IRBuilder() as builder:
with relax_builder.function():
R.func_name("main")
if has_pad:
p = (0, 0, 0, 0, padding[0], padding[1], padding[0], padding[1])
orig_data = R.arg("data", R.Tensor(data_shape, dtype))
data = R.nn.pad(orig_data, pad_width=p, pad_value=0.0)
padding = (0, 0)
else:
data = R.arg("data", R.Tensor(data_shape, dtype))
with R.dataflow() as frame:
output = R.emit(
R.nn.avg_pool2d(
data,
pool_size=pool_size,
strides=stride,
dilation=dilation,
padding=padding,
layout="NCHW",
)
)
R.output(output)
R.func_ret_value(frame.output_vars[0])
func = builder.get()
return tvm.IRModule({"main": func})
def get_avgpool_expected_codegen(input_shape, pool_size, stride, padding, pool_type, dtype):
import math
adjusted_input_shape = [
input_shape[0],
input_shape[1],
input_shape[2] + padding[0] + padding[1],
input_shape[3] + padding[2] + padding[3],
]
pool_height = math.floor(((adjusted_input_shape[2] - pool_size[0]) / stride[0]) + 1)
pool_width = math.floor(((adjusted_input_shape[3] - pool_size[1]) / stride[1]) + 1)
output_shape = [adjusted_input_shape[0], adjusted_input_shape[1], pool_height, pool_width]
attrs = {
"ceil_mode": 0,
"dilation": [1, 1],
"layout": "NCHW",
"num_inputs": 1,
"num_outputs": 1,
"out_layout": "NCHW",
"padding": list(padding),
"pool_size": pool_size,
"shape": [list(output_shape)],
"dtype": [dtype],
"strides": stride,
"count_include_pad": 0,
}
if sum(padding):
attrs["count_include_pad"] = 0
exp_codegen = [
{
"op": "input",
"name": "",
"attrs": {"shape": [list(adjusted_input_shape)], "dtype": [str(dtype)]},
},
{
"op": "kernel",
"name": "",
"inputs": [[0, 0, 0]],
"attrs": attrs,
},
]
return exp_codegen
def get_relax_reshape_mod(input_shape, output_shape, dtype):
"""
Args:
input_shape (tuple): Input tensor shape
output_shape (tuple): Desired output tensor shape
dtype (str, optional): Data type. Defaults to "float32".
Returns:
tvm.IRModule: Relax Reshape module
"""
with IRBuilder() as builder:
with relax_builder.function():
R.func_name("main")
data = R.arg("data", R.Tensor(input_shape, dtype))
with R.dataflow() as frame:
output = R.emit(R.reshape(data, output_shape))
R.output(output)
R.func_ret_value(frame.output_vars[0])
func = builder.get()
return tvm.IRModule({"main": func})
def get_relax_reshape_codegen(input_shape, output_shape, dtype):
def compute_output_shape(input_shape, output_shape):
input_elements = np.prod(input_shape)
specified_elements = np.prod([dim for dim in output_shape if dim != -1])
missing_dim = input_elements // specified_elements
return [int(dim) if dim != -1 else int(missing_dim) for dim in output_shape]
expected_output_shape = compute_output_shape(input_shape, output_shape)
expected_codegen_str = [
{
"attrs": {
"dtype": [dtype],
"shape": [list(input_shape)],
},
"name": "",
"op": "input",
},
{
"attrs": {
"dtype": [dtype],
"num_inputs": 1,
"num_outputs": 1,
"shape": [expected_output_shape],
},
"inputs": [[0, 0, 0]],
"name": "",
"op": "kernel",
},
]
return expected_codegen_str
def get_relax_global_avgpool_mod(data_shape, keepdims, dtype):
"""
Create a Relax module for Global Average Pooling (GAP).
Args:
data_shape (tuple): Input tensor shape (N, C, H, W)
dtype (str): Data type
Returns:
tvm.IRModule: Relax GAP module
"""
with IRBuilder() as builder:
with relax_builder.function():
R.func_name("main")
data = R.arg("data", R.Tensor(data_shape, dtype))
with R.dataflow() as frame:
output = R.emit(R.mean(data, axis=[2, 3], keepdims=keepdims))
R.output(output)
R.func_ret_value(frame.output_vars[0])
func = builder.get()
return tvm.IRModule({"main": func})
def get_global_avgpool_expected_codegen(input_shape, keep_dims, dtype):
"""
Generate expected codegen for Global Average Pooling.
Args:
input_shape (tuple): Input shape (N, C, H, W)
dtype (str): Data type
Returns:
dict: Expected codegen output
"""
output_shape = (
[input_shape[0], input_shape[1]]
if not keep_dims
else [input_shape[0], input_shape[1], 1, 1]
)
attrs = {
"num_inputs": 1,
"num_outputs": 1,
"shape": [list(output_shape)],
"dtype": [dtype],
"axis": [2, 3],
"keepdims": 1 if keep_dims else 0,
}
exp_codegen = [
{
"op": "input",
"name": "",
"attrs": {"shape": [list(input_shape)], "dtype": [str(dtype)]},
},
{"op": "kernel", "name": "", "inputs": [[0, 0, 0]], "attrs": attrs},
]
return exp_codegen
def get_relax_global_maxpool_mod(data_shape, keepdims, dtype):
"""
Create a Relax module for Global Average Pooling (GAP).
Args:
data_shape (tuple): Input tensor shape (N, C, H, W)
dtype (str): Data type
Returns:
tvm.IRModule: Relax GAP module
"""
N, C, H, W = data_shape
with IRBuilder() as builder:
with relax_builder.function():
R.func_name("main")
data = R.arg("data", R.Tensor(data_shape, dtype))
with R.dataflow() as frame:
output = R.emit(
R.nn.max_pool2d(
data, pool_size=(H, W), strides=(1, 1), padding=(0, 0), layout="NCHW"
)
)
R.output(output)
R.func_ret_value(frame.output_vars[0])
func = builder.get()
return tvm.IRModule({"main": func})
def get_global_maxpool_expected_codegen(input_shape, pool_size, stride, padding, pool_type, dtype):
import math
adjusted_input_shape = [
input_shape[0],
input_shape[1],
input_shape[2] + padding[0] + padding[1],
input_shape[3] + padding[2] + padding[3],
]
output_shape = [adjusted_input_shape[0], adjusted_input_shape[1], 1, 1]
attrs = {
"ceil_mode": 0,
"dilation": [1, 1],
"layout": "NCHW",
"num_inputs": 1,
"num_outputs": 1,
"out_layout": "NCHW",
"padding": padding,
"pool_size": pool_size,
"shape": [list(output_shape)],
"dtype": [dtype],
"strides": stride,
"count_include_pad": 0,
}
if sum(padding):
attrs["count_include_pad"] = 0
exp_codegen = [
{
"op": "input",
"name": "",
"attrs": {"shape": [list(adjusted_input_shape)], "dtype": [str(dtype)]},
},
{
"op": "kernel",
"name": "",
"inputs": [[0, 0, 0]],
"attrs": attrs,
},
]
return exp_codegen
def get_dequant_matmul_module(K, N):
@I.ir_module(s_tir=True)
class DequantMatmul:
@R.function
def main(
input: R.Tensor((1, "seq_len", K), dtype="float16"),
weight: R.Tensor((K // 8, N), dtype="uint32"),
scale: R.Tensor((K // 32, N), dtype="float16"),
):
seq_len = T.int64()
cls = DequantMatmul
with R.dataflow():
lv2 = relax.call_tir(
cls.dequantize,
(weight, scale),
out_ty=R.Tensor((K, N), dtype="float16"),
)
gv: R.Tensor((1, seq_len, N), dtype="float16") = relax.op.matmul(
input, lv2, out_dtype="float16"
)
R.output(gv)
return gv
@T.prim_func(s_tir=True)
def dequantize(weight: T.handle, scale: T.handle, var_dequantize: T.handle):
T.func_attr({"tirx.noalias": T.bool(True)})
lm_head_q_weight1 = T.match_buffer(weight, (T.int64(K // 8), T.int64(N)), "uint32")
lm_head_q_scale1 = T.match_buffer(scale, (T.int64(K // 32), T.int64(N)), "float16")
dequantize = T.match_buffer(var_dequantize, (T.int64(K), T.int64(N)), "float16")
# with T.sblock("root"):
compute = T.alloc_buffer((T.int64(K), T.int64(N)), "float16")
for i0, i1 in T.grid(T.int64(K), T.int64(N)):
with T.sblock("compute"):
v_i0, v_i1 = T.axis.remap("SS", [i0, i1])
T.reads(lm_head_q_weight1[v_i0 // T.int64(8), v_i1])
T.writes(compute[v_i0, v_i1])
compute[v_i0, v_i1] = T.Cast(
"float16",
T.bitwise_and(
T.shift_right(
lm_head_q_weight1[v_i0 // T.int64(8), v_i1],
T.Cast("uint32", v_i0 % T.int64(8) * T.int64(4)),
),
T.uint32(15),
),
)
for i0, i1 in T.grid(T.int64(K), T.int64(N)):
with T.sblock("dequantize"):
v_i0, v_i1 = T.axis.remap("SS", [i0, i1])
T.reads(compute[v_i0, v_i1], lm_head_q_scale1[v_i0 // T.int64(32), v_i1])
T.writes(dequantize[v_i0, v_i1])
dequantize[v_i0, v_i1] = (
compute[v_i0, v_i1] - T.float16(7.0)
) * lm_head_q_scale1[v_i0 // T.int64(32), v_i1]
return DequantMatmul
def get_dequant_vec_matmul_module(K, N):
@I.ir_module(s_tir=True)
class DequantVecMatmul:
@R.function
def main(
input: R.Tensor((1, 1, K), dtype="float16"),
weight: R.Tensor((K // 8, "vocab_size"), dtype="uint32"),
scale: R.Tensor((K // 32, "vocab_size"), dtype="float16"),
):
vocab_size = T.int64()
cls = DequantVecMatmul
with R.dataflow():
lv2 = relax.call_tir(
cls.dequantize,
(weight, scale),
out_ty=R.Tensor((K, vocab_size), dtype="float16"),
)
gv: R.Tensor((1, 1, vocab_size), dtype="float16") = relax.op.matmul(
input, lv2, out_dtype="float16"
)
R.output(gv)
return gv
@T.prim_func(s_tir=True)
def dequantize(weight: T.handle, scale: T.handle, var_dequantize: T.handle):
T.func_attr({"tirx.noalias": T.bool(True)})
vocab_size = T.int64()
lm_head_q_weight1 = T.match_buffer(weight, (T.int64(K // 8), vocab_size), "uint32")
lm_head_q_scale1 = T.match_buffer(scale, (T.int64(K // 32), vocab_size), "float16")
dequantize = T.match_buffer(var_dequantize, (T.int64(K), vocab_size), "float16")
# with T.sblock("root"):
compute = T.alloc_buffer((T.int64(K), vocab_size), "float16")
for i0, i1 in T.grid(T.int64(K), vocab_size):
with T.sblock("compute"):
v_i0, v_i1 = T.axis.remap("SS", [i0, i1])
T.reads(lm_head_q_weight1[v_i0 // T.int64(8), v_i1])
T.writes(compute[v_i0, v_i1])
compute[v_i0, v_i1] = T.Cast(
"float16",
T.bitwise_and(
T.shift_right(
lm_head_q_weight1[v_i0 // T.int64(8), v_i1],
T.Cast("uint32", v_i0 % T.int64(8) * T.int64(4)),
),
T.uint32(15),
),
)
for i0, i1 in T.grid(T.int64(K), vocab_size):
with T.sblock("dequantize"):
v_i0, v_i1 = T.axis.remap("SS", [i0, i1])
T.reads(compute[v_i0, v_i1], lm_head_q_scale1[v_i0 // T.int64(32), v_i1])
T.writes(dequantize[v_i0, v_i1])
dequantize[v_i0, v_i1] = (
compute[v_i0, v_i1] - T.float16(7.0)
) * lm_head_q_scale1[v_i0 // T.int64(32), v_i1]
return DequantVecMatmul
@@ -0,0 +1,675 @@
# 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.
# ruff: noqa: E501, F401, F841
"""CLML integration operator tests."""
import inspect
import json
import os
import numpy as np
import pytest
from mod_utils import (
get_avgpool_expected_codegen,
get_batchnorm_mod,
get_binary_op_mod,
get_clml_conv2d_codegen,
get_conv2d_transpose_expected_codegen,
get_dequant_matmul_module,
get_dequant_vec_matmul_module,
get_global_avgpool_expected_codegen,
get_global_maxpool_expected_codegen,
get_maxpool_expected_codegen,
get_relax_avgpool_mod,
get_relax_conv2d_mod,
get_relax_conv2d_transpose_mod,
get_relax_global_avgpool_mod,
get_relax_global_maxpool_mod,
get_relax_maxpool_mod,
get_relax_reshape_codegen,
get_relax_reshape_mod,
get_unary_op_mod,
)
from utils import skip_unless_adreno_clml, verify_results
import tvm
import tvm.testing
from tvm import relax, rpc
from tvm.relax.backend.adreno import clml
from tvm.relax.backend.adreno.clml import OpenCLMLOffLoad, OpenCLMLOffLoadForLLM
from tvm.script import ir as I
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
CLML_VERSION = clml.clml_sdk_version()
TARGET_CLML_VERSION = int(os.environ.get("ADRENO_TARGET_CLML_VERSION", 4))
clml_target = tvm.target.Target("qcom/adreno-opencl-clml")
ref_target = tvm.target.Target("opencl")
def verify_clml_codegen(clml_mod, clml_codegen):
clml_mod = OpenCLMLOffLoadForLLM(clml_target)(clml_mod)
clml_mod = OpenCLMLOffLoad()(clml_mod)
source = clml_mod.attrs["external_mods"][0].inspect_source()
codegen = json.loads(source)["nodes"]
for node in range(len(codegen)):
if codegen[node]["op"] == "input" or codegen[node]["op"] == "const":
codegen[node]["name"] = ""
if codegen[node]["op"] == "kernel":
codegen[node]["name"] = ""
codegen_str = json.dumps(codegen, sort_keys=True, indent=2)
known_good_codegen_str = json.dumps(clml_codegen, sort_keys=True, indent=2)
assert codegen_str == known_good_codegen_str, (
f"The JSON produced by codegen does not match the expected result. \n"
f"Actual={codegen_str} \n"
f"Expected={known_good_codegen_str}"
)
def verify(
mod, clml_codegen, inputs_np, params_np, target_minimum_clml_version=None, target_test=True
):
mod = tvm.relax.transform.BindParams("main", params_np)(mod)
codegen_mod, clml_mod = mod.clone(), mod
verify_clml_codegen(codegen_mod, clml_codegen)
if (
target_minimum_clml_version is not None
and TARGET_CLML_VERSION < target_minimum_clml_version
):
print(f"Skipped Eval Tests for {inspect.stack()[1].function} function", flush=True)
return
if "ADRENO_TARGET" not in os.environ:
return
if target_test:
verify_results(clml_mod, target=clml_target, ref_target=ref_target)
@pytest.mark.gpu
@skip_unless_adreno_clml
@pytest.mark.parametrize("dtype", ["float32"])
@pytest.mark.parametrize(
"kernel_h, kernel_w, padding, stride, dilation, out_channels, shape, has_bias, has_bn, has_activation, has_pad, is_depthwise",
[
(3, 3, (1, 1), (1, 1), (1, 1), 64, (3, 224, 224), False, True, False, True, False),
(3, 3, (1, 1), (1, 1), (1, 1), 64, (3, 224, 224), False, True, False, False, False),
# (5, 5, (2, 2), (1, 1), (1, 1), 16, (16, 64, 64), False, True, True, False, False),
# (7, 7, (3, 3), (2, 2), (1, 1), 32, (3, 224, 224), True, False, True, True, False),
(3, 3, (0, 0), (1, 1), (1, 1), 512, (256, 14, 14), True, False, True, False, False),
(1, 1, (0, 0), (1, 1), (1, 1), 1024, (512, 7, 7), True, False, True, False, False),
(1, 3, (0, 0), (1, 1), (1, 1), 64, (64, 7, 7), True, False, True, False, False),
(3, 1, (0, 0), (1, 1), (1, 1), 64, (64, 7, 7), False, True, True, True, False),
],
)
def test_conv2d_offload(
kernel_h,
kernel_w,
padding,
stride,
dilation,
out_channels,
shape,
has_bias,
has_bn,
has_activation,
has_pad,
is_depthwise,
dtype,
):
low, high = -0.01, 0.01
rtol, atol = 1e-3, 1e-3
if CLML_VERSION > 3:
rtol, atol = 1e-2, 1e-2 # @clml precision
data_shape = (1, *shape)
if is_depthwise:
groups = data_shape[1] // out_channels
else:
groups = 1
padding = (padding[0], padding[1], padding[0], padding[1])
weight_format = "IOHW" if is_depthwise else "OIHW"
weight_shape = (out_channels, data_shape[1] // groups, kernel_h, kernel_w)
data = np.random.uniform(low, high, size=data_shape).astype(dtype)
weight = np.random.uniform(low, high, size=weight_shape).astype(dtype)
bias = np.random.uniform(low, high, size=(1, weight_shape[0], 1, 1)).astype(dtype)
gamma = np.random.uniform(low, high, size=(weight_shape[0],)).astype(dtype)
beta = np.random.uniform(low, high, size=(weight_shape[0],)).astype(dtype)
mean = np.random.uniform(low, high, size=(weight_shape[0],)).astype(dtype)
variance = np.random.uniform(low, high, size=(weight_shape[0],)).astype(dtype)
inputs_np = [data]
params_np = {"weight": weight}
if has_bias:
params_np["bias"] = bias
if has_bn:
params_np.update({"gamma": gamma, "beta": beta, "mean": mean, "variance": variance})
mod = get_relax_conv2d_mod(
data_shape,
weight_shape,
stride=stride,
dilation=dilation,
padding=padding,
weight_layout=weight_format,
groups=groups,
dtype=dtype,
has_bias=has_bias,
has_bn=has_bn,
has_activation=has_activation,
has_pad=has_pad,
is_depthwise=is_depthwise,
)
clml_codegen = get_clml_conv2d_codegen(
data_shape,
weight_shape,
stride=stride,
dilation=dilation,
padding=padding,
weight_layout=weight_format,
groups=groups,
dtype=dtype,
has_bias=has_bias,
has_bn=has_bn,
has_activation=has_activation,
has_pad=has_pad,
is_depthwise=is_depthwise,
)
verify(mod, clml_codegen, inputs_np, params_np)
@pytest.mark.gpu
@skip_unless_adreno_clml
@pytest.mark.parametrize("dtype", ["float32"])
@pytest.mark.parametrize(
"dshape, kshape, channels, kernel_size, strides, padding, out_shape",
[
((1, 256, 100, 100), (64, 256, 4, 4), 64, (4, 4), (2, 2), (0, 0, 0, 0), (1, 64, 202, 202)),
((1, 64, 200, 200), (64, 64, 4, 4), 64, (4, 4), (2, 2), (1, 1, 1, 1), (1, 64, 400, 400)),
((1, 64, 200, 200), (64, 64, 4, 4), 64, (4, 4), (2, 2), (1, 1, 1, 1), (1, 64, 400, 400)),
((1, 64, 400, 400), (16, 64, 4, 4), 16, (4, 4), (2, 2), (1, 1, 1, 1), (1, 16, 800, 800)),
],
)
def test_conv2d_transpose(
dshape, kshape, channels, kernel_size, strides, padding, dtype, out_shape
):
low, high = -1, 1
data = np.random.uniform(low, high, size=dshape).astype(dtype)
weight = np.random.uniform(low, high, size=kshape).astype(dtype)
inputs_np = [data]
params_np = {"weight": weight}
mod = get_relax_conv2d_transpose_mod(
dshape,
kshape,
channels=channels,
stride=strides,
padding=padding,
dtype=dtype,
)
clml_codegen = get_conv2d_transpose_expected_codegen(
dshape=dshape,
kshape=kshape,
channels=channels,
kernel_size=kernel_size,
strides=strides,
padding=padding,
dilation=(1, 1),
dtype=dtype,
output_shape=out_shape,
)
verify(mod, clml_codegen, inputs_np, params_np, target_test=False)
@pytest.mark.gpu
@skip_unless_adreno_clml
@pytest.mark.skipif(
CLML_VERSION < 3,
reason="Requires compiler supporting CLML v5 or above",
)
@pytest.mark.parametrize("dtype", ["float32"])
@pytest.mark.parametrize(
"trials",
[
[(1, 64, 14, 14), 1, 3e-4],
[(1, 14, 256, 256), 1, 3e-4],
[(1, 14, 256, 256), 1, 3e-4],
[(1, 256, 1, 1), 1, 3e-4],
],
)
def test_batchnorm(dtype, trials):
low, high = 0, 1
(input_shape, axis, epsilon) = trials
channels = input_shape[axis]
def _get_axis_tuple(axis):
if axis == 0:
return (1, 2, 3)
elif axis == 1:
return (0, 2, 3)
elif axis == 2:
return (0, 1, 3)
else:
return (0, 1, 2)
data = np.random.uniform(low, high, size=(input_shape)).astype(dtype)
gamma = np.random.uniform(low, high, size=(channels)).astype(dtype)
beta = np.random.uniform(low, high, size=(channels)).astype(dtype)
mean = np.mean(data, _get_axis_tuple(axis), keepdims=False)
variance = np.var(data, _get_axis_tuple(axis), keepdims=False)
inputs_np = [data]
params_np = {"gamma": gamma, "beta": beta, "moving_mean": mean, "moving_var": variance}
mod = get_batchnorm_mod(input_shape, channels, axis, epsilon, dtype)
clml_codegen = [
{
"attrs": {"dtype": [dtype], "shape": [input_shape]},
"name": "",
"op": "input",
},
{"attrs": {"dtype": [dtype], "shape": [[channels]]}, "name": "", "op": "const"},
{"attrs": {"dtype": [dtype], "shape": [[channels]]}, "name": "", "op": "const"},
{"attrs": {"dtype": [dtype], "shape": [[channels]]}, "name": "", "op": "const"},
{"attrs": {"dtype": [dtype], "shape": [[channels]]}, "name": "", "op": "const"},
{
"attrs": {
"axis": axis,
"center": 1,
"dtype": [dtype],
"momentum": 0.10000000000000001,
"epsilon": 0.00029999999999999997,
"num_inputs": 5,
"num_outputs": 1,
"scale": 1,
"training": 1,
"shape": [input_shape],
},
"inputs": [[0, 0, 0], [1, 0, 0], [2, 0, 0], [3, 0, 0], [4, 0, 0]],
"name": "",
"op": "kernel",
},
]
verify(mod, clml_codegen, inputs_np, params_np)
@pytest.mark.gpu
@skip_unless_adreno_clml
@pytest.mark.parametrize("dtype", ["float32"])
@pytest.mark.parametrize(
"a_shape, b_shape, op",
[
((1, 64, 14, 14), (1, 64, 14, 14), R.add),
((1, 256), (1, 256), R.add),
((1, 64, 14, 14), (1, 64, 14, 14), R.subtract),
((1, 256), (1, 256), R.subtract),
((1, 64, 14, 14), (1, 64, 14, 14), R.multiply),
((1, 256), (1, 256), R.multiply),
((1, 64, 14, 14), (1, 64, 14, 14), R.divide),
((1, 256), (1, 256), R.divide),
((1, 64, 14, 14), (1, 64, 14, 14), R.minimum),
((1, 256), (1, 256), R.minimum),
((1, 64, 14, 14), (1, 64, 14, 14), R.maximum),
((1, 256), (1, 256), R.maximum),
],
)
@pytest.mark.gpu
@skip_unless_adreno_clml
def test_binary_ops(a_shape, b_shape, op, dtype):
(mod, inputs_np) = get_binary_op_mod(a_shape, b_shape, op, dtype)
clml_codegen = [
{
"attrs": {
"dtype": [dtype],
"shape": [a_shape],
},
"name": "",
"op": "input",
},
{
"attrs": {
"dtype": [dtype],
"shape": [b_shape],
},
"name": "",
"op": "input",
},
{
"attrs": {
"dtype": [dtype],
"num_inputs": 2,
"num_outputs": 1,
"shape": [a_shape],
},
"inputs": [[0, 0, 0], [1, 0, 0]],
"name": "",
"op": "kernel",
},
]
verify(mod, clml_codegen, inputs_np, {})
@pytest.mark.gpu
@skip_unless_adreno_clml
@pytest.mark.parametrize(
"dtype",
[
"float32",
],
)
@pytest.mark.parametrize(
"a_shape, op",
[
((1, 64, 14, 14), R.nn.relu),
((1, 256, 1, 1), R.nn.relu),
((1, 14, 256, 256), R.nn.relu),
((1, 14, 14, 256), R.nn.relu),
],
)
@pytest.mark.gpu
@skip_unless_adreno_clml
def test_unary_ops(a_shape, op, dtype):
(mod, inputs_np) = get_unary_op_mod(a_shape, op, dtype)
clml_codegen = [
{
"attrs": {
"dtype": [dtype],
"shape": [a_shape],
},
"name": "",
"op": "input",
},
{
"attrs": {
"activation_type": "relu",
"dtype": [dtype],
"num_inputs": 1,
"num_outputs": 1,
"shape": [a_shape],
},
"inputs": [[0, 0, 0]],
"name": "",
"op": "kernel",
},
]
verify(mod, clml_codegen, inputs_np, {})
@pytest.mark.gpu
@skip_unless_adreno_clml
@pytest.mark.parametrize("dtype", ["float32"])
@pytest.mark.parametrize(
"trials",
[
[(1, 64, 147, 147), (3, 3), (2, 2), (1, 1), (0, 0, 0, 0), False],
[(1, 256, 17, 17), (3, 3), (1, 1), (1, 1), (0, 0, 0, 0), False],
[(1, 1024, 14, 14), (3, 3), (1, 1), (1, 1), (0, 0, 0, 0), False],
# With padding is realized as nn.pad + pool
# [(1, 32, 256, 256), (3, 3), (2, 2), (1, 1), (1, 1, 1, 1), True],
# [(1, 32, 256, 256), (3, 3), (2, 2), (1, 1), (0, 1, 0, 1), True],
# [(1, 32, 256, 256), (2, 2), (2, 2), (1, 1), (1, 1, 1, 1), True],
# [(1, 32, 256, 256), (2, 2), (2, 2), (1, 1), (1, 0, 1, 0), True],
],
)
def test_max_pool(dtype, trials):
low, high = -1, 1
(input_shape, pool_size, stride, dilation, padding, has_pad) = trials
mod = get_relax_maxpool_mod(input_shape, dtype, pool_size, stride, dilation, padding, has_pad)
clml_codegen = get_maxpool_expected_codegen(
input_shape, pool_size, stride, padding, "maxpool2d", dtype
)
inputs_np = [np.random.uniform(low, high, size=input_shape).astype(dtype)]
verify(mod, clml_codegen, inputs_np, {})
@pytest.mark.gpu
@skip_unless_adreno_clml
@pytest.mark.parametrize("dtype", ["float32"])
@pytest.mark.parametrize(
"trials",
[
[(1, 64, 147, 147), (3, 3), (2, 2), (1, 1), (0, 0, 0, 0), False],
[(1, 256, 17, 17), (3, 3), (1, 1), (1, 1), (0, 0, 0, 0), False],
[(1, 1024, 14, 14), (3, 3), (1, 1), (1, 1), (0, 0, 0, 0), False],
# With padding is realized as nn.pad + pool
# [(1, 32, 256, 256), (3, 3), (2, 2), (1, 1), (1, 1, 1, 1), True],
# [(1, 32, 256, 256), (3, 3), (2, 2), (1, 1), (0, 1, 0, 1), True],
# [(1, 32, 256, 256), (2, 2), (2, 2), (1, 1), (1, 1, 1, 1), True],
# [(1, 32, 256, 256), (2, 2), (2, 2), (1, 1), (1, 0, 1, 0), True],
],
)
def test_avg_pool(dtype, trials):
low, high = -1, 1
(input_shape, pool_size, stride, dilation, padding, has_pad) = trials
mod = get_relax_avgpool_mod(input_shape, dtype, pool_size, stride, dilation, padding, has_pad)
clml_codegen = get_avgpool_expected_codegen(
input_shape, pool_size, stride, padding, "avg_pool2d", dtype
)
inputs_np = [np.random.uniform(low, high, size=input_shape).astype(dtype)]
params_np = {}
verify(mod, clml_codegen, inputs_np, {})
@pytest.mark.gpu
@skip_unless_adreno_clml
@pytest.mark.parametrize("dtype", ["float32"])
@pytest.mark.parametrize(
"trials",
[
[(1, 3, 32, 32), (1, 4, -1, 32)],
[(1, 4, 8, 32), (1, 4, -1, 16)],
[(1, 64, 3, 3), (1, 32, 3, -1)],
],
)
def test_reshape(dtype, trials):
low, high = -1, 1
(input_shape, output_shape) = trials
mod = get_relax_reshape_mod(input_shape, output_shape, dtype)
clml_codegen = get_relax_reshape_codegen(input_shape, output_shape, dtype)
inputs_np = [np.random.uniform(low, high, size=input_shape).astype(dtype)]
verify(mod, clml_codegen, inputs_np, {})
@pytest.mark.skip(reason="Codegen Comparision Failing")
@pytest.mark.gpu
@skip_unless_adreno_clml
@pytest.mark.parametrize("dtype", ["float32"])
@pytest.mark.parametrize(
"trials",
[
[(1, 64, 147, 147), True],
[(1, 256, 17, 17), False],
[(1, 1024, 14, 14), True],
[(1, 32, 256, 256), False],
],
)
def test_global_avg_pool(dtype, trials):
"""Test function for global average pooling."""
low, high = -1, 1
(input_shape, keep_dims) = trials
N, C, H, W = input_shape
pool_size, stride, padding = (H, W), (1, 1), (0, 0, 0, 0)
mod = get_relax_global_avgpool_mod(input_shape, keep_dims, dtype)
clml_codegen = get_global_maxpool_expected_codegen(
input_shape, pool_size, stride, padding, "global_max", dtype
)
inputs_np = [np.random.uniform(low, high, size=input_shape).astype(dtype)]
verify(mod, clml_codegen, inputs_np, {})
@pytest.mark.gpu
@skip_unless_adreno_clml
@pytest.mark.parametrize("dtype", ["float32"])
@pytest.mark.parametrize(
"trials",
[
[(1, 64, 147, 147), True],
[(1, 256, 17, 17), False],
[(1, 1024, 14, 14), True],
[(1, 32, 256, 256), False],
],
)
def test_global_max_pool(dtype, trials):
"""Test function for global average pooling."""
low, high = -1, 1
(input_shape, keep_dims) = trials
N, C, H, W = input_shape
pool_size, stride, padding = (H, W), (1, 1), (0, 0, 0, 0)
mod = get_relax_global_maxpool_mod(input_shape, keep_dims, dtype)
clml_codegen = get_global_maxpool_expected_codegen(
input_shape, pool_size, stride, padding, "global_max", dtype
)
inputs_np = [np.random.uniform(low, high, size=input_shape).astype(dtype)]
verify(mod, clml_codegen, inputs_np, {})
@pytest.mark.skipif(
CLML_VERSION < 5,
reason="Requires target device with CLML v5 or above",
)
@pytest.mark.parametrize(
"K, N, M",
[
(4096, 11008, 256),
(2048, 32768, 128),
(4096, 4096, 512),
(4096, 22016, 64),
(16384, 2048, 128),
(2048, 2560, 1024),
(3072, 9216, 256),
(14336, 4096, 128),
(1536, 17920, 128),
(8960, 1536, 1024),
],
)
def test_dequant_matmul(K, N, M):
x_data = np.random.uniform(-0.1, 0.1, size=(1, M, K)).astype("float16")
weight = np.random.randint(0, 100, size=(K // 8, N)).astype("uint32")
scale = np.random.uniform(-0.1, 0.1, size=(K // 32, N)).astype("float16")
mod = get_dequant_matmul_module(K, N)
clml_codegen = [
{
"op": "input",
"name": "",
"attrs": {"shape": [[[K // 8, N]]], "dtype": [["uint32"]]},
},
{
"op": "input",
"name": "",
"attrs": {"shape": [[[K // 32, N]]], "dtype": [["float16"]]},
},
{
"op": "input",
"name": "",
"attrs": {"shape": [[[1, -1, K]]], "dtype": [["float16"]]},
},
{
"op": "kernel",
"name": "",
"inputs": [[0, 0, 0], [1, 0, 0], [2, 0, 0]],
"attrs": {
"dtype": ["float16"],
"num_inputs": 3,
"num_outputs": 1,
"out_dtype": ["float16"],
"shape": [[1, -1, N]],
},
},
]
inputs_np = [x_data, weight, scale]
verify(mod, clml_codegen, inputs_np, {}, target_minimum_clml_version=5)
@pytest.mark.skipif(
CLML_VERSION < 5,
reason="Requires compiler supporting CLML v5 or above",
)
@pytest.mark.parametrize(
"K, N",
[
(4096, 11008),
(2048, 32768),
(4096, 4096),
(4096, 22016),
(16384, 2048),
(2048, 2560),
(3072, 9216),
(4096, 28672),
(14336, 4096),
(1536, 17920),
(8960, 1536),
],
)
def test_dequant_vec_matmul(K, N):
x_data = np.random.uniform(-0.1, 0.1, size=(1, 1, K)).astype("float16")
weight = np.random.randint(0, 100, size=(K // 8, N)).astype("uint32")
scale = np.random.uniform(-0.1, 0.1, size=(K // 32, N)).astype("float16")
mod = get_dequant_vec_matmul_module(K, N)
clml_codegen = [
{
"op": "input",
"name": "",
"attrs": {"shape": [[[K // 8, -1]]], "dtype": [["uint32"]]},
},
{
"op": "input",
"name": "",
"attrs": {"shape": [[[K // 32, -1]]], "dtype": [["float16"]]},
},
{
"op": "input",
"name": "",
"attrs": {"shape": [[[1, 1, K]]], "dtype": [["float16"]]},
},
{
"op": "kernel",
"name": "",
"inputs": [[0, 0, 0], [1, 0, 0], [2, 0, 0]],
"attrs": {
"dtype": ["float16"],
"num_inputs": 3,
"num_outputs": 1,
"out_dtype": ["float16"],
"shape": [[1, 1, -1]],
},
},
]
inputs_np = (x_data, weight, scale)
verify(mod, clml_codegen, inputs_np, {}, target_minimum_clml_version=5)
if __name__ == "__main__":
tvm.testing.main()
@@ -0,0 +1,789 @@
# 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.
# ruff: noqa: F401, F841
import copy
import json
import numpy as np
import pytest
pytest.importorskip("onnx")
import onnx
from utils import verify_results
import tvm
import tvm.testing
from tvm import relax
from tvm.relax.frontend.onnx import from_onnx
from tvm.relax.transform.legalize_ops import adreno as legalize_adreno
from tvm.script import ir as I
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
TARGETS = [tvm.target.Target("qcom/adreno-opencl-texture")]
@pytest.mark.gpu
@pytest.mark.skipif(not tvm.testing.device_enabled(TARGETS[0]), reason="opencl not enabled")
def test_network_resnet():
target = TARGETS[0]
@I.ir_module
class Resnet:
@R.function
def main(
data: R.Tensor((1, 3, 224, 224), dtype="float32"),
resnetv22_batchnorm0_gamma: R.Tensor((3,), dtype="float32"),
resnetv22_batchnorm0_beta: R.Tensor((3,), dtype="float32"),
resnetv22_batchnorm0_running_mea: R.Tensor((3,), dtype="float32"),
resnetv22_batchnorm0_running_var: R.Tensor((3,), dtype="float32"),
resnetv22_conv0_weight: R.Tensor((64, 3, 7, 7), dtype="float32"),
resnetv22_batchnorm1_gamma: R.Tensor((64,), dtype="float32"),
resnetv22_batchnorm1_beta: R.Tensor((64,), dtype="float32"),
resnetv22_batchnorm1_running_mea: R.Tensor((64,), dtype="float32"),
resnetv22_batchnorm1_running_var: R.Tensor((64,), dtype="float32"),
resnetv22_stage1_batchnorm0_gamma: R.Tensor((64,), dtype="float32"),
resnetv22_stage1_batchnorm0_beta: R.Tensor((64,), dtype="float32"),
resnetv22_stage1_batchnorm0_running_mea: R.Tensor((64,), dtype="float32"),
resnetv22_stage1_batchnorm0_running_var: R.Tensor((64,), dtype="float32"),
resnetv22_stage1_conv0_weight: R.Tensor((64, 64, 3, 3), dtype="float32"),
resnetv22_stage1_batchnorm1_gamma: R.Tensor((64,), dtype="float32"),
resnetv22_stage1_batchnorm1_beta: R.Tensor((64,), dtype="float32"),
resnetv22_stage1_batchnorm1_running_mea: R.Tensor((64,), dtype="float32"),
resnetv22_stage1_batchnorm1_running_var: R.Tensor((64,), dtype="float32"),
resnetv22_stage1_conv1_weight: R.Tensor((64, 64, 3, 3), dtype="float32"),
resnetv22_stage1_batchnorm2_gamma: R.Tensor((64,), dtype="float32"),
resnetv22_stage1_batchnorm2_beta: R.Tensor((64,), dtype="float32"),
resnetv22_stage1_batchnorm2_running_mea: R.Tensor((64,), dtype="float32"),
resnetv22_stage1_batchnorm2_running_var: R.Tensor((64,), dtype="float32"),
resnetv22_stage1_conv2_weight: R.Tensor((64, 64, 3, 3), dtype="float32"),
resnetv22_stage1_batchnorm3_gamma: R.Tensor((64,), dtype="float32"),
resnetv22_stage1_batchnorm3_beta: R.Tensor((64,), dtype="float32"),
resnetv22_stage1_batchnorm3_running_mea: R.Tensor((64,), dtype="float32"),
resnetv22_stage1_batchnorm3_running_var: R.Tensor((64,), dtype="float32"),
resnetv22_stage1_conv3_weight: R.Tensor((64, 64, 3, 3), dtype="float32"),
resnetv22_stage2_batchnorm0_gamma: R.Tensor((64,), dtype="float32"),
resnetv22_stage2_batchnorm0_beta: R.Tensor((64,), dtype="float32"),
resnetv22_stage2_batchnorm0_running_mea: R.Tensor((64,), dtype="float32"),
resnetv22_stage2_batchnorm0_running_var: R.Tensor((64,), dtype="float32"),
resnetv22_stage2_conv0_weight: R.Tensor((128, 64, 3, 3), dtype="float32"),
resnetv22_stage2_batchnorm1_gamma: R.Tensor((128,), dtype="float32"),
resnetv22_stage2_batchnorm1_beta: R.Tensor((128,), dtype="float32"),
resnetv22_stage2_batchnorm1_running_mea: R.Tensor((128,), dtype="float32"),
resnetv22_stage2_batchnorm1_running_var: R.Tensor((128,), dtype="float32"),
resnetv22_stage2_conv1_weight: R.Tensor((128, 128, 3, 3), dtype="float32"),
resnetv22_stage2_conv2_weight: R.Tensor((128, 64, 1, 1), dtype="float32"),
resnetv22_stage2_batchnorm2_gamma: R.Tensor((128,), dtype="float32"),
resnetv22_stage2_batchnorm2_beta: R.Tensor((128,), dtype="float32"),
resnetv22_stage2_batchnorm2_running_mea: R.Tensor((128,), dtype="float32"),
resnetv22_stage2_batchnorm2_running_var: R.Tensor((128,), dtype="float32"),
resnetv22_stage2_conv3_weight: R.Tensor((128, 128, 3, 3), dtype="float32"),
resnetv22_stage2_batchnorm3_gamma: R.Tensor((128,), dtype="float32"),
resnetv22_stage2_batchnorm3_beta: R.Tensor((128,), dtype="float32"),
resnetv22_stage2_batchnorm3_running_mea: R.Tensor((128,), dtype="float32"),
resnetv22_stage2_batchnorm3_running_var: R.Tensor((128,), dtype="float32"),
resnetv22_stage2_conv4_weight: R.Tensor((128, 128, 3, 3), dtype="float32"),
resnetv22_stage3_batchnorm0_gamma: R.Tensor((128,), dtype="float32"),
resnetv22_stage3_batchnorm0_beta: R.Tensor((128,), dtype="float32"),
resnetv22_stage3_batchnorm0_running_mea: R.Tensor((128,), dtype="float32"),
resnetv22_stage3_batchnorm0_running_var: R.Tensor((128,), dtype="float32"),
resnetv22_stage3_conv0_weight: R.Tensor((256, 128, 3, 3), dtype="float32"),
resnetv22_stage3_batchnorm1_gamma: R.Tensor((256,), dtype="float32"),
resnetv22_stage3_batchnorm1_beta: R.Tensor((256,), dtype="float32"),
resnetv22_stage3_batchnorm1_running_mea: R.Tensor((256,), dtype="float32"),
resnetv22_stage3_batchnorm1_running_var: R.Tensor((256,), dtype="float32"),
resnetv22_stage3_conv1_weight: R.Tensor((256, 256, 3, 3), dtype="float32"),
resnetv22_stage3_conv2_weight: R.Tensor((256, 128, 1, 1), dtype="float32"),
resnetv22_stage3_batchnorm2_gamma: R.Tensor((256,), dtype="float32"),
resnetv22_stage3_batchnorm2_beta: R.Tensor((256,), dtype="float32"),
resnetv22_stage3_batchnorm2_running_mea: R.Tensor((256,), dtype="float32"),
resnetv22_stage3_batchnorm2_running_var: R.Tensor((256,), dtype="float32"),
resnetv22_stage3_conv3_weight: R.Tensor((256, 256, 3, 3), dtype="float32"),
resnetv22_stage3_batchnorm3_gamma: R.Tensor((256,), dtype="float32"),
resnetv22_stage3_batchnorm3_beta: R.Tensor((256,), dtype="float32"),
resnetv22_stage3_batchnorm3_running_mea: R.Tensor((256,), dtype="float32"),
resnetv22_stage3_batchnorm3_running_var: R.Tensor((256,), dtype="float32"),
resnetv22_stage3_conv4_weight: R.Tensor((256, 256, 3, 3), dtype="float32"),
resnetv22_stage4_batchnorm0_gamma: R.Tensor((256,), dtype="float32"),
resnetv22_stage4_batchnorm0_beta: R.Tensor((256,), dtype="float32"),
resnetv22_stage4_batchnorm0_running_mea: R.Tensor((256,), dtype="float32"),
resnetv22_stage4_batchnorm0_running_var: R.Tensor((256,), dtype="float32"),
resnetv22_stage4_conv0_weight: R.Tensor((512, 256, 3, 3), dtype="float32"),
resnetv22_stage4_batchnorm1_gamma: R.Tensor((512,), dtype="float32"),
resnetv22_stage4_batchnorm1_beta: R.Tensor((512,), dtype="float32"),
resnetv22_stage4_batchnorm1_running_mea: R.Tensor((512,), dtype="float32"),
resnetv22_stage4_batchnorm1_running_var: R.Tensor((512,), dtype="float32"),
resnetv22_stage4_conv1_weight: R.Tensor((512, 512, 3, 3), dtype="float32"),
resnetv22_stage4_conv2_weight: R.Tensor((512, 256, 1, 1), dtype="float32"),
resnetv22_stage4_batchnorm2_gamma: R.Tensor((512,), dtype="float32"),
resnetv22_stage4_batchnorm2_beta: R.Tensor((512,), dtype="float32"),
resnetv22_stage4_batchnorm2_running_mea: R.Tensor((512,), dtype="float32"),
resnetv22_stage4_batchnorm2_running_var: R.Tensor((512,), dtype="float32"),
resnetv22_stage4_conv3_weight: R.Tensor((512, 512, 3, 3), dtype="float32"),
resnetv22_stage4_batchnorm3_gamma: R.Tensor((512,), dtype="float32"),
resnetv22_stage4_batchnorm3_beta: R.Tensor((512,), dtype="float32"),
resnetv22_stage4_batchnorm3_running_mea: R.Tensor((512,), dtype="float32"),
resnetv22_stage4_batchnorm3_running_var: R.Tensor((512,), dtype="float32"),
resnetv22_stage4_conv4_weight: R.Tensor((512, 512, 3, 3), dtype="float32"),
resnetv22_batchnorm2_gamma: R.Tensor((512,), dtype="float32"),
resnetv22_batchnorm2_beta: R.Tensor((512,), dtype="float32"),
resnetv22_batchnorm2_running_mea: R.Tensor((512,), dtype="float32"),
resnetv22_batchnorm2_running_var: R.Tensor((512,), dtype="float32"),
reshape_attr_tensor164: R.Tensor((2,), dtype="int64"),
resnetv22_dense0_weight: R.Tensor((1000, 512), dtype="float32"),
resnetv22_dense0_bias: R.Tensor((1000,), dtype="float32"),
) -> R.Tensor((1, 1000), dtype="float32"):
with R.dataflow():
lv: R.Tuple(
R.Tensor((1, 3, 224, 224), dtype="float32"),
R.Tensor((3,), dtype="float32"),
R.Tensor((3,), dtype="float32"),
) = R.nn.batch_norm(
data,
resnetv22_batchnorm0_gamma,
resnetv22_batchnorm0_beta,
resnetv22_batchnorm0_running_mea,
resnetv22_batchnorm0_running_var,
axis=1,
epsilon=9.9999997473787516e-06,
center=True,
scale=True,
momentum=0.10000000000000001,
)
lv1: R.Tensor((1, 3, 224, 224), dtype="float32") = lv[0]
lv2: R.Tensor((3,), dtype="float32") = lv[1]
lv3: R.Tensor((3,), dtype="float32") = lv[2]
lv4: R.Tensor((1, 64, 112, 112), dtype="float32") = R.nn.conv2d(
lv1,
resnetv22_conv0_weight,
strides=[2, 2],
padding=[3, 3, 3, 3],
dilation=[1, 1],
groups=1,
data_layout="NCHW",
kernel_layout="OIHW",
out_layout="NCHW",
)
lv5: R.Tuple(
R.Tensor((1, 64, 112, 112), dtype="float32"),
R.Tensor((64,), dtype="float32"),
R.Tensor((64,), dtype="float32"),
) = R.nn.batch_norm(
lv4,
resnetv22_batchnorm1_gamma,
resnetv22_batchnorm1_beta,
resnetv22_batchnorm1_running_mea,
resnetv22_batchnorm1_running_var,
axis=1,
epsilon=9.9999997473787516e-06,
center=True,
scale=True,
momentum=0.10000000000000001,
)
lv6: R.Tensor((1, 64, 112, 112), dtype="float32") = lv5[0]
lv7: R.Tensor((64,), dtype="float32") = lv5[1]
lv8: R.Tensor((64,), dtype="float32") = lv5[2]
lv9: R.Tensor((1, 64, 112, 112), dtype="float32") = R.nn.relu(lv6)
lv10: R.Tensor((1, 64, 56, 56), dtype="float32") = R.nn.max_pool2d(
lv9,
pool_size=[3, 3],
strides=[2, 2],
dilation=[1, 1],
padding=[1, 1, 1, 1],
ceil_mode=False,
count_include_pad=False,
layout="NCHW",
out_layout="NCHW",
)
lv11: R.Tuple(
R.Tensor((1, 64, 56, 56), dtype="float32"),
R.Tensor((64,), dtype="float32"),
R.Tensor((64,), dtype="float32"),
) = R.nn.batch_norm(
lv10,
resnetv22_stage1_batchnorm0_gamma,
resnetv22_stage1_batchnorm0_beta,
resnetv22_stage1_batchnorm0_running_mea,
resnetv22_stage1_batchnorm0_running_var,
axis=1,
epsilon=9.9999997473787516e-06,
center=True,
scale=True,
momentum=0.10000000000000001,
)
lv12: R.Tensor((1, 64, 56, 56), dtype="float32") = lv11[0]
lv13: R.Tensor((64,), dtype="float32") = lv11[1]
lv14: R.Tensor((64,), dtype="float32") = lv11[2]
lv15: R.Tensor((1, 64, 56, 56), dtype="float32") = R.nn.relu(lv12)
lv16: R.Tensor((1, 64, 56, 56), dtype="float32") = R.nn.conv2d(
lv15,
resnetv22_stage1_conv0_weight,
strides=[1, 1],
padding=[1, 1, 1, 1],
dilation=[1, 1],
groups=1,
data_layout="NCHW",
kernel_layout="OIHW",
out_layout="NCHW",
)
lv17: R.Tuple(
R.Tensor((1, 64, 56, 56), dtype="float32"),
R.Tensor((64,), dtype="float32"),
R.Tensor((64,), dtype="float32"),
) = R.nn.batch_norm(
lv16,
resnetv22_stage1_batchnorm1_gamma,
resnetv22_stage1_batchnorm1_beta,
resnetv22_stage1_batchnorm1_running_mea,
resnetv22_stage1_batchnorm1_running_var,
axis=1,
epsilon=9.9999997473787516e-06,
center=True,
scale=True,
momentum=0.10000000000000001,
)
lv18: R.Tensor((1, 64, 56, 56), dtype="float32") = lv17[0]
lv19: R.Tensor((64,), dtype="float32") = lv17[1]
lv20: R.Tensor((64,), dtype="float32") = lv17[2]
lv21: R.Tensor((1, 64, 56, 56), dtype="float32") = R.nn.relu(lv18)
lv22: R.Tensor((1, 64, 56, 56), dtype="float32") = R.nn.conv2d(
lv21,
resnetv22_stage1_conv1_weight,
strides=[1, 1],
padding=[1, 1, 1, 1],
dilation=[1, 1],
groups=1,
data_layout="NCHW",
kernel_layout="OIHW",
out_layout="NCHW",
)
lv23: R.Tensor((1, 64, 56, 56), dtype="float32") = R.add(lv22, lv10)
lv24: R.Tuple(
R.Tensor((1, 64, 56, 56), dtype="float32"),
R.Tensor((64,), dtype="float32"),
R.Tensor((64,), dtype="float32"),
) = R.nn.batch_norm(
lv23,
resnetv22_stage1_batchnorm2_gamma,
resnetv22_stage1_batchnorm2_beta,
resnetv22_stage1_batchnorm2_running_mea,
resnetv22_stage1_batchnorm2_running_var,
axis=1,
epsilon=9.9999997473787516e-06,
center=True,
scale=True,
momentum=0.10000000000000001,
)
lv25: R.Tensor((1, 64, 56, 56), dtype="float32") = lv24[0]
lv26: R.Tensor((64,), dtype="float32") = lv24[1]
lv27: R.Tensor((64,), dtype="float32") = lv24[2]
lv28: R.Tensor((1, 64, 56, 56), dtype="float32") = R.nn.relu(lv25)
lv29: R.Tensor((1, 64, 56, 56), dtype="float32") = R.nn.conv2d(
lv28,
resnetv22_stage1_conv2_weight,
strides=[1, 1],
padding=[1, 1, 1, 1],
dilation=[1, 1],
groups=1,
data_layout="NCHW",
kernel_layout="OIHW",
out_layout="NCHW",
)
lv30: R.Tuple(
R.Tensor((1, 64, 56, 56), dtype="float32"),
R.Tensor((64,), dtype="float32"),
R.Tensor((64,), dtype="float32"),
) = R.nn.batch_norm(
lv29,
resnetv22_stage1_batchnorm3_gamma,
resnetv22_stage1_batchnorm3_beta,
resnetv22_stage1_batchnorm3_running_mea,
resnetv22_stage1_batchnorm3_running_var,
axis=1,
epsilon=9.9999997473787516e-06,
center=True,
scale=True,
momentum=0.10000000000000001,
)
lv31: R.Tensor((1, 64, 56, 56), dtype="float32") = lv30[0]
lv32: R.Tensor((64,), dtype="float32") = lv30[1]
lv33: R.Tensor((64,), dtype="float32") = lv30[2]
lv34: R.Tensor((1, 64, 56, 56), dtype="float32") = R.nn.relu(lv31)
lv35: R.Tensor((1, 64, 56, 56), dtype="float32") = R.nn.conv2d(
lv34,
resnetv22_stage1_conv3_weight,
strides=[1, 1],
padding=[1, 1, 1, 1],
dilation=[1, 1],
groups=1,
data_layout="NCHW",
kernel_layout="OIHW",
out_layout="NCHW",
)
lv36: R.Tensor((1, 64, 56, 56), dtype="float32") = R.add(lv35, lv23)
lv37: R.Tuple(
R.Tensor((1, 64, 56, 56), dtype="float32"),
R.Tensor((64,), dtype="float32"),
R.Tensor((64,), dtype="float32"),
) = R.nn.batch_norm(
lv36,
resnetv22_stage2_batchnorm0_gamma,
resnetv22_stage2_batchnorm0_beta,
resnetv22_stage2_batchnorm0_running_mea,
resnetv22_stage2_batchnorm0_running_var,
axis=1,
epsilon=9.9999997473787516e-06,
center=True,
scale=True,
momentum=0.10000000000000001,
)
lv38: R.Tensor((1, 64, 56, 56), dtype="float32") = lv37[0]
lv39: R.Tensor((64,), dtype="float32") = lv37[1]
lv40: R.Tensor((64,), dtype="float32") = lv37[2]
lv41: R.Tensor((1, 64, 56, 56), dtype="float32") = R.nn.relu(lv38)
lv42: R.Tensor((1, 128, 28, 28), dtype="float32") = R.nn.conv2d(
lv41,
resnetv22_stage2_conv0_weight,
strides=[2, 2],
padding=[1, 1, 1, 1],
dilation=[1, 1],
groups=1,
data_layout="NCHW",
kernel_layout="OIHW",
out_layout="NCHW",
)
lv43: R.Tuple(
R.Tensor((1, 128, 28, 28), dtype="float32"),
R.Tensor((128,), dtype="float32"),
R.Tensor((128,), dtype="float32"),
) = R.nn.batch_norm(
lv42,
resnetv22_stage2_batchnorm1_gamma,
resnetv22_stage2_batchnorm1_beta,
resnetv22_stage2_batchnorm1_running_mea,
resnetv22_stage2_batchnorm1_running_var,
axis=1,
epsilon=9.9999997473787516e-06,
center=True,
scale=True,
momentum=0.10000000000000001,
)
lv44: R.Tensor((1, 128, 28, 28), dtype="float32") = lv43[0]
lv45: R.Tensor((128,), dtype="float32") = lv43[1]
lv46: R.Tensor((128,), dtype="float32") = lv43[2]
lv47: R.Tensor((1, 128, 28, 28), dtype="float32") = R.nn.relu(lv44)
lv48: R.Tensor((1, 128, 28, 28), dtype="float32") = R.nn.conv2d(
lv47,
resnetv22_stage2_conv1_weight,
strides=[1, 1],
padding=[1, 1, 1, 1],
dilation=[1, 1],
groups=1,
data_layout="NCHW",
kernel_layout="OIHW",
out_layout="NCHW",
)
lv49: R.Tensor((1, 128, 28, 28), dtype="float32") = R.nn.conv2d(
lv41,
resnetv22_stage2_conv2_weight,
strides=[2, 2],
padding=[0, 0, 0, 0],
dilation=[1, 1],
groups=1,
data_layout="NCHW",
kernel_layout="OIHW",
out_layout="NCHW",
)
lv50: R.Tensor((1, 128, 28, 28), dtype="float32") = R.add(lv48, lv49)
lv51: R.Tuple(
R.Tensor((1, 128, 28, 28), dtype="float32"),
R.Tensor((128,), dtype="float32"),
R.Tensor((128,), dtype="float32"),
) = R.nn.batch_norm(
lv50,
resnetv22_stage2_batchnorm2_gamma,
resnetv22_stage2_batchnorm2_beta,
resnetv22_stage2_batchnorm2_running_mea,
resnetv22_stage2_batchnorm2_running_var,
axis=1,
epsilon=9.9999997473787516e-06,
center=True,
scale=True,
momentum=0.10000000000000001,
)
lv52: R.Tensor((1, 128, 28, 28), dtype="float32") = lv51[0]
lv53: R.Tensor((128,), dtype="float32") = lv51[1]
lv54: R.Tensor((128,), dtype="float32") = lv51[2]
lv55: R.Tensor((1, 128, 28, 28), dtype="float32") = R.nn.relu(lv52)
lv56: R.Tensor((1, 128, 28, 28), dtype="float32") = R.nn.conv2d(
lv55,
resnetv22_stage2_conv3_weight,
strides=[1, 1],
padding=[1, 1, 1, 1],
dilation=[1, 1],
groups=1,
data_layout="NCHW",
kernel_layout="OIHW",
out_layout="NCHW",
)
lv57: R.Tuple(
R.Tensor((1, 128, 28, 28), dtype="float32"),
R.Tensor((128,), dtype="float32"),
R.Tensor((128,), dtype="float32"),
) = R.nn.batch_norm(
lv56,
resnetv22_stage2_batchnorm3_gamma,
resnetv22_stage2_batchnorm3_beta,
resnetv22_stage2_batchnorm3_running_mea,
resnetv22_stage2_batchnorm3_running_var,
axis=1,
epsilon=9.9999997473787516e-06,
center=True,
scale=True,
momentum=0.10000000000000001,
)
lv58: R.Tensor((1, 128, 28, 28), dtype="float32") = lv57[0]
lv59: R.Tensor((128,), dtype="float32") = lv57[1]
lv60: R.Tensor((128,), dtype="float32") = lv57[2]
lv61: R.Tensor((1, 128, 28, 28), dtype="float32") = R.nn.relu(lv58)
lv62: R.Tensor((1, 128, 28, 28), dtype="float32") = R.nn.conv2d(
lv61,
resnetv22_stage2_conv4_weight,
strides=[1, 1],
padding=[1, 1, 1, 1],
dilation=[1, 1],
groups=1,
data_layout="NCHW",
kernel_layout="OIHW",
out_layout="NCHW",
)
lv63: R.Tensor((1, 128, 28, 28), dtype="float32") = R.add(lv62, lv50)
lv64: R.Tuple(
R.Tensor((1, 128, 28, 28), dtype="float32"),
R.Tensor((128,), dtype="float32"),
R.Tensor((128,), dtype="float32"),
) = R.nn.batch_norm(
lv63,
resnetv22_stage3_batchnorm0_gamma,
resnetv22_stage3_batchnorm0_beta,
resnetv22_stage3_batchnorm0_running_mea,
resnetv22_stage3_batchnorm0_running_var,
axis=1,
epsilon=9.9999997473787516e-06,
center=True,
scale=True,
momentum=0.10000000000000001,
)
lv65: R.Tensor((1, 128, 28, 28), dtype="float32") = lv64[0]
lv66: R.Tensor((128,), dtype="float32") = lv64[1]
lv67: R.Tensor((128,), dtype="float32") = lv64[2]
lv68: R.Tensor((1, 128, 28, 28), dtype="float32") = R.nn.relu(lv65)
lv69: R.Tensor((1, 256, 14, 14), dtype="float32") = R.nn.conv2d(
lv68,
resnetv22_stage3_conv0_weight,
strides=[2, 2],
padding=[1, 1, 1, 1],
dilation=[1, 1],
groups=1,
data_layout="NCHW",
kernel_layout="OIHW",
out_layout="NCHW",
)
lv70: R.Tuple(
R.Tensor((1, 256, 14, 14), dtype="float32"),
R.Tensor((256,), dtype="float32"),
R.Tensor((256,), dtype="float32"),
) = R.nn.batch_norm(
lv69,
resnetv22_stage3_batchnorm1_gamma,
resnetv22_stage3_batchnorm1_beta,
resnetv22_stage3_batchnorm1_running_mea,
resnetv22_stage3_batchnorm1_running_var,
axis=1,
epsilon=9.9999997473787516e-06,
center=True,
scale=True,
momentum=0.10000000000000001,
)
lv71: R.Tensor((1, 256, 14, 14), dtype="float32") = lv70[0]
lv72: R.Tensor((256,), dtype="float32") = lv70[1]
lv73: R.Tensor((256,), dtype="float32") = lv70[2]
lv74: R.Tensor((1, 256, 14, 14), dtype="float32") = R.nn.relu(lv71)
lv75: R.Tensor((1, 256, 14, 14), dtype="float32") = R.nn.conv2d(
lv74,
resnetv22_stage3_conv1_weight,
strides=[1, 1],
padding=[1, 1, 1, 1],
dilation=[1, 1],
groups=1,
data_layout="NCHW",
kernel_layout="OIHW",
out_layout="NCHW",
)
lv76: R.Tensor((1, 256, 14, 14), dtype="float32") = R.nn.conv2d(
lv68,
resnetv22_stage3_conv2_weight,
strides=[2, 2],
padding=[0, 0, 0, 0],
dilation=[1, 1],
groups=1,
data_layout="NCHW",
kernel_layout="OIHW",
out_layout="NCHW",
)
lv77: R.Tensor((1, 256, 14, 14), dtype="float32") = R.add(lv75, lv76)
lv78: R.Tuple(
R.Tensor((1, 256, 14, 14), dtype="float32"),
R.Tensor((256,), dtype="float32"),
R.Tensor((256,), dtype="float32"),
) = R.nn.batch_norm(
lv77,
resnetv22_stage3_batchnorm2_gamma,
resnetv22_stage3_batchnorm2_beta,
resnetv22_stage3_batchnorm2_running_mea,
resnetv22_stage3_batchnorm2_running_var,
axis=1,
epsilon=9.9999997473787516e-06,
center=True,
scale=True,
momentum=0.10000000000000001,
)
lv79: R.Tensor((1, 256, 14, 14), dtype="float32") = lv78[0]
lv80: R.Tensor((256,), dtype="float32") = lv78[1]
lv81: R.Tensor((256,), dtype="float32") = lv78[2]
lv82: R.Tensor((1, 256, 14, 14), dtype="float32") = R.nn.relu(lv79)
lv83: R.Tensor((1, 256, 14, 14), dtype="float32") = R.nn.conv2d(
lv82,
resnetv22_stage3_conv3_weight,
strides=[1, 1],
padding=[1, 1, 1, 1],
dilation=[1, 1],
groups=1,
data_layout="NCHW",
kernel_layout="OIHW",
out_layout="NCHW",
)
lv84: R.Tuple(
R.Tensor((1, 256, 14, 14), dtype="float32"),
R.Tensor((256,), dtype="float32"),
R.Tensor((256,), dtype="float32"),
) = R.nn.batch_norm(
lv83,
resnetv22_stage3_batchnorm3_gamma,
resnetv22_stage3_batchnorm3_beta,
resnetv22_stage3_batchnorm3_running_mea,
resnetv22_stage3_batchnorm3_running_var,
axis=1,
epsilon=9.9999997473787516e-06,
center=True,
scale=True,
momentum=0.10000000000000001,
)
lv85: R.Tensor((1, 256, 14, 14), dtype="float32") = lv84[0]
lv86: R.Tensor((256,), dtype="float32") = lv84[1]
lv87: R.Tensor((256,), dtype="float32") = lv84[2]
lv88: R.Tensor((1, 256, 14, 14), dtype="float32") = R.nn.relu(lv85)
lv89: R.Tensor((1, 256, 14, 14), dtype="float32") = R.nn.conv2d(
lv88,
resnetv22_stage3_conv4_weight,
strides=[1, 1],
padding=[1, 1, 1, 1],
dilation=[1, 1],
groups=1,
data_layout="NCHW",
kernel_layout="OIHW",
out_layout="NCHW",
)
lv90: R.Tensor((1, 256, 14, 14), dtype="float32") = R.add(lv89, lv77)
lv91: R.Tuple(
R.Tensor((1, 256, 14, 14), dtype="float32"),
R.Tensor((256,), dtype="float32"),
R.Tensor((256,), dtype="float32"),
) = R.nn.batch_norm(
lv90,
resnetv22_stage4_batchnorm0_gamma,
resnetv22_stage4_batchnorm0_beta,
resnetv22_stage4_batchnorm0_running_mea,
resnetv22_stage4_batchnorm0_running_var,
axis=1,
epsilon=9.9999997473787516e-06,
center=True,
scale=True,
momentum=0.10000000000000001,
)
lv92: R.Tensor((1, 256, 14, 14), dtype="float32") = lv91[0]
lv93: R.Tensor((256,), dtype="float32") = lv91[1]
lv94: R.Tensor((256,), dtype="float32") = lv91[2]
lv95: R.Tensor((1, 256, 14, 14), dtype="float32") = R.nn.relu(lv92)
lv96: R.Tensor((1, 512, 7, 7), dtype="float32") = R.nn.conv2d(
lv95,
resnetv22_stage4_conv0_weight,
strides=[2, 2],
padding=[1, 1, 1, 1],
dilation=[1, 1],
groups=1,
data_layout="NCHW",
kernel_layout="OIHW",
out_layout="NCHW",
)
lv97: R.Tuple(
R.Tensor((1, 512, 7, 7), dtype="float32"),
R.Tensor((512,), dtype="float32"),
R.Tensor((512,), dtype="float32"),
) = R.nn.batch_norm(
lv96,
resnetv22_stage4_batchnorm1_gamma,
resnetv22_stage4_batchnorm1_beta,
resnetv22_stage4_batchnorm1_running_mea,
resnetv22_stage4_batchnorm1_running_var,
axis=1,
epsilon=9.9999997473787516e-06,
center=True,
scale=True,
momentum=0.10000000000000001,
)
lv98: R.Tensor((1, 512, 7, 7), dtype="float32") = lv97[0]
lv99: R.Tensor((512,), dtype="float32") = lv97[1]
lv100: R.Tensor((512,), dtype="float32") = lv97[2]
lv101: R.Tensor((1, 512, 7, 7), dtype="float32") = R.nn.relu(lv98)
lv102: R.Tensor((1, 512, 7, 7), dtype="float32") = R.nn.conv2d(
lv101,
resnetv22_stage4_conv1_weight,
strides=[1, 1],
padding=[1, 1, 1, 1],
dilation=[1, 1],
groups=1,
data_layout="NCHW",
kernel_layout="OIHW",
out_layout="NCHW",
)
lv103: R.Tensor((1, 512, 7, 7), dtype="float32") = R.nn.conv2d(
lv95,
resnetv22_stage4_conv2_weight,
strides=[2, 2],
padding=[0, 0, 0, 0],
dilation=[1, 1],
groups=1,
data_layout="NCHW",
kernel_layout="OIHW",
out_layout="NCHW",
)
lv104: R.Tensor((1, 512, 7, 7), dtype="float32") = R.add(lv102, lv103)
lv105: R.Tuple(
R.Tensor((1, 512, 7, 7), dtype="float32"),
R.Tensor((512,), dtype="float32"),
R.Tensor((512,), dtype="float32"),
) = R.nn.batch_norm(
lv104,
resnetv22_stage4_batchnorm2_gamma,
resnetv22_stage4_batchnorm2_beta,
resnetv22_stage4_batchnorm2_running_mea,
resnetv22_stage4_batchnorm2_running_var,
axis=1,
epsilon=9.9999997473787516e-06,
center=True,
scale=True,
momentum=0.10000000000000001,
)
lv106: R.Tensor((1, 512, 7, 7), dtype="float32") = lv105[0]
lv107: R.Tensor((512,), dtype="float32") = lv105[1]
lv108: R.Tensor((512,), dtype="float32") = lv105[2]
lv109: R.Tensor((1, 512, 7, 7), dtype="float32") = R.nn.relu(lv106)
lv110: R.Tensor((1, 512, 7, 7), dtype="float32") = R.nn.conv2d(
lv109,
resnetv22_stage4_conv3_weight,
strides=[1, 1],
padding=[1, 1, 1, 1],
dilation=[1, 1],
groups=1,
data_layout="NCHW",
kernel_layout="OIHW",
out_layout="NCHW",
)
lv111: R.Tuple(
R.Tensor((1, 512, 7, 7), dtype="float32"),
R.Tensor((512,), dtype="float32"),
R.Tensor((512,), dtype="float32"),
) = R.nn.batch_norm(
lv110,
resnetv22_stage4_batchnorm3_gamma,
resnetv22_stage4_batchnorm3_beta,
resnetv22_stage4_batchnorm3_running_mea,
resnetv22_stage4_batchnorm3_running_var,
axis=1,
epsilon=9.9999997473787516e-06,
center=True,
scale=True,
momentum=0.10000000000000001,
)
lv112: R.Tensor((1, 512, 7, 7), dtype="float32") = lv111[0]
lv113: R.Tensor((512,), dtype="float32") = lv111[1]
lv114: R.Tensor((512,), dtype="float32") = lv111[2]
lv115: R.Tensor((1, 512, 7, 7), dtype="float32") = R.nn.relu(lv112)
lv116: R.Tensor((1, 512, 7, 7), dtype="float32") = R.nn.conv2d(
lv115,
resnetv22_stage4_conv4_weight,
strides=[1, 1],
padding=[1, 1, 1, 1],
dilation=[1, 1],
groups=1,
data_layout="NCHW",
kernel_layout="OIHW",
out_layout="NCHW",
)
lv117: R.Tensor((1, 512, 7, 7), dtype="float32") = R.add(lv116, lv104)
lv118: R.Tuple(
R.Tensor((1, 512, 7, 7), dtype="float32"),
R.Tensor((512,), dtype="float32"),
R.Tensor((512,), dtype="float32"),
) = R.nn.batch_norm(
lv117,
resnetv22_batchnorm2_gamma,
resnetv22_batchnorm2_beta,
resnetv22_batchnorm2_running_mea,
resnetv22_batchnorm2_running_var,
axis=1,
epsilon=9.9999997473787516e-06,
center=True,
scale=True,
momentum=0.10000000000000001,
)
lv119: R.Tensor((1, 512, 7, 7), dtype="float32") = lv118[0]
lv120: R.Tensor((512,), dtype="float32") = lv118[1]
lv121: R.Tensor((512,), dtype="float32") = lv118[2]
lv122: R.Tensor((1, 512, 7, 7), dtype="float32") = R.nn.relu(lv119)
lv123: R.Tensor((1, 512, 1, 1), dtype="float32") = R.mean(
lv122, axis=[2, 3], keepdims=True
)
lv124: R.Tensor((1, 512), dtype="float32") = R.reshape(lv123, R.shape([1, 512]))
lv125: R.Tensor((512, 1000), dtype="float32") = R.permute_dims(
resnetv22_dense0_weight, axes=[1, 0]
)
lv126: R.Tensor((1, 1000), dtype="float32") = R.matmul(lv124, lv125)
gv: R.Tensor((1, 1000), dtype="float32") = R.add(lv126, resnetv22_dense0_bias)
R.output(gv)
return gv
verify_results(Resnet, target, tvm.target.Target("llvm"))
if __name__ == "__main__":
tvm.testing.main()
@@ -0,0 +1,792 @@
# 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.
import pytest
from utils import skip_unless_adreno_opencl_vulkan, verify_results
import tvm
import tvm.testing
from tvm.script.parser import ir as I
from tvm.script.parser import relax as R
TARGETS = [
tvm.target.Target("qcom/adreno-opencl-texture"),
# tvm.target.Target("qcom/adreno-vulkan-texture"),
]
ref_target = tvm.target.Target("llvm")
@pytest.mark.gpu
@skip_unless_adreno_opencl_vulkan
@pytest.mark.skipif(not tvm.testing.device_enabled(TARGETS[0]), reason="opencl not enabled")
def test_conv2d():
target = TARGETS[0]
@I.ir_module
class Input:
@R.function
def main(
x: R.Tensor((2, 64, 56, 56), "float32"), w: R.Tensor((32, 64, 3, 3), "float32")
) -> R.Tensor(None, "float32", ndim=4):
with R.dataflow():
gv: R.Tensor((2, 32, 54, 54), "float32") = R.nn.conv2d(x, w, out_dtype="float32")
R.output(gv)
return gv
verify_results(Input, target, ref_target)
@pytest.mark.gpu
@skip_unless_adreno_opencl_vulkan
@pytest.mark.skipif(not tvm.testing.device_enabled(TARGETS[0]), reason="opencl not enabled")
def test_conv2d_relu():
target = TARGETS[0]
@I.ir_module
class Input:
@R.function
def main(
x: R.Tensor((2, 16, 28, 28), "float32"), w: R.Tensor((4, 16, 3, 3), "float32")
) -> R.Tensor(None, "float32", ndim=4):
with R.dataflow():
gv: R.Tensor((2, 4, 26, 26), "float32") = R.nn.conv2d(x, w, out_dtype="float32")
gv2: R.Tensor((2, 4, 26, 26), "float32") = R.nn.relu(gv)
R.output(gv2)
return gv2
verify_results(Input, target, ref_target)
@pytest.mark.gpu
@skip_unless_adreno_opencl_vulkan
@pytest.mark.skipif(not tvm.testing.device_enabled(TARGETS[0]), reason="opencl not enabled")
def test_relu_conv2d_relu():
target = TARGETS[0]
@I.ir_module
class Input:
@R.function
def main(
x: R.Tensor((2, 16, 28, 28), "float32"), w: R.Tensor((4, 16, 3, 3), "float32")
) -> R.Tensor(None, "float32", ndim=4):
with R.dataflow():
x0: R.Tensor((2, 16, 28, 28), "float32") = R.nn.relu(x)
gv: R.Tensor((2, 4, 26, 26), "float32") = R.nn.conv2d(x0, w, out_dtype="float32")
gv2: R.Tensor((2, 4, 26, 26), "float32") = R.nn.relu(gv)
R.output(gv2)
return gv2
verify_results(Input, target, ref_target)
@pytest.mark.gpu
@skip_unless_adreno_opencl_vulkan
@pytest.mark.skipif(not tvm.testing.device_enabled(TARGETS[0]), reason="opencl not enabled")
def test_conv2d_relu_tanh():
target = TARGETS[0]
@I.ir_module
class Input:
@R.function
def main(
x: R.Tensor((2, 16, 28, 28), "float32"), w: R.Tensor((4, 16, 3, 3), "float32")
) -> R.Tensor(None, "float32", ndim=4):
with R.dataflow():
gv: R.Tensor((2, 4, 26, 26), "float32") = R.nn.conv2d(x, w, out_dtype="float32")
gv2: R.Tensor((2, 4, 26, 26), "float32") = R.nn.relu(gv)
gv3: R.Tensor((2, 4, 26, 26), "float32") = R.tanh(gv2)
R.output(gv3)
return gv3
verify_results(Input, target, ref_target)
@pytest.mark.gpu
@skip_unless_adreno_opencl_vulkan
@pytest.mark.skipif(not tvm.testing.device_enabled(TARGETS[0]), reason="opencl not enabled")
def test_conv2d_add():
target = TARGETS[0]
@I.ir_module
class Input:
@R.function
def main(
x: R.Tensor((2, 16, 28, 28), "float32"),
w: R.Tensor((4, 16, 3, 3), "float32"),
bias: R.Tensor((2, 4, 26, 26), "float32"),
) -> R.Tensor(None, "float32", ndim=4):
with R.dataflow():
gv: R.Tensor((2, 4, 26, 26), "float32") = R.nn.conv2d(x, w, out_dtype="float32")
gv2: R.Tensor((2, 4, 26, 26), "float32") = R.add(gv, bias)
R.output(gv2)
return gv2
verify_results(Input, target, ref_target)
@pytest.mark.gpu
@skip_unless_adreno_opencl_vulkan
@pytest.mark.skipif(not tvm.testing.device_enabled(TARGETS[0]), reason="opencl not enabled")
def test_conv2d_sum():
target = TARGETS[0]
@I.ir_module
class Input:
@R.function
def main(
x: R.Tensor((2, 16, 28, 28), "float32"), w: R.Tensor((4, 16, 3, 3), "float32")
) -> R.Tensor(None, "float32", ndim=2):
with R.dataflow():
gv: R.Tensor((2, 4, 26, 26), "float32") = R.nn.conv2d(x, w, out_dtype="float32")
gv2: R.Tensor((2, 4), "float32") = R.sum(gv, axis=[2, 3])
R.output(gv2)
return gv2
verify_results(Input, target, ref_target)
@pytest.mark.gpu
@skip_unless_adreno_opencl_vulkan
@pytest.mark.skipif(not tvm.testing.device_enabled(TARGETS[0]), reason="opencl not enabled")
def test_conv2d_sum_keepdims():
target = TARGETS[0]
@I.ir_module
class Input:
@R.function
def main(
x: R.Tensor((2, 16, 28, 28), "float32"), w: R.Tensor((4, 16, 3, 3), "float32")
) -> R.Tensor(None, "float32", ndim=2):
with R.dataflow():
gv: R.Tensor((2, 4, 26, 26), "float32") = R.nn.conv2d(x, w, out_dtype="float32")
gv2: R.Tensor((2, 4, 1, 1), "float32") = R.sum(gv, axis=[2, 3], keepdims=True)
R.output(gv2)
return gv2
verify_results(Input, target, ref_target)
@pytest.mark.gpu
@skip_unless_adreno_opencl_vulkan
@pytest.mark.skipif(not tvm.testing.device_enabled(TARGETS[0]), reason="opencl not enabled")
def test_conv2d_sum_reduce():
target = TARGETS[0]
@I.ir_module
class Input:
@R.function
def main(
x: R.Tensor((2, 16, 28, 28), "float32"), w: R.Tensor((4, 16, 3, 3), "float32")
) -> R.Tensor(None, "float32", ndim=2):
with R.dataflow():
gv: R.Tensor((2, 4, 26, 26), "float32") = R.nn.conv2d(x, w, out_dtype="float32")
gv2: R.Tensor((2, 26), "float32") = R.sum(gv, axis=[1, 2])
R.output(gv2)
return gv2
verify_results(Input, target, ref_target)
@pytest.mark.gpu
@skip_unless_adreno_opencl_vulkan
@pytest.mark.skipif(not tvm.testing.device_enabled(TARGETS[0]), reason="opencl not enabled")
def test_conv2d_transpose():
target = TARGETS[0]
@I.ir_module
class Input:
@R.function
def main(
x: R.Tensor((2, 16, 28, 28), "float32"), w: R.Tensor((4, 16, 3, 3), "float32")
) -> R.Tensor(None, "float32", ndim=4):
with R.dataflow():
gv: R.Tensor((2, 4, 26, 26), "float32") = R.nn.conv2d(x, w, out_dtype="float32")
gv2: R.Tensor((26, 26, 4, 2), "float32") = R.permute_dims(gv, axes=[3, 2, 1, 0])
R.output(gv2)
return gv2
verify_results(Input, target, ref_target)
@pytest.mark.gpu
@skip_unless_adreno_opencl_vulkan
@pytest.mark.skipif(not tvm.testing.device_enabled(TARGETS[0]), reason="opencl not enabled")
def test_conv2d_expand_dims():
target = TARGETS[0]
@I.ir_module
class Input:
@R.function
def main(
x: R.Tensor((2, 16, 28, 28), "float32"), w: R.Tensor((4, 16, 3, 3), "float32")
) -> R.Tensor(None, "float32", ndim=6):
with R.dataflow():
gv: R.Tensor((2, 4, 26, 26), "float32") = R.nn.conv2d(x, w, out_dtype="float32")
gv2: R.Tensor((2, 1, 4, 1, 26, 26), "float32") = R.expand_dims(gv, axis=(-3, 1))
R.output(gv2)
return gv2
verify_results(Input, target, ref_target)
@pytest.mark.gpu
@skip_unless_adreno_opencl_vulkan
@pytest.mark.skipif(not tvm.testing.device_enabled(TARGETS[0]), reason="opencl not enabled")
def test_conv2d_squeeze():
target = TARGETS[0]
@I.ir_module
class Input:
@R.function
def main(
x: R.Tensor((1, 16, 28, 28), "float32"), w: R.Tensor((4, 16, 3, 3), "float32")
) -> R.Tensor(None, "float32", ndim=3):
with R.dataflow():
gv: R.Tensor((1, 4, 26, 26), "float32") = R.nn.conv2d(x, w, out_dtype="float32")
gv2: R.Tensor((4, 26, 26), "float32") = R.squeeze(gv, axis=[0])
R.output(gv2)
return gv2
verify_results(Input, target, ref_target)
@pytest.mark.gpu
@skip_unless_adreno_opencl_vulkan
@pytest.mark.skipif(not tvm.testing.device_enabled(TARGETS[0]), reason="opencl not enabled")
def test_conv2d_strided_slice():
target = TARGETS[0]
@I.ir_module
class Input:
@R.function
def main(
x: R.Tensor((2, 16, 28, 28), "float32"), w: R.Tensor((4, 16, 3, 3), "float32")
) -> R.Tensor(None, "float32", ndim=4):
with R.dataflow():
gv: R.Tensor((2, 4, 26, 26), "float32") = R.nn.conv2d(x, w, out_dtype="float32")
gv2: R.Tensor((2, 2, 9, 7), dtype="float32") = R.strided_slice(
gv, begin=[0, 0, 0], end=[4, 26, 26], strides=[2, 3, 4], axes=[1, 2, 3]
)
R.output(gv2)
return gv2
verify_results(Input, target, ref_target)
@pytest.mark.gpu
@skip_unless_adreno_opencl_vulkan
@pytest.mark.skipif(not tvm.testing.device_enabled(TARGETS[0]), reason="opencl not enabled")
def test_conv2d_relu_concat():
target = TARGETS[0]
@I.ir_module
class Input:
@R.function
def main(
x: R.Tensor((2, 16, 28, 28), "float32"), w: R.Tensor((4, 16, 3, 3), "float32")
) -> R.Tensor(None, "float32", ndim=4):
with R.dataflow():
gv: R.Tensor((2, 4, 26, 26), "float32") = R.nn.conv2d(x, w, out_dtype="float32")
gv2: R.Tensor((2, 4, 26, 26), "float32") = R.nn.relu(gv)
gv3: R.Tensor((2, 8, 26, 26), "float32") = R.concat((gv, gv2), axis=1)
R.output(gv3)
return gv3
verify_results(Input, target, ref_target)
@pytest.mark.gpu
@skip_unless_adreno_opencl_vulkan
@pytest.mark.skipif(not tvm.testing.device_enabled(TARGETS[0]), reason="opencl not enabled")
def test_conv2d_relu_concat_split():
target = TARGETS[0]
@I.ir_module
class Input:
@R.function
def main(x: R.Tensor((2, 16, 28, 28), "float32"), w: R.Tensor((4, 16, 3, 3), "float32")):
with R.dataflow():
gv: R.Tensor((2, 4, 26, 26), "float32") = R.nn.conv2d(x, w, out_dtype="float32")
gv2: R.Tensor((2, 4, 26, 26), "float32") = R.nn.relu(gv)
gv3: R.Tensor((2, 8, 26, 26), "float32") = R.concat((gv, gv2), axis=1)
gv4 = R.split(gv3, indices_or_sections=2, axis=1)
# TODO @Siva: Multi value return have an issue at runtime.
gv5 = gv4[0]
R.output(gv5)
return gv5
verify_results(Input, target, ref_target)
@pytest.mark.gpu
@skip_unless_adreno_opencl_vulkan
@pytest.mark.skipif(not tvm.testing.device_enabled(TARGETS[0]), reason="opencl not enabled")
def test_conv2d_relu_concat_split_transpose_concat():
target = TARGETS[0]
@I.ir_module
class Input:
@R.function
def main(x: R.Tensor((2, 16, 28, 28), "float32"), w: R.Tensor((4, 16, 3, 3), "float32")):
with R.dataflow():
gv: R.Tensor((2, 4, 26, 26), "float32") = R.nn.conv2d(x, w, out_dtype="float32")
gv2: R.Tensor((2, 4, 26, 26), "float32") = R.nn.relu(gv)
gv3: R.Tensor((2, 8, 26, 26), "float32") = R.concat((gv, gv2), axis=1)
gv4 = R.split(gv3, indices_or_sections=2, axis=1)
gv5: R.Tensor((26, 26, 4, 2), "float32") = R.permute_dims(gv4[0], axes=[3, 2, 1, 0])
gv6: R.Tensor((26, 26, 4, 2), "float32") = R.permute_dims(gv4[1], axes=[3, 2, 1, 0])
gv7: R.Tensor((26, 26, 8, 2), "float32") = R.concat((gv5, gv6), axis=2)
R.output(gv7)
return gv7
verify_results(Input, target, ref_target)
@pytest.mark.skip(reason="Known failure: numerical mismatch in texture lowering")
@pytest.mark.gpu
@skip_unless_adreno_opencl_vulkan
@pytest.mark.skipif(not tvm.testing.device_enabled(TARGETS[0]), reason="opencl not enabled")
def test_conv2d_maxpool2d():
target = TARGETS[0]
@I.ir_module
class Input:
@R.function
def main(
x: R.Tensor((2, 16, 28, 28), "float32"), w: R.Tensor((4, 16, 3, 3), "float32")
) -> R.Tensor(None, "float32", ndim=4):
with R.dataflow():
gv: R.Tensor((2, 4, 26, 26), "float32") = R.nn.conv2d(x, w, out_dtype="float32")
gv2 = R.nn.max_pool2d(
gv,
pool_size=[2, 2],
strides=[2, 2],
padding=[0, 0],
layout="NCHW",
out_layout="NCHW",
)
R.output(gv2)
return gv2
verify_results(Input, target, ref_target)
@pytest.mark.skip(reason="Known failure: numerical mismatch in texture lowering")
@pytest.mark.gpu
@skip_unless_adreno_opencl_vulkan
@pytest.mark.skipif(not tvm.testing.device_enabled(TARGETS[0]), reason="opencl not enabled")
def test_conv2d_avgpool2d():
target = TARGETS[0]
@I.ir_module
class Input:
@R.function
def main(
x: R.Tensor((2, 16, 28, 28), "float32"), w: R.Tensor((4, 16, 3, 3), "float32")
) -> R.Tensor(None, "float32", ndim=4):
with R.dataflow():
gv: R.Tensor((2, 4, 26, 26), "float32") = R.nn.conv2d(x, w, out_dtype="float32")
gv2 = R.nn.adaptive_avg_pool2d(gv, output_size=[13, 13], layout="NCHW")
R.output(gv2)
return gv2
verify_results(Input, target, ref_target)
@pytest.mark.gpu
@skip_unless_adreno_opencl_vulkan
@pytest.mark.skipif(not tvm.testing.device_enabled(TARGETS[0]), reason="opencl not enabled")
def test_conv2d_softmax():
target = TARGETS[0]
@I.ir_module
class Input:
@R.function
def main(
x: R.Tensor((2, 16, 28, 28), "float32"), w: R.Tensor((4, 16, 3, 3), "float32")
) -> R.Tensor(None, "float32", ndim=4):
with R.dataflow():
gv: R.Tensor((2, 4, 26, 26), "float32") = R.nn.conv2d(x, w, out_dtype="float32")
gv2 = R.nn.softmax(gv, axis=1)
R.output(gv2)
return gv2
verify_results(Input, target, ref_target)
@pytest.mark.gpu
@skip_unless_adreno_opencl_vulkan
@pytest.mark.skipif(not tvm.testing.device_enabled(TARGETS[0]), reason="opencl not enabled")
def test_conv2d_layernorm():
target = TARGETS[0]
@I.ir_module
class Input:
@R.function
def main(
x: R.Tensor((2, 16, 28, 28), "float32"),
w: R.Tensor((4, 16, 3, 3), "float32"),
gamma: R.Tensor((26, 26), dtype="float32"),
beta: R.Tensor((26, 26), dtype="float32"),
) -> R.Tensor(None, "float32", ndim=4):
with R.dataflow():
gv: R.Tensor((2, 4, 26, 26), "float32") = R.nn.conv2d(x, w, out_dtype="float32")
gv2: R.Tensor((2, 4, 26, 26), dtype="float32") = R.nn.layer_norm(
gv, gamma, beta, axes=[-2, -1]
)
R.output(gv2)
return gv2
verify_results(Input, target, ref_target)
@pytest.mark.gpu
@skip_unless_adreno_opencl_vulkan
@pytest.mark.skipif(not tvm.testing.device_enabled(TARGETS[0]), reason="opencl not enabled")
def test_binary_broadcast():
target = TARGETS[0]
@I.ir_module
class Input:
@R.function
def main(
x: R.Tensor((2, 16, 28, 28), "float32"),
w: R.Tensor((4, 16, 3, 3), "float32"),
bias: R.Tensor((26, 26), "float32"),
) -> R.Tensor(None, "float32", ndim=4):
with R.dataflow():
gv: R.Tensor((2, 4, 26, 26), "float32") = R.nn.conv2d(x, w, out_dtype="float32")
gv2: R.Tensor((2, 4, 26, 26), "float32") = R.add(gv, bias)
R.output(gv2)
return gv2
verify_results(Input, target, ref_target)
@pytest.mark.gpu
@skip_unless_adreno_opencl_vulkan
@pytest.mark.skipif(not tvm.testing.device_enabled(TARGETS[0]), reason="opencl not enabled")
def test_binary_ewise_scalar():
target = TARGETS[0]
@I.ir_module
class Input:
@R.function
def main(
x: R.Tensor((2, 16, 28, 28), "float32"), w: R.Tensor((4, 16, 3, 3), "float32")
) -> R.Tensor(None, "float32", ndim=4):
with R.dataflow():
gv: R.Tensor((2, 4, 26, 26), "float32") = R.nn.conv2d(x, w, out_dtype="float32")
gv2: R.Tensor((2, 4, 26, 26), "float32") = R.add(gv, R.const(1, "float32"))
R.output(gv2)
return gv2
verify_results(Input, target, ref_target)
@pytest.mark.gpu
@skip_unless_adreno_opencl_vulkan
@pytest.mark.skipif(not tvm.testing.device_enabled(TARGETS[0]), reason="opencl not enabled")
def test_residual_block():
target = TARGETS[0]
r"""
- some kind of residual block followed by convolution to have texture after residual block
- scalar data type verification which should be mapped to global memory scope
layout_transform (NCHW->NCHW4c)
| <- buffer
conv2d (1) <- to get textures as output
/ \
conv2d (2) |
\ /
add <- add should be fused into conv2d (2)
multiply to scalar <- buffer to the input of multiply scalar value
relu
| <- texture in intermediate tensor
conv2d (3)
relu
| <- buffer
layout_transform (NCHW4c->NCHW)
"""
@I.ir_module
class Input:
@R.function
def main(
x: R.Tensor((2, 32, 40, 40), "float32"),
w1: R.Tensor((32, 32, 2, 2), "float32"),
w2: R.Tensor((32, 32, 1, 1), "float32"),
w3: R.Tensor((32, 32, 2, 2), "float32"),
bias: R.Tensor((1, 32, 1, 1), "float32"),
) -> R.Tensor(None, "float32", ndim=4):
with R.dataflow():
gv = R.nn.conv2d(x, w1, strides=[2, 2], out_dtype="float32")
gv1 = R.add(gv, bias)
gv2 = R.nn.relu(gv1)
gv3 = R.nn.conv2d(gv2, w2, strides=[1, 1], out_dtype="float32")
bias_1 = R.multiply(bias, R.const(0.15, "float32"))
gv4 = R.add(gv3, bias_1)
gv5 = R.nn.relu(gv4)
gv6 = R.nn.conv2d(gv5, w3, strides=[2, 2], out_dtype="float32")
gv7 = R.nn.relu(gv6)
R.output(gv7)
return gv7
verify_results(Input, target, ref_target)
@pytest.mark.gpu
@skip_unless_adreno_opencl_vulkan
@pytest.mark.skipif(not tvm.testing.device_enabled(TARGETS[0]), reason="opencl not enabled")
def test_conv2d_conv2d_fallback_to_buffer_conv2d():
target = TARGETS[0]
r"""
layout_transform (NCHW->NCHW4c)
| <- texture
conv2d (1) <- textures as output
/ \
conv2d (2) conv2d (3) <- conv2d (2) emits texture, conv2d (3) emits buffer
\ / <- concat shouldn't support textures here
concatenation
| <- buffer
layout_transform (NCHW4c->NCHW)
"""
@I.ir_module
class Input:
@R.function
def main(
x: R.Tensor((2, 32, 40, 40), "float32"),
w1: R.Tensor((96, 32, 2, 2), "float32"),
w2: R.Tensor((32, 96, 2, 2), "float32"),
w3: R.Tensor((5, 96, 2, 2), "float32"),
bias1: R.Tensor((1, 96, 1, 1), "float32"),
bias2: R.Tensor((1, 32, 1, 1), "float32"),
) -> R.Tensor(None, "float32", ndim=4):
with R.dataflow():
gv = R.nn.conv2d(x, w1, strides=[2, 2], out_dtype="float32")
gv1 = R.add(gv, bias1)
gv2 = R.nn.relu(gv1)
gv3 = R.nn.conv2d(gv2, w2, strides=[2, 2], out_dtype="float32")
gv6 = R.nn.conv2d(gv2, w3, strides=[2, 2], out_dtype="float32")
gv7 = R.concat((gv3, gv6), axis=1)
R.output(gv7)
return gv7
verify_results(Input, target, ref_target)
@pytest.mark.gpu
@skip_unless_adreno_opencl_vulkan
@pytest.mark.skipif(not tvm.testing.device_enabled(TARGETS[0]), reason="opencl not enabled")
def test_conv2d_conv2d_conv2d_concat():
target = TARGETS[0]
r"""
layout_transform (NCHW->NCHW4c)
| <- texture
conv2d (1) <- textures as output
/ \
conv2d (2) conv2d (3)
\ / <- concat does support textures here
concatenation
| <- buffer
layout_transform (NCHW4c->NCHW)
"""
@I.ir_module
class Input:
@R.function
def main(
x: R.Tensor((2, 32, 40, 40), "float32"),
w1: R.Tensor((96, 32, 2, 2), "float32"),
w2: R.Tensor((32, 96, 2, 2), "float32"),
w3: R.Tensor((8, 96, 2, 2), "float32"),
bias1: R.Tensor((1, 96, 1, 1), "float32"),
bias2: R.Tensor((1, 32, 1, 1), "float32"),
) -> R.Tensor(None, "float32", ndim=4):
with R.dataflow():
gv = R.nn.conv2d(x, w1, strides=[2, 2], out_dtype="float32")
gv1 = R.add(gv, bias1)
gv2 = R.nn.relu(gv1)
gv3 = R.nn.conv2d(gv2, w2, strides=[2, 2], out_dtype="float32")
gv6 = R.nn.conv2d(gv2, w3, strides=[2, 2], out_dtype="float32")
gv7 = R.concat((gv3, gv6), axis=1)
R.output(gv7)
return gv7
verify_results(Input, target, ref_target)
@pytest.mark.skip(reason="Known failure: numerical mismatch in texture lowering")
@pytest.mark.gpu
@skip_unless_adreno_opencl_vulkan
@pytest.mark.skipif(not tvm.testing.device_enabled(TARGETS[0]), reason="opencl not enabled")
def test_pooling_branching_texture_params():
target = TARGETS[0]
r"""
Verification of the pooling and many branches having textures
layout_transform (NCHW->NCHW4c)
| <- texture
conv2d (0) <- to get textures
| <- textures
pooling
/ \ \ <- textures
conv2d (1) conv2d (2) conv2d (3)
\ / |
add | <- to have the only one output, will be fused
\ /
add <- to have the only one output, will be fused
| <- buffer
layout_transform (NCHW4c->NCHW)
"""
@I.ir_module
class Input:
@R.function
def main(
x: R.Tensor((2, 32, 40, 40), "float32"),
w1: R.Tensor((32, 32, 1, 1), "float32"),
w2: R.Tensor((32, 32, 2, 2), "float32"),
w3: R.Tensor((32, 32, 1, 1), "float32"),
w4: R.Tensor((32, 32, 2, 2), "float32"),
bias1: R.Tensor((1, 32, 1, 1), "float32"),
) -> R.Tensor(None, "float32", ndim=4):
with R.dataflow():
gv = R.nn.conv2d(x, w1, strides=[1, 1], out_dtype="float32")
gv1 = R.nn.max_pool2d(gv, pool_size=[2, 2], strides=[2, 2])
gv2 = R.nn.conv2d(
gv1, w2, padding=[0, 0, 1, 1], strides=[1, 1], out_dtype="float32"
)
gv5 = R.nn.conv2d(
gv1, w3, padding=[0, 0, 0, 0], strides=[1, 1], out_dtype="float32"
)
gv6 = R.nn.conv2d(
gv1, w4, padding=[0, 1, 1, 0], strides=[1, 1], out_dtype="float32"
)
gv8 = R.add(gv2, gv5)
gv9 = R.add(gv8, gv6)
R.output(gv9)
return gv9
verify_results(Input, target, ref_target)
@pytest.mark.gpu
@skip_unless_adreno_opencl_vulkan
@pytest.mark.skipif(not tvm.testing.device_enabled(TARGETS[0]), reason="opencl not enabled")
def test_injective_inputs1():
target = TARGETS[0]
r"""
Input
/ \
/ |
| /
conv2d (1) /
| /
conv2d (2) mean
/ \ /
| | \ /
| | (3) add
| | |
| \ /
\ mul
\ /
add
"""
@I.ir_module
class Input:
@R.function
def main(
x: R.Tensor((1, 4, 40, 40), "float32"),
w1: R.Tensor((4, 4, 3, 3), "float32"),
w2: R.Tensor((4, 4, 3, 3), "float32"),
w3: R.Tensor((4, 4, 3, 3), "float32"),
) -> R.Tensor(None, "float32", ndim=4):
with R.dataflow():
mean = R.mean(x, axis=1, keepdims=True)
conv1 = R.nn.conv2d(
x, w1, padding=[1, 1, 1, 1], strides=[1, 1], out_dtype="float32"
)
conv2 = R.nn.conv2d(
conv1, w2, padding=[1, 1, 1, 1], strides=[1, 1], out_dtype="float32"
)
ad3 = R.add(conv1, conv2)
ad1 = R.add(mean, conv1)
ad2 = R.multiply(ad1, conv2)
gv = R.add(ad3, ad2)
R.output(gv)
return gv
verify_results(Input, target, ref_target)
@pytest.mark.gpu
@skip_unless_adreno_opencl_vulkan
@pytest.mark.skipif(not tvm.testing.device_enabled(TARGETS[0]), reason="opencl not enabled")
def test_injective_nwo_inputs2():
target = TARGETS[0]
r"""
Input
/ \
| \
conv2d \
| /
conv2d mean /
/ \ /
add | \ |
| | \ |
| | \ /
| | (3) add
| | |
| \ /
| \ /
\ mul
\ /
add
"""
@I.ir_module
class Input:
@R.function
def main(
x: R.Tensor((1, 4, 40, 40), "float32"),
w1: R.Tensor((4, 4, 3, 3), "float32"),
w2: R.Tensor((4, 4, 3, 3), "float32"),
w3: R.Tensor((4, 4, 3, 3), "float32"),
) -> R.Tensor(None, "float32", ndim=4):
with R.dataflow():
mean = R.mean(x, axis=1, keepdims=True)
conv1 = R.nn.conv2d(
x, w1, padding=[1, 1, 1, 1], strides=[1, 1], out_dtype="float32"
)
conv2 = R.nn.conv2d(
conv1, w2, padding=[1, 1, 1, 1], strides=[1, 1], out_dtype="float32"
)
ad3 = R.add(conv1, conv2)
ad1 = R.add(mean, conv1)
ad2 = R.multiply(ad1, conv2)
gv = R.add(ad2, ad3)
R.output(gv)
return gv
verify_results(Input, target, ref_target)
if __name__ == "__main__":
tvm.testing.main()
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,283 @@
# 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.
# ruff: noqa: F401
import tvm
import tvm.testing
from tvm import relax
from tvm.ir.module import IRModule
from tvm.script.parser import ir as I
from tvm.script.parser import relax as R
from tvm.script.parser import tirx as T
def verify(input, expected):
mod = tvm.relax.backend.adreno.transform.FoldVDeviceScopeChange()(input)
tvm.ir.assert_structural_equal(mod, expected)
def test_maxpool2d_scope_folding():
@I.ir_module(s_tir=True)
class Input:
I.module_global_infos(
{
"vdevice": [
I.vdevice({"device": "adreno", "kind": "opencl"}, 0, "global.texture-weight"),
I.vdevice({"device": "adreno", "kind": "opencl"}, 0, "global"),
]
}
)
@T.prim_func(private=True, s_tir=True)
def max_pool2d_opencl(
gv: T.Buffer((T.int64(2), T.int64(1), T.int64(26), T.int64(26), T.int64(4)), "float32"),
pool_max: T.Buffer(
(T.int64(2), T.int64(1), T.int64(13), T.int64(13), T.int64(4)), "float32"
),
):
# with T.sblock("root"):
for ax0, ax1, ax2, ax3, ax4, rv0, rv1 in T.grid(
T.int64(2), T.int64(1), T.int64(13), T.int64(13), T.int64(4), T.int64(2), T.int64(2)
):
with T.sblock("pool_max"):
v_ax0, v_ax1, v_ax2, v_ax3, v_ax4, v_rv0, v_rv1 = T.axis.remap(
"SSSSSRR", [ax0, ax1, ax2, ax3, ax4, rv0, rv1]
)
T.reads(
gv[
v_ax0,
v_ax1,
v_ax2 * T.int64(2) + v_rv0,
v_ax3 * T.int64(2) + v_rv1,
v_ax4,
]
)
T.writes(pool_max[v_ax0, v_ax1, v_ax2, v_ax3, v_ax4])
T.sblock_attr({"schedule_rule": "meta_schedule.pool_max"})
with T.init():
pool_max[v_ax0, v_ax1, v_ax2, v_ax3, v_ax4] = T.float32(
-340282346638528859811704183484516925440.0
)
pool_max[v_ax0, v_ax1, v_ax2, v_ax3, v_ax4] = T.max(
pool_max[v_ax0, v_ax1, v_ax2, v_ax3, v_ax4],
gv[
v_ax0,
v_ax1,
v_ax2 * T.int64(2) + v_rv0,
v_ax3 * T.int64(2) + v_rv1,
v_ax4,
],
)
@T.prim_func(private=True, s_tir=True)
def te_layout_transform(
x: T.Buffer((T.int64(2), T.int64(4), T.int64(26), T.int64(26)), "float32"),
te_layout_transform: T.Buffer(
(T.int64(2), T.int64(1), T.int64(26), T.int64(26), T.int64(4)), "float32"
),
):
# with T.sblock("root"):
for self, i0, i1, i2 in T.grid(T.int64(2), T.int64(4), T.int64(26), T.int64(26)):
with T.sblock("te_layout_transform"):
v_self, v_i0, v_i1, v_i2 = T.axis.remap("SSSS", [self, i0, i1, i2])
T.reads(x[v_self, v_i0, v_i1, v_i2])
T.writes(
te_layout_transform[
v_self, v_i0 // T.int64(4), v_i1, v_i2, v_i0 % T.int64(4)
]
)
te_layout_transform[
v_self, v_i0 // T.int64(4), v_i1, v_i2, v_i0 % T.int64(4)
] = x[v_self, v_i0, v_i1, v_i2]
@T.prim_func(private=True, s_tir=True)
def te_layout_transform2(
lv2: T.Buffer(
(T.int64(2), T.int64(1), T.int64(13), T.int64(13), T.int64(4)), "float32"
),
te_layout_transform: T.Buffer(
(T.int64(2), T.int64(4), T.int64(13), T.int64(13)), "float32"
),
):
# with T.sblock("root"):
for self, i0, i1, i2, i3 in T.grid(
T.int64(2), T.int64(1), T.int64(13), T.int64(13), T.int64(4)
):
with T.sblock("te_layout_transform"):
v_self, v_i0, v_i1, v_i2, v_i3 = T.axis.remap("SSSSS", [self, i0, i1, i2, i3])
T.reads(lv2[v_self, v_i0, v_i1, v_i2, v_i3])
T.writes(te_layout_transform[v_self, v_i3, v_i1, v_i2])
te_layout_transform[v_self, v_i3, v_i1, v_i2] = lv2[
v_self, v_i0, v_i1, v_i2, v_i3
]
@R.function
def main(
x: R.Tensor((2, 4, 26, 26), dtype="float32", vdevice="opencl:1:global"),
) -> R.Tensor((2, 4, 13, 13), dtype="float32", vdevice="opencl:1:global"):
cls = Input
with R.dataflow():
lv = R.call_tir(
cls.te_layout_transform,
(x,),
out_ty=R.Tensor(
(2, 1, 26, 26, 4), dtype="float32", vdevice="opencl:0:global.texture-weight"
),
)
lv2 = R.call_tir(
cls.max_pool2d_opencl,
(lv,),
out_ty=R.Tensor(
(2, 1, 13, 13, 4), dtype="float32", vdevice="opencl:0:global.texture-weight"
),
)
lv5: R.Tensor((2, 1, 13, 13, 4), dtype="float32", vdevice="opencl:1:global") = (
R.to_vdevice(lv2, dst_vdevice="opencl:1:global")
)
gv2 = R.call_tir(
cls.te_layout_transform2,
(lv5,),
out_ty=R.Tensor((2, 4, 13, 13), dtype="float32", vdevice="opencl:1:global"),
)
R.output(gv2)
return gv2
@I.ir_module(s_tir=True)
class Expected:
I.module_global_infos(
{
"vdevice": [
I.vdevice({"device": "adreno", "kind": "opencl"}, 0, "global.texture-weight"),
I.vdevice({"device": "adreno", "kind": "opencl"}, 0, "global"),
]
}
)
@T.prim_func(private=True, s_tir=True)
def max_pool2d_opencl(
gv: T.Buffer((T.int64(2), T.int64(1), T.int64(26), T.int64(26), T.int64(4)), "float32"),
pool_max: T.Buffer(
(T.int64(2), T.int64(1), T.int64(13), T.int64(13), T.int64(4)), "float32"
),
):
# with T.sblock("root"):
for ax0, ax1, ax2, ax3, ax4, rv0, rv1 in T.grid(
T.int64(2), T.int64(1), T.int64(13), T.int64(13), T.int64(4), T.int64(2), T.int64(2)
):
with T.sblock("pool_max"):
v_ax0, v_ax1, v_ax2, v_ax3, v_ax4, v_rv0, v_rv1 = T.axis.remap(
"SSSSSRR", [ax0, ax1, ax2, ax3, ax4, rv0, rv1]
)
T.reads(
gv[
v_ax0,
v_ax1,
v_ax2 * T.int64(2) + v_rv0,
v_ax3 * T.int64(2) + v_rv1,
v_ax4,
]
)
T.writes(pool_max[v_ax0, v_ax1, v_ax2, v_ax3, v_ax4])
T.sblock_attr({"schedule_rule": "meta_schedule.pool_max"})
with T.init():
pool_max[v_ax0, v_ax1, v_ax2, v_ax3, v_ax4] = T.float32(
-340282346638528859811704183484516925440.0
)
pool_max[v_ax0, v_ax1, v_ax2, v_ax3, v_ax4] = T.max(
pool_max[v_ax0, v_ax1, v_ax2, v_ax3, v_ax4],
gv[
v_ax0,
v_ax1,
v_ax2 * T.int64(2) + v_rv0,
v_ax3 * T.int64(2) + v_rv1,
v_ax4,
],
)
@T.prim_func(private=True, s_tir=True)
def te_layout_transform(
x: T.Buffer((T.int64(2), T.int64(4), T.int64(26), T.int64(26)), "float32"),
te_layout_transform: T.Buffer(
(T.int64(2), T.int64(1), T.int64(26), T.int64(26), T.int64(4)), "float32"
),
):
# with T.sblock("root"):
for self, i0, i1, i2 in T.grid(T.int64(2), T.int64(4), T.int64(26), T.int64(26)):
with T.sblock("te_layout_transform"):
v_self, v_i0, v_i1, v_i2 = T.axis.remap("SSSS", [self, i0, i1, i2])
T.reads(x[v_self, v_i0, v_i1, v_i2])
T.writes(
te_layout_transform[
v_self, v_i0 // T.int64(4), v_i1, v_i2, v_i0 % T.int64(4)
]
)
te_layout_transform[
v_self, v_i0 // T.int64(4), v_i1, v_i2, v_i0 % T.int64(4)
] = x[v_self, v_i0, v_i1, v_i2]
@T.prim_func(private=True, s_tir=True)
def te_layout_transform2(
lv2: T.Buffer(
(T.int64(2), T.int64(1), T.int64(13), T.int64(13), T.int64(4)), "float32"
),
te_layout_transform: T.Buffer(
(T.int64(2), T.int64(4), T.int64(13), T.int64(13)), "float32"
),
):
# with T.sblock("root"):
for self, i0, i1, i2, i3 in T.grid(
T.int64(2), T.int64(1), T.int64(13), T.int64(13), T.int64(4)
):
with T.sblock("te_layout_transform"):
v_self, v_i0, v_i1, v_i2, v_i3 = T.axis.remap("SSSSS", [self, i0, i1, i2, i3])
T.reads(lv2[v_self, v_i0, v_i1, v_i2, v_i3])
T.writes(te_layout_transform[v_self, v_i3, v_i1, v_i2])
te_layout_transform[v_self, v_i3, v_i1, v_i2] = lv2[
v_self, v_i0, v_i1, v_i2, v_i3
]
@R.function
def main(
x: R.Tensor((2, 4, 26, 26), dtype="float32", vdevice="opencl:1:global"),
) -> R.Tensor((2, 4, 13, 13), dtype="float32", vdevice="opencl:1:global"):
cls = Expected
with R.dataflow():
lv = R.call_tir(
cls.te_layout_transform,
(x,),
out_ty=R.Tensor(
(2, 1, 26, 26, 4), dtype="float32", vdevice="opencl:0:global.texture-weight"
),
)
lv5 = R.call_tir(
cls.max_pool2d_opencl,
(lv,),
out_ty=R.Tensor((2, 1, 13, 13, 4), dtype="float32", vdevice="opencl:1:global"),
)
gv2 = R.call_tir(
cls.te_layout_transform2,
(lv5,),
out_ty=R.Tensor((2, 4, 13, 13), dtype="float32", vdevice="opencl:1:global"),
)
R.output(gv2)
return gv2
verify(Input, Expected)
if __name__ == "__main__":
tvm.testing.main()
+218
View File
@@ -0,0 +1,218 @@
# 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.
import os
import tempfile
import numpy as np
import pytest
import tvm
import tvm.testing
from tvm import relax
from tvm.support import ndk
# Test Infra
class run_time_check:
def __init__(self, device):
self.device = device
def check(self):
# Ensure adreno specific tests
if self.device == "real":
return "ADRENO_TARGET" in os.environ
# Adreno CI
if "ADRENO_TARGET" in os.environ:
return True
# Tests that can run on generic targets too
elif self.device == "opencl":
return tvm.opencl().exist
elif self.device == "vulkan":
return tvm.vulkan().exist
elif self.device == "any":
return tvm.opencl().exist or tvm.vulkan().exist
else:
return False
def __call__(self):
return self.check
# Eager skips for Adreno GPU tests, resolved at import time. Pair each with
# ``@pytest.mark.gpu`` at the test site so CI's ``-m gpu`` filter selects it.
# OpenCL or Vulkan
skip_unless_adreno_opencl_vulkan = pytest.mark.skipif(
not run_time_check("any").check(),
reason="need adreno opencl or vulkan",
)
# CLML Codegen
skip_unless_adreno_clml = pytest.mark.skipif(
tvm.get_global_func("relax.is_openclml_runtime_enabled", allow_missing=True) is None,
reason="need adreno openclml",
)
def is_target_available(target):
if "clml" in target.attrs.get("keys", []) and "ADRENO_TARGET" not in os.environ:
return False
return True
class SessionManager:
def __init__(self):
self.is_remote = SessionManager.is_target_rpc()
def __enter__(self):
if self.is_remote:
self.RPC_TRACKER_HOST = os.getenv("TVM_TRACKER_HOST", "localhost")
self.RPC_TRACKER_PORT = int(os.getenv("TVM_TRACKER_PORT", 7979))
self.RPC_DEVICE_KEY = os.getenv("RPC_DEVICE_KEY", "android")
self.tracker = tvm.rpc.connect_tracker(self.RPC_TRACKER_HOST, self.RPC_TRACKER_PORT)
self.rpc = self.tracker.request(self.RPC_DEVICE_KEY, priority=0, session_timeout=600)
else:
self.rpc = tvm.rpc.LocalSession()
return self
def __exit__(self, exc_type, exc_value, traceback):
self.rpc.get_function("CloseRPCConnection")()
def load_module(self, ex: relax.VMExecutable):
with tempfile.TemporaryDirectory() as tempdir:
file_name = "vm_library.so"
file_path = os.path.join(tempdir, file_name)
if self.is_remote:
ex.export_library(
file_path, fcompile=ndk.create_shared, options=["-shared", "-fPIC", "-lm"]
)
else:
ex.export_library(file_path)
self.rpc.upload(file_path)
rexec = self.rpc.load_module(file_name)
return rexec
def device(self, device: str):
return self.rpc.device(device)
@staticmethod
def is_target_rpc():
"""
Checks if the target is a remote device.
Returns
-------
bool: True if RPC_TARGET is set, False otherwise
"""
return os.environ.get("ADRENO_TARGET") == "adreno"
def run_local(mod, inputs, target):
"""
Run the Relax module on the local CPU for verification.
Parameters
----------
mod : tvm.IRModule
The Relax IRModule to execute.
inputs : list of numpy.ndarray
The input data for the module.
save_lib : bool, optional
Whether to save the compiled library. Default is False.
Returns
-------
tvm.runtime.NDArray or tuple of tvm.runtime.NDArray
The output from the module execution.
"""
ex = relax.build(mod, target)
dev = tvm.cpu()
vm = relax.VirtualMachine(ex, dev)
inputs = [tvm.runtime.tensor(inp, dev) for inp in inputs]
vm.set_input("main", *inputs)
vm.invoke_stateful("main")
tvm_output = vm.get_outputs("main")
if isinstance(tvm_output, tuple):
tvm_output = tuple(out.numpy() for out in tvm_output)
else:
tvm_output = (tvm_output.numpy(),)
return tvm_output
def build_and_run(mod, inputs, tgt):
if SessionManager.is_target_rpc():
tgt = tvm.target.Target(tgt, host={"kind": "llvm", "mtriple": "aarch64-linux-gnu"})
else:
tgt = tvm.target.Target(tgt, host={"kind": "llvm"})
relax_pipeline = relax.pipeline.get_default_pipeline(tgt)
tir_pipeline = tvm.tirx.get_default_tir_pipeline(tgt)
mod = relax_pipeline(mod)
ex = tvm.compile(mod, tgt, tir_pipeline=tir_pipeline)
def run_and_check():
with SessionManager() as sess:
rexec = sess.load_module(ex)
dev = sess.device(tgt.kind.name)
if "vdevice" in mod.global_infos:
device_arr = [dev for _ in range(len(mod.global_infos["vdevice"]))]
else:
device_arr = [dev]
vm = relax.VirtualMachine(rexec, device_arr)
device_inputs = [tvm.runtime.tensor(ip, dev) for ip in inputs]
vm.set_input("main", *device_inputs)
vm.invoke_stateful("main")
tvm_output = vm.get_outputs("main")
if isinstance(tvm_output, tuple):
return tuple(out.numpy() for out in tvm_output)
return (tvm_output.numpy(),)
if SessionManager.is_target_rpc():
return run_and_check()
return tvm.testing.run_with_gpu_lock(run_and_check)
def verify_results(mod, target, ref_target):
if not is_target_available(target):
print("Skipping Eval Tests", flush=True)
return
inputs = []
for arg in mod["main"].params:
shape = tuple(shape_val.value for shape_val in arg.ty.shape.values)
inputs.append(np.random.uniform(0, 1, size=shape).astype(arg.ty.dtype))
mod_org, mod_ref = mod, mod.clone()
mod_ref = tvm.relax.transform.DecomposeOpsForInference()(mod_ref)
if ref_target.kind.name == "llvm":
rs_ref = run_local(mod_ref, inputs, ref_target)
else:
rs_ref = build_and_run(mod_ref, inputs, ref_target)
rs_org = build_and_run(mod_org, inputs, target)
for vl_org, vl_ref in zip(rs_org, rs_ref):
tvm.testing.assert_allclose(vl_org, vl_ref, rtol=1e-3, atol=1e-3)