1. 案例介绍

        本文展示的是基于简单神经网络模型的房价预测案例,在经过数据集获取、模型构建、模型训练与验证和模型评估后,完成本次的案例演示。

2.数据源

        数据来源于公开的房价数据集,使用的House Prices数据集,大家可以动手尝试。

        数据集:https://www.kaggle.com/c/house-prices-advanced-regression-techniques

3. 导入所需模块

# 导入所需模块
import torch
import torch.nn as nn
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from torch.utils.data import TensorDataset,DataLoader,Dataset
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler,OneHotEncoder
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.impute import SimpleImputer

4. 数据处理与包装 

        在数据处理与包装过程中,我们使用Pipeline管道操作,流水线式的对数据进行批处理。具体对数据分为数值型和类别型进行分别处理,构建管道Pipeline和列转换器ColumnTransformer,对数值型数据:缺失值填充和标准化;对类别型数据:缺失值填充和one-hot编码。

# 1. 处理数据,返回tensor数据集
def create_dataset():
    # 1.读取数据
    data = pd.read_csv(r"G:\learning video\07_深度学习核心\4.视频\day10\house_prices.csv")
    # print(data)

    # 2. 提取特征和标签
    data.drop(['Id'],axis=1,inplace=True)
    x = data.drop(['SalePrice'],axis=1)
    y = data['SalePrice']

    # 3.划分数据集
    x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.25,random_state=12)


    # 4.特征工程
    # 4.1 筛选两类数据,数值型和类别型
    numerical_data = x.select_dtypes(exclude=['object']).columns
    categorical_data = x.select_dtypes(include=['object']).columns

    # 4.2 构建两类Pipeline
    numerical_transform = Pipeline(steps=[
        ("fiLLnan",SimpleImputer(strategy='mean')),
        ('Std',StandardScaler())
    ])

    categorical_transform = Pipeline(steps=[
        ('fillnan',SimpleImputer(strategy='constant',fill_value='nan')),
        ('one_hot',OneHotEncoder(handle_unknown='ignore'))
    ])

    # 4.3 构造列转换器
    transform = ColumnTransformer(
        transformers=[
        ('num',numerical_transform,numerical_data),
        ('cat',categorical_transform,categorical_data)
    ])

    # 4.4 开始列转换
    x_train = pd.DataFrame(transform.fit_transform(x_train).toarray(),columns=transform.get_feature_names_out())
    x_test = pd.DataFrame(transform.transform(x_test).toarray(),columns=transform.get_feature_names_out())


    # 5 转换为tensor数据集
    train_dataset = TensorDataset((torch.tensor(x_train.values,dtype=torch.float)),torch.tensor(y_train.values,dtype=torch.float))
    test_dataset = TensorDataset((torch.tensor(x_test.values,dtype=torch.float)),torch.tensor(y_test.values,dtype=torch.float))

    return train_dataset,test_dataset,x_train.shape[1]

# 得到数据集
train_dataset,test_dataset,shape = create_dataset()

5. 模型构建

        在模型构建方面,我搭建了一个简单的神经网络模型,利用用到了线性层Linear、批量标准化BatchNorm、激活函数Relu以及正则化项随机失活DropOut。

# 构建模型
model = nn.Sequential(
    nn.Linear(shape,128),    # 随机数种子不同,输入features不要写死
    nn.BatchNorm1d(128),
    nn.ReLU(),
    nn.Dropout(0.2),
    nn.Linear(128,1)
)

6. 模型训练与验证

        在模型训练与验证过程中,损失函数:自定义了一个log_loss,即对均方根误差取对数,这更加符合损失的度量。优化器:选用了Adam,可以更换不同的优化器尝试。模型训练与验证流程:我采取了一轮训练一轮验证的模式,不断在验证集上测试,防止在训练集上过拟合。

# 定义损失函数衡量
def loss(y_pred,y_true):
    y_pred.squeeze_()     # 压缩tensor,[[1]] --- [1]
    y_pred = torch.clamp(y_pred,1,float('inf'))  # 限制预测范围,避免不合理的情况
    loss = nn.MSELoss()
    loss_value = torch.sqrt(loss(torch.log(y_pred),torch.log(y_true)))
    return loss_value

# 模型训练和预测
def model_train_test(model,train_dataset,test_dataset,device,lr,epoch,batch_size):
    # 1. 参数初始化
    # 1.1 遍历sequential,选择合适的参数进行初始化
    def init_weights_bias(m):
            if isinstance(m, nn.Linear):
                # 找“下一个”非 Linear 的激活
                nn.init.kaiming_uniform_(m.weight)
                if m.bias is not None:
                    nn.init.zeros_(m.bias)

    model.apply(init_weights_bias)   # 模型参数初始化
    model.to(device)    # 指定平台

    # 2 定义优化器
    optimizer = torch.optim.Adam(model.parameters(),lr=lr)

    train_loss = []
    test_loss = []

    # 训练与测试
    for i in range(0,epoch):
        # 开启训练模式
        model.train()
        total_loss = 0    # 每个epoch的sum(loss)
        train_data = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)  # 加载数据

        for batch_count,(X,y) in enumerate(train_data):
            X = X.to(device)
            y = y.to(device)
            y_pred = model(X)   # 前向传播
            loss_value = loss(y_pred,y) # 计算损失

            total_loss += loss_value.item()    # 累加loss

            loss_value.backward()   # 反向传播
            optimizer.step()    # 参数更新
            optimizer.zero_grad()   # 梯度清零

            # 打印进度条
            print(f"\repoch{i+1:0>3}[{'=' * 50 * int((batch_count+1) / len(train_data)):<50}]",end='')

        loss_epoch = total_loss / len(train_data)
        train_loss.append(loss_epoch)


        # 开启测试模式
        model.eval()
        total_loss_test = 0    # 每个epoch的sum(loss)
        test_data = DataLoader(test_dataset, batch_size=batch_size, shuffle=True)  # 加载数据
        with torch.no_grad():
            for X,y in test_data:
                X = X.to(device)
                y = y.to(device)
                y_pred_test = model(X)   # 前向传播
                loss_value_test = loss(y_pred_test,y) # 计算损失
                total_loss_test += loss_value_test.item()    # 累加loss

            loss_epoch_test = total_loss_test / len(test_data)
            test_loss.append(loss_epoch_test)
            print(f"第{i+1}轮epoch训练,train_loss_mean:,{loss_epoch:.6f},test_loss_mean,{loss_epoch_test:.6f}")

    return train_loss,test_loss

7. 模型评估

device = 'cuda' if torch.cuda.is_available() else 'cpu'  # 指定平台
train_dataset,test_dataset,shape = create_dataset()
train_loss,test_loss = model_train_test(model,train_dataset,test_dataset,device,lr=0.01,epoch=200,batch_size=10)

# 可视化结果
plt.plot(train_loss,'r',label='train loss')
plt.plot(test_loss,'y',label='test loss')
plt.legend()
plt.show()

        模型效果

8. 总结

        在这个简单的回归案例中,我使用了公开的房价数据集进行训练与验证,整体模型的架构比较简单:搭建了简单的神经网络模型,配合了一些标准化和正则化方法,后续过程是一轮训练一轮验证,统计每个轮次的平均损失,并对模型效果进行评估,大家可以动手试试。

Logo

鲲鹏昇腾开发者社区是面向全社会开放的“联接全球计算开发者,聚合华为+生态”的社区,内容涵盖鲲鹏、昇腾资源,帮助开发者快速获取所需的知识、经验、软件、工具、算力,支撑开发者易学、好用、成功,成为核心开发者。

更多推荐