【深度学习入门系列】 pytorch实现多层感知机(MLP)(内含分类、回归任务实例)

news2024/12/23 20:52:45

文章目录

  • 0. BP和MLP
  • 1 分类
    • 1.0 数据集
    • 1.1 网络架构
    • 1.2 代码
    • 1.3 结果
  • 2 回归
    • 2.0 数据集
    • 2.1 网络架构
    • 2.2 代码
    • 2.3 结果
  • 3 代码(可直接食用)

众所周知,sklearn提供了MLP函数。个人认为这个东西虽然蛮好用的——有的时候比你自己写的效果都好,但是,不是长久之计。通过Pytorch能建立自定义程度更高的人工神经网络,往后在网络里面加乱七八糟的东西都很方便(比如GA/PSO求解超参之类的、比如微调模型架构之类的)。本文将不再对MLP的理论基础进行赘述,直接介绍MLP的具体搭建方法。

0. BP和MLP

在做这个之前,我突然想到一个问题

我现在出了一篇 MLP 的文章,要不要再出一个 BP 的?

沉默……

这俩有什么区别啊???

跟某知名大博主讨论了一下,感觉大概是这样的:

我们先明确3个概念:

  • BP:BP的全称是back propagation(反向传播算法),这并不是一个神经网络。
  • BP神经网络:用了BP算法的神经网络。
  • MLP:多层感知机,也就是我们说的神经网络。

那么我们不难发现,所谓的BP神经网络其实应该是(BP-MLP )
<=> BP神经网络 = BP算法 + MLP(多层感知机)

也就是说,BP 和 MLP 本身是平行的两个概念,不是一件事;它们是 BP 神经网络这个事物的两个不同的方面。

猜测

最开始的时候,神经网络方面的知识还不够丰富,这个时候人们把刚开始的那个简单的结构称作MLP。

随着时间的流逝,人们发现了反向传播算法(BP),这个时候开始强调训练方法了,所以将其相关的神经网络称为BP神经网络。

再往后,因为人们都用BP了,BP不那么新那么火了,这个时候又开始强调模型结构了,就出现了乱七八糟的其他神经网络。

1 分类

1.0 数据集

数据集我采用的是之前接手的一个保险理赔项目。

目标是判断用户是不是来骗保的,给了一大堆特征,这里我就不详细解释是哪些特征了,这篇文章主要负责搭建模型。

归一化之后发现数据还是非常稀疏的,而且看着可能二值化效果会不错,嫌麻烦,不尝试了,就直接拿这个用也没什么大问题。

是一个4分类任务,结果可能没2分类好看,这跟项目的数据也有关,本身数据也比较脏、噪声也比较多,感觉特征与 label 之间的联系也不是特别紧密。不过问题不大,我们的重心还是放在搭网络上。

数据集缺点还包括样本不平衡,确实会影响结果。

data.csv (36221x24)=> 已经包括 label 了

在这里插入图片描述

1.1 网络架构

torch 输出的架构如下

在这里插入图片描述

一共是4层隐藏层(10->10->10->10)

也尝试过 128->64->16 和一些大的复杂的多层感知机,效果反而没这个好,从混淆矩阵看能发现过拟合了。

1.2 代码

分类任务的相关文件如下

在这里插入图片描述

MLP_clf.py			分类模型架构
data.csv			分类数据集
run.py				主函数
utils.py			相关函数和类

run.py

import os
import numpy
import torch
import random
from utils import Config, CLF_Model, REG_Model
from clf_model.MLP_clf import MLP

# 随机数种子确定
seed = 1129
random.seed(seed)
numpy.random.seed(seed)
torch.manual_seed(seed)
torch.cuda.manual_seed(seed)
torch.cuda.manual_seed_all(seed)
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False
os.environ['PYTHONHASHSEED'] = str(seed)


# 分类
if __name__ == '__main__':
	# 读数据
    config = Config(
        data_path="dataset_clf/data.csv",
        name="MLP",
        batch_size=128,
        learning_rate=0.000005,
        epoch=200
    )
    # 搭模型
    clf = MLP(
        input_n=len(config.input_col),
        output_n=len(config.output_class),
        num_layer=4,
        layer_list=[10,10,10,10],
        dropout=0.5
    )
    print(clf)
    # 训练模型并评价模型
    model = CLF_Model(clf, config)
    model.run()

MLP_clf.py

import torch
from torch.nn import Linear, ReLU, ModuleList, Sequential, Dropout, Softmax, Tanh
import torch.nn.functional as F

