This is my implementation for Conv1d that supports groups and bias, you need to unsqueeze input to be 4d

groups = 3
batch = 4
out_channels = 6
in_channels = 6
kernel = 5
bias = torch.rand(out_channels)
inp = torch.randn(batch, in_channels, 1, 12)
w = torch.randn(out_channels, in_channels // groups, 1, kernel)
inp_unf = torch.nn.functional.unfold(inp.view(batch * groups, in_channels // groups, 1, 12), (1, kernel))
# inp_unf.size()   # 10 is kernel * in_channels // groups, 8 is conv output width
# torch.Size([12, 10, 8])
out_unf = inp_unf.view(batch, groups, inp_unf.size(1), inp_unf.size(2)).transpose(2, 3).matmul(w.view(1, groups, out_channels // groups, -1).permute(0, 1, 3, 2)).transpose(2,3)
# out_unf.size()
# torch.Size([4, 3, 2, 8])
e_out = torch.nn.functional.conv2d(inp, w, bias=bias, groups=3)
# e_out.size()
# torch.Size([4, 6, 1, 8])
(out_unf.reshape(batch, out_channels, 1, inp_unf.size(2)) + bias.unsqueeze(0).unsqueeze(2).unsqueeze(3) - e_out).abs().max()
# tensor(4.7684e-07)