Skip to content

Commit 45694c4

Browse files
committed
Fix DW ConvGradX weight tile size (L1 OOB in MobileNet backward)
DWConvGradX2DTileConstraint shares serializeTilingSolution with the regular-conv base class, which built the per-tile weight cube as (Cout, dxCube.dims[1], P, Q). That is right for regular conv where W[1] == Cin, but depthwise weight layout is [C, 1, P, Q]: dim 1 is always 1 and the per-channel slice should track dim 0 (Cout == C). For MobileNetV1 block_12 (C=256, 3x3 DW) the base formula produced a 2.36MB weight cube instead of the real 9KB, and the resulting DMA copy flooded L1 past all 16 banks starting at bank offset 0x4000, crashing the first backward pass. Extract the weight-cube construction into a _make_weight_cube hook on the base class and override it in DWConvGradX2DTileConstraint to produce ([offset_c, 0, 0, 0], [c_size, 1, P, Q]). With this, MobileNet training now runs 4 steps through gvsoc without OOB; ResNet8 (regular conv only) is unaffected.
1 parent a9b0242 commit 45694c4

1 file changed

Lines changed: 24 additions & 9 deletions

File tree

Deeploy/Targets/PULPOpen/TileConstraints/ConvGradConstraint.py

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,16 @@ def extraSerializeChecks(cls, ctxt: NetworkContext, operatorRepresentation: Oper
269269
"""Hook for DW checks etc."""
270270
return
271271

272+
@classmethod
273+
def _make_weight_cube(cls, dxCube: HyperRectangle,
274+
wShape: Tuple[int, int, int, int]) -> HyperRectangle:
275+
"""Per-tile weight cube. Regular conv: W layout [Cout, Cin/group, P, Q],
276+
so the Cin slice tracks dxCube.dims[1]. Subclasses override for DW."""
277+
return HyperRectangle(
278+
(0, dxCube.offset[1], 0, 0),
279+
(wShape[0], dxCube.dims[1], wShape[2], wShape[3]),
280+
)
281+
272282
# ---------------------------------------------------
273283
# 4) serialize: dx tiles -> dy halo tiles
274284
# ---------------------------------------------------
@@ -371,15 +381,9 @@ def serializeTilingSolution(
371381
dxAbsOff=abs_off
372382
)
373383

374-
# Per-tile W cube: slice C_in (dim 1) to match the dx channel range.
375-
# For regular conv the geometrical constraint ties dxName[1] == wName[1],
376-
# so dxCube.offset[1]/dims[1] line up with the W slice we need.
377-
# For DW or PW this degenerates to a full cube when the tiler didn't
378-
# split the axis (wShape[1] either 1 for DW or already == Cin full).
379-
wCube = HyperRectangle(
380-
(0, dxCube.offset[1], 0, 0),
381-
(wShape[0], dxCube.dims[1], wShape[2], wShape[3]),
382-
)
384+
# Per-tile W cube: layout differs between regular and DW conv,
385+
# so delegate to the subclass-overridable helper.
386+
wCube = cls._make_weight_cube(dxCube, wShape)
383387

384388
replacements["dim_im_in_x"].append(dxCube.dims[2]) # H_in_tile
385389
replacements["dim_im_in_y"].append(dxCube.dims[3]) # W_in_tile
@@ -526,6 +530,17 @@ def get_dy_channels(
526530
# DW: dY channels is C
527531
return dyFull[1]
528532

533+
@classmethod
534+
def _make_weight_cube(cls, dxCube: HyperRectangle,
535+
wShape: Tuple[int, int, int, int]) -> HyperRectangle:
536+
# DW weight layout [C, 1, P, Q]: the Cout axis (dim 0) tracks dxCube's
537+
# channel axis, Cin is always 1. Returning the regular-conv cube here
538+
# multiplies the weight transfer by Cin and blows past L1.
539+
return HyperRectangle(
540+
(dxCube.offset[1], 0, 0, 0),
541+
(dxCube.dims[1], 1, wShape[2], wShape[3]),
542+
)
543+
529544
class ConvGradWTileConstraintBase(TileConstraint):
530545
"""
531546
Base for ConvGradW2D tiling (im2col-style):

0 commit comments

Comments
 (0)