第三节 回归实战 下

数据处理

超参:人为指定不能改变

测试数据只有x没有标签y
训练数据拆分,82开,作训练集和验证集(验证模型好坏),模型训练不是一路上升的过程,训练几次验证一次,最好的模型save下来

one-hot独热编码 猪(1 0 0) 狗(0 1 0) 猫(0 0 1)

def get_feature_importance(feature_data, label_data, k = 4, column = None):
    """
    feature_data, label_data 要求字符串形式
    k为选择的特征数量
    如果需要打印column,需要传入行名
    此处省略 feature_data, label_data 的生成代码。
    如果是 CSV 文件,可通过 read_csv() 函数获得特征和标签。
    这个函数的目的是, 找到所有的特征种, 比较有用的k个特征, 并打印这些列的名字。
    """
    model = SelectKBest(chi2, k=k)      #定义一个选择k个最佳特征的函数
    feature_data = np.array(feature_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] for i in indices[0:k].tolist()]         # 选中这些列 打印
        print('k best features are: ',k_best_features)
    return X_new, indices[0:k]                  # 返回选中列的特征和他们的下标。
class Covid_dataset(Dataset):
    def __init__(self, file_path, mode, dim=4, all_feature=False):
        with open(file_path, "r") as f:
            csv_data = list(csv.reader(f)) #list会变为数据
            data = np.array(csv_data[1:]) #去掉第一行
            if mode == "train": #逢五取一
                indices = [i for i in range(len(data)) if i % 5 !=0]
            elif mode == "val":
                indices = [i for i in range(len(data)) if i % 5 ==0]

            if all_feature:
                col_idx = [i for i in range(0,93)] #col是array indices为列,故把col转化为列
            else:
                _, col_idx = get_feature_importance(data[:,1:-1], data[:,-1], k=dim,column =csv_data[0][1:-1])#不是全选则选取关键列 column是关键列的名字

            if mode == "test":
                x = data[:, 1:].astype(float)#将数据由字符型转为浮点型
                x = torch.tensor(x[:, col_idx])
            else:
                x = data[indices, 1:-1].astype(float) #x 选indices的行 x要去掉最后一列
                x = torch.tensor(x[:, col_idx])
                y = data[indices, -1].astype(float)
                self.y = torch.tensor(y)
            self.x = (x-x.mean(dim=0, keepdim=True))/x.std(dim=0, keepdim=True)#数据的量纲不同,要归一化.每列的数值差距大mean()平均值要在一列中取第0维同时保持维度不变
            self.mode = mode #把mode传到self中
    def __getitem__(self, item):
        if self.mode == "test":
            return self.x[item].float()#测试集没有y float是把变量变为32位,消耗不会太大
        else:
            return self.x[item].float(), self.y[item].float() 
    def __len__(self):
        return len(self.x)

Dataset类 xy

  1. init 初始化 filepath x[] Y[]
  2. getitem 取数据 idx->X[idx] Y[idx]
  3. len 数据长度


    模型部分
class myModel(nn.Module):#模型首先关注维度变化 回归中用全连接linear 上一层输出一定是下一层输入 输入维度(16,93)16为样本数量,93为样本维度
    def __init__(self, dim):#初始化 模型长什么样 dim为输入维度
        super(myModel, self).__init__()#修改这里的初始化
        self.fc1 = nn.Linear(dim, 100)#全连接(输入维度,输出维度)
        self.relu = nn.ReLU() #激活函数 不需要参数
        self.fc2 = nn.Linear(100, 1) #输入100维 输出1维

    def forward(self, x):#模型前向过程
        x = self.fc1(x) 
        x = self.relu(x)
        x = self.fc2(x)

        if len(x.size())>1: #x有两维要减去一维 去掉第二维,去掉第二个
            x = x.squeeze(dim=1)
        return x

超参部分

config = {
    "lr" : 0.001,
    "momentum": 0.9,#动量,惯性,继续冲一下
    "epochs":20,
    "save_path": "model_save/model.pth", #保存路径
    "rel_path" : "pred.csv" #预测结果
}
loss = nn.MSELoss()

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"], device, test_loader, config["rel_path"])

