I am not sure that this insight helps resolving issue, it seems that this happens when a func passes ir_pass.fuse_ops (called in https://github.com/dmlc/tvm/blob/master/python/tvm/relay/build_module.py#L269).
import tvm
import tvm.relay as relay
import numpy as np
fallback_device = tvm.context("cpu")
target = {"cpu": "llvm", "cuda": "cuda"}
dev_ctx = tvm.context("cuda")
cpu_ctx = fallback_device
x = relay.var("x", shape=(1, 10))
y = relay.var("y", shape=(10, 10))
add = relay.add(x, y)
sqrt = relay.sqrt(add)
_sqrt = relay.annotation.on_device(sqrt, dev_ctx)
log = relay.log(add)
subtract = relay.subtract(sqrt, log)
exp = relay.exp(subtract)
_exp = relay.annotation.on_device(exp, dev_ctx)
func = relay.Function([x, y], relay.Tuple(tvm.convert([_sqrt, _exp, exp])))
func = relay.ir_pass.infer_type(func)
func = relay.ir_pass.rewrite_annotated_ops(func, cpu_ctx.device_type)
func = relay.ir_pass.infer_type(func)
func = relay.Function(relay.ir_pass.free_vars(func.body[2]), func.body[2])
##Storage_device_info seems correct
Storage_device_info = tvm.relay.backend._backend.GraphPlanMemory(func)
for k,[[x],[y]] in Storage_device_info.items():
print k
print y
free_var %x: Tensor[(1, 10), float32]
free_var %y: Tensor[(10, 10), float32]
%0 = add(%x, %y) # ty=Tensor[(10, 10), float32]
%0
1
free_var %x: Tensor[(1, 10), float32]
free_var %y: Tensor[(10, 10), float32]
%0 = add(%x, %y) # ty=Tensor[(10, 10), float32]
%1 = device_copy(%0, meta[relay.attrs.DeviceCopyAttrs][0]) # ty=Tensor[(10, 10), float32]
%2 = sqrt(%1) # ty=Tensor[(10, 10), float32]
%3 = device_copy(%2, meta[relay.attrs.DeviceCopyAttrs][1]) # ty=Tensor[(10, 10), float32]
%4 = log(%0) # ty=Tensor[(10, 10), float32]
%5 = subtract(%3, %4) # ty=Tensor[(10, 10), float32]
%6 = device_copy(%5, meta[relay.attrs.DeviceCopyAttrs][2]) # ty=Tensor[(10, 10), float32]
%6
# meta data omitted. you can use show_meta_data=True to include meta-data
2
free_var %y: Tensor[(10, 10), float32]
%y
1
free_var %x: Tensor[(1, 10), float32]
free_var %y: Tensor[(10, 10), float32]
%0 = add(%x, %y) # ty=Tensor[(10, 10), float32]
%1 = device_copy(%0, meta[relay.attrs.DeviceCopyAttrs][0]) # ty=Tensor[(10, 10), float32]
%1
# meta data omitted. you can use show_meta_data=True to include meta-data
2
free_var %x: Tensor[(1, 10), float32]
%x
1
free_var %x: Tensor[(1, 10), float32]
free_var %y: Tensor[(10, 10), float32]
%0 = add(%x, %y) # ty=Tensor[(10, 10), float32]
%1 = device_copy(%0, meta[relay.attrs.DeviceCopyAttrs][0]) # ty=Tensor[(10, 10), float32]
%2 = sqrt(%1) # ty=Tensor[(10, 10), float32]
%3 = device_copy(%2, meta[relay.attrs.DeviceCopyAttrs][1]) # ty=Tensor[(10, 10), float32]
%4 = log(%0) # ty=Tensor[(10, 10), float32]
%5 = subtract(%3, %4) # ty=Tensor[(10, 10), float32]
%5
# meta data omitted. you can use show_meta_data=True to include meta-data
1
free_var %x: Tensor[(1, 10), float32]
free_var %y: Tensor[(10, 10), float32]
%0 = add(%x, %y) # ty=Tensor[(10, 10), float32]
%1 = device_copy(%0, meta[relay.attrs.DeviceCopyAttrs][0]) # ty=Tensor[(10, 10), float32]
%2 = sqrt(%1) # ty=Tensor[(10, 10), float32]
%3 = device_copy(%2, meta[relay.attrs.DeviceCopyAttrs][1]) # ty=Tensor[(10, 10), float32]
%3
# meta data omitted. you can use show_meta_data=True to include meta-data
1
free_var %x: Tensor[(1, 10), float32]
free_var %y: Tensor[(10, 10), float32]
%0 = add(%x, %y) # ty=Tensor[(10, 10), float32]
%1 = device_copy(%0, meta[relay.attrs.DeviceCopyAttrs][0]) # ty=Tensor[(10, 10), float32]
%2 = sqrt(%1) # ty=Tensor[(10, 10), float32]
%2
# meta data omitted. you can use show_meta_data=True to include meta-data
2
free_var %x: Tensor[(1, 10), float32]
free_var %y: Tensor[(10, 10), float32]
%0 = add(%x, %y) # ty=Tensor[(10, 10), float32]
%1 = device_copy(%0, meta[relay.attrs.DeviceCopyAttrs][0]) # ty=Tensor[(10, 10), float32]
%2 = sqrt(%1) # ty=Tensor[(10, 10), float32]
%3 = device_copy(%2, meta[relay.attrs.DeviceCopyAttrs][1]) # ty=Tensor[(10, 10), float32]
%4 = log(%0) # ty=Tensor[(10, 10), float32]
%5 = subtract(%3, %4) # ty=Tensor[(10, 10), float32]
%6 = device_copy(%5, meta[relay.attrs.DeviceCopyAttrs][2]) # ty=Tensor[(10, 10), float32]
%7 = exp(%6) # ty=Tensor[(10, 10), float32]
%7
# meta data omitted. you can use show_meta_data=True to include meta-data
2
free_var %x: Tensor[(1, 10), float32]
free_var %y: Tensor[(10, 10), float32]
%0 = add(%x, %y) # ty=Tensor[(10, 10), float32]
%1 = log(%0) # ty=Tensor[(10, 10), float32]
%1
1
func = relay.ir_pass.infer_type(func)
func = relay.ir_pass.fuse_ops(func, 1)
func = relay.ir_pass.infer_type(func)
#Storage_device_info seems wrong(only free vars are on 1)
Storage_device_info = tvm.relay.backend._backend.GraphPlanMemory(func)
for k,[[x],[y]] in Storage_device_info.items():
print k
print y
free_var %x: Tensor[(1, 10), float32]
free_var %y: Tensor[(10, 10), float32]
%0 = fn(%p0: Tensor[(1, 10), float32],
%p1: Tensor[(10, 10), float32])
-> Tensor[(10, 10), float32] {
%1 = add(%p0, %p1) # ty=Tensor[(10, 10), float32]
%1
}
%2 = %0(%x, %y) # ty=Tensor[(10, 10), float32]
%3 = fn(%p01: Tensor[(10, 10), float32])
-> Tensor[(10, 10), float32] {
%4 = device_copy(%p01, meta[relay.attrs.DeviceCopyAttrs][0]) # ty=Tensor[(10, 10), float32]
%4
}
%5 = %3(%2) # ty=Tensor[(10, 10), float32]
%5
# meta data omitted. you can use show_meta_data=True to include meta-data
2
free_var %x: Tensor[(1, 10), float32]
free_var %y: Tensor[(10, 10), float32]
%0 = fn(%p0: Tensor[(1, 10), float32],
%p1: Tensor[(10, 10), float32])
-> Tensor[(10, 10), float32] {
%1 = add(%p0, %p1) # ty=Tensor[(10, 10), float32]
%1
}
%2 = %0(%x, %y) # ty=Tensor[(10, 10), float32]
%2
2
free_var %x: Tensor[(1, 10), float32]
free_var %y: Tensor[(10, 10), float32]
%0 = fn(%p0: Tensor[(1, 10), float32],
%p1: Tensor[(10, 10), float32])
-> Tensor[(10, 10), float32] {
%1 = add(%p0, %p1) # ty=Tensor[(10, 10), float32]
%1
}
%2 = %0(%x, %y) # ty=Tensor[(10, 10), float32]
%3 = fn(%p01: Tensor[(10, 10), float32])
-> Tensor[(10, 10), float32] {
%4 = device_copy(%p01, meta[relay.attrs.DeviceCopyAttrs][0]) # ty=Tensor[(10, 10), float32]
%4
}
%5 = %3(%2) # ty=Tensor[(10, 10), float32]
%6 = fn(%p02: Tensor[(10, 10), float32])
-> Tensor[(10, 10), float32] {
%7 = sqrt(%p02) # ty=Tensor[(10, 10), float32]
%7
}
%8 = %6(%5) # ty=Tensor[(10, 10), float32]
%9 = fn(%p03: Tensor[(10, 10), float32])
-> Tensor[(10, 10), float32] {
%10 = device_copy(%p03, meta[relay.attrs.DeviceCopyAttrs][1]) # ty=Tensor[(10, 10), float32]
%10
}
%11 = %9(%8) # ty=Tensor[(10, 10), float32]
%12 = fn(%p04: Tensor[(10, 10), float32],
%p11: Tensor[(10, 10), float32])
-> Tensor[(10, 10), float32] {
%13 = log(%p11) # ty=Tensor[(10, 10), float32]
%14 = subtract(%p04, %13) # ty=Tensor[(10, 10), float32]
%14
}
%15 = %12(%11, %2) # ty=Tensor[(10, 10), float32]
%16 = fn(%p05: Tensor[(10, 10), float32])
-> Tensor[(10, 10), float32] {
%17 = device_copy(%p05, meta[relay.attrs.DeviceCopyAttrs][2]) # ty=Tensor[(10, 10), float32]
%17
}
%18 = %16(%15) # ty=Tensor[(10, 10), float32]
%19 = fn(%p06: Tensor[(10, 10), float32])
-> Tensor[(10, 10), float32] {
%20 = exp(%p06) # ty=Tensor[(10, 10), float32]
%20
}
%21 = %19(%18) # ty=Tensor[(10, 10), float32]
%21
# meta data omitted. you can use show_meta_data=True to include meta-data
2
free_var %y: Tensor[(10, 10), float32]
%y
1
free_var %x: Tensor[(1, 10), float32]
free_var %y: Tensor[(10, 10), float32]
%0 = fn(%p0: Tensor[(1, 10), float32],
%p1: Tensor[(10, 10), float32])
-> Tensor[(10, 10), float32] {
%1 = add(%p0, %p1) # ty=Tensor[(10, 10), float32]
%1
}
%2 = %0(%x, %y) # ty=Tensor[(10, 10), float32]
%3 = fn(%p01: Tensor[(10, 10), float32])
-> Tensor[(10, 10), float32] {
%4 = device_copy(%p01, meta[relay.attrs.DeviceCopyAttrs][0]) # ty=Tensor[(10, 10), float32]
%4
}
%5 = %3(%2) # ty=Tensor[(10, 10), float32]
%6 = fn(%p02: Tensor[(10, 10), float32])
-> Tensor[(10, 10), float32] {
%7 = sqrt(%p02) # ty=Tensor[(10, 10), float32]
%7
}
%8 = %6(%5) # ty=Tensor[(10, 10), float32]
%9 = fn(%p03: Tensor[(10, 10), float32])
-> Tensor[(10, 10), float32] {
%10 = device_copy(%p03, meta[relay.attrs.DeviceCopyAttrs][1]) # ty=Tensor[(10, 10), float32]
%10
}
%11 = %9(%8) # ty=Tensor[(10, 10), float32]
%11
# meta data omitted. you can use show_meta_data=True to include meta-data
2
free_var %x: Tensor[(1, 10), float32]
free_var %y: Tensor[(10, 10), float32]
%0 = fn(%p0: Tensor[(1, 10), float32],
%p1: Tensor[(10, 10), float32])
-> Tensor[(10, 10), float32] {
%1 = add(%p0, %p1) # ty=Tensor[(10, 10), float32]
%1
}
%2 = %0(%x, %y) # ty=Tensor[(10, 10), float32]
%3 = fn(%p01: Tensor[(10, 10), float32])
-> Tensor[(10, 10), float32] {
%4 = device_copy(%p01, meta[relay.attrs.DeviceCopyAttrs][0]) # ty=Tensor[(10, 10), float32]
%4
}
%5 = %3(%2) # ty=Tensor[(10, 10), float32]
%6 = fn(%p02: Tensor[(10, 10), float32])
-> Tensor[(10, 10), float32] {
%7 = sqrt(%p02) # ty=Tensor[(10, 10), float32]
%7
}
%8 = %6(%5) # ty=Tensor[(10, 10), float32]
%9 = fn(%p03: Tensor[(10, 10), float32])
-> Tensor[(10, 10), float32] {
%10 = device_copy(%p03, meta[relay.attrs.DeviceCopyAttrs][1]) # ty=Tensor[(10, 10), float32]
%10
}
%11 = %9(%8) # ty=Tensor[(10, 10), float32]
%12 = fn(%p04: Tensor[(10, 10), float32],
%p11: Tensor[(10, 10), float32])
-> Tensor[(10, 10), float32] {
%13 = log(%p11) # ty=Tensor[(10, 10), float32]
%14 = subtract(%p04, %13) # ty=Tensor[(10, 10), float32]
%14
}
%15 = %12(%11, %2) # ty=Tensor[(10, 10), float32]
%16 = fn(%p05: Tensor[(10, 10), float32])
-> Tensor[(10, 10), float32] {
%17 = device_copy(%p05, meta[relay.attrs.DeviceCopyAttrs][2]) # ty=Tensor[(10, 10), float32]
%17
}
%18 = %16(%15) # ty=Tensor[(10, 10), float32]
%18
# meta data omitted. you can use show_meta_data=True to include meta-data
2
free_var %x: Tensor[(1, 10), float32]
free_var %y: Tensor[(10, 10), float32]
%0 = fn(%p0: Tensor[(1, 10), float32],
%p1: Tensor[(10, 10), float32])
-> Tensor[(10, 10), float32] {
%1 = add(%p0, %p1) # ty=Tensor[(10, 10), float32]
%1
}
%2 = %0(%x, %y) # ty=Tensor[(10, 10), float32]
%3 = fn(%p01: Tensor[(10, 10), float32])
-> Tensor[(10, 10), float32] {
%4 = device_copy(%p01, meta[relay.attrs.DeviceCopyAttrs][0]) # ty=Tensor[(10, 10), float32]
%4
}
%5 = %3(%2) # ty=Tensor[(10, 10), float32]
%6 = fn(%p02: Tensor[(10, 10), float32])
-> Tensor[(10, 10), float32] {
%7 = sqrt(%p02) # ty=Tensor[(10, 10), float32]
%7
}
%8 = %6(%5) # ty=Tensor[(10, 10), float32]
%8
# meta data omitted. you can use show_meta_data=True to include meta-data
2
free_var %x: Tensor[(1, 10), float32]
free_var %y: Tensor[(10, 10), float32]
%0 = fn(%p0: Tensor[(1, 10), float32],
%p1: Tensor[(10, 10), float32])
-> Tensor[(10, 10), float32] {
%1 = add(%p0, %p1) # ty=Tensor[(10, 10), float32]
%1
}
%2 = %0(%x, %y) # ty=Tensor[(10, 10), float32]
%3 = fn(%p01: Tensor[(10, 10), float32])
-> Tensor[(10, 10), float32] {
%4 = device_copy(%p01, meta[relay.attrs.DeviceCopyAttrs][0]) # ty=Tensor[(10, 10), float32]
%4
}
%5 = %3(%2) # ty=Tensor[(10, 10), float32]
%6 = fn(%p02: Tensor[(10, 10), float32])
-> Tensor[(10, 10), float32] {
%7 = sqrt(%p02) # ty=Tensor[(10, 10), float32]
%7
}
%8 = %6(%5) # ty=Tensor[(10, 10), float32]
%9 = fn(%p03: Tensor[(10, 10), float32])
-> Tensor[(10, 10), float32] {
%10 = device_copy(%p03, meta[relay.attrs.DeviceCopyAttrs][1]) # ty=Tensor[(10, 10), float32]
%10
}
%11 = %9(%8) # ty=Tensor[(10, 10), float32]
%12 = fn(%p04: Tensor[(10, 10), float32],
%p11: Tensor[(10, 10), float32])
-> Tensor[(10, 10), float32] {
%13 = log(%p11) # ty=Tensor[(10, 10), float32]
%14 = subtract(%p04, %13) # ty=Tensor[(10, 10), float32]
%14
}
%15 = %12(%11, %2) # ty=Tensor[(10, 10), float32]
%15
# meta data omitted. you can use show_meta_data=True to include meta-data
2
free_var %x: Tensor[(1, 10), float32]
%x
1