class MLP(torch.nn.Module):
    # 默认三层隐藏层,分别有128个 64个 16个神经元
    def __init__(self, input_n, output_n, num_layer=3, layer_list=[128, 64, 16], dropout=0.5):
        """
        :param input_n: int 输入神经元个数
        :param output_n: int 输出神经元个数
        :param num_layer: int 隐藏层层数
        :param layer_list: list(int) 每层隐藏层神经元个数
        :param dropout: float 训练完丢掉多少
        """
        super(MLP, self).__init__()
        self.input_n = input_n
        self.output_n = output_n
        self.num_layer = num_layer
        self.layer_list = layer_list

        # 输入层
        self.input_layer = Sequential(
            Linear(input_n, layer_list[0], bias=False),
            ReLU()
        )

        # 隐藏层
        self.hidden_layer = Sequential()

        for index in range(num_layer-1):
            self.hidden_layer.extend([Linear(layer_list[index], layer_list[index+1], bias=False), ReLU()])

        self.dropout = Dropout(dropout)

        # 输出层
        self.output_layer = Sequential(
            Linear(layer_list[-1], output_n, bias=False),
            Softmax(dim=1),
        )

    def forward(self, x):
        input = self.input_layer(x)
        hidden = self.hidden_layer(input)
        hidden = self.dropout(hidden)
        output = self.output_layer(hidden)
        return output

util.py

import sys

import numpy as np
import pandas as pd
import torch
import torch.nn.functional as F
from matplotlib import pyplot as plt
from sklearn import metrics
from sklearn.metrics import mean_squared_error, r2_score
from sklearn.model_selection import train_test_split
import time
from datetime import timedelta


# 一个数据格式。感觉这玩意好多余啊,但是nlp写多了就很习惯的写了一个上去 => 主要是不写没法封装
class Dataset(torch.utils.data.Dataset):
    def __init__(self, data_df):
        self.label = torch.from_numpy(data_df['label'].values)
        self.data = torch.from_numpy(data_df[data_df.columns[:-1]].values).to(torch.float32)

    # 每次迭代取出对应的data和author
    def __getitem__(self, idx):
        batch_data = self.get_batch_data(idx)
        batch_label = self.get_batch_label(idx)
        return batch_data, batch_label

    # 下面的几条没啥用其实,就是为__getitem__服务的
    def classes(self):
        return self.label

    def __len__(self):
        return self.data.size(0)

    def get_batch_label(self, idx):
        return np.array(self.label[idx])

    def get_batch_data(self, idx):
        return self.data[idx]


# 存数据,加载数据用的
class Config:
    def __init__(self, data_path, name, batch_size, learning_rate, epoch):
        """
        :param data_path: string 数据文件路径
        :param name: string 模型名字
        :param batch_size: int 多少条数据组成一个batch
        :param learning_rate: float 学习率
        :param epoch: int 学几轮
        """
        self.name = name
        self.data_path = data_path
        self.batch_size = batch_size
        self.learning_rate = learning_rate
        self.epoch = epoch
        self.train_loader, self.dev_loader, self.test_loader = self.load_tdt()
        self.input_col, self.output_class = self.get_class()
    
    # 加载train, dev, test,把数据封装成Dataloader类
    def load_tdt(self):
        file = self.read_file()
        train_dev_test = self.cut_data(file)
        tdt_loader = [self.load_data(i) for i in train_dev_test]
        return tdt_loader[0], tdt_loader[1], tdt_loader[2]

    # 读文件
    def read_file(self):
        file = pd.read_csv(self.data_path, encoding="utf-8-sig", index_col=None)
        # 保险起见,确认最后一列列名为label
        file.columns.values[-1] = "label"
        self.if_nan(file)
        return file

    # 切7:1:2 => 训练:验证:测试
    def cut_data(self, data_df):
        try:
            train_df, test_dev_df = train_test_split(data_df, test_size=0.3, random_state=1129, stratify=data_df["label"])
            dev_df, test_df = train_test_split(test_dev_df, test_size=0.66, random_state=1129, stratify=test_dev_df["label"])
        except ValueError:
            train_df, test_dev_df = train_test_split(data_df, test_size=0.3, random_state=1129)
            dev_df, test_df = train_test_split(test_dev_df, test_size=0.66, random_state=1129)
        return [train_df, dev_df, test_df]

    # Dataloader 封装进去
    def load_data(self, data_df):
        dataset = Dataset(data_df)
        return torch.utils.data.DataLoader(dataset, batch_size=self.batch_size)

    # 检验输入输出是否有空值
    def if_nan(self, data):
        if data.isnull().any().any():
            empty = data.isnull().any()
            print(empty[empty].index)
            print("Empty data exists")
            sys.exit(0)

    # 后面输出混淆矩阵用的
    def get_class(self):
        file = self.read_file()
        label = file[file.columns[-1]]
        label = list(set(list(label)))
        return file.columns[:-1], label


