LitchiCheng 发表于 2024-10-27 15:15

一起读《动手学深度学习(PyTorch版)》- 多项式回归:欠拟合、过拟合

<div class='showpostmsg'> 本帖最后由 LitchiCheng 于 2024-10-27 15:15 编辑

<article data-content="[{&quot;type&quot;:&quot;block&quot;,&quot;id&quot;:&quot;1OUW-1729913377363&quot;,&quot;name&quot;:&quot;heading&quot;,&quot;data&quot;:{&quot;level&quot;:&quot;h3&quot;},&quot;nodes&quot;:[{&quot;type&quot;:&quot;text&quot;,&quot;id&quot;:&quot;eBem-1729913377361&quot;,&quot;leaves&quot;:[{&quot;text&quot;:&quot;多项式回归&quot;,&quot;marks&quot;:[]}]}],&quot;state&quot;:{}},{&quot;type&quot;:&quot;block&quot;,&quot;id&quot;:&quot;hb2I-1729911922843&quot;,&quot;name&quot;:&quot;paragraph&quot;,&quot;data&quot;:{&quot;version&quot;:1},&quot;nodes&quot;:[{&quot;type&quot;:&quot;text&quot;,&quot;id&quot;:&quot;91ls-1729911922842&quot;,&quot;leaves&quot;:[{&quot;text&quot;:&quot;这样可以避免很大的 \rx^i 带来的特别大的指数值,变成 x^i / i !,也就是x的i次幂 / i的阶乘,如下图可以对比&quot;,&quot;marks&quot;:[]}]}],&quot;state&quot;:{}}]">
<p><iframe allowfullscreen="true" frameborder="0" height="450" src="//player.bilibili.com/player.html?bvid=1KR1aYxEpL&amp;page=1" style="background:#eee;margin-bottom:10px;" width="700"></iframe><br />
&nbsp;</p>

<p>多项式回归</p>

<p>这样可以避免很大的 x^i 带来的特别大的指数值,变成 x^i / i !,也就是x的i次幂 / i的阶乘,如下图可以对比</p>

<pre>
<code>import matplotlib.pyplot as plt
import math

num = 3
x = range(0, 1000)
y = []
y1 = []
for i in x:
    y.append(i**num)
    y1.append((i**num)/math.factorial(num))
plt.plot(x, y)
plt.plot(x, y1)
plt.show()</code></pre>

<p> &nbsp;</p>

<article data-content="[{&quot;type&quot;:&quot;block&quot;,&quot;id&quot;:&quot;qVK1-1729996268765&quot;,&quot;name&quot;:&quot;heading&quot;,&quot;data&quot;:{&quot;level&quot;:&quot;h3&quot;},&quot;nodes&quot;:[{&quot;type&quot;:&quot;text&quot;,&quot;id&quot;:&quot;Y59U-1729996268766&quot;,&quot;leaves&quot;:[{&quot;text&quot;:&quot;3阶多项式拟合&quot;,&quot;marks&quot;:[]}]}],&quot;state&quot;:{}},{&quot;type&quot;:&quot;block&quot;,&quot;id&quot;:&quot;0d4u-1729996634248&quot;,&quot;name&quot;:&quot;paragraph&quot;,&quot;data&quot;:{&quot;version&quot;:1},&quot;nodes&quot;:[{&quot;type&quot;:&quot;text&quot;,&quot;id&quot;:&quot;mDGb-1729996634249&quot;,&quot;leaves&quot;:[{&quot;text&quot;:&quot;100个训练样本,100和验证样本&quot;,&quot;marks&quot;:[]}]}],&quot;state&quot;:{}},{&quot;type&quot;:&quot;block&quot;,&quot;id&quot;:&quot;Dj1F-1729996654708&quot;,&quot;name&quot;:&quot;paragraph&quot;,&quot;data&quot;:{&quot;version&quot;:1},&quot;nodes&quot;:[{&quot;type&quot;:&quot;text&quot;,&quot;id&quot;:&quot;V2sg-1729996654707&quot;,&quot;leaves&quot;:[{&quot;text&quot;:&quot;设定多项式的权重,3阶多项式,有4个权重值,经过400次训练&quot;,&quot;marks&quot;:[]}]}],&quot;state&quot;:{}}]">
<p>3阶多项式拟合</p>