训练流程

def train_val(model, train_loader, val_loader, device, epochs, optimizer, loss, save_path):
    model = model.to(device)

    plt_train_loss = [] #每轮训练记录loss值,记录所有轮次loss值
    plt_val_loss = []
    min_val_loss = 9999999999 #记录最好的模型,最小的loss值


    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 = loss(pred, target) #得到loss
            train_bat_loss.backward() #回传
            optimizer.step() #更新模型
            optimizer.zero_grad() #模型梯度清0
            train_loss += train_bat_loss.cpu().item()#在gpu上是张量没法和浮点数相加 item为把数值取出来

        plt_train_loss.append(train_loss/train_loader.dataset.__len__())#加在所有的loss值里,记录的是平均值


        model.eval() #调整为验证模式
        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_bat_loss = loss(pred, target)
                val_loss += val_bat_loss.cpu().item()
        plt_val_loss.append(val_loss / val_loader.dataset.__len__())
        if val_loss < min_val_loss: #模型效果最好,保存模型
            torch.save(model, save_path)
            min_val_loss = val_loss

        print("[%03d/%03d]  %2.2f secs 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_loader = DataLoader(train_data, batch_size=16, shuffle=True)
val_loader = DataLoader(val_data, batch_size=16, shuffle=True)
test_loader = DataLoader(test_data, batch_size=1, shuffle=False)#测试集batchsize为1 不能打乱
def evaluate(save_path, device, test_loader, rel_path): #得出测试结果文件
    model = torch.load(save_path).to(device) #加载模型
    rel = [] #记录结果的列表
    model.eval()

    with torch.no_grad(): #模型在测试时不能计算出梯度
        for x in test_loader: #测试集只有x了
            pred = model(x.to(device)) #得出预测值
            rel.append(pred.cpu().item()) #预测值加到列表中 放在CPU上再取出来
    print(rel)

    with open(rel_path,"w") as f:
        csv_writer = csv.writer(f) #定义写指针
        csv_writer.writerow(["id", "tested_positive"])#第一行写这个
        for i in range(len(rel)):#访问到每一个下标
            csv_writer.writerow([str(i), str(rel[i])])#下标和结果
        print("文件已经保存到"+rel_path)

对项目进行一些更改

一 正则化 让模型曲线更平滑,防止过拟合,让参数W更靠近0

相关系数 挑选比较重要的那几列

def get_feature_importance(feature_data, label_data, k = 4, column = None):
    """
    feature_data, label_data 要求字符串形式
    k为选择的特征数量
    如果需要打印column,需要传入行名
    此处省略 feature_data, label_data 的生成代码。
    如果是 CSV 文件,可通过 read_csv() 函数获得特征和标签。
    这个函数的目的是, 找到所有的特征种, 比较有用的k个特征, 并打印这些列的名字。
    """
    model = SelectKBest(chi2, k=k)      #定义一个选择k个最佳特征的函数
    feature_data = np.array(feature_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为带下标排序,返回下标
    # argsort这个函数, 可以矩阵排序后的下标。 比如 indices[0]表示的是,scores中最小值的下标。

    if column:                            # 如果需要打印选中的列名字
        k_best_features = [column[i] for i in indices[0:k].tolist()]         # 选中这些列 打印
        print('k best features are: ',k_best_features)
    return X_new, indices[0:k]                  # 返回选中列的特征和他们的下标。
all_feature = False
if all_feature:
    dim = 93
else:
    dim = 6 #选6个关键的
device = "cuda" if torch.cuda.is_available() else "cpu"

主成分分析PCA--降维(后续可自行了解)

一轮一轮训练改变的是模型 预测到一个比较准测的y
每次取一批数据 经过f得到y,求loss 更新模型 取完一轮是一个epoch

posted @ 2025-01-15 19:44  JYP0222  阅读(35)  评论(0)    收藏  举报