# 跑clf用的,里面包含了训练,测试,评价等等的代码
class CLF_Model:
    def __init__(self, model, config):
        self.model = model
        self.config = config

    def run(self):
        self.train(self.model)

    def train(self, model):
        dev_best_loss = float('inf')
        start_time = time.time()
        # 模型为训练模式
        model.train()
        # 定义优化器
        optimizer = torch.optim.Adam(model.parameters(), lr=self.config.learning_rate)
        # 记录训练、验证的准确率和损失
        acc_list = [[], []]
        loss_list = [[], []]
        # 记录损失不下降的epoch数,到达20之后就直接退出 => 训练无效,再训练下去可能过拟合
        break_epoch = 0
        for epoch in range(self.config.epoch):
            print('Epoch [{}/{}]'.format(epoch + 1, self.config.epoch))
            for index, (trains, labels) in enumerate(self.config.train_loader):
                # 归零
                model.zero_grad()
                # 得到预测结果,是一堆概率
                outputs = model(trains)
                # 交叉熵计算要long的类型
                labels = labels.long()
                # 计算交叉熵损失
                loss = F.cross_entropy(outputs, labels)
                # 反向传播loss
                loss.backward()
                # 优化参数
                optimizer.step()
                # 每100个迭代或者跑完一个epoch后,验证一下
                if (index % 100 == 0 and index != 0) or index == len(self.config.train_loader) - 1:
                    true = labels.data.cpu()
                    # 预测类别
                    predict = torch.max(outputs.data, 1)[1].cpu()
                    # 计算训练准确率
                    train_acc = metrics.accuracy_score(true, predict)
                    # 计算验证准确率和loss
                    dev_acc, dev_loss = self.evaluate(model)
                    # 查看验证loss是不是进步了
                    if dev_loss < dev_best_loss:
                        dev_best_loss = dev_loss
                        improve = '*'
                        break_epoch = 0
                    else:
                        improve = ''
                        break_epoch += 1
                    time_dif = self.get_time_dif(start_time)
                    # 输出阶段性结果
                    msg = 'Iter: {0:>6},  Train Loss: {1:>5.3},  Train Acc: {2:>6.3%},  Val Loss: {3:>5.3},  Val Acc: {4:>6.3%},  Time: {5} {6}'
                    print(msg.format(index, loss.item(), train_acc, dev_loss, dev_acc, time_dif, improve))
                    # 为了画图准备的,记录每个epoch的结果
                    if index == len(self.config.train_loader) - 1:
                        acc_list[0].append(train_acc)
                        acc_list[1].append(dev_acc)
                        loss_list[0].append(loss.item())
                        loss_list[1].append(dev_loss)
                    # 验证集评估时模型编程验证模式了,现在变回训练模式
                    model.train()
            # 20个epoch损失不变,直接退出训练
            if break_epoch > 20:
                self.config.epoch = epoch+1
                break
        # 测试
        self.test(model)
        # 画图
        self.draw_curve(acc_list, loss_list, self.config.epoch)

    def test(self, model):
        start_time = time.time()
        # 测试准确率,测试损失,测试分类报告,测试混淆矩阵
        test_acc, test_loss, test_report, test_confusion = self.evaluate(model, test=True)
        msg = 'Test Loss: {0:>5.3},  Test Acc: {1:>6.3%}'
        print(msg.format(test_loss, test_acc))
        print("Precision, Recall and F1-Score...")
        print(test_report)
        print("Confusion Matrix...")
        print(test_confusion)
        time_dif = self.get_time_dif(start_time)
        print("Time usage:", time_dif)

    def evaluate(self, model, test=False):
        # 模型模式变一下
        model.eval()
        loss_total = 0
        predict_all = np.array([], dtype=int)
        labels_all = np.array([], dtype=int)
        # 如果是测试模式(这一段写的不是很好)
        if test:
            with torch.no_grad():
                for (dev, labels) in self.config.test_loader:
                    outputs = model(dev)
                    labels = labels.long()
                    loss = F.cross_entropy(outputs, labels)
                    loss_total += loss
                    labels = labels.data.cpu().numpy()
                    predict = torch.max(outputs.data, 1)[1].cpu().numpy()
                    labels_all = np.append(labels_all, labels)
                    predict_all = np.append(predict_all, predict)
            acc = metrics.accuracy_score(labels_all, predict_all)
            report = metrics.classification_report(labels_all, predict_all, target_names=[str(i) for i in self.config.get_class()[1]], digits=4)
            confusion = metrics.confusion_matrix(labels_all, predict_all)
            return acc, loss_total / len(self.config.dev_loader), report, confusion
        # 不是测试模式
        with torch.no_grad():
            for (dev, labels) in self.config.dev_loader:
                outputs = model(dev)
                labels = labels.long()
                loss = F.cross_entropy(outputs, labels)
                loss_total += loss
                labels = labels.data.cpu().numpy()
                predict = torch.max(outputs.data, 1)[1].cpu().numpy()
                labels_all = np.append(labels_all, labels)
                predict_all = np.append(predict_all, predict)
        acc = metrics.accuracy_score(labels_all, predict_all)
        return acc, loss_total / len(self.config.dev_loader)
    
    # 算时间损耗
    def get_time_dif(self, start_time):
        end_time = time.time()
        time_dif = end_time - start_time
        return timedelta(seconds=int(round(time_dif)))

    # 画图
    def draw_curve(self, acc_list, loss_list, epochs):
        x = range(0, epochs)
        y1 = loss_list[0]
        y2 = loss_list[1]
        y3 = acc_list[0]
        y4 = acc_list[1]
        plt.figure(figsize=(13, 13))
        plt.subplot(2, 1, 1)
        plt.plot(x, y1, color="blue", label="train_loss", linewidth=2)
        plt.plot(x, y2, color="orange", label="val_loss", linewidth=2)
        plt.title("Loss_curve", fontsize=20)
        plt.xlabel(xlabel="Epochs", fontsize=15)
        plt.ylabel(ylabel="Loss", fontsize=15)
        plt.legend()
        plt.subplot(2, 1, 2)
        plt.plot(x, y3, color="blue", label="train_acc", linewidth=2)
        plt.plot(x, y4, color="orange", label="val_acc", linewidth=2)
        plt.title("Acc_curve", fontsize=20)
        plt.xlabel(xlabel="Epochs", fontsize=15)
        plt.ylabel(ylabel="Accuracy", fontsize=15)
        plt.legend()
        plt.savefig("images/"+self.config.name+"_Loss&acc.png")

