自学内容网 自学内容网

神经网络基础-价格分类案例


学习目标:

  1. 掌握构建分类模型流程
  2. 动手实践整个过程

1. 需求分析

小明创办了一家手机公司,他不知道如何估算手机产品的价格。为了解决这个问题,他收集了多家公司的手机销售数据。该数据为二手手机的各个性能的数据,最后根据这些性能得到4个价格区间,作为这些二手手机售出的价格区间。主要包括:

battery_power电池一次可存储的电量,单位:毫安/时
blue是否有蓝牙
clock_speed微处理器执行指令的速度
dual_sim是否支持双卡
fc前置摄像头百万像素
four_g是否有4G
int_memory内存(GB)
m_dep移动深度(cm)
mobile_wt手机重量
n_cores处理器内核数
pc主摄像头百万像素
px_height像素分辨率高度
px_width像素分辨率宽度
ram随机存储器(兆字节)
sc_h手机屏幕高度(cm)
sc_w手机屏幕宽度(cm)
talk_time一次充电持续时长
three_g是否有3G
touch_screen是否有触屏控制
wifi是否能连wifi
price_range价格区间(0,1,2,3)

我们需要帮助小明找出手机的功能(例如:RAM等)与其售价之间的某种关系。我们可以使用机器学习的方法来解决这个问题,也可以构建一个全连接的网络。

需要注意的是: 在这个问题中,我们不需要预测实际价格,而是一个价格范围,它的范围使用 0、1、2、3 来表示,所以该问题也是一个分类问题。接下来我们还是按照四个步骤来完成这个任务:

  • 准备训练集数据

  • 构建要使用的模型

  • 模型训练

  • 模型预测评估

2. 导入所需工具包

# 导入相关模块
import torch
from torch.utils.data import TensorDataset
from torch.utils.data import DataLoader
import torch.nn as nn
import torch.optim as optim
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import time

3. 构建数据集

数据共有 2000 条, 其中 1600 条数据作为训练集, 400 条数据用作测试集。 我们使用 sklearn 的数据集划分工作来完成。并使用 PyTorch 的 TensorDataset 来将数据集构建为 Dataset 对象,方便构造数据集加载对象。

#1. 导入相关模块
import torch
from torch.utils.data import TensorDataset
from torch.utils.data import DataLoader
import torch.nn as nn
import torch.optim as optim
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import time

# 构建数据集
def load_dataset():
    # 使用pandas 读取数据
    data = pd.read_csv('data/手机价格预测.csv')
    # 特征值和目标值
    x,y = data.iloc[:,:-1],data.iloc[:,-1]
    # 类型转换:特征值,目标值
    x = x.astype(np.float32)
    y = y.astype(np.int64)
    # 划分训练集和测试集
    x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=88)
    # 构建数据集,转换为pytorch格式
    train_dataset = TensorDataset(torch.from_numpy(x_train.values), torch.from_numpy(y_train.values))
    test_dataset = TensorDataset(torch.from_numpy(x_test.values), torch.from_numpy(y_test.values))
    #返回结果
    return train_dataset, test_dataset,x_train.shape[1],len(np.unique(y))

if __name__ == '__main__':
    train_dataset, test_dataset,input_dim,class_num = load_dataset()
    print("输入特征数:",input_dim)
    print("分类个数:",class_num)

输出结果为:

输入特征数: 20
分类个数: 4

4. 构建分类网络模型

构建全连接神经网络来进行手机价格分类,该网络主要由三个线性层来构建,使用relu激活函数。

网络共有 3 个全连接层, 具体信息如下:

  1. 第一层: 输入为维度为 20, 输出维度为: 128
  2. 第二层: 输入为维度为 128, 输出维度为: 256
  3. 第三层: 输入为维度为 256, 输出维度为: 4
# 构建网络模型
class PhonePriceModel(nn.Module):
    def __init__(self,input_dim,output_dim):
        super(PhonePriceModel, self).__init__()
        # 1. 第一层: 输入为维度为 20, 输出维度为: 128
        self.linear1 = nn.Linear(input_dim, 128)
        # 2. 第二层: 输入为维度为 128, 输出维度为: 256
        self.linear2 = nn.Linear(128, 256)
        # 3. 第三层: 输入为维度为 256, 输出维度为: 4
        self.linear3 = nn.Linear(256, output_dim)

    def forward(self, x):
        # 前向传播过程
        x = torch.relu(self.linear1(x))
        x = torch.relu(self.linear2(x))
        output = self.linear3(x)
        # 获取数据结果
        return output

