Error message gives the wrong solution
While debugging @bung87 script

(fixed)
```Nim
import arraymancer
import sequtils
import random
import strformat

iterator data_iter[T](batch_size:Natural, features:Tensor[T], labels:Tensor[T]): (Tensor[T],Tensor[T]) =
  let num_examples = len(features)
  var indices = toSeq(countup(0,num_examples - 1))
  random.shuffle(indices)
  for i in countup(0, num_examples - 1 , batch_size):
    let j = indices[i: min(i + batch_size, num_examples)]
    yield (features.take(j), labels.take(j)) # take batch_size elements in each row.

proc linreg[T](X:Tensor[T], w:Tensor[T], b:T):Tensor[T] =
  # linear regression
  return X * w +. b

# proc squared_loss[T](y_hat:Tensor[T], y:Tensor[T]):
#   # loss function
#   return (y_hat - y.reshape(y_hat.shape)) ** 2 / 2

# proc sgd(params, lr, batch_size):
#   # Stochastic Batch Gradient Descent, optimization algorithm
#   for param in params:
#     param[:] = param - lr * param.grad / batch_size

let batch_size = 10


let num_inputs = 2
let num_examples = 1000
let true_w = [2.0'f32,-3.4'f32] # weights
let true_b = 4.2'f32 # bais
let features = randomTensor[float32]([num_examples, num_inputs], 1.0'f32)
var labels = true_w[0] * features[_,0] + true_w[1] * features[_,1] +. true_b
# noise
# labels += randomTensor[float32]([num_examples,1],0.01'f32)

# var w = randomTensor[float32]([num_inputs, 1],0.01'f32)
# var b = zeros[float32](1)


let ctx = newContext Tensor[float32]

let (N, D_in, H, D_out) = (num_examples, 2, num_examples + 1, 1)
# Create random Tensors to hold inputs and outputs, and wrap them in Variables.
let
  x = ctx.variable(features)
  y = labels

  batch = num_examples
  in_features = num_inputs
  out_features = 1

# WHen not initializing via the network DSL you need requires_grad = true
var w = ctx.variable(
              randomTensor[float32]([out_features, in_features],0.01'f32),
              requires_grad = true)
var b = ctx.variable(
              zeros[float32]([1, out_features]),
              requires_grad = true) # Shape [1, out_features], check is good but error message is wrong
# ##################################################################
# Define the model.

network ctx, TwoLayersNet:
  # layers:
  #   # fc1: Linear(D_in, H)
  #   fc2: Linear(H, D_out)
  forward x:
    x.linear(w,b)

let
  model = ctx.init(TwoLayersNet)
  optim = model.optimizerSGD(learning_rate = 0.03'f32)

# ##################################################################
# Training

for t in 0 ..< 3:
  let
    y_pred = model.forward(x)
    loss = y_pred.mse_loss(y)

  echo &"Epoch {t}: loss {loss.value[0]}"

  loss.backprop()
  optim.update()
# lr = 0.03 num_epochs = 3
# net = linreg
# loss = squared_loss
# for epoch in range(num_epochs):
# # 在每一个迭代周期中，会使用训练数据集中所有样本一次(假设样本数能够被批量大小整除)。X
#   # 和y分别是小批量样本的特征和标签
#   for X, y in data_iter(batch_size, features, labels):
#     with autograd.record():
#       l = loss(net(X, w, b), y) # l是有关小批量X和y的损失
#     l.backward() # 小批量的损失对模型参数求梯度
#     sgd([w, b], lr, batch_size) # 使用小批量随机梯度下降迭代模型参数
#   train_l = loss(net(features, w, b), labels)
#   print('epoch %d, loss %f' % (epoch + 1, train_l.mean().asnumpy()))
# true_w, w
# true_b, b
```

https://github.com/mratsim/Arraymancer/blob/974efe7a57481c06d4fc6995629e99603e33c017/src/nn/layers/linear.nim#L73-L100
The error message contradicts the function documentation and the actual test.

It can be replaced by something more descriptive lie
```Nim
    # weight has shape: Out_features * In_features
    # bias must have shape: Out_features * 1
    if not bias.isNil and not (bias.value.shape == [1, weight.value.shape[0]].toMetadataArray):
      raise newException(ValueError, "Incompatible shape: bias must be a vector of shape [1, out_features] but found: " &
        $bias.value.shape & " (for reference weight [out_features, in_features] was " & $weight.value.shape)
```