魔镜er头像
关注

08-案例-手机价格分类

1. 需求分析

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

2. 数据说明

数据来源:手机价格分类_数据集-阿里云天池

字段名字段说明
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)

3. 建模

import time
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from torch import nn, optim
from torch.utils.data import TensorDataset, DataLoader
import torch
from torchsummary import summary

3.1 准备数据

# todo 1: 数据准备
def load_data():
    # 1. 读取数据
    data = pd.read_csv('./data/mobile_phone_price_cls/train.csv')
    # print(data.head())
    # print(data.shape)
    # print(data.info())

    # 2. 提取特征和标签
    x, y = data.iloc[:, :-1], data.iloc[:, -1]
    x = x.astype(np.float32)  # 转换数据类型
    # print(x.head(), y[:5])

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

    # 4. 把数据集转换成张量(数据->张量Tensor->数据集TensorDataset->数据加载器DataLoader(后续再做))
    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))
    print(f'训练集对象:{train_dataset}')
    print(f'测试集对象:{test_dataset}')

    # 5. 获取特征数量和标签数量
    input_dim = x_train.shape[1]  # 输入的特征数量
    output_dim = len(np.unique(y)) # 输出的标签类别数量
    print(f'输入的特征数量:{input_dim}')
    print(f'输出的标签数量:{output_dim}')

    return train_dataset, test_dataset, input_dim, output_dim

3.2 搭建神经网络

# todo 2: 搭建神经网络
class MobilePhonePriceClassification(torch.nn.Module):
    # 1. 初始化
    def __init__(self, input_dim, output_dim):  # 输入特征数量,输出标签类别数量
        # 1.1 继承父类初始化方法
        super().__init__()
        # 1.2 定义神经网络
        # 1.2.1 隐藏层
        self.linear1 = nn.Linear(input_dim, 128)
        self.linear2 = nn.Linear(128, 256)
        # 1.2.2 输出层
        self.output = nn.Linear(256, output_dim)
        
    # 2. 前向传播
    def forward(self, x):
        # 2.1 隐藏层: relu
        x = torch.relu(self.linear1(x))
        x = torch.relu(self.linear2(x))
        # 2.2 输出层: softmax
        # 这里不用写成softmax(x),因为nn.CrossEntropyLoss()里面已经包含了softmax()
        x = self.output(x)  # 加权求和

        return x

3.3 模型训练与保存

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

