张春成

V2

2023/03/30阅读:17主题:默认主题

雾里看花:从MLP看验证集的作用

雾里看花:从MLP看验证集的作用

机器学习难,难在观测到的数据稀疏,从稀疏数据中估计总体分布如隔岸观火,如隔靴搔痒,如雾里看花。因此,交叉验证方法能利用有限的数据对估计出的分类器进行辅助评价和验证。


  • 雾里看花:从MLP看验证集的作用[1]
    • 估计效果与验证集损失的耦合关系[2]
      • 样例1[3]
      • 样例2[4]
      • 样例3[5]
    • MLP 的分布估计模拟实验[6]

估计效果与验证集损失的耦合关系

交叉验证是机器学习常用的分析方法,而每轮交叉过程中分割出的验证集的特点和作用就是本文的主要讨论内容。

3.1. Cross-validation: evaluating estimator performance[7]

Untitled
Untitled
Untitled
Untitled

本文的结果图为 3x2 的 6 宫格图,

  • 顶部两张图分别代表真实分布和估计出的分布,它们越相似代表估计效果越好。
  • 中间两张图分别代表训练集和验证集的分布,严格来说这种验证集的选择方式是相当理想的,因为它补全了训练集中没有观测到的位置,从而可以在训练过程之外,比较有效地对模型进行评价。
  • 底部两张图分别代表损失函数在训练过程中的变化趋势,以及估计分布与真实分布之间的差异。我们主要关注损失函数,两条曲线分别是训练集的损失函数(红色)和验证集的损失函数(蓝色)。

从损失函数的变化规律可以看到,虽然训练集损失函数在训练过程中单调下降,但验证集的损失函数却呈现出两个截然不同的趋势。当训练效果较好时,验证集的损失函数同样单调下降。而训练效果不佳时,验证集的损失函数几乎呈现单调上升的趋势,这种现象表示 MLP 模型陷入了过拟合的尴尬境地,也就是说它的估计准确率必然不佳。

另外,从估计结果来看,本文使用的分布函数对于如此小规模的 MLP 来说过于复杂了,但我觉得这种复杂度对于说明验证集的作用是比较合适的。

样例1

如下给出了三个样例,每个样例都用两张图表示,左侧的图代表比较准确的估计结果,右侧的图代表比较不准确的估计结果。

1680163556.2792869-0.10869824138213235.png
1680163556.2792869-0.10869824138213235.png
1680163558.726584-0.39880271315444493.png
1680163558.726584-0.39880271315444493.png

样例2

1680164471.972665-0.621015031589568.png
1680164471.972665-0.621015031589568.png
1680164464.2363122-0.4362663303007521.png
1680164464.2363122-0.4362663303007521.png

样例3

1680164848.641574-0.7953803257960314.png
1680164848.641574-0.7953803257960314.png
1680164844.7651284-0.03890981354210621.png
1680164844.7651284-0.03890981354210621.png

MLP 的分布估计模拟实验

本文使用简单的数学方法生成了 3 组不同的分布,它们的形式相似,其表达式如下,其中 分别代表两个相互独立的特征值。我们从整体分布中进行均匀采样,采样点的数量为 10000。

# Dataset generation core code
[a, b] = np.meshgrid(100100)
a = a.ravel()
b = b.ravel()

# example-1
y_total = np.cos((a + b) * 15)

# example-2
y_total = np.cos((a**0.5 + b**2) * 15)

# example-3
y_total = np.cos((a**0.5 - b**2) * 15)

接下来,将数据分割为训练集和验证集。为了贴近真实的机器学习算法应用场景,我们采用栅栏透视式的方式从全部采样值中选择 800 个点作为训练集,选择另外 200 个点作为验证集。为了保证验证集的有效性,验证集与训练集分别属于不同的透视列。

# Select 800 points as training set
# and select 200 points as validation set.

num_train = 800
num_valid = 200

X = X_total.copy()
y = y_total.copy()

def _type(x):
    return any([
        (x[0] < 0.2),
        (x[0] > 0.4 and x[0] < 0.6),
        (x[0] > 0.8),
    ])

select = [(j, _type(e)) for j, e in enumerate(X)]

idx_train = [e[0for e in select if e[1]]
np.random.shuffle(idx_train)
X_train = X[idx_train[:num_train]]
y_train = y[idx_train[:num_train]]

idx_valid = [e[0for e in select if not e[1]]
np.random.shuffle(idx_valid)
X_valid = X[idx_valid[:num_valid]]
y_valid = y[idx_valid[:num_valid]]

最后,使用 MLP 进行整体分布估计, MLP 的设计和损失函数如下,训练的迭代次数为 20000 次。这个网络虽然不是最优的,但其复杂度点到即止,足以说明验证集的作用即可。

# MLP design and optimizer

class Net(nn.Module):
    def __init__(self):
        super().__init__()
        self.mlp = torchvision.ops.MLP(
            num_features, [41041], activation_layer=nn.LeakyReLU)
        self.act = nn.Tanh()

    def forward(self, x):
        output = self.mlp(x)
        output = self.act(output)
        return output

net = Net().cuda()

optimizer = torch.optim.AdamW(net.parameters())
criterion = nn.MSELoss()

参考资料

[1]

雾里看花:从MLP看验证集的作用: #雾里看花从mlp看验证集的作用

[2]

估计效果与验证集损失的耦合关系: #估计效果与验证集损失的耦合关系

[3]

样例1: #样例1

[4]

样例2: #样例2

[5]

样例3: #样例3

[6]

MLP 的分布估计模拟实验: #mlp-的分布估计模拟实验

[7]

3.1. Cross-validation: evaluating estimator performance: https://scikit-learn.org/stable/modules/cross_validation.html

分类:

后端

标签:

后端

作者介绍

张春成
V2