1.3 结果

训练ing……

在这里插入图片描述

第三类的精确率感人,不过其他分类效果挺好的。感觉是数据集的问题,悄悄拿sklearn试了一下,就差1%。

在这里插入图片描述

曲线如下(感觉不是正常的曲线,主要是数据集的问题,70%的数据区分度很大,剩下的很难辨认)

在这里插入图片描述

2 回归

2.0 数据集

用的2023美赛春季赛Y题数据,在原有的数据集上加了很多船的参数,再把两个 dataset 合一起。

预处理的操作简单暴力,重复值的行删掉,部分含空值多的行删掉,方便填充的随机森林下,不方便填充的直接暴力填0。

平时肯定是不能这么干的,但是这里我们只是需要一个数据集而已,重点还是模型。

data.csv(2793x39)=> 已经包括 label 了

在这里插入图片描述

label.csv(2793x1)

在这里插入图片描述

2.1 网络架构

torch 输出的架构如下

在这里插入图片描述

一共是4层隐藏层(512->128->32->8)

也尝试过 10->10->10 和一些大的复杂的多层感知机,效果都一般。

2.2 代码

回归任务的相关文件如下

在这里插入图片描述

data.csv			回归数据集
MLP_reg.py		回归模型架构
run.py				主函数
utils.py				相关函数和类

run.py

import os
import numpy
import torch
import random
from utils import Config, CLF_Model, REG_Model
from clf_model.MLP_clf import MLP


seed = 1129
random.seed(seed)
numpy.random.seed(seed)
torch.manual_seed(seed)
torch.cuda.manual_seed(seed)
torch.cuda.manual_seed_all(seed)
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False
os.environ['PYTHONHASHSEED'] = str(seed)



from reg_model.MLP_reg import MLP
# 回归
if __name__ == '__main__':
    config = Config(
        data_path="dataset_reg/data.csv",
        name="MLP",
        batch_size=16,
        learning_rate=0.015,
        epoch=200
    )
    # 看是几输出问题
    reg = MLP(
        input_n=len(config.input_col),
        output_n=1,
        num_layer=4,
        layer_list=[512, 128, 32, 8],
        dropout=0.5
    )
    print(reg)
    model = REG_Model(reg, config)
    model.run()

utils.py

import sys

import numpy as np
import pandas as pd
import torch
import torch.nn.functional as F
from matplotlib import pyplot as plt
from sklearn import metrics
from sklearn.metrics import mean_squared_error, r2_score
from sklearn.model_selection import train_test_split
import time
from datetime import timedelta


# 一个数据格式。感觉这玩意好多余啊,但是nlp写多了就很习惯的写了一个上去 => 主要是不写没法封装
class Dataset(torch.utils.data.Dataset):
    def __init__(self, data_df):
        self.label = torch.from_numpy(data_df['label'].values)
        self.data = torch.from_numpy(data_df[data_df.columns[:-1]].values).to(torch.float32)

    # 每次迭代取出对应的data和author
    def __getitem__(self, idx):
        batch_data = self.get_batch_data(idx)
        batch_label = self.get_batch_label(idx)
        return batch_data, batch_label

    # 下面的几条没啥用其实,就是为__getitem__服务的
    def classes(self):
        return self.label

    def __len__(self):
        return self.data.size(0)

    def get_batch_label(self, idx):
        return np.array(self.label[idx])

    def get_batch_data(self, idx):
        return self.data[idx]