# todo 3: 模型训练
def train(train_dataset, input_dim, output_dim):
    # 1. 获取数据加载器DataLoader
    # 参1: 数据集;参2: 批次大小;参数3: 是否打乱数据(训练集打乱,测试集不打乱)
    train_loader = DataLoader(train_dataset, batch_size=16, shuffle=True)
    # 2. 创建模型
    model = MobilePhonePriceClassification(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.3.1 切换模型(状态)
            model.train()  # 训练模式
            # 5.2.3.2 模型预测
            y_pred = model(x)
            # 5.2.3.3 计算损失值
            loss = criterion(y_pred, y)
            # 5.2.3.4 梯度清零,反向传播,优化参数
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
            # 5.2.3.5 累计损失值和批次数
            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. 此处多轮训练结束,保存模型(参数)
    # 参1: 模型参数信息;参2: 模型保存路径
    torch.save(model.state_dict(), './model/mobile_phone_price_cls.pth')

3.4 模型预测和评估

# todo 4: 模型测试
def evaluate(test_dataset, input_dim, output_dim):
    # 1. 创建神经网络分类对象
    model = MobilePhonePriceClassification(input_dim, output_dim)
    # 2. 加载模型参数
    model.load_state_dict(torch.load('./model/mobile_phone_price_cls.pth'))
    # 3. 创建数据加载器DataLoader
    test_loader = DataLoader(test_dataset, batch_size=16, shuffle=False)
    # 4. 记录预测正确的样本个数
    correct = 0
    # 5. 从数据加载器中获取每批次的数据
    for x, y in test_loader:
        # 5.1 切换测试模式
        model.eval()
        # 5.2 模型预测
        y_pred = model(x)
        # print(f'y_pred: {y_pred}')  # 加权求和的结果
        # 5.3 根据加权求和,得到类别,用argmax()获取最大值对应的下标,即类别
        y_pred = torch.argmax(y_pred, dim=1)
        print(f'预测类别:{y_pred}')  # 如果值全都一样,可能是学习率太大了,调小试一下
        # 5.4 统计预测正确的样本个数
        correct += (y_pred == y).sum().item()

    # 6. 模型预测结束,计算准确率
    print(f'准确率:{correct / len(test_dataset):.4f}')

3.5 运行

if __name__ == '__main__':
    # 1. 数据准备
    train_dataset, test_dataset, input_dim, output_dim = load_data()

    # 2. 搭建神经网络
    model = MobilePhonePriceClassification(input_dim, output_dim)
    # 2.1 计算模型参数
    summary(model, input_size=(16, input_dim))  # input_size=(batch_size, input_dim), 每批16条,每条20个特征

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

    # 4. 模型评估
    evaluate(test_dataset, input_dim, output_dim)

3.6 网络优化

"""
案例-手机价格分类
网络优化思路:
    1. 数据标准化/批量归一正则化
    2. 梯度下降法优化:SGD -> Adam
    3. 调整学习率:0.001 -> 0.0001
    4. 增加网络层数、神经元个数:增加两层
    5. 增加训练轮数:50 -> 200

结果:
    0. 不优化:ACC=0.585
    1. 仅优化1:ACC=0.67
    2. 仅优化2:ACC=0.71
    3. 仅优化3:ACC=0.7975
    4. 仅优化4:ACC=0.6825
    5. 仅优化5:ACC=0.6450
    6. 同时优化12345:ACC=0.9175  --> 完美!!
"""
import time

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from torch import nn, optim
from torch.utils.data import TensorDataset, DataLoader
import torch
from torchsummary import summary


# todo 1: 数据准备
def load_data():
    # 1. 读取数据
    data = pd.read_csv('./data/mobile_phone_price_cls/train.csv')
    # print(data.head())
    # print(data.shape)
    # print(data.info())

    # 2. 提取特征和标签
    x, y = data.iloc[:, :-1], data.iloc[:, -1]
    x = x.astype(np.float32)  # 转换数据类型
    # print(x.head(), y[:5])

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

    # todo: 优化1: 数据标准化
    transfer = StandardScaler()
    x_train = transfer.fit_transform(x_train)
    x_test = transfer.transform(x_test)

    # 4. 把数据集转换成张量(数据->张量Tensor->数据集TensorDataset->数据加载器DataLoader(后续再做))
    train_dataset = TensorDataset(torch.from_numpy(x_train), torch.from_numpy(y_train.values))
    test_dataset = TensorDataset(torch.from_numpy(x_test), torch.from_numpy(y_test.values))
    print(f'训练集对象:{train_dataset}')
    print(f'测试集对象:{test_dataset}')

    # 5. 获取特征数量和标签数量
    input_dim = x_train.shape[1]  # 输入的特征数量
    output_dim = len(np.unique(y)) # 输出的标签类别数量
    print(f'输入的特征数量:{input_dim}')
    print(f'输出的标签数量:{output_dim}')

    return train_dataset, test_dataset, input_dim, output_dim

# todo 2: 搭建神经网络
class MobilePhonePriceClassification(torch.nn.Module):
    # 1. 初始化
    def __init__(self, input_dim, output_dim):  # 输入特征数量,输出标签类别数量
        # 1.1 继承父类初始化方法
        super().__init__()
        # 1.2 定义神经网络
        # 1.2.1 隐藏层
        self.linear1 = nn.Linear(input_dim, 128)
        self.linear2 = nn.Linear(128, 256)

        # todo: 优化4:增加网络层数、神经元个数
        self.linear3 = nn.Linear(256, 512)
        self.linear4 = nn.Linear(512, 128)

        # 1.2.2 输出层
        self.output = nn.Linear(128, output_dim)

    # 2. 前向传播
    def forward(self, x):
        # 2.1 隐藏层: relu
        x = torch.relu(self.linear1(x))
        x = torch.relu(self.linear2(x))

        x = torch.relu(self.linear3(x))
        x = torch.relu(self.linear4(x))

        # 2.2 输出层: softmax
        # 这里不用写成softmax(x),因为nn.CrossEntropyLoss()里面已经包含了softmax()
        x = self.output(x)  # 加权求和

        return x


# todo 3: 模型训练
def train(train_dataset, input_dim, output_dim):
    # 1. 获取数据加载器DataLoader
    # 参1: 数据集;参2: 批次大小;参数3: 是否打乱数据(训练集打乱,测试集不打乱)
    train_loader = DataLoader(train_dataset, batch_size=16, shuffle=True)
    # 2. 创建模型
    model = MobilePhonePriceClassification(input_dim, output_dim)
    # 3. 创建损失函数:多分类交叉熵损失函数
    criterion = nn.CrossEntropyLoss()
    # 4. 创建优化器
    # todo: 优化2: SGC 改为 Adam
    optimizer = optim.Adam(model.parameters(), lr=0.0001)

    # 5. 训练模型
    # 5.1 训练轮数
    # todo: 优化5: 增加训练轮数
    epochs = 200

    # 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.3.1 切换模型(状态)
            model.train()  # 训练模式
            # 5.2.3.2 模型预测
            y_pred = model(x)
            # 5.2.3.3 计算损失值
            loss = criterion(y_pred, y)
            # 5.2.3.4 梯度清零,反向传播,优化参数
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
            # 5.2.3.5 累计损失值和批次数
            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. 此处多轮训练结束,保存模型(参数)
    # 参1: 模型参数信息;参2: 模型保存路径
    torch.save(model.state_dict(), './model/mobile_phone_price_cls.pth')


# todo 4: 模型测试
def evaluate(test_dataset, input_dim, output_dim):
    # 1. 创建神经网络分类对象
    model = MobilePhonePriceClassification(input_dim, output_dim)
    # 2. 加载模型参数
    model.load_state_dict(torch.load('./model/mobile_phone_price_cls.pth'))
    # 3. 创建数据加载器DataLoader
    test_loader = DataLoader(test_dataset, batch_size=16, shuffle=False)
    # 4. 记录预测正确的样本个数
    correct = 0
    # 5. 从数据加载器中获取每批次的数据
    for x, y in test_loader:
        # 5.1 切换测试模式
        model.eval()
        # 5.2 模型预测
        y_pred = model(x)
        # print(f'y_pred: {y_pred}')  # 加权求和的结果
        # 5.3 根据加权求和,得到类别,用argmax()获取最大值对应的下标,即类别
        y_pred = torch.argmax(y_pred, dim=1)
        print(f'预测类别:{y_pred}')  # 如果值全都一样,可能是学习率太大了,调小试一下
        # 5.4 统计预测正确的样本个数
        correct += (y_pred == y).sum().item()

    # 6. 模型预测结束,计算准确率
    print(f'准确率:{correct / len(test_dataset):.4f}')



if __name__ == '__main__':
    # 1. 数据准备
    train_dataset, test_dataset, input_dim, output_dim = load_data()

    # 2. 搭建神经网络
    model = MobilePhonePriceClassification(input_dim, output_dim)
    # 2.1 计算模型参数
    summary(model, input_size=(16, input_dim))  # input_size=(batch_size, input_dim), 每批16条,每条20个特征

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

    # 4. 模型评估
    evaluate(test_dataset, input_dim, output_dim)

 

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/lvmealn/article/details/163676958

文章来源crawl

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--