【问题标题】:MSE with predictions not expected没有预期的 MSE
【发布时间】:2020-11-12 13:23:10
【问题描述】:

这是一个回归模型,我尝试从 x 值(输入)预测 y 值(输出)。每个类都有不同的平均值,并使用 l2 归一化进行归一化:

x_values = sklearn.preprocessing.normalize(x_values, norm="l2")

这可能表现为试图使用回归解决的分类问题。我试图理解 PyTorch 中的多类回归,因为 PyTorch 文档给出了以下示例,表明多类回归是可能的:

>>> loss = nn.MSELoss()
>>> input = torch.randn(3, 5, requires_grad=True)
>>> target = torch.randn(3, 5)
>>> output = loss(input, target)
>>> output.backward()

源代码:https://pytorch.org/docs/master/generated/torch.nn.MSELoss.html

完整代码:

% reset - f

from datetime import datetime
from sklearn import metrics
import torch
import torch.nn as nn
import torchvision
import torchvision.transforms as transforms
import numpy as np
import matplotlib.pyplot as plt
import torch.utils.data as data_utils
import torch.nn as nn
import torch.nn.functional as F
import random
from torch.autograd import Variable
import pandas as pd
import unittest
import time
from collections import Counter
import sklearn

x_values = []
y_values = []
input_size = 17
lr = .1

# Class1
mu, sigma = 0, 0.1  # mean and standard deviation
x_values.append(np.random.normal(mu, sigma, input_size))
x_values.append(np.random.normal(mu, sigma, input_size))
x_values.append(np.random.normal(mu, sigma, input_size))

# Class2
mu, sigma = 5, 0.5  # mean and standard deviation
x_values.append(np.random.normal(mu, sigma, input_size))
x_values.append(np.random.normal(mu, sigma, input_size))
x_values.append(np.random.normal(mu, sigma, input_size))

# Class3
mu, sigma = 10, 1.0  # mean and standard deviation
x_values.append(np.random.normal(mu, sigma, input_size))
x_values.append(np.random.normal(mu, sigma, input_size))
x_values.append(np.random.normal(mu, sigma, input_size))

# Class4
mu, sigma = 15, 1.5  # mean and standard deviation
x_values.append(np.random.normal(mu, sigma, input_size))
x_values.append(np.random.normal(mu, sigma, input_size))
x_values.append(np.random.normal(mu, sigma, input_size))

# Class5
mu, sigma = 20, 2.0  # mean and standard deviation
x_values.append(np.random.normal(mu, sigma, input_size))
x_values.append(np.random.normal(mu, sigma, input_size))
x_values.append(np.random.normal(mu, sigma, input_size))

x_values = sklearn.preprocessing.normalize(x_values, norm="l2")

y_values.append(0)
y_values.append(0)
y_values.append(0)

y_values.append(1)
y_values.append(1)
y_values.append(1)

y_values.append(2)
y_values.append(2)
y_values.append(2)

y_values.append(3)
y_values.append(3)
y_values.append(3)

y_values.append(4)
y_values.append(4)
y_values.append(4)

num_classes = len(y_values)


class NeuralNet(nn.Module):
    def __init__(self):
        super(NeuralNet, self).__init__()
        self.criterion = torch.nn.MSELoss()
        self.model = torch.nn.Sequential(
            torch.nn.Linear(input_size, 100),
            torch.nn.ReLU(),
            torch.nn.Linear(100, 50),
            torch.nn.ReLU(),
            torch.nn.Linear(50, num_classes)
            #                         torch.nn.ReLU()
        )
        self.optimizer = torch.optim.Adam(self.model.parameters(), lr)

    def update(self, state, action):
        y_pred = self.model(torch.Tensor(state))
        loss = self.criterion(y_pred, Variable(torch.Tensor(action)))
        self.optimizer.zero_grad()
        loss.backward()
        self.optimizer.step()
        return loss

    def predict(self, s):
        with torch.no_grad():
            return self.model(torch.Tensor(s))


def weights_init(m):
    if type(m) == nn.Linear:
        m.weight.data.normal_(0.0, 1)


model = NeuralNet()
model.apply(weights_init)
print('len(states)', len(x_values))

i = 0

for s in range(7000):

    if i == 15:
        i = 0
    x = x_values[i]
    loss_value = model.update(x, y_values)

    if s % 1000 == 0:
        print('loss_value', loss_value)

    i = i + 1

预测x_values

[torch.argmax(model.predict(s)) for s in x_values]

返回:

[tensor(14),
 tensor(14),
 tensor(14),
 tensor(14),
 tensor(14),
 tensor(14),
 tensor(14),
 tensor(14),
 tensor(14),
 tensor(14),
 tensor(14),
 tensor(14),
 tensor(14),
 tensor(14),
 tensor(14)]

由于我定义了具有差异均值的类并且最终损失值较低 (4.7370e-15),我希望预测值更接近:

[tensor(0)
 tensor(0),
 tensor(0),
 tensor(1),
 tensor(1),
 tensor(1),
 tensor(2),
 tensor(2),
 tensor(2),
 tensor(3),
 tensor(3),
 tensor(3),
 tensor(4),
 tensor(4),
 tensor(4)]

哪些预测输出不符合我的预期?

我的模型设置不正确吗?

【问题讨论】:

  • 多类回归到底是什么意思?您想为每个数据点分配一个类一个回归值,还是您有其他想法?
  • @Coolness 是的,这是我的目标 - 为每个数据点分配一个类别和回归值,但预测回归值。

