基于PyTorch拟合圆:实现坐标平方和输出的网络拟合困境
问题分析与解决方案
你的网络无法拟合x²+y²的核心原因是线性网络无法表达非线性关系,再加上初始化、训练参数的不合理设置,导致损失居高不下。以下是具体问题和修正方案:
核心问题点
- 缺少非线性激活函数:当前网络是纯线性结构(两个
Linear层串联),只能拟合线性映射,而x²+y²是二次非线性函数,必须引入非线性激活才能让网络学到非线性特征。 - 偏差初始化错误且未生效:你定义了
init_bias函数但从未调用,而且用Xavier初始化偏差是不合理的——偏差通常初始为0或极小常数,Xavier是针对权重的初始化方法。 - 训练轮数不足:仅10轮训练不足以让网络收敛到合适的参数。
- 学习率偏低:0.001的学习率对于这个简单任务来说收敛速度太慢。
修正后的代码
import torch import torch.nn as nn from torch.utils.data import TensorDataset, DataLoader device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") # 明确指定数据类型为float32,避免潜在类型问题 features = torch.tensor([ [8.3572,-11.3008,1],[6.2795,-12.5886,1],[4.0056,-13.4958,1], [1.6219,-13.9933,1],[-0.8157,-14.0706,1],[-3.2280,-13.7250,1], [-5.5392,-12.9598,1],[-7.6952,-11.8073,1],[-9.6076,-10.3035,1], [-11.2532,-8.4668,1],[-12.5568,-6.3425,1],[-13.4558,-4.0691,1], [-13.9484,-1.7293,1],[-14.0218,0.7224,1],[-13.6791,3.1211,1], [-12.9064,5.4561,1],[-11.7489,7.6081,1],[-10.2251,9.5447,1], [5.4804,12.8044,1],[7.6332,11.6543,1],[9.5543,10.1454,1], [11.1890,8.3117,1],[12.4705,6.2460,1],[13.3815,3.9556,1], [13.8733,1.5884,1],[13.9509,-0.8663,1],[13.6014,-3.2793,1], [12.8572,-5.5526,1],[11.7042,-7.7191,1],[10.1761,-9.6745,1], [-8.4301,11.1605,1],[-6.3228,12.4433,1],[-4.0701,13.3401,1], [-1.6816,13.8352,1],[0.7599,13.9117,1],[3.1672,13.5653,1] ], dtype=torch.float32).to(device) # 简化标签计算,直接用张量运算 labels = (features[:,0]**2 + features[:,1]**2).to(device) num_input ,num_hidden,num_output = 3,64,1 net = nn.Sequential( nn.Linear(num_input,num_hidden), nn.ReLU(), # 添加非线性激活层,这是关键! nn.Linear(num_hidden,num_output) ).to(device) # 修正初始化:权重用Xavier,偏差初始为0 def init_weights(m): if type(m) == nn.Linear: nn.init.xavier_normal_(m.weight) nn.init.constant_(m.bias, 0.0) # 偏差初始为0 net.apply(init_weights) loss = nn.MSELoss() # 调整训练参数:增加轮数、调大学习率 num_epochs = 500 batch_size = 6 lr=0.005 trainer = torch.optim.RAdam(net.parameters(),lr=lr) dataset = TensorDataset(features,labels) data_loader = DataLoader(dataset,batch_size=batch_size,shuffle=True) # 训练时打印每轮的平均损失,而不是最后一个batch的损失 for epoch in range(num_epochs): total_loss = 0.0 for X,y in data_loader: y_hat = net(X) l = loss(y_hat,y.reshape(y_hat.shape)) trainer.zero_grad() l.backward() trainer.step() total_loss += l.item() # 每20轮打印一次损失,避免输出过多 if (epoch+1) % 20 == 0: with torch.no_grad(): print(f"Epoch {epoch+1}, Average Loss: {total_loss/len(data_loader):.4f}")
额外优化建议
- 输入归一化:可以将x、y除以它们的最大值(比如14),让输入范围落在[-1,1]之间,能进一步加快收敛速度,示例代码:
features[:,0] /= 14.0 features[:,1] /= 14.0 - 调整隐藏层大小:这个任务很简单,隐藏层不用64这么大,16或32足够,能减少计算量。
内容的提问来源于stack exchange,提问作者jwTTy
相关产品推荐
相关产品推荐

