制作数据集
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)
模型(预测圆)(我们知道圆的方程 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)
训练循环
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())
如果我按照上述方式训练模型,它会预测 1 为 0,O 为 1。 IE。 ytrain[:10] =
tensor([1., 0., 0., 0., 1., 0., 1., 1., 0., 0.])
。预测值为: torch.round(torch.sigmoid(m(xtrain[:10]))) = tensor([0., 1., 1., 1., 0., 1., 0., 0., 1., 1.])
但是,当我绘制圆时,它的预测正确(圆的半径预测正确)
我试图预测一个圆。里面都是0,外面都是1。但训练后,它以相反的顺序进行预测(即外部 0 和内部 1)。请检查一次。我已经提供了完整的代码。
模型返回此 logit:
x0 ** 2 + x1 ** 2 - r_optimal ** 2
上面的返回值使得样本insider_optimal返回负值,而r_optimal之外的样本返回正值。
我们可以按照这个进行预测类别:
同样,对于 r_optimal 之外的样本:
因此,r_optimal 内部/外部的样本将得到 yhat=0/yhat=1 - 但这与训练集相反,其中实际标签为 y=1/y=0。
解决此问题的一种方法是反转返回值的符号。这意味着圆圈内的样本返回一个positive值,并将获得预测类别 yhat = round(sigmoid(+ve))) = 1.
return -(x[:, 0]**2 + x[:, 1]**2 - self.r**2)