其实 我们一般所说的的 test_data 只是通俗的叫法 , 其实是验证数据集
训练数据集 & 验证数据集 & 测试数据集:
训练数据集 : 用来训练模型参数
验证数据集 : 用来选 超参数
用来评估模型好坏的数据集
例如拿出50%的训练数据
不要跟训练数据混在一起 (常犯错误)
测试数据集 :只用一次的数据集。也就是作为最终的结果
例如
未来的考试 , 我出价的房子的实际成交价
没有足够多数据使用 -> 用k则交叉验证
模型容量 要与 数据规模 匹配
拟合各种函数的能力
低容量的模型难以拟合训练数据
高容量的模型可以记住所有的训练数据
任务 : 降低 泛化误差
机器学习的核心:在模型足够大的前提下 -> 通过某种手段 使泛化损失下降
max_degree = 20 # 多项式的最大阶数
n_train, n_test = 100, 100 # 训练和测试数据集大小
true_w = np.zeros(max_degree) # 分配大量的空间
true_w[0:4] = np.array([5, 1.2, -3.4, 5.6])
features = np.random.normal(size=(n_train + n_test, 1))
np.random.shuffle(features)
""" np.power()用法详见笔记"""
poly_features = np.power(features, np.arange(max_degree).reshape(1, -1))
for i in range(max_degree):
poly_features[:, i] /= math.gamma(i + 1) # gamma(n)=(n-1)!
# labels的维度:(n_train+n_test,)
labels = np.dot(poly_features, true_w)
labels += np.random.normal(scale=0.1, size=labels.shape)
print(poly_features.shape)
true_w 前4项是参数 ,后面的16项作为噪音项
features 训练+测试数据集 (n,1) -> 这里的 features
np.power() 用法: 对features 每一行也就是每一个x 做 20 个方, 一行类似于 (0 ,x, x2,x3…x^19)
参考:
poly_features 就是一个(200, 20) 的矩阵,200个样本,然后每一行是 阶数累加的x
再除以gamma -> 目的防止 带来的特别大的指数值
根据 poly_features 的值 人为造出一个 labels ,其中加上了一些噪音
def evaluate_loss(net,data_iter,loss):
参考softmax 这个函数是为了评估 一个epoch 的 loss
生成的三个图像:
train(poly_features[:n_train,:4],poly_features[n_train:,:4],
labels[:n_train],labels[n_train:])
# 从多项式特征中选择前2个维度,即1和x
train(poly_features[:n_train, :2], poly_features[n_train:, :2],
labels[:n_train], labels[n_train:])
# 从多项式特征中选取所有维度
train(poly_features[:n_train, :], poly_features[n_train:, :],
labels[:n_train], labels[n_train:], num_epochs=1500)
可以看到 用 poly_features 的前4列 当输入,无论是训练误差还是测试误差都很低
前2列当输入,测试误差训练误差都很高 -> 欠拟合
所有列当输入,测试误差会比训练误差高一点 -> 过拟合
[注] : module ‘d2l.torch’ has no attribute ‘train_epochs_ch3’
可能开发人员把 ch3 章节代码删了
解决办法:
import d2l
print(d2l._file_)
查出你的电脑里d2l的包的地址
然后进去 torch.py
把 之前 softmax的0开始实现里的 train_epoch_ch3 和 train_ch3 复制粘贴进去,然后就可以了
这个多项式回归问题可以准确地解出吗?提示:使用线性代数。
答:不怎么会 ,线性代数可以解决 多维度问题么?
代码如下:
# 随着feature_num的增加 loss的变化
def train1(train_features,test_features,train_labels,
test_labels,num_epochs= 400):
loss = nn.MSELoss(reduction='none')
input_shape = train_features.shape[-1]
net = nn.Sequential(nn.Linear(input_shape,1,bias=False))
batch_size = min(10,train_labels.shape[0])
train_iter = d2l.load_array((train_features,
train_labels.reshape(-1,1)),batch_size)
test_iter = d2l.load_array((test_features,
test_labels.reshape(-1,1)),batch_size,is_train=False)
trainer = torch.optim.SGD(net.parameters(),lr=0.01)
for epoch in range(num_epochs):
d2l.train_epoch_ch3(net, train_iter, loss, trainer)
if epoch == 399:
train_loss=evaluate_loss(net,train_iter,loss)
test_loss = evaluate_loss(net,test_iter,loss)
return train_loss,test_loss
import matplotlib.pyplot as plt
a = range(1,20)
animator = d2l.Animator(xlabel='feature_nums', ylabel='loss', yscale='log',
xlim=[1, 20], ylim=[1e-3, 1e2],
legend=['train', 'test'])
for i in a:
c=0
d=0
c,d=train1(poly_features[:n_train,:i],poly_features[n_train:,:i],
labels[:n_train],labels[n_train:])
animator.add(i,(c,d))
结论 : 随着 feature_nums 的增加模型的 loss 趋于稳定,虽然没有最低点nums=4效果好
但是 误差已经很小了,测试集和训练集相差结果也不是很大,过拟合可以接受
随着训练数据量的增加 loss的变化:
def train2(train_features,test_features,train_labels,
test_labels,num_epochs=400):
loss = nn.MSELoss(reduction='none')
input_shape = train_features.shape[-1]
net = nn.Sequential(nn.Linear(input_shape,1,bias=False))
batch_size = min(10,train_labels.shape[0])
train_iter = d2l.load_array((train_features,
train_labels.reshape(-1,1)),batch_size)
test_iter = d2l.load_array((test_features,
test_labels.reshape(-1,1)),batch_size,is_train=False)
trainer = torch.optim.SGD(net.parameters(),lr=0.01)
for epoch in range(num_epochs):
d2l.train_epoch_ch3(net, train_iter, loss, trainer)
if epoch == (num_epochs-1):
return evaluate_loss(net, train_iter, loss),evaluate_loss(net, test_iter, loss)
b= range(1,n_train)
anm = d2l.Animator(xlabel='data_nums',ylabel='loss',yscale='log',
xlim=[1,n_train],ylim=[1e-3, 1e2],
legend=['train','test'])
for i in b:
c=0
d=0
c,d = train2(poly_features[:i,:4],poly_features[n_train:,:4],
labels[:i],labels[n_train:])
anm.add(i,(c,d))
结论: 一开始明显过拟合 ,数据量太小 ,训练集误差小,测试集误差大
随着训练数据量的增加,训练集和测试集的loss 差距逐渐减小
80个epochs 后二者都趋于平稳
可能会发生上溢出 , 超过数据表示范围 ,而且数据太大也不利于计算
误差误差,泛化误差和训练误差都不可能为0(除非只有一个样本,训练误差为0)
模型容量需要匹配数据复杂度, 否则可能导致欠拟合过拟合