需求分析:

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

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

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

  • l准备训练集数据
  • l构建要使用的模型
  • l模型训练
  • l模型预测评估
  • 数据字段如下:

主要分为4个部分:

        1:处理数据

# 1.自定义处理数据的api,batch_size是每批次的数据数量
def get_data(phone_path, batch_size):
    # 1.1 读取数据
    data = pd.read_csv(phone_path)
    # 1.2 了解数据
    print(data.shape)
    # 1.3 处理数据
    # 先分别获取x特征,y标签
    x = data.iloc[:, :-1].astype(np.float32)
    y = data.iloc[:, -1].astype(np.int64)
    # 然后使用train_test_split切割数据
    x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=666)
    # 最后封装TensorDataset
    train_dataset = TensorDataset(torch.from_numpy(x_train.values), torch.tensor(y_train.values))
    test_dataset = TensorDataset(torch.from_numpy(x_test.values), torch.tensor(y_test.values))
    # 1.4 封装dataloader数据加载器,shuffle=True是开启自动打乱数据,
    train_dataloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
    test_dataloader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)
    # 1.5 获取输入特征数和输出类别数(去重),x_train[0][1]分别是行和列数
    input_nums = x_train.shape[1]
    output_nums = len(y_train.unique())
    # TODO 返回结果
    return train_dataloader, test_dataloader, input_nums, output_nums
        2:构建模型
# 2.自定义模型
class PhonePriceModel(torch.nn.Module):
    # 重写init方法,input_nums:特征数量 output_nums:类别数量
    def __init__(self, input_nums, output_nums):
        # 调用父类初始化方法
        super().__init__()
        # 定义网络结构
        self.linear1 = torch.nn.Linear(input_nums, 128)
        self.linear2 = torch.nn.Linear(128, 256)
        self.out = torch.nn.Linear(256, output_nums)

    # 重写forward
    def forward(self, x):
        # 前向传播(加权求和->激活函数)
        x = torch.relu(self.linear1(x))
        x = torch.relu(self.linear2(x))
        # TODO 注意: 本次项目是多分类项目,后续要使用多分类交叉熵损失函数,所以此处不使用softmax激活函数
        x = self.out(x)
        return x
        3:模型训练
# 3.模型训练
def model_train(train_dataloader, model, epochs, model_path):
    # todo 1.准备数据(已经传参)
    # todo 2.准备模型(已经传参)
    # todo 3.准备损失函数
    loss_fn = torch.nn.CrossEntropyLoss()
    # todo 4.准备优化器
    optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
    # todo 5.训练模型
    # 5.1 遍历轮次
    for epoch in range(epochs):
        # 提前定义变量用于存储总损失,批次次数,时间
        total_loss, batch_cnt, start_time = 0.0, 0, time.time()
        # 5.2 遍历训练数据
        for batch_x, batch_y in train_dataloader:
            # todo 前向传播
            # 获取预测数据
            logits = model(batch_x)
            # 计算损失
            loss = loss_fn(logits, batch_y)  # 底层先用softmax转概率,再计算交叉熵损失
            # 累计损失和批次次数
            total_loss += loss.item()
            batch_cnt += 1
            # todo 反向传播
            # 梯度清零
            optimizer.zero_grad()
            # 计算梯度
            loss.backward()
            # 参数更新
            optimizer.step()
        epoch_loss = total_loss / batch_cnt
        print(f"第{epoch + 1}轮,最新损失为:{epoch_loss},耗时:{time.time() - start_time}")
    # todo 模型保存
    torch.save(model.state_dict(), model_path)
        4:模型评估
def model_evaluate(input_nums, output_nums, model_path, test_dataloader):
    # 1.创建空模型并加载训练好的模型参数
    model = PhonePriceModel(input_nums, output_nums)
    model.load_state_dict(torch.load(model_path))
    # 2.设置模型评估模式
    model.eval()
    # 3.模型预测
    correct_nums = 0
    for batch_x, batch_y in test_dataloader:
        # 前向传播
        logits = model(batch_x)
        # 获取预测结果,获取得分最高的类别索引,得分最高的类别即是预测的类别
        pred = torch.argmax(logits, dim=1)
        # 计算正确数量
        correct_nums += (pred == batch_y).sum()
    # 4.todo 计算准确率
    print(f"准确率:{correct_nums / len(test_dataloader.dataset)}")

主函数:
if __name__ == '__main__':
    # TODO 1.处理数据
    phone_path = "data/手机价格预测.csv"
    batch_size = 20
    # 调用get_data()
    train_dataloader, test_dataloader, input_nums, output_nums = get_data(phone_path, batch_size)
    print(
        f"训练批次数:{len(train_dataloader)},数据{len(train_dataloader.dataset)};测试批次数:{len(test_dataloader)},数据{len(test_dataloader.dataset)};输入特征数:{input_nums},输出类别数:{output_nums}")
    # TODO 2.构建模型
    model = PhonePriceModel(input_nums, output_nums)
    # TODO 3.模型训练
    epochs = 50
    model_path = "model/PhoneModel.pth"
    model_train(train_dataloader, model, epochs, model_path)
    # TODO 4.模型评估
    model_evaluate(input_nums, output_nums, model_path, test_dataloader)

