Search code examples
machine-learningdeep-learningpytorch

my model is predicting completely opposite values after training. (i.e. predicting circle's inside values as outside and outside values as inside)


making datasets

from sklearn.datasets import make_circles
n_samples=1000
x, y = make_circles(n_samples, noise=0.03, random_state=42)
X = torch.from_numpy(x).type(torch.float)
Y = torch.from_numpy(y).type(torch.float)
from sklearn.model_selection import train_test_split
xtrain, xtest, ytrain, ytest = train_test_split(X, Y, test_size=0.2, random_state=42)

model(predicting circle) (we know equation of circle s (x**2 + y**2 = r**2)

class cp(nn.Module):
    def __init__(self):
        super().__init__()
        self.r = nn.Parameter(torch.randn(1, requires_grad = True, dtype=torch.float))
    def forward(self, x):
        return x[:, 0]**2 + x[:, 1]**2 - self.r**2
torch.manual_seed(42)
m = cp()
loss_fn = nn.BCEWithLogitsLoss()
opt = torch.optim.SGD(params = m.parameters(), lr=0.1)

training loop

e = 1000
for i in range(e+1):
    m.train()
    p = m(xtrain).squeeze()
    f = torch.round(torch.sigmoid(p))
    l = loss_fn(p, ytrain)
    acc = accuracy_fn(f, ytrain)
    opt.zero_grad()
    l.backward()
    opt.step()
    if(i%10==0):
        with torch.inference_mode():
            tp = m(xtest).squeeze()
            tf= torch.round(torch.sigmoid(tp))
            tl = loss_fn(tp, ytest)
            tacc = accuracy_fn(tf, ytest)
            print(f"epoch: {i} | train loss: {l:.4f} | train acc: {acc} | test loss: {tl:.4f} | test acc: {tacc}")
            if(i%100==0): print(m.state_dict())

IF I TRAIN MY MODEL IN ABOVE WAY, ITS PREDICTING 1 AS 0, AND O AS 1. I.E. ytrain[:10] = tensor([1., 0., 0., 0., 1., 0., 1., 1., 0., 0.]). predicted values are: torch.round(torch.sigmoid(m(xtrain[:10]))) = tensor([0., 1., 1., 1., 0., 1., 0., 0., 1., 1.]) But, when i plot the circle, its predicting correctly (radius of circle is predicted correctly) predicted circle

i tried to predict a circle. all inside are 0's and outside are 1's. But after training, its predicting in reverse order( i.e. outside 0's and inside 1's). please check it once. i have provided entire code.


Solution

  • The model returns this logit:

    x0 ** 2 + x1 ** 2 - r_optimal ** 2

    The return value above is such that samples inside r_optimal return a negative value, and samples outside of r_optimal return a positive value.

    We can follow this through to the predicted class yhat:

    • sample inside r_optimal -> model returns negative value
    • sigmoid(negative) is <0.5, so yhat = round(<0.5) = 0

    Similarly, for a sample outside r_optimal:

    • sample outside r_optimal -> model returns positive value
    • sigmoid(positive) is >0.5, so yhat = round(>0.5) = 1

    So samples that are inside/outside r_optimal will get yhat=0/yhat=1 - but this is the reverse of your training set where the actual labels are y=1/y=0.

    One way to fix this is to reverse the sign of the return value. That will mean samples inside the circle return a positive value and will get a predicted class of yhat = round(sigmoid(+ve))) = 1.

    return -(x[:, 0]**2 + x[:, 1]**2 - self.r**2)
    

    enter image description here