if __name__ == '__main__':
    train_dataset, test_dataset,input_dim,class_num = load_dataset()
    print("输入特征数:",input_dim)
    print("分类个数:",class_num)
    # 模型实例化
    model = PhonePriceModel(input_dim,class_num)

5. 训练模型

网络编写完成之后,我们需要编写训练函数。所谓的训练函数,指的是输入数据读取、送入网络、计算损失、更新参数的流程,该流程较为固定。我们使用的是多分类交叉生损失函数、使用 SGD 优化方法。最终,将训练好的模型持久化到磁盘中。

# 模型训练过程
def train(train_dataset,input_dim,class_num):
    # 固定随机数种子
    torch.manual_seed(0)
    # 初始化模型
    model = PhonePriceModel(input_dim,class_num)
    # 损失函数
    criterion = nn.CrossEntropyLoss()
    # 优化方法
    optimizer = optim.SGD(model.parameters(), lr=1e-3)
    # 训练轮数
    num_epochs = 50
    # 遍历轮数
    for epoch_idx in range(num_epochs):
        # 初始化数据加载器
        dataloader = DataLoader(train_dataset, batch_size=8, shuffle=True)
        # 训练时间
        start = time.time()
        # 计算损失
        total_loss = 0.0
        total_num = 1
        # 遍历每个batch数据进行处理
        for x,y in dataloader:
            # 将数据送入网络中进行预测
            output = model(x)
            # 计算损失
            loss = criterion(output, y)
            #梯度清零
            optimizer.zero_grad()
            # 方向传播
            loss.backward()
            # 参数更新
            optimizer.step()
            # 损失计算
            total_num += 1
            total_loss += loss.item()
        # 打印损失变换结果
        print('epoch: %4s loss: %.2f, time: %.2fs' % (epoch_idx + 1, total_loss / total_num, time.time() - start))

    # 保存模型
    torch.save(model.state_dict(), 'model/phone.ptn')

6. 模型训练

if __name__ == '__main__':
    train_dataset, test_dataset,input_dim,class_num = load_dataset()
    print("输入特征数:",input_dim)
    print("分类个数:",class_num)
    # 模型训练过程
    train(train_dataset,input_dim,class_num)

输出结果:

epoch:    1 loss: 13.31, time: 0.25s
epoch:    2 loss: 0.96, time: 0.24s
epoch:    3 loss: 0.90, time: 0.24s
epoch:    4 loss: 0.89, time: 0.25s
epoch:    5 loss: 0.86, time: 0.26s
...
epoch:   46 loss: 0.68, time: 0.25s
epoch:   47 loss: 0.69, time: 0.26s
epoch:   48 loss: 0.68, time: 0.28s
epoch:   49 loss: 0.69, time: 0.24s
epoch:   50 loss: 0.69, time: 0.24s

7. 评估模型

使用训练好的模型,对未知的样本的进行预测的过程。我们这里使用前面单独划分出来的验证集来进行评估。

# 4 评估模型
def test(test_dataset,input_dim,class_num):
    # 加载模型和训练好的网络参数
    model = PhonePriceModel(input_dim,class_num)

    model.load_state_dict(torch.load('model/phone.ptn',weights_only=False))
    # 构建加载器
    dataloader = DataLoader(test_dataset, batch_size=8, shuffle=True)
    # 评估测试集
    correct = 0
    # 遍历测试集中的数据
    for x,y in dataloader:
        # 将其送入网络中
        output = model(x)
        # 获取类别结果
        y_pred = torch.argmax(output, dim=1)
        # 获取预测正确的个数
        correct += (y_pred == y).sum().sum()
    # 求预测精度
    print('Acc: %.5f' % (correct.item() / len(test_dataset)))
if __name__ == '__main__':
    train_dataset, test_dataset,input_dim,class_num = load_dataset()
    print("输入特征数:",input_dim)
    print("分类个数:",class_num)
    # 评估模型
    test(test_dataset,input_dim,class_num)

输出结果:

Acc: 0.62500

8. 模型优化

我们前面的网络模型在测试集的准确率为: 0.54750, 我们可以通过以下方面进行调优:

  1. 优化方法由 SGD 调整为 Adam
  2. 学习率由 1e-3 调整为 1e-4
  3. 对数据数据进行标准化
  4. Dropout 正则化
  5. 调整训练轮次
# 使用Adam方法优化网络
#1. 导入相关模块
import torch
from tensorboard import summary
from torch.utils.data import TensorDataset
from torch.utils.data import DataLoader
import torch.nn as nn
import torch.optim as optim
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import time