<p>100个训练样本,100和验证样本</p>

<p>设定多项式的权重,3阶多项式,有4个权重值,经过400次训练</p>

<pre>
<code>import torch
import torchvision
from torch.utils import data
from torchvision import transforms
import matplotlib.pyplot as plt
from torch import nn
import numpy as np
import math

def get_dataloader_workers():
    return 6

def accurancy(y_hat, y):
    if len(y_hat.shape) &gt; 1 and y_hat.shape &gt; 1:
      y_hat = y_hat.argmax(axis=1)
    # cmp is a dict which restore true or false
    cmp = y_hat.type(y.dtype) == y
    # calc the num of true
    return float(cmp.type(y.dtype).sum())

class Accumulator:
    def __init__(self, n) -&gt; None:
      self.data = *n
   
    def add(self, *args):
      # args is a tupe
      self.data =

    def reset(self):
      self.data = * len(self.data)

    def __getitem__(self, idx):
      return self.data

def evaluate_accurancy(net, data_iter):
    if isinstance(net, torch.nn.Module):
      net.eval()
    metric = Accumulator(2)
    with torch.no_grad():
      for X, y in data_iter:
            metric.add(accurancy(net(X), y), y.numel())
    return metric / metric

def train_epoch_ch3(net, train_iter, loss, updater):
    if isinstance(net, torch.nn.Module):
      print(&quot;is instance nn.Module&quot;)
      net.train()
    metric = Accumulator(3)
    for X, y in train_iter:
      y_hat = net(X)
      # print(y, y_hat)
      l = loss(y_hat, y)
      if isinstance(updater, torch.optim.Optimizer):
            updater.zero_grad()
            l.mean().backward()
            updater.step()
      else:
            l.sum().backward()
            updater(X.shape)
      metric.add(float(l.sum()), accurancy(y_hat, y), y.numel())
    #   print(metric , metric, metric)
    # print(&quot;&quot;, metric , metric, metric)
    # return metric / metric, metric / metric

def set_axes(axes, xlable, ylable, xlim, ylim, xscale, yscale, legend):
    axes.set_xlabel(xlable)
    axes.set_ylabel(ylable)
    axes.set_xscale(xscale)
    axes.set_yscale(yscale)
    axes.set_xlim(xlim)
    axes.set_ylim(ylim)
    if legend:
      axes.legend(legend)
      axes.grid()