# 存数据,加载数据用的
class Config:
    def __init__(self, data_path, name, batch_size, learning_rate, epoch):
        """
        :param data_path: string 数据文件路径
        :param name: string 模型名字
        :param batch_size: int 多少条数据组成一个batch
        :param learning_rate: float 学习率
        :param epoch: int 学几轮
        """
        self.name = name
        self.data_path = data_path
        self.batch_size = batch_size
        self.learning_rate = learning_rate
        self.epoch = epoch
        self.train_loader, self.dev_loader, self.test_loader = self.load_tdt()
        self.input_col, self.output_class = self.get_class()

    # 加载train, dev, test,把数据封装成Dataloader类
    def load_tdt(self):
        file = self.read_file()
        train_dev_test = self.cut_data(file)
        tdt_loader = [self.load_data(i) for i in train_dev_test]
        return tdt_loader[0], tdt_loader[1], tdt_loader[2]

    # 读文件
    def read_file(self):
        file = pd.read_csv(self.data_path, encoding="utf-8-sig", index_col=None)
        # 保险起见,确认最后一列列名为label
        file.columns.values[-1] = "label"
        self.if_nan(file)
        return file

    # 切7:1:2 => 训练:验证:测试
    def cut_data(self, data_df):
        try:
            train_df, test_dev_df = train_test_split(data_df, test_size=0.3, random_state=1129, stratify=data_df["label"])
            dev_df, test_df = train_test_split(test_dev_df, test_size=0.66, random_state=1129, stratify=test_dev_df["label"])
        except ValueError:
            train_df, test_dev_df = train_test_split(data_df, test_size=0.3, random_state=1129)
            dev_df, test_df = train_test_split(test_dev_df, test_size=0.66, random_state=1129)
        return [train_df, dev_df, test_df]

    # Dataloader 封装进去
    def load_data(self, data_df):
        dataset = Dataset(data_df)
        return torch.utils.data.DataLoader(dataset, batch_size=self.batch_size)

    # 检验输入输出是否有空值
    def if_nan(self, data):
        if data.isnull().any().any():
            empty = data.isnull().any()
            print(empty[empty].index)
            print("Empty data exists")
            sys.exit(0)

    # 后面输出混淆矩阵用的
    def get_class(self):
        file = self.read_file()
        label = file[file.columns[-1]]
        label = list(set(list(label)))
        return file.columns[:-1], label