#2. 构建数据集
def load_dataset():
    # 使用pandas 读取数据
    data = pd.read_csv('data/手机价格预测.csv')
    # 特征值和目标值
    x,y = data.iloc[:,:-1],data.iloc[:,-1]
    # 类型转换:特征值,目标值
    x = x.astype(np.float32)
    y = y.astype(np.int64)
    # 划分训练集和测试集
    x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=88)
    # 数据标准化
    scaler = StandardScaler()
    x_train = scaler.fit_transform(x_train)
    x_test = scaler.fit_transform(x_test)
    x_train = torch.tensor(x_train,dtype=torch.float32)
    x_test = torch.tensor(x_test,dtype=torch.float32)
    # 构建数据集,转换为pytorch格式
    train_dataset = TensorDataset(x_train, torch.from_numpy(y_train.values))
    test_dataset = TensorDataset(x_test, torch.from_numpy(y_test.values))
    #返回结果
    return train_dataset, test_dataset,x_train.shape[1],len(np.unique(y))
#2. 构建网络模型
class PhonePriceModel(nn.Module):
    def __init__(self,input_dim,output_dim,p_dropout=0.4):
        super(PhonePriceModel, self).__init__()
        # 第一层: 输入为维度为 20, 输出维度为: 128
        self.linear1 = nn.Linear(input_dim, 128)
        # Dropout优化
        self.dropout = nn.Dropout(p_dropout)
        # 第二层: 输入为维度为 128, 输出维度为: 256
        self.linear2 = nn.Linear(128, 256)
        # Dropout优化
        self.dropout = nn.Dropout(p_dropout)
        # 第三层: 输入为维度为 256, 输出维度为: 4
        self.linear3 = nn.Linear(256, output_dim)

    def forward(self, x):
        # 前向传播过程
        x = torch.relu(self.linear1(x))
        x = torch.relu(self.linear2(x))
        output = self.linear3(x)
        # 获取数据结果
        return output

# 3. 模型训练过程
def train(train_dataset,input_dim,class_num):
    # 固定随机数种子
    torch.manual_seed(0)
    # 初始化模型
    model = PhonePriceModel(input_dim,class_num)
    # 损失函数
    criterion = nn.CrossEntropyLoss()
    # 优化方法
    # optimizer = optim.SGD(model.parameters(), lr=1e-3)
    # Adam优化方法 调整学习率为 lr=1e-4
    optimizer = torch.optim.Adam(model.parameters(), lr=1e-4, betas=(0.9, 0.99))
    # 训练轮数 100 - 0.9075 50 - 0.9125
    num_epochs = 50
    # 遍历轮数
    for epoch_idx in range(num_epochs):
        # 初始化数据加载器
        dataloader = DataLoader(train_dataset, batch_size=8, shuffle=True)
        # 训练时间
        start = time.time()
        # 计算损失
        total_loss = 0.0
        total_num = 1
        # 遍历每个batch数据进行处理
        for x,y in dataloader:
            # 将数据送入网络中进行预测
            output = model(x)
            # 计算损失
            loss = criterion(output, y)
            #梯度清零
            optimizer.zero_grad()
            # 方向传播
            loss.backward()
            # 参数更新
            optimizer.step()
            # 损失计算
            total_num += 1
            total_loss += loss.item()
        # 打印损失变换结果
        print('epoch: %4s loss: %.2f, time: %.2fs' % (epoch_idx + 1, total_loss / total_num, time.time() - start))

    # 保存模型
    torch.save(model.state_dict(), 'model/phone2.ptn')
# 4 评估模型
def test(test_dataset,input_dim,class_num):
    # 加载模型和训练好的网络参数
    model = PhonePriceModel(input_dim,class_num)

    model.load_state_dict(torch.load('model/phone2.ptn',weights_only=False))
    # 构建加载器
    dataloader = DataLoader(test_dataset, batch_size=8, shuffle=True)
    # 评估测试集
    correct = 0
    # 遍历测试集中的数据
    for x,y in dataloader:
        # 将其送入网络中
        output = model(x)
        # 获取类别结果
        y_pred = torch.argmax(output, dim=1)
        # 获取预测正确的个数
        correct += (y_pred == y).sum().sum()
    # 求预测精度
    print('Acc: %.5f' % (correct.item() / len(test_dataset)))
if __name__ == '__main__':
    train_dataset, test_dataset,input_dim,class_num = load_dataset()
    print("输入特征数:",input_dim)
    print("分类个数:",class_num)
    # 模型训练
    train(train_dataset,input_dim,class_num)
    test(test_dataset,input_dim,class_num)

这里我们调整 Adam方法优化梯度下降,学习率调整为1e-4,样本数据采用标准化处理。采用Dropout正则化。最后输出结果:

Acc: 0.91250

原文地址:https://blog.csdn.net/dwjf321/article/details/145185756

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!