Skip to content

Commit 2123d28

Browse files
committed
fixed nchw and nhwc conversion tests
1 parent de6a026 commit 2123d28

File tree

5 files changed

+14
-217
lines changed

5 files changed

+14
-217
lines changed

src/Core/Tensor/tensor.zig

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,6 +1013,9 @@ pub fn from_NCHW_to_NHWC(comptime T: type, alloc: *const std.mem.Allocator, tens
10131013
if (tensor_nchw.shape.len != 4) {
10141014
return error.InvalidShape;
10151015
}
1016+
if (tensor_nchw.data.len == 0) {
1017+
return error.EmptyTensor;
1018+
}
10161019

10171020
// Extract dimensions assuming NCHW layout
10181021
const N = tensor_nchw.shape[0];
@@ -1023,14 +1026,6 @@ pub fn from_NCHW_to_NHWC(comptime T: type, alloc: *const std.mem.Allocator, tens
10231026
// New shape will be NHWC
10241027
var new_shape = [_]usize{ N, H, W, C };
10251028

1026-
// Handle empty tensor case
1027-
if (tensor_nchw.data.len == 0) {
1028-
const result = try alloc.create(Tensor(T));
1029-
errdefer alloc.destroy(result);
1030-
result.* = try Tensor(T).init(alloc);
1031-
return result;
1032-
}
1033-
10341029
const result = try alloc.create(Tensor(T));
10351030
errdefer alloc.destroy(result);
10361031

@@ -1063,6 +1058,9 @@ pub fn from_NHWC_to_NCHW(comptime T: type, alloc: *const std.mem.Allocator, tens
10631058
if (tensor_nhwc.shape.len != 4) {
10641059
return error.InvalidShape;
10651060
}
1061+
if (tensor_nhwc.data.len == 0) {
1062+
return error.EmptyTensor;
1063+
}
10661064

10671065
const N = tensor_nhwc.shape[0];
10681066
const H = tensor_nhwc.shape[1];
@@ -1071,13 +1069,6 @@ pub fn from_NHWC_to_NCHW(comptime T: type, alloc: *const std.mem.Allocator, tens
10711069

10721070
var new_shape = [_]usize{ N, C, H, W };
10731071

1074-
if (tensor_nhwc.data.len == 0) {
1075-
const result = try alloc.create(Tensor(T));
1076-
errdefer alloc.destroy(result);
1077-
result.* = try Tensor(T).init(alloc);
1078-
return result;
1079-
}
1080-
10811072
const result = try alloc.create(Tensor(T));
10821073
errdefer alloc.destroy(result);
10831074

src/IR_zant/utils.zig

Lines changed: 0 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -557,99 +557,6 @@ pub fn getAllTensors(hashMap: *std.StringHashMap(TensorZant)) ![]TensorZant {
557557
return inputs.toOwnedSlice(allocator);
558558
}
559559

560-
// ...existing code...
561-
562-
/// Converte un TensorZant da layout NCHW a NHWC
563-
/// MODIFICA FISICA: riorganizza i dati in memoria
564-
/// CONSUMA il tensor_nchw originale (ownership transfer)
565-
pub fn from_NCHW_to_NHWC(alloc: std.mem.Allocator, tensor_nchw: *TensorZant) !*TensorZant {
566-
// Validazione: deve essere 4D
567-
if (tensor_nchw.shape.len != 4) {
568-
std.log.err("Expected 4D tensor (NCHW), got {d}D with shape: {any}", .{
569-
tensor_nchw.shape.len,
570-
tensor_nchw.shape,
571-
});
572-
return error.InvalidTensorShape;
573-
}
574-
575-
// Validazione: nessuna dimensione può essere zero
576-
for (tensor_nchw.shape, 0..) |dim, i| {
577-
if (dim == 0) {
578-
std.log.err("Invalid dimension at index {d}: cannot be zero", .{i});
579-
return error.InvalidDimension;
580-
}
581-
}
582-
583-
const N = tensor_nchw.shape[0];
584-
const C = tensor_nchw.shape[1];
585-
const H = tensor_nchw.shape[2];
586-
const W = tensor_nchw.shape[3];
587-
588-
// Caso 1: Tensor senza dati (solo shape) - conversione logica
589-
if (tensor_nchw.ptr == null) {
590-
const new_shape = try alloc.alloc(usize, 4);
591-
new_shape[0] = N;
592-
new_shape[1] = H;
593-
new_shape[2] = W;
594-
new_shape[3] = C;
595-
596-
const result = try alloc.create(TensorZant);
597-
result.* = try TensorZant.init(
598-
tensor_nchw.name,
599-
null,
600-
null,
601-
new_shape,
602-
tensor_nchw.tc,
603-
);
604-
605-
// Cleanup originale
606-
alloc.free(tensor_nchw.shape);
607-
alloc.free(tensor_nchw.stride);
608-
alloc.destroy(tensor_nchw);
609-
610-
return result;
611-
}
612-
613-
// Caso 2: Tensor con dati - CONVERSIONE FISICA
614-
615-
// Converti fisicamente i dati usando la funzione di tensor.zig
616-
const new_any_tensor = try zant.core.tensor.convertNCHWtoNHWC(
617-
tensor_nchw.ptr.?.*,
618-
alloc,
619-
);
620-
621-
// Ottieni il nuovo shape dal tensore convertito
622-
const new_shape = switch (new_any_tensor) {
623-
inline else => |tensor_ptr| tensor_ptr.shape,
624-
};
625-
626-
// Calcola nuovo stride per layout NHWC
627-
const new_stride = try computeStride(alloc, new_shape);
628-
629-
// Crea wrapper AnyTensor
630-
const new_any_tensor_ptr = try alloc.create(AnyTensor);
631-
new_any_tensor_ptr.* = new_any_tensor;
632-
633-
// Crea nuovo TensorZant con i dati fisicamente riorganizzati
634-
const result = try alloc.create(TensorZant);
635-
result.* = TensorZant{
636-
.name = tensor_nchw.name,
637-
.ty = tensor_nchw.ty,
638-
.tc = tensor_nchw.tc,
639-
.ptr = new_any_tensor_ptr,
640-
.shape = new_shape,
641-
.stride = new_stride,
642-
};
643-
644-
// Cleanup del wrapper originale (i dati sono già stati deallocati in convertNCHWtoNHWC)
645-
alloc.destroy(tensor_nchw.ptr.?); // Solo il wrapper AnyTensor
646-
alloc.free(tensor_nchw.shape);
647-
alloc.free(tensor_nchw.stride);
648-
alloc.destroy(tensor_nchw);
649-
650-
return result;
651-
}
652-
653560
/// Calcola stride per un dato shape (row-major order)
654561
fn computeStride(alloc: std.mem.Allocator, shape: []const usize) ![]usize {
655562
const stride = try alloc.alloc(usize, shape.len);

tests/Core/Tensor/test_tensor.zig

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -534,28 +534,11 @@ test "from_NHWC_to_NCHW and vice versa" {
534534
alloc.*.free(tensor_nhwc.data);
535535
tensor_nhwc.data = &[_]f32{};
536536

537-
const result = try from_NHWC_to_NCHW(f32, alloc, &tensor_nhwc);
538-
defer {
539-
result.deinit();
540-
alloc.*.destroy(result);
541-
}
537+
const result1 = from_NHWC_to_NCHW(f32, alloc, &tensor_nhwc);
538+
try std.testing.expectError(error.EmptyTensor, result1);
542539

543-
// Verify it's truly empty
544-
try std.testing.expectEqual(@as(usize, 0), result.shape.len);
545-
try std.testing.expectEqual(@as(usize, 0), result.data.len);
546-
try std.testing.expectEqual(@as(usize, 0), result.size);
547-
548-
// and viceversa...
549-
const tensor_viceversa = try from_NCHW_to_NHWC(f32, alloc, result);
550-
defer {
551-
tensor_viceversa.deinit();
552-
alloc.*.destroy(tensor_viceversa);
553-
}
554-
// Verify data reordering
555-
for (0..tensor_nhwc.data.len) |i| {
556-
const res: f32 = @floatFromInt(i);
557-
try std.testing.expectEqual(res, tensor_viceversa.data[i]);
558-
}
540+
const result2 = from_NCHW_to_NHWC(f32, alloc, &tensor_nhwc);
541+
try std.testing.expectError(error.EmptyTensor, result2);
559542
}
560543

561544
//invalid shape (3D tensor should fail)
@@ -624,7 +607,7 @@ test "from_NHWC_to_NCHW and vice versa" {
624607

625608
// Fill with deterministic pattern for verification
626609
for (0..total_elements) |i| {
627-
tensor_nhwc.data[i] = @floatFromInt(i % 256); // Simulate pixel values 0-255
610+
tensor_nhwc.data[i] = @floatFromInt(i); // Simulate pixel values 0-255
628611
}
629612

630613
const tensor_nchw = try from_NHWC_to_NCHW(f32, alloc, &tensor_nhwc);

tests/Utils/test_utils.zig

Lines changed: 0 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ const TensorCategory = IR_zant.TensorCategory;
1111
const TensorType = IR_zant.tensorZant_lib.TensorType;
1212
const Tensor = zant.core.tensor.Tensor;
1313
const AnyTensor = zant.core.tensor.AnyTensor;
14-
const from_NCHW_to_NHWC = utils.from_NCHW_to_NHWC;
1514

1615
const tests_log = std.log.scoped(.test_utils);
1716

@@ -209,86 +208,3 @@ fn cleanupConvertedTensor(alloc: std.mem.Allocator, tensor: *TensorZant) void {
209208
alloc.free(tensor.stride);
210209
alloc.destroy(tensor);
211210
}
212-
213-
test "from_NCHW_to_NHWC - physical data reordering" {
214-
tests_log.info("\n from_NCHW_to_NHWC - physical data reordering", .{});
215-
216-
const alloc = std.testing.allocator;
217-
218-
// Crea tensor NCHW: [1, 2, 2, 3] = 12 elementi
219-
// N=1, C=2, H=2, W=3
220-
const tensor_nchw = try createTensorZant([4]usize{ 1, 2, 2, 3 });
221-
222-
// Dati originali NCHW (sequenziali: 0,1,2,...)
223-
// Canale 0: [0,1,2, 3,4,5] (H=2, W=3)
224-
// Canale 1: [6,7,8, 9,10,11] (H=2, W=3)
225-
226-
const tensor_nhwc = try from_NCHW_to_NHWC(alloc, tensor_nchw);
227-
228-
defer cleanupConvertedTensor(alloc, tensor_nhwc);
229-
230-
// Verifica shape NHWC: [1, 2, 3, 2]
231-
try std.testing.expectEqual(@as(usize, 1), tensor_nhwc.shape[0]); // N
232-
try std.testing.expectEqual(@as(usize, 2), tensor_nhwc.shape[1]); // H
233-
try std.testing.expectEqual(@as(usize, 3), tensor_nhwc.shape[2]); // W
234-
try std.testing.expectEqual(@as(usize, 2), tensor_nhwc.shape[3]); // C
235-
236-
// Verifica stride NHWC: [12, 6, 2, 1]
237-
try std.testing.expectEqual(@as(usize, 12), tensor_nhwc.stride[0]);
238-
try std.testing.expectEqual(@as(usize, 6), tensor_nhwc.stride[1]);
239-
try std.testing.expectEqual(@as(usize, 2), tensor_nhwc.stride[2]);
240-
try std.testing.expectEqual(@as(usize, 1), tensor_nhwc.stride[3]);
241-
242-
// Verifica riorganizzazione FISICA dei dati
243-
const data_nhwc = switch (tensor_nhwc.ptr.?.*) {
244-
.f32 => |ptr| ptr.data,
245-
else => unreachable,
246-
};
247-
248-
// Layout NHWC atteso:
249-
// [n=0, h=0, w=0]: [C0=0, C1=6] -> indici 0,1
250-
// [n=0, h=0, w=1]: [C0=1, C1=7] -> indici 2,3
251-
// [n=0, h=0, w=2]: [C0=2, C1=8] -> indici 4,5
252-
// [n=0, h=1, w=0]: [C0=3, C1=9] -> indici 6,7
253-
// [n=0, h=1, w=1]: [C0=4, C1=10] -> indici 8,9
254-
// [n=0, h=1, w=2]: [C0=5, C1=11] -> indici 10,11
255-
256-
try std.testing.expectEqual(@as(f32, 0.0), data_nhwc[0]); // n=0,h=0,w=0,c=0
257-
try std.testing.expectEqual(@as(f32, 6.0), data_nhwc[1]); // n=0,h=0,w=0,c=1
258-
try std.testing.expectEqual(@as(f32, 1.0), data_nhwc[2]); // n=0,h=0,w=1,c=0
259-
try std.testing.expectEqual(@as(f32, 7.0), data_nhwc[3]); // n=0,h=0,w=1,c=1
260-
try std.testing.expectEqual(@as(f32, 2.0), data_nhwc[4]); // n=0,h=0,w=2,c=0
261-
try std.testing.expectEqual(@as(f32, 8.0), data_nhwc[5]); // n=0,h=0,w=2,c=1
262-
try std.testing.expectEqual(@as(f32, 3.0), data_nhwc[6]); // n=0,h=1,w=0,c=0
263-
try std.testing.expectEqual(@as(f32, 9.0), data_nhwc[7]); // n=0,h=1,w=0,c=1
264-
try std.testing.expectEqual(@as(f32, 4.0), data_nhwc[8]); // n=0,h=1,w=1,c=0
265-
try std.testing.expectEqual(@as(f32, 10.0), data_nhwc[9]); // n=0,h=1,w=1,c=1
266-
try std.testing.expectEqual(@as(f32, 5.0), data_nhwc[10]); // n=0,h=1,w=2,c=0
267-
try std.testing.expectEqual(@as(f32, 11.0), data_nhwc[11]); // n=0,h=1,w=2,c=1
268-
}
269-
270-
test "from_NCHW_to_NHWC - verify contiguous memory layout" {
271-
tests_log.info("\n from_NCHW_to_NHWC - verify contiguous memory layout", .{});
272-
273-
const alloc = std.testing.allocator;
274-
275-
const tensor_nchw = try createTensorZant([4]usize{ 1, 3, 2, 2 });
276-
277-
const tensor_nhwc = try from_NCHW_to_NHWC(alloc, tensor_nchw);
278-
279-
defer cleanupConvertedTensor(alloc, tensor_nhwc);
280-
281-
const data = switch (tensor_nhwc.ptr.?.*) {
282-
.f32 => |ptr| ptr.data,
283-
else => unreachable,
284-
};
285-
286-
// Verifica che i dati siano contigui in memoria
287-
// Nel layout NHWC, i canali devono essere adiacenti
288-
for (0..data.len - 1) |i| {
289-
const ptr_curr = @intFromPtr(&data[i]);
290-
const ptr_next = @intFromPtr(&data[i + 1]);
291-
// Ogni elemento f32 è 4 bytes
292-
try std.testing.expectEqual(ptr_curr + 4, ptr_next);
293-
}
294-
}

tests/test_lib.zig

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const test_name = test_options.test_name;
44

55
comptime {
66
_ = @import("Core/test_core.zig");
7-
// _ = @import("Utils/test_utils.zig");
8-
// _ = @import("ImageToTensor/test_imgToTensor.zig");
9-
// _ = @import("IR_graph/IR_graph.zig");
7+
_ = @import("Utils/test_utils.zig");
8+
_ = @import("ImageToTensor/test_imgToTensor.zig");
9+
_ = @import("IR_graph/IR_graph.zig");
1010
}

0 commit comments

Comments
 (0)