标签: deep-learning pytorch loss-function mse


【解决方案1】:

你确定你有回归问题吗?当我们谈论输出是一个特定的类时,通常会使用分类问题而不管输入。

另一个概念是您试图表示某种有序分类变量。

您可以通过两种方式提出问题:

1 - 考虑到您有分类问题。

class NeuralNet(nn.Module):
    class ExpActivation(nn.Module):
        def __init__(self):
            super().__init__()

        def forward(self, x):
            return torch.exp(x)

    class BoundedPositiveNumber(nn.Module):
        def __init__(self):
            super().__init__()
            self.max_value = 4

        def forward(self, x):
            return self.max_value * torch.sigmoid(x)


    def __init__(self):
        super(NeuralNet, self).__init__()
        self.criterion = torch.nn.CrossEntropyLoss()
        self.model = torch.nn.Sequential(
            torch.nn.Linear(input_size, 100),
            torch.nn.ReLU(),
            torch.nn.Linear(100, 50),
            torch.nn.ReLU(),
            torch.nn.Linear(50, num_classes),
            torch.nn.Softmax()
        )
        self.optimizer = torch.optim.Adam(self.model.parameters(), lr)

    def update(self, state, action):
        y_pred = self.model(state)
        loss = self.criterion(y_pred, action)
        # print(torch.argmax(y_pred, axis=-1), action, loss)
        self.optimizer.zero_grad()
        loss.backward()
        self.optimizer.step()
        return loss

    def predict(self, s):
        with torch.no_grad():
            return self.model(torch.Tensor(s))


def weights_init(m):
    if type(m) == nn.Linear:
        m.weight.data.normal_(0.0, 1)


model = NeuralNet()
#model.apply(weights_init)
print('len(states)', len(x_values))

i = 0

x_values = torch.from_numpy(x_values).float()
y_values = torch.from_numpy(np.array(y_values)).long()

for s in range(700000):

    if i == 15:
        i = 0
    x = x_values[i:i+1]
    y = y_values[i:i+1]
    loss_value = model.update(x_values, y_values)

    if s % 1000 == 0:
        print('loss_value', loss_value)

    i = i + 1

# Example
f = model.model(x)
proba = torch.softmax(f) # obtain the probability distribution
np.argmax(proba.cpu().numpy()) # or np.argmax(f.cpu().numpy()), in this case are equivalent

2 - 考虑到您想将该“数字”作为回归和 不作为一个班级。您不是在寻找概率分布,而是直接寻找值。在这种情况下,它不是很常见,但如果你只想要正值,使用指数作为激活是很有趣的。所以你把 -inf, inf 压缩成 0, inf。

class NeuralNet(nn.Module):
    class ExpActivation(nn.Module):
        def __init__(self):
            super().__init__()

        def forward(self, x):
            return torch.exp(x)

    class AcotatedPositiveNumber(nn.Module):
        def __init__(self):
            super().__init__()
            self.max_value = 4

        def forward(self, x):
            return self.max_value * torch.sigmoid(x)


    def __init__(self):
        super(NeuralNet, self).__init__()
        self.criterion = torch.nn.MSELoss()
        self.model = torch.nn.Sequential(
            torch.nn.Linear(input_size, 100),
            torch.nn.ReLU(),
            torch.nn.Linear(100, 50),
            torch.nn.ReLU(),
            torch.nn.Linear(50, 1),
            NeuralNet.ExpActivation()
        )
        self.optimizer = torch.optim.Adam(self.model.parameters(), lr)

    def update(self, state, action):
        y_pred = self.model(state)
        loss = self.criterion(y_pred, action.unsqueeze(-1))
        # print(torch.round(y_pred.squeeze()).long(), action, loss)
        self.optimizer.zero_grad()
        loss.backward()
        self.optimizer.step()
        return loss

    def predict(self, s):
        with torch.no_grad():
            return self.model(torch.Tensor(s))


def weights_init(m):
    if type(m) == nn.Linear:
        m.weight.data.normal_(0.0, 1)


model = NeuralNet()
#model.apply(weights_init)
print('len(states)', len(x_values))

i = 0

x_values = torch.from_numpy(x_values).float()
y_values = torch.from_numpy(np.array(y_values)).float()

for s in range(700000):

    if i == 15:
        i = 0
    x = x_values[i:i+1]
    y = y_values[i:i+1]
    loss_value = model.update(x_values, y_values)

    if s % 1000 == 0:
        print('loss_value', loss_value)

    i = i + 1

# Example
regresion_value = model.model(x)
regresion_value.cpu().numpy()

【讨论】:

  • 谢谢,但您在 2 中的代码无法运行 - 存在许多问题。例如 - 'torch.nn.Linear(50, 1)' 应该是 'torch.nn.Linear(50, 1), '
  • 我已经更新了代码。原则上,他们为我工作,你在原始代码中也有很高的 LR。如果动作的空间是有限的,你会更好地进行分类。
  • 请注意,此答案中的分类代码在训练期间两次应用 Softmax:一次在 CrossEntropyLoss 中,并分别作为模型的最后一层。使用示例也这样做,因为模型调用中已经采用了 Softmax。可能不是故意的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-18
  • 2013-10-18
  • 2019-08-02
  • 2016-05-29
  • 2014-05-06
  • 2018-09-12
相关资源
最近更新 更多