深度学习——ANN案例_手机价格分类案例

问题背景

小明创办了一家手机公司,他不知道如何估算手机产品的价格。为了解决这个问题,他收集了多家公司的手机销售数据。该数据为二手手机的各个性能的数据,最后根据这些性能得到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 来表示,所以该问题也是一个分类问题。接下来我们还是按照四个步骤来完成这个任务:

  • 准备训练集数据
  • 构建要使用的模型
  • 模型训练
  • 模型预测评估

代码实现

导入相关模块

import torch # pytorch 框架,封装了张量的各种操作
from torch.utils.data import TensorDataset # 数据集对象. 数据 ——> Tensor ——> 数据集 ——> 数据加载器
from torch.utils.data import DataLoader # 数据加载器
import torch.nn as nn # neural network,封装了神经网络的各种操作
import torch.optim as optim # 优化器
import matplotlib.pyplot as plt
import numpy as np
from sklearn.model_selection import train_test_split
import pandas as pd
import time # 时间模块
from torchsummary import summary

1.定义函数,构建数据集

def create_dataset():
    # 1. 加载csv文件数据集
    data = pd.read_csv('手机价格预测.csv')
    #print(f'data: {data.head()}')
    #print(f'data.shape: {data.shape}')

    # 2.获取x特征列,和y标签列
    x,y = data.iloc[:,0:-1],data.iloc[:,-1]
    # print(f'x:{x.head()},x.shape:{x.shape}')
    # print(f'y:{y.head()},y.shape:{y.shape}')

    # 3.把特征列转成浮点型
    x = x.astype(np.float32)

    # 4. 切分训练集和测试集.
    x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.2,random_state=3,stratify=y)

    # 5.把数据集封装成张量数据集
    # 思路:数据——>张量Tensor——>数据集TensorDataSet——>数据加载器DataLoader
    train_dataset = TensorDataset(torch.tensor(x_train.values),torch.tensor(y_train.values))
    test_dataset = TensorDataset(torch.tensor(x_test.values),torch.tensor(y_test.values))
    # print(f'train_dataset:{train_dataset},test_dataset:{test_dataset}')

    # 6. 返回结果                       20(充当输入特指数) 4(充当 输出标签数)
    return train_dataset,test_dataset,x_train.shape[1],len(np.unique(y))

2. 搭建神经网络

class PhonePriceModel(nn.Module):
    # 1. 在init 魔法方法中,初始化父类成员,及搭建神经网络
    def __init__(self,input_dim,output_dim):
        # 1.1 初始化父类成员
        super().__init__()
        # 1.2 搭建神经网络
        # 隐藏层1
        self.linear1 = nn.Linear(input_dim,128)
        # 隐藏层2
        self.linear2 = nn.Linear(128,256)
        # 输出层
        self.output = nn.Linear(256,output_dim)
    # 2.定义前向传播方法 forward()
    def forward(self,x):
        # 2.1 隐藏层1:加权求和 + 激活函数(relu)
        x = torch.relu(self.linear1(x))
        # 2.2 隐藏层2:加权求和 + 激活函数(relu)
        x = torch.relu(self.linear2(x))
        # 2.3 输出层:加权求和 + 激活函数(softmax)——>这里只需要做 加权求和
        # 正常写法,但是不需要,后续用多分类交叉熵损失函数CrossEntropyLoss()替代
        # CrossEntropyLoss() = softmax() + 损失计算
        x = self.output(x)
        # 2.4 返回处理结果
        return x

3. 模型训练