# 跑reg用的,里面包含了训练,测试,评价等等的代码
class REG_Model:
    def __init__(self, model, config):
        self.model = model
        self.config = config

    def run(self):
        self.train(self.model)

    def train(self, model):
        dev_best_loss = float('inf')
        start_time = time.time()
        # 模型为训练模式
        model.train()
        # 定义优化器
        optimizer = torch.optim.Adam(model.parameters(), lr=self.config.learning_rate)
        acc_list = [[], []]
        loss_list = [[], []]
        # 记录损失不下降的epoch数,到达20之后就直接退出 => 训练无效,再训练下去可能过拟合
        break_epoch = 0
        for epoch in range(self.config.epoch):
            print('Epoch [{}/{}]'.format(epoch + 1, self.config.epoch))
            for index, (trains, labels) in enumerate(self.config.train_loader):
                # 归零
                model.zero_grad()
                # 得到预测结果
                outputs = model(trains)
                # MSE计算要float的类型
                labels = labels.to(torch.float)
                # 计算MSE损失
                loss = torch.nn.MSELoss()(outputs, labels)
                # 反向传播loss
                loss.backward()
                # 优化参数
                optimizer.step()
                # 每100个迭代或者跑完一个epoch后,验证一下
                if (index % 100 == 0 and index != 0) or index == len(self.config.train_loader) - 1:
                    true = labels.data.cpu()
                    # 预测数据
                    predict = outputs.data.cpu()
                    # 计算训练准确度 R2
                    train_acc = r2_score(true, predict)
                    # 计算验证准确度 R2 和 loss
                    dev_acc, dev_loss, dev_mse = self.evaluate(model)
                    # 查看验证loss是不是进步了
                    if dev_loss < dev_best_loss:
                        dev_best_loss = dev_loss
                        improve = '*'
                        break_epoch = 0
                    else:
                        improve = ''
                        break_epoch += 1
                    time_dif = self.get_time_dif(start_time)
                    # 输出阶段性结果
                    msg = 'Iter: {0:>6},  Train Loss: {1:>5.3},  Train R2: {2:>6.3},  Val Loss: {3:>5.3},  Val R2: {4:>6.3},  Val Mse: {5:>6.3},  Time: {6} {7}'
                    print(msg.format(index, loss.item(), train_acc, dev_loss, dev_acc, dev_mse, time_dif, improve))
                    # 为了画图准备的,记录每个epoch的结果
                    if index == len(self.config.train_loader) - 1:
                        acc_list[0].append(train_acc)
                        acc_list[1].append(dev_acc)
                        loss_list[0].append(loss.item())
                        loss_list[1].append(dev_loss)
                    # 验证集评估时模型编程验证模式了,现在变回训练模式
                    model.train()
            # 20个epoch损失不变,直接退出训练
            if break_epoch > 20:
                self.config.epoch = epoch+1
                break
        # 测试
        self.test(model)
        # 画图
        self.draw_curve(acc_list, loss_list, self.config.epoch)

    def test(self, model):
        start_time = time.time()
        # 测试准确度 R2,测试损失,测试MSE
        test_acc, test_loss, mse = self.evaluate(model, test=True)
        msg = 'Test R2: {0:>5.3},  Test loss: {1:>6.3},  Test MSE: {2:>6.3}'
        print(msg.format(test_acc, test_loss, mse))
        time_dif = self.get_time_dif(start_time)
        print("Time usage:", time_dif)

    def evaluate(self, model, test=False):
        # 模型模式变一下
        model.eval()
        loss_total = 0
        predict_all = np.array([], dtype=int)
        labels_all = np.array([], dtype=int)
        # 如果是测试模式(这一段写的不是很好)
        if test:
            with torch.no_grad():
                for (dev, labels) in self.config.test_loader:
                    outputs = model(dev)
                    labels = labels.to(torch.float)
                    loss = torch.nn.MSELoss()(outputs, labels)
                    loss_total += loss
                    labels = labels.data.cpu().numpy()
                    predict = outputs.data.cpu().numpy()
                    labels_all = np.append(labels_all, labels)
                    predict_all = np.append(predict_all, predict)
        # 不是测试模式
        else:
            with torch.no_grad():
                for (dev, labels) in self.config.dev_loader:
                    outputs = model(dev)
                    labels = labels.long()
                    loss = torch.nn.MSELoss()(outputs, labels)
                    loss_total += loss
                    labels = labels.data.cpu().numpy()
                    predict = outputs.data.cpu().numpy()
                    labels_all = np.append(labels_all, labels)
                    predict_all = np.append(predict_all, predict)
        r2 = r2_score(labels_all, predict_all)
        mse = mean_squared_error(labels_all, predict_all)
        if test:
            return r2, loss_total / len(self.config.test_loader), mse
        else:
            return r2, loss_total / len(self.config.dev_loader), mse

    # 算时间损耗
    def get_time_dif(self, start_time):
        end_time = time.time()
        time_dif = end_time - start_time
        return timedelta(seconds=int(round(time_dif)))

    # 画图
    def draw_curve(self, acc_list, loss_list, epochs):
        x = range(0, epochs)
        y1 = loss_list[0]
        y2 = loss_list[1]
        y3 = acc_list[0]
        y4 = acc_list[1]
        plt.figure(figsize=(13, 13))
        plt.subplot(2, 1, 1)
        plt.plot(x, y1, color="blue", label="train_loss", linewidth=2)
        plt.plot(x, y2, color="orange", label="val_loss", linewidth=2)
        plt.title("Loss_curve", fontsize=20)
        plt.xlabel(xlabel="Epochs", fontsize=15)
        plt.ylabel(ylabel="Loss", fontsize=15)
        plt.legend()
        plt.subplot(2, 1, 2)
        plt.plot(x, y3, color="blue", label="train_acc", linewidth=2)
        plt.plot(x, y4, color="orange", label="val_acc", linewidth=2)
        plt.title("Acc_curve", fontsize=20)
        plt.xlabel(xlabel="Epochs", fontsize=15)
        plt.ylabel(ylabel="Accuracy", fontsize=15)
        plt.legend()
        plt.savefig("images/"+self.config.name+"_Loss&acc.png")

MLP_reg.py

import torch
from torch.nn import Linear, ReLU, ModuleList, Sequential, Dropout, Softmax, Tanh
import torch.nn.functional as F

