I tried to implement a basic neural network in zig. The layers part of the program has been tested and works fine. But when i wrote the logic for weights. which is basically an array of matrices(i am representing a matrix with nested ArrayList), the compiler tells me there is a double free even though i wrote deinit properly(at least i think i did) .
I am not looking for alternate ways of setting up the matrices or the network, i just want to know how the double free occured.
#Not sure where the double free is occuring
1 messages · Page 1 of 1 (latest)
const std = @import("std");
const print = std.debug.print;
const math_ex = @import("math_ex.zig");
pub fn Hivemind() type {
return struct {
const Self = @This();
name: []const u8,
layers_count: usize,
layers_shape: []u8,
layers: std.ArrayList(std.ArrayList(f32)),
weights: std.ArrayList(std.ArrayList(std.ArrayList(f32))),
pub fn init(
allocator: std.mem.Allocator,
name: []const u8,
layers_shape: []u8,
) !Self {
var layers = std.ArrayList(std.ArrayList(f32)).init(allocator);
for (layers_shape) |size| {
var layer = std.ArrayList(f32).init(allocator);
try layer.appendNTimes(0.0, size);
try layers.append(layer);
}
// An array of matrices
var weights = std.ArrayList(std.ArrayList(std.ArrayList(f32))).init(allocator);
var i: u8 = 1;
while (i < layers.items.len) : (i += 1) {
// A matrix
var weights_ji = std.ArrayList(std.ArrayList(f32)).init(allocator);
// Row of matrix weights_ji
var row = std.ArrayList(f32).init(allocator);
// the num of cols of the matrix will be the length of the previous layer
try row.appendNTimes(0.0, layers.items[i].items.len);
//the num of rows of the matrix will be the length of the current layer
try weights_ji.appendNTimes(row, layers.items[i - 1].items.len);
try weights.append(weights_ji);
}
return Self{
.name = name,
.layers_shape = layers_shape,
.layers_count = layers_shape.len,
.layers = layers,
.weights = weights,
};
}
pub fn deinit(self: Self) void {
for (self.layers.items) |layer| {
layer.deinit();
}
self.layers.deinit();
for (self.weights.items) |weights_ji| {
for (weights_ji.items) |row| {
row.deinit();
}
weights_ji.deinit();
}
self.weights.deinit();
}
}
};
discord does not allow long messages, i hope that is readable
below is the main function
const std = @import("std");
const hivemind = @import("hivemind.zig");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
var layers_shape = [_]u8{ 4, 2, 2, 4, 2 };
var first = try hivemind.Hivemind().init(gpa.allocator(), "first", &layers_shape);
defer first.deinit();
hivemind.printHivemind(first);
}
here's the file since it looks quite messy on discord
I think you're treating the ArrayList row wrong
see this like try weights_ji.appendNTimes(row, layers.items[i - 1].items.len);
I'm going to go out on a very small limb and say that that is not giving the behaviour you expect
essentially that copies the value row layers.items[i - 1].items.len times
but it's not a deep copy
so the reference to the memory that row uses is repeated
so when you're freeing that data in .deinit, you're freeing that memory multiple times
I *think* you mean something like this:
while (i < layers.items.len) : (i += 1) {
var weights_ji = std.ArrayList(std.ArrayList(f32)).init(allocator);
for (0..layers.items[i].items.len) |_| {
var row = std.ArrayList(f32).init(allocator);
try row.appendNTimes(0.0, layers.items[i].items.len);
try weights_ji.append(row);
}
try weights.append(weights_ji);
}
this doesn't crash for me
I'm not really exactly sure what the expected output is, I just tried to remove the error
are you trying to tell that the same copy of row is being appended instead of getting n rows?