import torch
import torch.nn as nn
import torch.optim as optim

# single neuron
# only to demonstrate the training process

# https://playground.tensorflow.org/

def forward(X, w, b):
    return torch.matmul(X, w) + b 

w = torch.rand(1, 1, requires_grad=True)
b = torch.rand(1, 1, requires_grad=True)

print(w, b)

X = torch.tensor(( [1.0], [0.3], [0.5], [0.7] ),dtype=torch.float)

y = torch.tensor(( [0.95], [0.51], [0.65], [0.87] ),dtype=torch.float)

print(X.shape)
print(y.shape)


epochs=100
learning_rate=0.01
optim = torch.optim.SGD([w, b], learning_rate)
for epoch in range(epochs):

    # forward pass
    o = forward(X, w, b)
    loss = torch.mean((y - o)**2)
    
    # backward pass
    loss.backward()
    optim.step()
    optim.zero_grad()
    
    # what is behind SGD
    #with torch.no_grad():
    #    w -= w.grad * learning_rate
    #    b -= b.grad * learning_rate
    #    w.grad.zero_()
    #    b.grad.zero_()
       
    print(f"Epoch {epoch + 1}/{epochs}, Loss: {loss.item():.3f}")
