李哥考研复式班--回归实战

class CovidDataset(Dataset):
    def __init__(self, file_path, mode="train", all_feature=False, feature_dim=6):
        with open(file_path, "r") as f:
            ori_data = list(csv.reader(f))
            column = ori_data[0]
            csv_data = np.array(ori_data[1:])[:, 1:].astype(float)
        feature = np.array(ori_data[1:])[:, 1:-1]
        label_data = np.array(ori_data[1:])[:, -1]
        # 特征选择
        if all_feature:
            col = np.array([i for i in range(0, 93)])
        else:
            _, col = get_feature_importance(feature, label_data, feature_dim, column)
        col = col.tolist()
        # 训练,验证,测试数据集分离
        if mode == "train":
            indices = [i for i in range(len(csv_data)) if i % 5 != 0]
            data = torch.tensor(csv_data[indices, :-1])
            self.y = torch.tensor(csv_data[indices, -1])
        elif mode == "val":
            indices = [i for i in range(len(csv_data)) if i % 5 == 0]
            data = torch.tensor(csv_data[indices, :-1])
            self.y = torch.tensor(csv_data[indices, -1])
        elif mode == "test":
            indices = [i for i in range(len(csv_data))]
            data = torch.tensor(csv_data[indices, :])
        # 数据归一化处理
        data = data[:, col]
        self.data = (data - data.mean(dim=0, keepdim=True)) / data.std(dim=0, keepdim=True)
        self.mode = mode

    def __getitem__(self, idx):
        if self.mode != "test":
            return self.data[idx].float(), self.y[idx].float()
        else:
            return self.data[idx].float()

    def __len__(self):
        return len(self.data)
  1. init 方法
    数据读取:
    打开指定的 CSV 文件,读取文件内容。
    提取列名和数据,并将数据转换为 numpy 数组。
    特征选择:
    如果 all_feature 为 True,则选择所有特征;否则,调用 get_feature_importance 函数选择重要特征。
    数据集划分:
    根据 mode 参数,将数据划分为训练集、验证集或测试集。
    数据归一化:
    对选择的特征数据进行归一化处理,使其均值为 0,标准差为 1。
  2. getitem 方法
    根据索引 idx 获取数据样本。
    如果模式不是测试模式,则返回特征数据和标签;否则,只返回特征数据。
  3. len 方法
    返回数据集的长度。
class MyModel(nn.Module):
    def __init__(self, inDim):
        super(MyModel, self).__init__()
        self.fc1 = nn.Linear(inDim, 20)
        self.relu1 = nn.ReLU()
        self.fc2 = nn.Linear(20, 1)

    def forward(self, x):
        x = self.fc1(x)
        x = self.relu1(x)
        x = self.fc2(x)

        if len(x.size()) > 1:
            return x.squeeze(1)

        return x

这段代码定义了一个简单的 PyTorch 神经网络模型 MyModel,它继承自 nn.Module。该模型包含一个输入层、一个具有 20 个神经元的隐藏层和一个输出层。具体结构如下:
初始化部分 (init):
定义了两个全连接层 self.fc1 和 self.fc2,以及一个 ReLU 激活函数 self.relu1。(Linear方法就是全链接的意思)
self.fc1 接收 inDim 个输入特征,并输出 20 个特征。
self.relu1 作为非线性激活函数,增加模型的表达能力。
self.fc2 将 20 个输入特征映射到 1 个输出特征。
前向传播部分 (forward):
输入数据 x 首先通过 self.fc1 层。
然后经过 self.relu1 激活函数进行非线性变换。
最后通过 self.fc2 层得到输出。
如果输出的维度大于 1,使用 squeeze(1) 方法去除维度为 1 的第二维。