贴上一个简单优化版本

# 导包
import time

import pandas as pd
import numpy as np
import torch
from sklearn.model_selection import train_test_split
from torch.utils.data import TensorDataset, DataLoader


# 1.自定义处理数据的api
def get_data(phone_path, batch_size):
    # 1.1 读取数据
    data = pd.read_csv(phone_path)
    # 1.2 了解数据
    print(data.shape)
    # 1.3 处理数据
    # 先分别获取x特征,y标签
    x = data.iloc[:, :-1].astype(np.float32)
    y = data.iloc[:, -1].astype(np.int64)
    # 然后使用train_test_split切割数据
    x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=88)
    # 最后封装TensorDataset
    train_dataset = TensorDataset(torch.from_numpy(x_train.values), torch.tensor(y_train.values))
    test_dataset = TensorDataset(torch.from_numpy(x_test.values), torch.tensor(y_test.values))
    # 1.4 封装dataloader数据加载器
    train_dataloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
    test_dataloader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)
    # 1.5 获取输入特征数和输出类别数(去重)
    input_nums = x_train.shape[1]
    output_nums = len(y_train.unique())
    # TODO 返回结果
    return train_dataloader, test_dataloader, input_nums, output_nums


# 2.自定义模型
class PhonePriceModel(torch.nn.Module):
    # 重写init方法
    def __init__(self, input_nums, output_nums):
        # 调用父类初始化方法
        super().__init__()
        # 定义网络结构
        self.linear1 = torch.nn.Linear(input_nums, 128)
        self.linear2 = torch.nn.Linear(128, 256)
        self.linear3 = torch.nn.Linear(256, 256)
        self.linear4 = torch.nn.Linear(256, 256)
        self.linear5 = torch.nn.Linear(256, 256)
        self.out = torch.nn.Linear(256, output_nums)

    # 重写forward
    def forward(self, x):
        # 前向传播(加权求和->激活函数)
        x = torch.relu(self.linear1(x))
        x = torch.relu(self.linear2(x))
        x = torch.relu(self.linear3(x))
        x = torch.relu(self.linear4(x))
        x = torch.relu(self.linear5(x))
        # TODO 注意: 本次项目是多分类项目,后续要使用多分类交叉熵损失函数,所以此处不使用softmax激活函数
        x = self.out(x)
        return x


# 3.模型训练
def model_train(train_dataloader, model, epochs, model_path):
    # todo 1.准备数据(已经传参)
    # todo 2.准备模型(已经传参)
    # todo 3.准备损失函数
    loss_fn = torch.nn.CrossEntropyLoss()
    # todo 4.准备优化器
    optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
    # todo 5.训练模型
    # 5.1 遍历轮次
    for epoch in range(epochs):
        # 提前定义变量用于存储总损失,批次次数,时间
        total_loss, batch_cnt, start_time = 0.0, 0, time.time()
        # 5.2 遍历训练数据
        for batch_x, batch_y in train_dataloader:
            # todo 前向传播
            # 获取预测数据
            logits = model(batch_x)
            # 计算损失
            loss = loss_fn(logits, batch_y)  # 底层先用softmax转概率,再计算交叉熵损失
            # 累计损失和批次次数
            total_loss += loss.item()
            batch_cnt += 1
            # todo 反向传播
            # 梯度清零
            optimizer.zero_grad()
            # 计算梯度
            loss.backward()
            # 参数更新
            optimizer.step()
        epoch_loss = total_loss / batch_cnt
        print(f"第{epoch + 1}轮,最新损失为:{epoch_loss},耗时:{time.time() - start_time}")
    # todo 模型保存
    torch.save(model.state_dict(), model_path)


# 4.模型评估
def model_evaluate(input_nums, output_nums, model_path, test_dataloader):
    # 1.创建空模型并加载训练好的模型参数
    model = PhonePriceModel(input_nums, output_nums)
    model.load_state_dict(torch.load(model_path))
    # 2.设置模型评估模式
    model.eval()
    # 3.模型预测
    correct_nums = 0
    for batch_x, batch_y in test_dataloader:
        # 前向传播
        logits = model(batch_x)
        # 获取预测结果
        pred = torch.argmax(logits,dim=1)
        # 计算正确数量
        correct_nums += (pred == batch_y).sum()
    # 4.todo 计算准确率
    print(f"准确率:{correct_nums / len(test_dataloader.dataset)}")



if __name__ == '__main__':
    # TODO 1.处理数据
    phone_path = "data/手机价格预测.csv"
    batch_size = 16
    # 调用get_data()
    train_dataloader, test_dataloader, input_nums, output_nums = get_data(phone_path, batch_size)
    print(f"训练批次数:{len(train_dataloader)},数据{len(train_dataloader.dataset)};测试批次数:{len(test_dataloader)},数据{len(test_dataloader.dataset)};输入特征数:{input_nums},输出类别数:{output_nums}")
    # TODO 2.构建模型
    model = PhonePriceModel(input_nums, output_nums)
    # TODO 3.模型训练
    epochs = 200
    model_path = "model/PhoneModel.pth"
    model_train(train_dataloader, model, epochs, model_path)
    # TODO 4.模型评估
    model_evaluate(input_nums, output_nums, model_path, test_dataloader)

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