def train(train_dataset,input_dim,output_dim):
    # 1. 创建数据加载器,流程:数据——>张量——>数据集——>数据加载器
    # 参1:数据集对象(1600条),参2:每批次的数据条数,参3:是否打乱数据(训练集打乱,测试集不打乱)
    # DataLoader要求传入的参数为TensorDataset数据集,这样可以分批训练
    train_loader = DataLoader(train_dataset,batch_size=16,shuffle=True)
    # 2. 创建神经网络模型
    model = PhonePriceModel(input_dim,output_dim)
    # 3. 定义损失函数,因为是多分类,这里用的是:多分类交叉熵损失函数
    criterion = nn.CrossEntropyLoss()
    # 4. 创建优化器对象
    optimizer = optim.SGD(model.parameters(),lr=0.001)
    # 5. 模型训练
    # 5.1 定义变量,记录训练的 总轮数
    epochs = 50
    # 5.2 开始(每轮的)训练
    for epoch in range(epochs):
        # 5.2.1 定义变量,记录每次训练的损失值,训练批次数
        total_loss,batch_num = 0.0,0
        # 5.2.2 定义变量,表示训练开始的时间
        start = time.time()
        # 5.2.3 开始本轮的 各个批次的训练
        for x,y in train_loader:
            # 5.2.4 切换模型(状态)
            model.train() # 训练模式    model.eval() # 测试状态
            # 5.2.5 模型预测
            y_pred = model(x)
            # 5.2.6 计算损失
            loss = criterion(y_pred,y)
            # 5.2.7 梯度清零,反向传播,优化参数
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
            # 5.2.8 累加损失值
            total_loss += loss.item() # 把本轮的每批次(16条)的平均损失累积起来
            batch_num += 1
        # 5.2.4 至此,本轮训练结束,打印训练信息
        # print(f'epoch:{epoch+1},loss:{total_loss/batch_num:.4f},time:{time.time() - start:2f}s')

    # 6. 走到这里,说明多轮训练结束,保存模型(参数)
    # print(f'\n\n模型的参数信息:{model.state_dict()}\n\n')
    # 参1:模型对象的参数(权重矩阵,偏置矩阵) 参2:模型保存的文件名
    torch.save(model.state_dict(),'phone.pth')

4. 模型测试

def evaluate(test_dataset,input_dim,output_dim):
    # 1. 创建神经网络分类对象
    model = PhonePriceModel(input_dim,output_dim)
    # 2. 加载模型参数
    model.load_state_dict(torch.load('phone.pth'))
    # 3. 创建测试集的数据加载器对象
    test_loader = DataLoader(test_dataset,batch_size=16,shuffle=True)
    # 4. 定义变量,记录预测正确的样本个数
    correct = 0
    # 5. 从数据加载器中获取每批次的数据
    for x,y in test_loader:
        # 5.1 切换模型状态 ——>模型测试
        model.eval()
        # 5.2 模型预测
        y_pred = model(x) # 表示[[],[],[]...,[]] 表示分类的一个概率
        # 5.3 更具加权求和得到类别,用argmax()获取最大值对应的下标(类别)
        y_pred = torch.argmax(y_pred,dim=1) # dim=1 逐行处理
        # print(y_pred) # [第一条数据的预测分类,...]
        # 5.4 统计预测正确的样本个数
        # print(y_pred == y)
        # print((y_pred == y).sum())
        correct += (y_pred == y).sum()

    # 6. 走到这里,模型预测结束,打印准确率即可
    print(f'准确率:{correct/len(test_dataset):2f}')

5.测试

# 1. 准备训练集
train_dataset,test_dataset,input_dim,output_dim = create_dataset()
# print(f'训练集 数据集对象:{train_dataset}')
# print(f'测试集 数据集对象:{test_dataset}')
# print(f'输入特征数:{input_dim}')
# print(f'输出标签数量:{output_dim}')
# 2. 构建神经网络模型
model = PhonePriceModel(input_dim,output_dim)
# 计算模型参数
# 参1:模型对象;参2:输入数据的形状(批次大小,输入特征数),每批16条
# summary(model,input_size=(16,input_dim))

# 3.模型训练
train(train_dataset,input_dim,output_dim)

# 4.模型测试
evaluate(test_dataset,input_dim,output_dim)

优化思路

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

  1. 优化方法由 SGD 调整为 Adam
  2. 学习率由 1e-3 调整为 1e-4
  3. 对数据进行标准化
  4. 增加网络深度,即:增加网络参数量
  5. 调整训练轮次
  6. ......
posted @ 2026-07-18 15:24  王新文  阅读(2)  评论(0)    收藏  举报