简体   繁体   English

为什么我的神经网络无法预测正弦波的下一个值?

[英]Why is my neural network having trouble predicting the next value of a sin wave?

Why is my neural.network not able to predict the next number for a sin wave?为什么我的神经网络无法预测正弦波的下一个数字?

I don't know if I need a better loss function or what the issue is.我不知道我是否需要更好的损失 function 或问题是什么。 It seems to optimize for about 500 steps and then it just flounders with predictions that look nothing like a wave.它似乎优化了大约 500 步,然后它只是在看起来一点也不像波浪的预测中挣扎。

The input to the model is 120. That's 120 of the previous numbers of the sin wave. model 的输入是 120。这是正弦波先前数字的 120。 The model is asked to predict where the next number will be and I store the sin wave values in a deque.要求 model 预测下一个数字的位置,我将正弦波值存储在双端队列中。 I insert the next sin wave value to the end of its deque.我将下一个 sin wave 值插入到其双端队列的末尾。

The targets and the predictions are arrays in a shape of (200,).目标和预测是 arrays,形状为 (200,)。
Every index in the array below 100 represents a negative number and those above 100 represent a positive number.数组中低于 100 的每个索引表示一个负数,高于 100 的每个索引表示一个正数。
All values to the hundredth between -1 and 0 are represented by indexes 0 to 100.所有介于-10之间的百分之一的值都由索引 0 到 100 表示。
Above 100, every hundredth between 0 to 1 are represented.在 100 以上,表示01之间的百分之一。 In other words, 200 possible values in array form to show the neural.network what to target and what the prediction is.换句话说,200 个可能的数组形式的值来显示神经网络的目标是什么以及预测是什么。

The code (which I had broken up in a Jupyter Notebook)...代码(我在 Jupyter Notebook 中分解的代码)...

%matplotlib inline

import torch
import random
import numpy as np
from collections import deque
from matplotlib import pyplot as plt
from matplotlib.pyplot import figure
from torch import nn
import time
import math

plt.rcParams["figure.figsize"]=(12, 8)  

class Network(nn.Module):
    def __init__(self):
        super().__init__()
        
        self.net = nn.Sequential(
            nn.Linear(120, 136),
            nn.ReLU(),
            nn.Dropout(0.05),
            nn.Linear(136, 146),
            nn.ReLU(),
            nn.Dropout(0.05),
            nn.Linear(146, 156),
            nn.ReLU(),
            nn.Dropout(0.05),
            nn.Linear(156, 170),
            nn.ReLU(),
            nn.Linear(170, 188),
            nn.Dropout(0.05),
            nn.ReLU(),
            nn.Linear(188, 200))  

    def forward(self, x):
        return self.net(x)  

online_net = Network().cuda("cuda:2")

optimizer = torch.optim.Adam(online_net.parameters(), lr=1e-5)
device = torch.device("cuda:2" if torch.cuda.is_available() else "cpu")  

sensor_buffer = deque(maxlen=120)
action_buffer = deque(maxlen=120)

[sensor_buffer.append(np.array([random.random() for _ in range(4)]).mean()) for __ in range(121)]
[action_buffer.append(0) for _ in range(121)]  

def format_target(n):
    n = (n * 100)
    l = [-1 for o in range(200)]
    l[int(n)] = 1
    return l  

for steps in range(1400):
    
    adder += (random.random() * 0.2)
    sensor_buffer.append(adder)
    sensor_sinwave = np.sin(sensor_buffer[-1])

    outers = torch.tensor(np.sin(sensor_buffer), dtype=torch.float32).cuda("cuda:2").T

    outer = online_net.forward(outers)

    prediction = torch.argmax(outer).item()

    n_prediction = (prediction * 0.01) -1

    action_buffer.append(n_prediction)

    target = format_target(sensor_sinwave)
    target_t = torch.as_tensor(target, dtype=torch.float32, device=device)

    loss = nn.functional.smooth_l1_loss(outer, target_t)


    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    if steps % 150 == 0:
        print(loss.item(), n_prediction, sensor_sinwave)

The sin wave I'm trying to predict我试图预测的罪恶浪潮在此处输入图像描述

My predictions我的预测在此处输入图像描述

Your model has two main problems: one is mechanical and one is theoretical.您的 model 有两个主要问题:一个是机械问题,一个是理论问题。

  1. Your loss (and accompanying architecture) do not model the problem appropriately.你的损失(和伴随的架构)没有适当地解决 model 问题。 You are effectively attempting to train a regression problem (R^n -> R), but you're framing it as a classification problem (R^n -> Z^m).您实际上是在尝试训练回归问题 (R^n -> R),但您将其定义为分类问题 (R^n -> Z^m)。 Typically (and coarsely), for classification problems you'll use cross-entropy loss while for regression you'll use L2 loss.通常(粗略地),对于分类问题,您将使用交叉熵损失,而对于回归问题,您将使用 L2 损失。 If you change the output dimension of your model to 1 and the loss to L2, you should be in better shape.如果您将 model 的 output 维度更改为 1,并将损失更改为 L2,您的状态应该会更好。

  2. Your model is too complex for such a simple function. The more parameters your model has, the more variance you are likely to introduce.你的 model 对于这样一个简单的 function 来说太复杂了。你的 model 的参数越多,你可能引入的方差就越大。 This amounts to a higher likelihood of overfitting and less chance of generalization.这相当于更高的过度拟合可能性和更小的泛化机会。 Make your model a few layers shallower and you'll likely be happier with its performance.让您的 model 浅几层,您可能会对它的性能感到满意。

Here is a tiny C++ code to predict the next sin() value.这是一个很小的 C++ 代码,用于预测下一个 sin() 值。 Hopefully it is useful to you.希望它对你有用。

#include <cmath>
#include <iostream>
#include <vector>
using namespace std;

const float pi = 4.0f * atanf(1.0f);

int main(void)
{
    // Replace these samples with your input data
    vector<float> samples(120, 0.0f);

    for (size_t i = 0; i < samples.size(); i++)
    {
        const float n = (i + 1) / static_cast<float>(samples.size());
        samples[i] = sin(2 * pi * n);

        cout << samples[i] << endl;
    }

    cout << endl;

    vector<float> arc_samples(120, 0.0f);

    for (size_t i = 0; i < arc_samples.size(); i++)
    {
        arc_samples[i] = asin(samples[i]);

        cout << arc_samples[i] << endl;
    }

    cout << endl;

    size_t avg_count = 0;
    float avg_diff = 0.0f;

    for (size_t i = 1; i < arc_samples.size(); i++)
    {
        avg_diff += fabsf(arc_samples[i] - arc_samples[i - 1]);
        avg_count++;
    }

    avg_diff /= avg_count;

    float next_sample = arc_samples[arc_samples.size() - 1] + avg_diff;

    cout << "Next sin() value = " << sin(next_sample) << endl;

    return 0;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM