bevdet-p150 / code /scripts /debug_l1res.py
changh95's picture
tt-model push bevdet-p150 (container)
d160c10 verified
Raw History Blame Contribute Delete
4.31 kB
# SPDX-License-Identifier: Apache-2.0
"""Bring-up check of ``tt.l1res`` (OPT round 4): the real encoder weights, the round-3 encoder vs the L1-resident one,
per bottleneck of layers 3-4, every intermediate (conv1, conv2, conv3, identity, output) compared bit for bit.
Both encoders get the same layer-2 output (the round-3 encoder's).
bin/devrun -t 900 -- python -u code/scripts/debug_l1res.py
"""
from __future__ import annotations
import sys
import numpy as np
def main():
import torch
import ttnn
from tt_bevdet.device import close_device, open_device
from tt_bevdet.reference.config import default_config
from tt_bevdet.reference.weights import BEVDetWeights
from tt_bevdet.tests import paths
from tt_bevdet.tt.conv_tune import apply_tune
from tt_bevdet.tt.image_encoder import TtImageEncoder
from tt_bevdet.tt.l1res import L1ResBlock, block_mc, ensure
from tt_bevdet.tt.params import DEFAULT_PRECISION, BEVDetParams
from tt_bevdet.ttaw.ops.conv import is_dram
def bits(t):
if t.memory_config().is_sharded():
t = ttnn.to_memory_config(t, ttnn.DRAM_MEMORY_CONFIG)
return ttnn.to_torch(ttnn.from_device(t)).to(torch.bfloat16).view(torch.int16).numpy().reshape(
-1, int(t.shape[-1]))
def cmp(tag, a, b):
x, y = bits(a), bits(b)
print(f" {tag}: {int(np.count_nonzero(x != y))} differ; l1 mc "
f"{'dram' if is_dram(b) else b.memory_config().shard_spec.shape if b.memory_config().is_sharded() else 'l1'}",
flush=True)
cfg = default_config()
params = BEVDetParams(BEVDetWeights(paths.weights_onnx()), cfg)
dev = open_device()
try:
kw = dict(precision=DEFAULT_PRECISION, stem_in="kin", conv_l1="all", backbone_res="next12", mm1x1=True)
ref = TtImageEncoder(params, **kw)
l1 = TtImageEncoder(params, l1res=True, **kw)
apply_tune(ref.convs())
apply_tune(l1.convs())
n, (h, w) = cfg.n_cams, cfg.input_hw
rng = np.random.default_rng(7)
crop = rng.integers(0, 256, (n, h, w, 3), dtype=np.uint8)
din = ttnn.from_torch(torch.from_numpy(crop.reshape(1, 1, n * h, w * 3)), dtype=ttnn.uint8,
layout=ttnn.ROW_MAJOR_LAYOUT, device=dev, memory_config=ttnn.DRAM_MEMORY_CONFIG)
x = ref.kin_stem(din)
for blk in ref.stages.stages[0] + ref.stages.stages[1]:
x = blk(x)
xr = xl = x
gy = int(dev.compute_with_storage_grid_size().y)
for s in (2, 3):
for rb, lb in zip(ref.stages.stages[s], l1.stages.stages[s]):
b = rb
lbb: L1ResBlock = lb
print(f"{b.name}: in ref {'dram' if is_dram(xr.tensor) else 'l1'} / l1 "
f"{'dram' if is_dram(xl.tensor) else 'l1'}", flush=True)
y_r = b.conv1(xr)
if is_dram(xl.tensor):
y_l = lbb.blk.conv1(xl)
else:
y_l = lbb._mm(ensure(xl, block_mc(xl.rows, xl.channels, 8, gy))[0], lbb.w1,
b.conv3.in_channels, True, gy)
cmp("conv1", y_r.tensor, y_l.tensor)
z_r = b.conv2(y_r)
getattr(lbb.blk.conv2, "conv").slicing = "l1" if is_dram(y_l.tensor) else "auto"
z_l = lbb.blk.conv2(y_l)
cmp("conv2", z_r.tensor, z_l.tensor)
zs, mv = ensure(z_l, block_mc(z_l.rows, z_l.channels, 8, gy))
print(" conv2 moved:", mv, flush=True)
y3_r = b.conv3(z_r)
y3_l = lbb._mm(zs, lbb.w3, b.conv3.out_channels, False, gy)
cmp("conv3", y3_r.tensor, y3_l.tensor)
if b.downsample is not None:
d_r = b.downsample(xr)
xd = xl if is_dram(xl.tensor) else xl.with_tensor(
ttnn.to_memory_config(xl.tensor, ttnn.DRAM_MEMORY_CONFIG)) # as L1ResBlock does
d_l = lbb.blk.downsample(xd)
cmp("downsample", d_r.tensor, d_l.tensor)
xr = b(xr)
xl = lb(xl)
cmp("out", xr.tensor, xl.tensor)
finally:
close_device(dev)
return 0
if __name__ == "__main__":
sys.exit(main())