class Animator:
    def __init__(self, xlable=None, ylable=None, legend=None, xlim=None, ylim=None,
    xscale=&#39;linear&#39;, yscale=&#39;linear&#39;,fmts=(&#39;-&#39;,&#39;m--&#39;,&#39;g-.&#39;,&#39;r:&#39;), nrows=1, ncols=1, figsize=(3.5, 2.5)):
      if legend is None:
            legend = []
      self.fig, self.axes = plt.subplots(nrows, ncols, figsize=figsize)
      if nrows * ncols == 1:
            self.axes =
      self.config_axes = lambda: set_axes(self.axes, xlable, ylable, xlim, ylim, xscale, yscale, legend)
      self.X, self.Y, self.fmts = None, None, fmts
   
    def add(self, x, y):
      if not hasattr(y, &quot;__len__&quot;):
            y=
      n = len(y)
      if not hasattr(x, &quot;__len__&quot;):
            x = * n
      if not self.X:
            self.X = [[] for _ in range(n)]
      if not self.Y:
            self.Y = [[] for _ in range(n)]
      for i, (a,b) in enumerate(zip(x, y)):
            if a is not None and b is not None:
                self.X.append(a)
                self.Y.append(b)
      self.axes.cla()
      for x, y, fmt in zip(self.X, self.Y, self.fmts):
            self.axes.plot(x, y, fmt)
      self.config_axes()

def load_array(data_arrays, batch_size, is_train=True):#<a href="home.php?mod=space&amp;uid=472666" target="_blank">@save </a>dataset = data.TensorDataset(*data_arrays)
    return data.DataLoader(dataset, batch_size, shuffle=is_train, num_workers=get_dataloader_workers())

max_degree = 20# 20 power
n_train, n_test = 100, 100
true_w = np.zeros(max_degree)
true_w = np.array()

features = np.random.normal(size=(n_train + n_test, 1))
np.random.shuffle(features)
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 = np.dot(poly_features, true_w)
labels += np.random.normal(scale=0.1, size=labels.shape)

true_w, features, poly_features, labels = [torch.tensor(x, dtype=
    torch.float32) for x in ]

# print(features[:2], poly_features[:2, :], labels[:2])

def evaluate_loss(net, data_iter, loss):
    metric = Accumulator(2)
    for X, y in data_iter:
      out = net(X)
      y = y.reshape(out.shape)
      l = loss(out, y)
      metric.add(l.sum(), l.numel())
    return metric / metric

def train(train_features, test_features, train_labels, test_labels,
          num_epochs=400):
    loss = nn.MSELoss(reduction=&#39;none&#39;)
    input_shape = train_features.shape[-1]
    net = nn.Sequential(nn.Linear(input_shape, 1, bias=False))
    batch_size = min(10, train_labels.shape)
    train_iter = load_array((train_features, train_labels.reshape(-1,1)),
                              batch_size)
    test_iter = load_array((test_features, test_labels.reshape(-1,1)),
                               batch_size, is_train=False)
    trainer = torch.optim.SGD(net.parameters(), lr=0.01)
    animator = Animator(xlable=&#39;epoch&#39;, ylable=&#39;loss&#39;, yscale=&#39;log&#39;,
                            xlim=, ylim=,
                            legend=[&#39;train&#39;, &#39;test&#39;])
    for epoch in range(num_epochs):
      train_epoch_ch3(net, train_iter, loss, trainer)
      if epoch == 0 or (epoch + 1) % 20 == 0:
            animator.add(epoch + 1, (evaluate_loss(net, train_iter, loss),
                                     evaluate_loss(net, test_iter, loss)))
    print(&#39;weight:&#39;, net.weight.data.numpy())

train(poly_features[:n_train, :4], poly_features,
      labels[:n_train], labels)

plt.show()</code></pre>

<article data-content="[{&quot;type&quot;:&quot;block&quot;,&quot;id&quot;:&quot;aUXB-1729996286961&quot;,&quot;name&quot;:&quot;paragraph&quot;,&quot;data&quot;:{},&quot;nodes&quot;:[{&quot;type&quot;:&quot;text&quot;,&quot;id&quot;:&quot;jvsj-1729996286959&quot;,&quot;leaves&quot;:[{&quot;text&quot;:&quot;可以看到权重值也就是多项式系数和最初设定的系数基本相同,loss也逐渐变小&quot;,&quot;marks&quot;:[]}]}],&quot;state&quot;:{}}]">
<p>可以看到权重值也就是多项式系数和最初设定的系数基本相同,loss也逐渐变小</p>

<p> &nbsp;</p>

<article data-content="[{&quot;type&quot;:&quot;block&quot;,&quot;id&quot;:&quot;of3r-1729996547781&quot;,&quot;name&quot;:&quot;heading&quot;,&quot;data&quot;:{&quot;level&quot;:&quot;h3&quot;},&quot;nodes&quot;:[{&quot;type&quot;:&quot;text&quot;,&quot;id&quot;:&quot;9wsX-1729996547780&quot;,&quot;leaves&quot;:[{&quot;text&quot;:&quot;线性函数,欠拟合&quot;,&quot;marks&quot;:[]}]}],&quot;state&quot;:{}},{&quot;type&quot;:&quot;block&quot;,&quot;id&quot;:&quot;n1eW-1729998152880&quot;,&quot;name&quot;:&quot;paragraph&quot;,&quot;data&quot;:{},&quot;nodes&quot;:[{&quot;type&quot;:&quot;text&quot;,&quot;id&quot;:&quot;NeSS-1729998152879&quot;,&quot;leaves&quot;:[{&quot;text&quot;:&quot;原因:由四个系数构成的20阶多项式,当训练系数只有2个时,不太可能表达出4个的效果,再增加数量或者训练次数,都不能减少损失&quot;,&quot;marks&quot;:[]}]}],&quot;state&quot;:{}}]">
<p>线性函数,欠拟合</p>

<p>原因:由四个系数构成的20阶多项式,当训练系数只有2个时,不太可能表达出4个的效果,再增加数量或者训练次数,都不能减少损失</p>

<pre>
<code>train(poly_features[:n_train, :2], poly_features,
      labels[:n_train], labels)</code></pre>

<p> &nbsp;</p>

<article data-content="[{&quot;type&quot;:&quot;block&quot;,&quot;id&quot;:&quot;k5VY-1729998028844&quot;,&quot;name&quot;:&quot;heading&quot;,&quot;data&quot;:{&quot;level&quot;:&quot;h3&quot;},&quot;nodes&quot;:[{&quot;type&quot;:&quot;text&quot;,&quot;id&quot;:&quot;v90a-1729998028843&quot;,&quot;leaves&quot;:[{&quot;text&quot;:&quot;高阶多项式,过拟合&quot;,&quot;marks&quot;:[]}]}],&quot;state&quot;:{}},{&quot;type&quot;:&quot;block&quot;,&quot;id&quot;:&quot;JRaI-1730005831145&quot;,&quot;name&quot;:&quot;paragraph&quot;,&quot;data&quot;:{&quot;version&quot;:1},&quot;nodes&quot;:[{&quot;type&quot;:&quot;text&quot;,&quot;id&quot;:&quot;cs5U-1730005831146&quot;,&quot;leaves&quot;:[{&quot;text&quot;:&quot;3阶以上的系数未指定,本身应该时0值,但因为添加了噪声,没有明显的规律,所以训练结果很好,但面对随机的噪声怎么可能预估的出来&quot;,&quot;marks&quot;:[]}]}],&quot;state&quot;:{}}]">
<p>高阶多项式,过拟合</p>

<p>3阶以上的系数未指定,本身应该时0值,但因为添加了噪声,没有明显的规律,所以训练结果很好,但面对随机的噪声怎么可能预估的出来</p>

<pre>
<code>train(poly_features[:n_train, :], poly_features,
      labels[:n_train], labels, num_epochs=1000)</code></pre>

<p> &nbsp;</p>
</article>
</article>
</article>
</article>
</article>
</div><script>                                        var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;"   style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
                                       
                                        if(parseInt(discuz_uid)==0){
                                                                                                (function($){
                                                        var postHeight = getTextHeight(400);
                                                        $(".showpostmsg").html($(".showpostmsg").html());
                                                        $(".showpostmsg").after(loginstr);
                                                        $(".showpostmsg").css({height:postHeight,overflow:"hidden"});
                                                })(jQuery);
                                        }                </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script>

风尘流沙 发表于 2024-10-29 15:23

<p>谢谢楼主的分享,《动手学深度学习(PyTorch版)》,已下载第二版拜读了。</p>

freebsder 发表于 2024-10-29 15:25

<p>随机噪声可能需要估计噪声分布,白噪声还是高斯噪声,可以先处理一下。虽然现在深度学习网络很强大,但是必要的前处理还是可以有的。</p>

LitchiCheng 发表于 2024-10-29 21:28

freebsder 发表于 2024-10-29 15:25
随机噪声可能需要估计噪声分布,白噪声还是高斯噪声,可以先处理一下。虽然现在深度学习网络很强大,但是必 ...

<p>这个是真实噪声,消除就意味失真</p>
页: [1]
查看完整版本: 一起读《动手学深度学习(PyTorch版)》- 多项式回归:欠拟合、过拟合