def train_val(model, train_loader, val_loader, device, epochs, optimizer, loss, save_path):
    # 参数解析
    # model:待训练和验证的 PyTorch 模型。
    # train_loader:训练数据加载器,用于加载训练数据。
    # val_loader:验证数据加载器,用于加载验证数据。
    # device:指定模型和数据运行的设备,如 'cuda' 或 'cpu'。
    # epochs:训练的轮数。
    # optimizer:优化器,用于更新模型的参数。
    # loss:损失函数,用于计算模型的损失。
    # save_path:保存模型的路径。
    model = model.to(device)
    plt_train_loss = []
    plt_val_loss = []
    min_val_loss = 9999999999999

    for epoch in range(epochs):  # 开始一轮的训练
        train_loss = 0.0
        val_loss = 0.0
        start_time = time.time()
        model.train()  # 模型调整为训练模式
        for batch_x, batch_y in train_loader:
            x, target = batch_x.to(device), batch_y.to(device)
            # 向前计算
            pred = model(x)
            train_bat_loss = loss(pred, target, model)
            # 进行反向传播,计算损失函数关于模型参数的梯度。
            train_bat_loss.backward()
            optimizer.step()  # 更新模型作用
            optimizer.zero_grad()  # 清除无用的方向梯度
            train_loss += train_bat_loss.cpu().item()
        plt_train_loss.append(train_loss / train_loader.dataset.__len__())
        # 将模型设置为评估模式
        model.eval()
        # 这是一个上下文管理器,用于临时禁用 PyTorch 的自动求导机制。
        with torch.no_grad():
            for batch_x, batch_y in val_loader:
                x, target = batch_x.to(device), batch_y.to(device)
                pred = model(x)
                val_bat_loss = loss(pred, target, model)
                val_loss += val_bat_loss.cpu().item()
        plt_val_loss.append(val_loss / val_loader.__len__())
        if val_loss < min_val_loss:
            torch.save(model, save_path)
            min_val_loss = val_loss

        print('[%03d/%03d] %2.2f sec(s) TrainLoss : %.6f | ValLoss: %.6f' % \
              (epoch, epochs, time.time() - start_time, plt_train_loss[-1], plt_val_loss[-1]))

    plt.plot(plt_train_loss)
    plt.plot(plt_val_loss)
    plt.title("loss图")
    plt.legend(["train", "val"])
    plt.show()

这段代码定义了一个名为 train_val 的函数,用于对 PyTorch 模型进行训练和验证。具体功能如下:
模型初始化:将模型移动到指定的设备(如 GPU 或 CPU)上。
训练循环:在指定的轮数(epochs)内进行训练和验证。
训练阶段:将模型设置为训练模式,遍历训练数据加载器 train_loader,计算损失,进行反向传播和参数更新。
训练模式代码实现了一个完整的训练批次的处理过程,包括数据加载、前向传播、损失计算、反向传播、参数更新和梯度清零,并记录了当前轮次的平均训练损失。
验证阶段:将模型设置为评估模式,遍历验证数据加载器 val_loader,计算验证损失。
验证模式代码实现了在验证阶段对模型进行评估的过程,包括设置模型为评估模式、禁用自动求导、遍历验证数据、计算验证损失、记录平均验证损失以及保存性能最优的模型。
损失记录与保存:记录每一轮的训练损失和验证损失,并在验证损失最小时保存模型。
可视化:使用 matplotlib 库绘制训练损失和验证损失的变化曲线。
model:待训练和验证的 PyTorch 模型。
train_loader:训练数据加载器,用于加载训练数据。
val_loader:验证数据加载器,用于加载验证数据。
device:指定模型和数据运行的设备,如 ‘cuda’ 或 ‘cpu’。
epochs:训练的轮数。
optimizer:优化器,用于更新模型的参数。
loss:损失函数,用于计算模型的损失。
save_path:保存模型的路径。

def evaluate(save_path, test_loader, device, rel_path):  # 得出测试文件
    # save_path:保存预训练模型的文件路径。
    # test_loader:测试数据加载器,用于加载测试数据。
    # device:指定模型和数据运行的设备,如 'cuda' 或 'cpu'。
    # rel_path:保存测试结果的 CSV 文件的路径。
    model = torch.load(save_path).to(device)
    rel = []
    with torch.no_grad():
        for x in test_loader:
            pred = model(x.to(device))
            rel.append(pred.cpu().item())
    with open(rel_path, 'w', newline="") as f:
        csvWriter = csv.writer(f)
        csvWriter.writerow(["id", "tested_positive"])
        for i, value in enumerate(rel):
            csvWriter.writerow([str(i), str(value)])
    print("文件已经保存到" + rel_path)

这个函数完成了加载预训练模型、对测试数据进行推理、保存预测结果到列表,并将结果写入 CSV 文件的整个过程。

def mseLoss_with_reg(pred, target, model):
    # pred:模型的预测值,通常是一个张量。
    # target:真实的目标值,同样是一个张量。
    # model:训练的模型,类型为 torch.nn.Module 的实例。
    loss = nn.MSELoss(reduction='mean')
    ''' Calculate loss '''
    regularization_loss = 0  # 正则项
    for param in model.parameters():
        # TODO: you may implement L1/L2 regularization here
        # 使用L2正则项
        # regularization_loss += torch.sum(abs(param))
        regularization_loss += torch.sum(param ** 2)  # 计算所有参数平方
    return loss(pred, target) + 0.00075 * regularization_loss  # 返回损失

