1.原理理解
对于多项式 若用更高阶的函数去拟合,在训练集上大多是可以得到更好的结果的,但在测试集上的结果并没有很好;若用比其低阶的函数去拟合,在训练集和测试集上大多都不能得到优良的结果。
(1).过拟合
过拟合:盲目追求损失值最小,如上图,好似对已知特征求值,再将所求值用平滑曲线相连得到拟合函数。这样的拟合曲线因为更偏向于求函数值所以导致网络只在训练集上表现良好而对未知数据的到来会显得“手足无措”
(2).欠拟合
欠拟合:用简单的函数去拟合复杂的数据,显然损失值会偏大。
(3).理想的拟合曲线
这种拟合曲线才可以对未知数据进行良好预测
(4).过拟合和欠拟合产生原因
2.定义多项式函数
#多项式计算,gama函数防止数据溢出
def fun(features,w,power):
val = 0
for i in range(power):
val += w[i]*pow(features,i)/math.gamma(i+1) #math.gamma(i+1) == i!
return val
除以gama(i+1)防止计算loss.sum()时数据溢出
3.生成特征和标签
#生成features,labels
def creat(train_size,test_size):
true_w = np.array([-1, 3.6, 4.2, -6.5]) #真实权重
print('真实w :',true_w)
features = np.random.normal(0,1,size=(train_size+test_size,1)) #生成特征值(期望0,标准差1)
np.random.shuffle(features) #特征值顺序打乱
noise = np.random.normal(0,0.1,size=(train_size+test_size,1)) #噪音
labels = fun(features,true_w,len(true_w))+noise #生成标签
features = torch.tensor(features)
labels = torch.tensor(labels)
return features,labels
使用最高幂为3的函数产生特征值和标签,生成的特征和标签包含训练集和测试集两部分,训练集只用来训练,测试集用于验证训练所得参数的优劣
噪声一定不可以太大,太大的噪声会使数据标签太过分散,而不只是在某条曲线附近分散,从而会导致训练所得参数结果和真实值相差很大
4.定义损失函数,均方损失
#损失函数,均方损失
def loss_fun(y_hat,y):
return (y_hat-y)**2 /2
5.批量梯度下降
#批量梯度下降
def bgd(w,lr,batch_size):
with torch.no_grad():
w -= lr*w.grad/batch_size
w.grad.zero_()
return w
因为多项式 恒成立,我们将该项作为偏移项,所以这里只有w参数的更新而没有偏移参数b。
6.训练
#训练
def train(train_features,train_labels,train_w,power,size,batch_size):
epoch = 800 #训练轮数
lr =0.1 #训练步长
train_data = d2l.load_array((train_features,train_labels),batch_size)
for i in range(epoch):
loss_train = 0
for x,y in train_data:
y_hat = fun(x,train_w,power)
loss = loss_fun(y_hat,y)
loss_train += loss.sum()
loss.sum().backward()
train_w = bgd(train_w,lr,batch_size)
print('训练后预测w :',train_w.reshape(1,-1))
print('训练集平均损失 :',loss_train.sum()/size)
return train_w
使用d2l.load_array( ( features, labels ), batchsize ) 来产生批量训练的效果
7.测试集上的表现
#验证
def verify(test_features,test_labels,final_w,power,size):
y_hat = fun(test_features,final_w,power)
loss = loss_fun(y_hat,test_labels)
print('验证集平均损失 :',loss.sum()/size)
8.封装
def mul():
train_size,test_size = 100,100 #训练集和测试集大小
power = 4 #最高幂为power-1,调整power大小以验证过拟合欠拟合
batch_size = 10 #批量大小
init_w = torch.normal(0,1,size=(power,1),requires_grad=True)
features,labels = creat(train_size,test_size)
train_features,train_labels = features[0:train_size],labels[0:train_size] #规定训练集数据分别为前100个数据
test_features,test_labels = features[train_size:(train_size+test_size)], labels[train_size:(train_size+test_size)] #规定测试集数据
final_w = train(train_features,train_labels,init_w,power,train_size,batch_size) #训练
verify(test_features,test_labels,final_w,power,test_size) #验证
return
规定训练集和测试集大小均为100,超参数power用来调整用最高幂为几的函数去拟合训练集数据,规定生成的特征值和标签的前100个数据作为训练集,后100个数据作为测试集。
9.拟合
#拟合
mul()
10.运行结果
(1).正常,使用最高幂等于3的函数去拟合
(2).过拟合,使用最高幂大于3的函数去拟合
(3).欠拟合,使用最高幂小于3的函数去拟合