Czysto edukacyjnie, neuron to funkcja linowa + funkcja aktywacji tak obliczasz wynik, a uczysz w drugą stronę licząc funkcja liniowa + funkcja aktywacji + funkcja błędu i pochodną po wadze neuronu i po biasie neuronu i tak dla każdego neuronu.
W twoim przypadku możesz bez funkcji aktywacji, czyli sama funkcja liniowa i potem funkcja błędu.
np. x to dane wejściowe, W - waga, b - bias, target to jakiego wyniku się spodziewasz, y = (x * W + b) funkcja błędu (target - y)^2 i liczysz pochodną po funkcji błędu to ci wychodzi (target - (x * W +b))^2 to pochodna W/funkcji_loss = 2*(z - y) * -x1, a b/funkcji_loss = 2*(z - y) * -1, i teraz dodajesz te wartości b+= b/funkcji_loss W+=W/funkcji_loss, to są po prostu wyniki pochodnych po funkcji (z - (x * W +b))**2, po W i po b, wyniki gradientu dodajesz do zmiennych i to jest jeden krok uczenia, a do przewidzenia wyniku używasz funkcji (x * W + b), to jest forward poprzednie backward.
Za pomocą pytorch coś takiego możesz napisać:
optimizer.zero_grad() # ustawienie zmiennych zawierających gradient na zero
y = linear_model(x, W, b) # model sieci
loss = (y - target) ** 2 # tu funkcja mierzenia błędu
loss.backward() # to liczy pochodną i zapisuje w zmiennej W.grad, b.grad
optimizer.step() # dodanie gradientu czyli W+=W.grad i b+=b.grad, ale to też zależy od wybranego optimizera, jak gradient descent to tak będzie to wyglądać, ale są jeszcze inne.
Najprościej chyba i tak będzie ci użyć biblioteki Keras i zaprojektować jakiś model, wydaje mi się że ta akurat jest najprostsza biblioteka.