Skip to content

Commit 51c3e36

Browse files
Merge branch 'fc/astral-fix-3x3' into fc/neureka-ecc-regs
2 parents fe2be29 + c20c03c commit 51c3e36

6 files changed

Lines changed: 79 additions & 44 deletions

File tree

neureka/hal/neureka_task.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ void neureka_task_set_strides(neureka_task_t *task, const uint32_t k_in,
169169
if (task->kernel_shape == 1) { // 1x1
170170
task->data.cfg.weights_stride.d0 = NEUREKA_WEIGHT_BANDWIDTH_BYTES_1x1;
171171
task->data.cfg.weights_stride.d1 =
172-
NEUREKA_WEIGHT_BANDWIDTH_BYTES_1x1 * num_k_in;
172+
(NEUREKA_WEIGHT_BANDWIDTH_BYTES_1x1 / 8) * task->qw * num_k_in;
173173
} else if (!task->depthwise) { // 3x3
174174
task->data.cfg.weights_stride.d0 = NEUREKA_WEIGHT_BANDWIDTH_BYTES_3x3;
175175
task->data.cfg.weights_stride.d1 =

test/NeuralEngineFunctionalModel.py

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,23 @@
22

33
import torch
44
import torch.nn.functional as F
5+
import numpy as np
56

67
from TestClasses import IntegerType, Padding, Stride
78

89

910
class NeuralEngineFunctionalModel:
1011
ACCUMULATOR_TYPE = IntegerType(name="int32")
1112

13+
@staticmethod
14+
def _tensor_to_hex(tensor):
15+
int_tensor = np.asarray(torch.floor(tensor).to(torch.int64))
16+
int_tensor[int_tensor < 0] = 0xffffffff + (int_tensor[int_tensor < 0]+1)
17+
hex_tensor = np.empty(int_tensor.shape, dtype=object)
18+
for idx in np.ndindex(int_tensor.shape):
19+
hex_tensor[idx] = hex(int_tensor[idx].item())
20+
return hex_tensor
21+
1222
@staticmethod
1323
def _cast(
1424
tensor: torch.Tensor, _type: IntegerType, saturate: bool = False
@@ -36,7 +46,10 @@ def _norm_quant(
3646

3747
if verbose:
3848
print("INTERMEDIATE RESULTS (after scale):")
39-
print(tensor)
49+
current_threshold = np.get_printoptions()['threshold']
50+
np.set_printoptions(threshold=np.inf)
51+
print(NeuralEngineFunctionalModel._tensor_to_hex(tensor))
52+
np.set_printoptions(threshold=current_threshold)
4053

4154
if has_bias:
4255
assert bias is not None
@@ -54,7 +67,10 @@ def _norm_quant(
5467

5568
if verbose:
5669
print("INTERMEDIATE RESULTS (after bias):")
57-
print(tensor)
70+
current_threshold = np.get_printoptions()['threshold']
71+
np.set_printoptions(threshold=np.inf)
72+
print(NeuralEngineFunctionalModel._tensor_to_hex(tensor))
73+
np.set_printoptions(threshold=current_threshold)
5874

5975
if has_relu:
6076
tensor = F.relu(tensor)
@@ -63,7 +79,10 @@ def _norm_quant(
6379

6480
if verbose:
6581
print("INTERMEDIATE RESULTS (after shift):")
66-
print(tensor)
82+
current_threshold = np.get_printoptions()['threshold']
83+
np.set_printoptions(threshold=np.inf)
84+
print(NeuralEngineFunctionalModel._tensor_to_hex(tensor))
85+
np.set_printoptions(threshold=current_threshold)
6786

6887
# Saturate into out_type
6988
tensor = NeuralEngineFunctionalModel._cast(tensor, out_type, saturate=True)
@@ -102,6 +121,15 @@ def convolution(
102121
0,
103122
)
104123

124+
if verbose:
125+
print("INPUTS (padded):")
126+
current_threshold = np.get_printoptions()['threshold']
127+
np.set_printoptions(threshold=np.inf)
128+
print(NeuralEngineFunctionalModel._tensor_to_hex(input_padded))
129+
print("WEIGHTS (padded):")
130+
print(NeuralEngineFunctionalModel._tensor_to_hex(weight))
131+
np.set_printoptions(threshold=current_threshold)
132+
105133
# Accumulators are 32bit non-saturating.
106134
# Calculate in higher precision (int64)
107135
output = F.conv2d(
@@ -118,7 +146,10 @@ def convolution(
118146

119147
if verbose:
120148
print("INTERMEDIATE RESULTS (pre-normalization/requant):")
121-
print(output)
149+
current_threshold = np.get_printoptions()['threshold']
150+
np.set_printoptions(threshold=np.inf)
151+
print(NeuralEngineFunctionalModel._tensor_to_hex(output))
152+
np.set_printoptions(threshold=current_threshold)
122153

123154
if has_norm_quant:
124155
assert scale is not None

test/NeurekaMemoryLayout.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -88,15 +88,8 @@ def weightEncode(
8888
elif height == 1 and width == 1:
8989
# (cout * cinMajor, Bits * cinSubtile)
9090
weight = weight.reshape(-1, bits * cinSubtile)
91-
# Pad only the last dimension to weight bandwidth size
92-
# (-1, Weight Bandwidth)
93-
weight = np.pad(
94-
weight,
95-
((0, 0), (0, NeurekaMemoryLayout._WEIGHT_BANDWIDTH_1x1 - weight.shape[-1])),
96-
"constant",
97-
constant_values=0,
98-
)
99-
weightBandwidthBytes = int(np.ceil(NeurekaMemoryLayout._WEIGHT_BANDWIDTH_1x1 / 8))
91+
# No padding needed here
92+
weightBandwidthBytes = int(np.ceil(bits * cinSubtile / 8))
10093

10194
# Prepare for packing
10295
# (-1, Weight Bandwidth Bytes, 8)

test/NeurekaTestConf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ def check_valid_out_type(cls, v: IntegerType) -> IntegerType:
6565
@field_validator("weight_type")
6666
@classmethod
6767
def check_valid_weight_type(cls, v: IntegerType) -> IntegerType:
68-
NeurekaTestConf._check_type("weight_type", v, ["int8"])
68+
NeurekaTestConf._check_type("weight_type", v, ["int8", "int7", "int6", "int5", "int4", "int3", "int2"])
6969
return v
7070

7171
@field_validator("scale_type")

test/NnxTestClasses.py

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ class NnxTestConf(BaseModel):
4848
has_norm_quant: bool
4949
has_bias: bool
5050
has_relu: bool
51+
synthetic_weights: bool
52+
synthetic_inputs: bool
5153

5254
@model_validator(mode="after") # type: ignore
5355
def check_valid_depthwise_channels(self) -> NnxTestConf:
@@ -116,6 +118,8 @@ def __init__(
116118
scale: Optional[torch.Tensor] = None,
117119
bias: Optional[torch.Tensor] = None,
118120
global_shift: Optional[torch.Tensor] = torch.Tensor([0]),
121+
synthetic_weights: Optional[bool] = False,
122+
synthetic_inputs: Optional[bool] = False,
119123
) -> None:
120124
self.conf = conf
121125
self.input = input
@@ -124,6 +128,8 @@ def __init__(
124128
self.scale = scale
125129
self.bias = bias
126130
self.global_shift = global_shift
131+
self.synthetic_weights = synthetic_weights
132+
self.synthetic_inputs = synthetic_inputs
127133

128134
def is_valid(self) -> bool:
129135
return all(
@@ -207,7 +213,11 @@ def _calculate_global_shift(
207213
"""Calculate global shift so that the output values are in the range of out_type"""
208214
s = tensor.type(torch.float64).std()
209215
target_s = 2 ** (out_type._bits - 1)
210-
return torch.ceil(torch.log2(s / target_s)).type(torch.int32)
216+
shift = torch.ceil(torch.log2(s / target_s)).type(torch.int32)
217+
if shift < 1:
218+
return torch.zeros((1,)).type(torch.int32)
219+
else:
220+
return shift
211221

212222
@staticmethod
213223
def _random_data(_type: IntegerType, shape: Tuple, extremes: Tuple = None):
@@ -243,20 +253,30 @@ def from_conf(
243253
bias_shape = (1, conf.out_channel, 1, 1)
244254

245255
if input is None:
246-
input = NnxTestGenerator._random_data(
247-
_type=conf.in_type,
248-
shape=input_shape,
249-
)
256+
if conf.synthetic_inputs:
257+
inputs = torch.zeros((1, conf.in_channel, conf.in_height, conf.in_width), dtype=torch.int64)
258+
for i in range(conf.in_channel):
259+
inputs[:, i,0,0] = i
260+
else:
261+
input = NnxTestGenerator._random_data(
262+
_type=conf.in_type,
263+
shape=input_shape,
264+
)
250265

251266
if weight is None:
252-
weight_mean = NnxTestGenerator._DEFAULT_WEIGHT_MEAN
253-
weight_std = NnxTestGenerator._DEFAULT_WEIGHT_STDEV * (1<<(conf.weight_type._bits-1)-1)
254-
weight = NnxTestGenerator._random_data_normal(
255-
mean = weight_mean,
256-
std = weight_std,
257-
_type=conf.weight_type,
258-
shape=weight_shape,
259-
)
267+
if conf.synthetic_weights:
268+
weight = torch.zeros((conf.out_channel, 1 if conf.depthwise else conf.in_channel, conf.kernel_shape.height, conf.kernel_shape.width), dtype=torch.int64)
269+
for i in range(0, min(weight.shape[0], weight.shape[1])):
270+
weight[i,i,0,0] = 1
271+
else:
272+
weight_mean = NnxTestGenerator._DEFAULT_WEIGHT_MEAN
273+
weight_std = NnxTestGenerator._DEFAULT_WEIGHT_STDEV * (1<<(conf.weight_type._bits-1)-1)
274+
weight = NnxTestGenerator._random_data_normal(
275+
mean = weight_mean,
276+
std = weight_std,
277+
_type=conf.weight_type,
278+
shape=weight_shape,
279+
)
260280

261281
if conf.has_norm_quant:
262282
if scale is None:
@@ -306,6 +326,8 @@ def from_conf(
306326
scale=scale,
307327
bias=bias,
308328
global_shift=global_shift,
329+
synthetic_inputs=conf.synthetic_inputs,
330+
synthetic_weights=conf.synthetic_weights,
309331
)
310332

311333
@staticmethod
@@ -361,7 +383,10 @@ def generate(self, test_name: str, test: NnxTest):
361383
weight_type = test.conf.weight_type
362384
weight_bits = weight_type._bits
363385
assert weight_bits > 1 and weight_bits <= 8
364-
weight_offset = -(2 ** (weight_bits - 1))
386+
if test.synthetic_weights:
387+
weight_offset = 0
388+
else:
389+
weight_offset = -(2 ** (weight_bits - 1))
365390
weight_out_ch, weight_in_ch, weight_ks_h, weight_ks_w = test.weight.shape
366391
weight_data: np.ndarray = test.weight.numpy() - weight_offset
367392
weight_init = self.weightEncode(

test/testgen.py

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -86,21 +86,7 @@ def test_gen(
8686
exit(-1)
8787

8888
test_conf = nnxTestConfCls.model_validate(test_conf_dict)
89-
if test_conf_dict['synthetic_weights']:
90-
import torch
91-
weight = torch.zeros((test_conf.out_channel, 1 if test_conf.depthwise else test_conf.in_channel, test_conf.kernel_shape.height, test_conf.kernel_shape.width), dtype=torch.int64)
92-
for i in range(0, min(weight.shape[0], weight.shape[1])):
93-
weight[i,i,0,0] = 1
94-
else:
95-
weight = None
96-
if test_conf_dict['synthetic_inputs']:
97-
import torch
98-
inputs = torch.zeros((1, test_conf.in_channel, test_conf.in_height, test_conf.in_width), dtype=torch.int64)
99-
for i in range(test_conf.in_channel):
100-
inputs[:, i,0,0] = i
101-
else:
102-
inputs = None
103-
test = NnxTestGenerator.from_conf(test_conf, verbose=args.print_tensors, weight=weight, input=inputs)
89+
test = NnxTestGenerator.from_conf(test_conf, verbose=args.print_tensors)
10490
if not args.skip_save:
10591
test.save(args.test_dir)
10692
if args.headers:

0 commit comments

Comments
 (0)