class MLP(torch.nn.Module):
    def __init__(self, input_n, output_n, num_layer=2, layer_list=[16, 8], dropout=0.5):
        super(MLP, self).__init__()
        self.input_n = input_n
        self.output_n = output_n
        self.num_layer = num_layer
        self.layer_list = layer_list

        self.input_layer = Sequential(
            Linear(input_n, layer_list[0], bias=False),
            ReLU()
        )
        self.hidden_layer = Sequential()

        for index in range(num_layer-1):
            self.hidden_layer.extend([Linear(layer_list[index], layer_list[index+1], bias=False), ReLU()])

        self.dropout = Dropout(dropout)

        self.output_layer = Sequential(
            Linear(layer_list[-1], output_n, bias=False),
            # ReLU()
            # Softmax(dim=1),
        )

    def forward(self, x):
        input = self.input_layer(x)
        hidden = self.hidden_layer(input)
        hidden = self.dropout(hidden)
        output = self.output_layer(hidden)
        output = output.view(-1)
        return output

2.3 结果

训练ing……

在这里插入图片描述

R2 有0.73。怎么说呢,还可以吧,不高不低。
拿 sklearn 默认的 MLP 才-2.7400039908485083,SVR才-0.15191155233964238。

在这里插入图片描述

曲线如下(感觉不是正常的曲线,训练集太飘了=> 也可能是epoch不到位)

在这里插入图片描述

3 代码(可直接食用)

记得一键三连噢~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/455258.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux应用程序开发:进程的一些事儿

目录 一、进程的简介1、什么是进程&#xff0c;进程的概念2、进程状态3、什么是进程号4、进程间的通信方法&#xff08;IPC&#xff09; 二、 fork()创建子进程三、父、 子进程间的文件共享1、实验12、实验2 四、使用execl函数执行新程序五、关于终端上对进程的一些指令操作六、…

AI绘图风格对照表/画风样稿详细研究记录及经验总结(分析Midjourney和Stable Diffusion风格提示词实际使用情况)不断更新中...

Midjourney和Stable Diffusion都可以通过输入文本生成出令人惊叹的AI图像。 Midjourney是一个收费的在线服务&#xff0c;通过discord对话的形式来生图&#xff0c;局限性较大&#xff0c;但由于后台官方模型做得好&#xff0c;因此出图效果非常完美&#xff1b; Stable Diffus…

3.Spring Security实现JWT token验证

目录 1. Spring Security详细介绍 2. Spring Security详细使用 3. Spring Security实现JWT token验证 4. JWT&#xff08;JSON Web Token&#xff0c;JSON令牌&#xff09; 5. Spring Security安全注解 Spring Security实现JWT token验证 Spring Security是Spring提供的一…

图数据库

1 前言 图数据结构&#xff0c;能够很自然地表征现实世界。比如用户、门店、骑手这些实体可以用图中的点来表示&#xff0c;用户到门店的消费行为、骑手给用户的送餐行为可以用图中的边来表示。使用图的方式对场景建模&#xff0c;便于描述复杂关系。在美团&#xff0c;也有比较…

超全实战操作详解合集——阿里云ECS服务器(CentOS 7.8 64位)安装rpm格式jdk、tomcat8、mysql8三件套

一、下载rpm格式的jdk 网上自行下载下载jdk&#xff0c;使用Xftp连接Linux主机&#xff0c;将jdk文件放入任意目录下&#xff08;为方便后续操作&#xff0c;重命名为1.rpm&#xff09; 二、安装jdk 进入存放jdk文件的目录&#xff0c;使用命令yum -y install 1.rpm 进行安装…

前端工具 Prettier 详细使用流程(兼容ESLint)

一、简介 中文文档&#xff0c;英文官网。 Prettier 是一个开箱即用的代码格式化程序。用来批量处理旧代码的统一&#xff0c;涉及引号、分号、换行、缩进等。支持目前大部分语言处理&#xff0c;包括 JavaScript、Flow、TypeScript、CSS、SCSS、Less、JSX、Vue、GraphQL、JSO…

【计算机视觉】华为天才少年谢凌曦:关于视觉识别领域发展的个人观点!

文章目录 一、前言二、CV的三大基本困难和对应研究方向三、以下简要分析各个研究方向3.1 方向1a&#xff1a;神经网络架构设计3.2 方向1b&#xff1a;视觉预训练3.3 方向2&#xff1a;模型微调和终身学习3.4 方向3&#xff1a;无限细粒度视觉识别任务 四、在上述方向之外五、结…

“踏浪”自动驾驶量产潮,商业化加速的知行科技奔赴IPO

今春过半&#xff0c;自动驾驶产业链扎堆上市的情况在延续&#xff0c;一位新的重量级选手加入了这场热潮。 4月4日&#xff0c;自动驾驶领域领先的解决方案提供商知行汽车科技(苏州)股份有限公司&#xff08;即“知行科技”&#xff09;&#xff0c;向港交所递交招股书&#…

全网多种方法解决error: failed to push some refs to ‘xxx‘

