cofiber-detection / circuit /cofiber_detector.sv
phanerozoic's picture
update repository
dbbceb8
Raw
History Blame Contribute Delete
6.71 kB
// Cofiber detection head — fully combinational per-token detector
//
// Input: 768 signed 8-bit feature values (one spatial token)
// Output: 80 classification scores + 4 box regression values + 1 centerness
//
// All weights are ROM (analytically derived, zero training).
// The cofiber decomposition and pooling happen upstream in the spatial
// processing module — this module handles per-token prediction only.
//
// Parameters:
// FEAT_DIM - feature dimension (768 for EUPE-ViT-B)
// NUM_CLASSES - detection classes (80 for COCO)
// BIT_WIDTH - weight/activation precision
module cofiber_detector #(
parameter FEAT_DIM = 768,
parameter NUM_CLASSES = 80,
parameter BIT_WIDTH = 8,
parameter ACC_WIDTH = 24 // accumulator width for MAC results
)(
input logic signed [BIT_WIDTH-1:0] features [0:FEAT_DIM-1],
output logic signed [ACC_WIDTH-1:0] cls_scores [0:NUM_CLASSES-1],
output logic signed [ACC_WIDTH-1:0] box_ltrb [0:3],
output logic signed [ACC_WIDTH-1:0] centerness
);
// Weight ROMs — loaded from analytical solution
logic signed [BIT_WIDTH-1:0] cls_weight [0:NUM_CLASSES-1][0:FEAT_DIM-1];
logic signed [BIT_WIDTH-1:0] cls_bias [0:NUM_CLASSES-1];
logic signed [BIT_WIDTH-1:0] reg_weight [0:3][0:FEAT_DIM-1];
logic signed [BIT_WIDTH-1:0] reg_bias [0:3];
logic signed [BIT_WIDTH-1:0] ctr_weight [0:FEAT_DIM-1];
logic signed [BIT_WIDTH-1:0] ctr_bias;
initial begin
$readmemh("rom/cls_weight.hex", cls_weight);
$readmemh("rom/cls_bias.hex", cls_bias);
$readmemh("rom/reg_out_weight.hex", reg_weight);
$readmemh("rom/reg_out_bias.hex", reg_bias);
$readmemh("rom/ctr_weight.hex", ctr_weight);
$readmemh("rom/ctr_bias.hex", ctr_bias);
end
// Classification: 80 parallel dot products
// cls_scores[c] = sum(features[d] * cls_weight[c][d]) + cls_bias[c]
genvar c, d;
generate
for (c = 0; c < NUM_CLASSES; c = c + 1) begin : cls_mac
logic signed [ACC_WIDTH-1:0] acc;
always_comb begin
acc = {{(ACC_WIDTH-BIT_WIDTH){cls_bias[c][BIT_WIDTH-1]}}, cls_bias[c]};
for (int dd = 0; dd < FEAT_DIM; dd = dd + 1) begin
acc = acc + (features[dd] * cls_weight[c][dd]);
end
cls_scores[c] = acc;
end
end
endgenerate
// Box regression: 4 parallel dot products
generate
for (c = 0; c < 4; c = c + 1) begin : reg_mac
logic signed [ACC_WIDTH-1:0] acc;
always_comb begin
acc = {{(ACC_WIDTH-BIT_WIDTH){reg_bias[c][BIT_WIDTH-1]}}, reg_bias[c]};
for (int dd = 0; dd < FEAT_DIM; dd = dd + 1) begin
acc = acc + (features[dd] * reg_weight[c][dd]);
end
box_ltrb[c] = acc;
end
end
endgenerate
// Centerness: 1 dot product
logic signed [ACC_WIDTH-1:0] ctr_acc;
always_comb begin
ctr_acc = {{(ACC_WIDTH-BIT_WIDTH){ctr_bias[BIT_WIDTH-1]}}, ctr_bias};
for (int dd = 0; dd < FEAT_DIM; dd = dd + 1) begin
ctr_acc = ctr_acc + (features[dd] * ctr_weight[dd]);
end
centerness = ctr_acc;
end
endmodule
// Cofiber spatial decomposition — operates on the full feature grid
// Produces 3 scale bands from the input feature map
module cofiber_decompose #(
parameter FEAT_DIM = 768,
parameter BIT_WIDTH = 8,
parameter H = 40,
parameter W = 40
)(
input logic signed [BIT_WIDTH-1:0] features [0:FEAT_DIM-1][0:H-1][0:W-1],
output logic signed [BIT_WIDTH-1:0] scale0 [0:FEAT_DIM-1][0:H-1][0:W-1], // stride 16 cofiber
output logic signed [BIT_WIDTH-1:0] scale1 [0:FEAT_DIM-1][0:H/2-1][0:W/2-1], // stride 32 cofiber
output logic signed [BIT_WIDTH-1:0] scale2 [0:FEAT_DIM-1][0:H/4-1][0:W/4-1] // stride 64 residual
);
// Intermediate: pooled features at half resolution
logic signed [BIT_WIDTH+1:0] pool0 [0:FEAT_DIM-1][0:H/2-1][0:W/2-1];
logic signed [BIT_WIDTH+1:0] pool1 [0:FEAT_DIM-1][0:H/4-1][0:W/4-1];
genvar ch, r, col;
generate
// Pool0: 2x2 average pool of input features
for (ch = 0; ch < FEAT_DIM; ch = ch + 1) begin : pool0_ch
for (r = 0; r < H/2; r = r + 1) begin : pool0_r
for (col = 0; col < W/2; col = col + 1) begin : pool0_c
assign pool0[ch][r][col] = (features[ch][2*r][2*col]
+ features[ch][2*r+1][2*col]
+ features[ch][2*r][2*col+1]
+ features[ch][2*r+1][2*col+1]) >>> 2;
end
end
end
// Scale0: cofiber = features - upsample(pool0)
// Nearest-neighbor upsample for exact integer arithmetic
for (ch = 0; ch < FEAT_DIM; ch = ch + 1) begin : s0_ch
for (r = 0; r < H; r = r + 1) begin : s0_r
for (col = 0; col < W; col = col + 1) begin : s0_c
assign scale0[ch][r][col] = features[ch][r][col]
- pool0[ch][r/2][col/2][BIT_WIDTH-1:0];
end
end
end
// Pool1: 2x2 average pool of pool0
for (ch = 0; ch < FEAT_DIM; ch = ch + 1) begin : pool1_ch
for (r = 0; r < H/4; r = r + 1) begin : pool1_r
for (col = 0; col < W/4; col = col + 1) begin : pool1_c
assign pool1[ch][r][col] = (pool0[ch][2*r][2*col]
+ pool0[ch][2*r+1][2*col]
+ pool0[ch][2*r][2*col+1]
+ pool0[ch][2*r+1][2*col+1]) >>> 2;
end
end
end
// Scale1: cofiber of pool0
for (ch = 0; ch < FEAT_DIM; ch = ch + 1) begin : s1_ch
for (r = 0; r < H/2; r = r + 1) begin : s1_r
for (col = 0; col < W/2; col = col + 1) begin : s1_c
assign scale1[ch][r][col] = pool0[ch][r][col][BIT_WIDTH-1:0]
- pool1[ch][r/2][col/2][BIT_WIDTH-1:0];
end
end
end
// Scale2: the low-frequency residual
for (ch = 0; ch < FEAT_DIM; ch = ch + 1) begin : s2_ch
for (r = 0; r < H/4; r = r + 1) begin : s2_r
for (col = 0; col < W/4; col = col + 1) begin : s2_c
assign scale2[ch][r][col] = pool1[ch][r][col][BIT_WIDTH-1:0];
end
end
end
endgenerate
endmodule