MSE 预测未预期

MSE with predictions not expected

这是一个回归模型,我试图从 x 值(输入)预测 y 值(输出)。每个 class 被赋予不同的均值并使用 l2 归一化进行归一化:

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

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

>>> 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]

returns:

[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)]

正如我定义的 classes 具有差异均值且最终损失值较低 (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)]

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

我的模型设置有误吗?

你确定你有回归问题吗?当我们谈论输出是特定的 class 时,通常使用 class化问题而不考虑输入。

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

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

1 - 考虑到您遇到了 class化问题。

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 - 考虑到你想得到那个“数字”作为回归和 不是 class。您不是在寻找概率分布,而是在直接寻找值。在这种情况下,它不是很常见,但如果您只想要正值,那么使用指数作为激活值会很有趣。所以你将 -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()