文章目录 1. 复现错误2. 分析错误3. 解决错误4. 解决该错误的其他方法 1. 复现错误 今天使用git status查看文件状态&#xff0c;发现有一个文件未提交&#xff0c;如下代码所示&#xff1a; D:\project\test>git status On branch master Your branch is up to date with …

【剑指offer】学习计划day1

目录 一. 前言 二. 用两个栈实现队列 a.题目 b.题解分析 c.AC代码 二. 包含min函数的栈 a.题目 b.题解分析 c.AC代码 一. 前言 本系列是针对Leetcode中剑指offer学习计划的记录与思路讲解。详情查看以下链接&#xff1a; 剑指offer-学习计划https://leetcode.cn/study-pla…

Java八大基本数据类型

Java八大基本数据类型 byteshortintlongfloatdoublebooleanchar byte byte数据类型是8位、有符号的&#xff0c;以二进制补码表示的整数 最小值是-128&#xff08;-2^7&#xff09;&#xff1b; 最大值是127&#xff08;2^7-1&#xff09;; 默认值是0&#xff1b; byte类型用在…

stm32读写内部Flash

stm32内部flash地址架构映射 因为我的stm32f407的内部flash是1M的所以块2不存在&#xff0c;但他的地址仍然存在&#xff0c;只是没有作用&#xff0c;这是stm32的整体框架。 主存储器 一般我们说 STM32 内部 FLASH 的时候&#xff0c;都是指这个主存储器区域&#xff0c;它…

duilib窗口拖动

直接使用如下就可以了&#xff0c;不用再使用继承。 LRESULT CXmlWnd::OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {POINT pt;RECT rcClient;RECT rcCaption;CControlUI * pControl NULL;rcCaption m_P…

C++练级之初级:第五篇

C练级之初级&#xff1a;第五篇 第五篇 C练级之初级&#xff1a;第五篇1.auto关键字2.for循环改进3.指针空值nullptr4.内联函数4.1内联函数的概念4.2内联函数的注意点 总结 1.auto关键字 &#x1f914;什么是auto(automatic的缩写&#xff0c;自动的意思)关键字&#xff1f; au…

OpenShift 4 - 在 CI/CD Pipeline 中创建 KubeVirt 容器虚拟机 - 方法1+2 (视频)

《OpenShift / RHEL / DevSecOps 汇总目录》 说明&#xff1a;本文已经在支持 OpenShift 4.12 的 OpenShift 环境中验证 文章目录 准备环境安装可实现 KubeVirt 操作的 Tekton 资源创建密钥对 在 CI/CD 流水线管道中创建 VM方法1&#xff1a;通过 Manifest 任务创建 VM方法2&am…

如何实现Spring AOP以及Spring AOP的实现原理

AOP:面向切面编程,它和OOP&#xff08;面向对象编程)类似。 AOP组成: 1、切面:定义AOP是针对那个统一的功能的&#xff0c;这个功能就叫做一个切面&#xff0c;比如用户登录功能或方法的统计日志&#xff0c;他们就各种是一个切面。切面是有切点加通知组成的。 2、连接点:所有可…

ClickHouse快速入门

目录 1 ClickHouse介绍1.1 ClickHouse 的特点1.1.1 列式存储1.1.2 DBMS 的功能1.1.3 多样化引擎1.1.4 高吞吐写入能力1.1.5 数据分区与线程级并行1.1.6 性能对比 2 数据类型2.1 整型2.2 浮点型2.3 布尔型2.4 Decimal 型2.5 字符串2.6 枚举类型2.7 时间类型2.8 数组 3 表引擎3.1…

SpringBoot tomcat核心参数

server.tomcat.threads.min-spare10server.tomcat.threads.max200server.tomcat.max-connections8192server.tomcat.accept-count100 第一个参数代表程序启动就会开启10个线程。 如果我改成20个&#xff0c;看看什么情况&#xff0c;可以看到初始化了20个线程 看第二个参数&am…

2022年中国云市场份额:阿里云腾讯云下降

我是卢松松&#xff0c;点点上面的头像&#xff0c;欢迎关注我哦&#xff01; 4月23日&#xff0c;IDC发布《中国公有云服务市场(2022下半年)跟踪》&#xff0c;占据前四的分别为阿里云(40.6%)、华为云(11.0%)、腾讯云(11.0%)、中国电信(8.7%)。咱们说重点&#xff0c;如下图所…

DFMEA 在车用燃料电池空压机设计中的应用

摘要&#xff1a; DFMEA在空压机研发中的应用 氢气具有资源丰富、热值高和无污染等特点&#xff0c;因而是燃料电池汽车最理想的二次能源。空压机作为燃料电池汽车的关键总成&#xff0c;掌握其核心部件的设计和制造技术非常必要。应用传统的设计方法进行相关零部件如空气轴承…