mseLoss_with_reg 函数的主要功能是计算带有 L2 正则化项的均方误差损失(MSE Loss)。在机器学习中,均方误差损失用于衡量模型预测值与真实值之间的差异,而正则化项则用于防止模型过拟合,通过对模型参数进行约束,使模型更加泛化。该函数结合了这两部分,最终返回一个综合的损失值。

def get_feature_importance(feature_data, label_data, k=4, column=None):
    """
    此处省略 feature_data, label_data 的生成代码。
    如果是 CSV 文件,可通过 read_csv() 函数获得特征和标签。
    这个函数的目的是, 找到所有的特征种, 比较有用的k个特征, 并打印这些列的名字。
    """
    model = SelectKBest(chi2, k=k)  # 定义一个选择k个最佳特征的函数
    feature_data = np.array(feature_data, dtype=np.float64)
    # label_data = np.array(label_data, dtype=np.float64)
    X_new = model.fit_transform(feature_data, label_data)  # 用这个函数选择k个最佳特征
    # feature_data是特征数据,label_data是标签数据,该函数可以选择出k个特征
    print('x_new', X_new)
    scores = model.scores_  # scores即每一列与结果的相关性
    # 按重要性排序,选出最重要的 k 个
    indices = np.argsort(scores)[::-1]  # [::-1]表示反转一个列表或者矩阵。
    # argsort这个函数, 可以矩阵排序后的下标。 比如 indices[0]表示的是,scores中最小值的下标。

    if column:  # 如果需要打印选中的列
        k_best_features = [column[i + 1] for i in indices[0:k].tolist()]  # 选中这些列 打印
        print('k best features are: ', k_best_features)
    return X_new, indices[0:k]  # 返回选中列的特征和他们的下标。

该函数通过卡方检验选择最重要的 k 个特征,并提供了打印列名和返回结果的功能。

config = {
    "lr": 0.001,
    "epochs": 20,
    "momentum": 0.9,
    "save_path": "model_save/best_model.pth",
    "rel_path": "pred.csv"
}
# lr:学习率,控制模型参数更新的步长,这里设置为 0.001。
# epochs:训练的轮数,即整个数据集被模型训练的次数,这里设置为 20 轮。
# momentum:随机梯度下降(SGD)优化器中的动量参数,用于加速收敛,这里设置为 0.9。
# save_path:保存最佳模型的文件路径,这里指定为 model_save/best_model.pth。
# rel_path:保存测试结果的 CSV 文件路径,这里指定为 pred.csv。

all_feature = False
if all_feature:
    feature_dim = 93
else:
    feature_dim = 6

train_file = "covid.train.csv"
test_file = "covid.test.csv"
file = pd.read_csv(train_file)
train_data = CovidDataset(train_file, "train",all_feature=all_feature, feature_dim=feature_dim)
val_data = CovidDataset(train_file, "val",all_feature=all_feature, feature_dim=feature_dim)
test_data = CovidDataset(test_file, "test",all_feature=all_feature, feature_dim=feature_dim)
# batch_size:设置每个批次加载的数据样本数量为 16。
# train_loader 和 val_loader:分别创建训练数据加载器和验证数据加载器。DataLoader 是 PyTorch 提供的用于批量加载数据的工具,shuffle=True 表示在每个 epoch 开始时打乱数据顺序,有助于模型更好地学习。
# test_loader:创建测试数据加载器,batch_size=1 表示每次只加载一个样本,shuffle=False 表示不打乱测试数据的顺序。
batch_size = 16
train_loader = DataLoader(train_data, batch_size=batch_size, shuffle=True)
val_loader = DataLoader(val_data, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(test_data, batch_size=1, shuffle=False)
device = "cuda" if torch.cuda.is_available() else "cpu"
model = MyModel(inDim=feature_dim).to(device)
# loss:指定损失函数为 mseLoss_with_reg,这是一个自定义的带有 L2 正则化的均方误差损失函数。
# optimizer:创建随机梯度下降(SGD)优化器,用于更新模型的参数。model.parameters() 表示需要优化的模型参数,lr=config["lr"] 和 momentum=config["momentum"] 分别设置学习率和动量参数,从之前定义的 config 字典中获取相应的值。
loss = mseLoss_with_reg
optimizer = optim.SGD(model.parameters(), lr=config["lr"], momentum=config["momentum"])
train_val(model, train_loader, val_loader, device, config["epochs"], optimizer, loss, config["save_path"])
evaluate(config["save_path"], test_loader, device, config["rel_path"])

这段代码完成了从数据加载、模型初始化、训练和验证到最终测试评估的整个流程,通过配置参数和自定义函数实现了一个完整的机器学习实验。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值