【9】多层感知机代码实例

数据、代码等相关资料来源于b站日月光华老师视频,此博客作为学习记录。

一、数据集及处理

人力资源数据集:根据各类信息,预测该员工是否会离职。
数据集长这样:
在这里插入图片描述

import torch
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

data = pd.read_csv(r'E:\Code\pytorch\第5章\HR.csv')
print(data.info)   # 可查看数据集多少行多少列的大概情况

在这里插入图片描述

  • 想查看某部分有什么值可使用.unique()方法
print(data.part.unique())   
# 返回data中part部分的单一值,就是看part部分有什么样的值

在这里插入图片描述

  • 假设现在想知道在哪个part中salary为high的更多,使用.groupby()方法:
print(data.groupby(['salary', 'part']).size()) 

在这里插入图片描述
这种文本的东西是不能直接在深度学习中使用的,要计算首先要经过预处理进行数值化

使用pd.get_dummies()方法进行数值化:该方法可将数据转化成独热编码(one-hot编码):

# 示例:
print(pd.get_dummies(data.salary))

在这里插入图片描述
数值化方法:

# 在数据集后再加三列分别是high、low、medium对应的独热编码
data = data.join(pd.get_dummies(data.salary))
# 删去原有的salary的列
del data['salary']
# 同样的方法应用至part
data = data.join(pd.get_dummies(data.part))
del data['part']

此时,数据集中的所有数据不再包含字符,全为数值。这个数据集是看员工会不会离职,所以left这一列是结果。可查看:

# 对left中的值进行计数
print(data.left.value_counts())

在这里插入图片描述

Y_data = data.left.values.reshape(-1, 1) # 转为1维
Y = torch.from_numpy(Y_data).type(torch.float32)  # 转换成tensor
# 取出除了left这一列的其他列作为X_data,data.values是转成ndarrary
X_data = data[[c for c in data.columns if c != 'left']].values
X = torch.from_numpy(X_data).type(torch.float32)

数据预处理完毕。
无注释完整预处理代码:

data = pd.read_csv(r'E:\Code\pytorch\第5章\HR.csv')

data = data.join(pd.get_dummies(data.salary))
del data['salary']
data = data.join(pd.get_dummies(data.part))
del data['part']

Y_data = data.left.values.reshape(-1, 1)
Y = torch.from_numpy(Y_data).type(torch.float32)
X_data = data[[c for c in data.columns if c != 'left']].values
X = torch.from_numpy(X_data).type(torch.float32)

二、模型的建立和训练

接下来是对模型的建立:

# nn.Module:继承这个类
# __init__:初始化所有层
# forward:定义模型的运算过程
class Model(nn.Module):
    def __init__(self):
        super().__init__()   # 继承父类的所有属性
        self.linear_1 = nn.Linear(20, 64)  # 输入20列的特征(数据集决定),输出为64(假设给64个隐藏层)
        self.linear_2 = nn.Linear(64, 64)  # 接上层64输入,输出64维
        self.linear_3 = nn.Linear(64, 1)   # 因为是逻辑回归,只要一个输出
        self.relu = nn.ReLU()
        self.sigmoid = nn.Sigmoid()
    def forward(self, input):
        x = self.linear_1(input)
        x = self.relu(x)
        x = self.linear_2(x)
        x = self.relu(x)
        x = self.linear_3(x)
        x = self.sigmoid(x)
        return x

训练:

lr = 0.0001

# 每次运行得到模型和其优化方法
def get_model():
    model = Model()
    opt = torch.optim.Adam(model.parameters(), lr=lr)
    return model, opt

model, optim = get_model()

# 定义loss
loss_fn = nn.BCELoss()
batch = 64
num_of_batches = len(data)//batch
epochs = 100

# 开始训练
for epoch in range(epochs):
    for i in range(num_of_batches):
        start = i*batch
        end = start + batch
        x = X[start: end]
        y = Y[start: end]

        y_pred = model(x)
        loss = loss_fn(y_pred, y)
        optim.zero_grad()
        loss.backward()
        optim.step()
    # 打印出每个epoch的loss情况
    with torch.no_grad():
        print('epoch:', epoch,'loss:', loss_fn(model(X), Y).data.item())

在这里插入图片描述
略……
在这里插入图片描述
可看到随着epoch数增加,loss逐渐从0.68左右降到了0.55

三、改进

3.1 dataset方法

对于每次对数据切片不方便,使用dataset进行改进。

# 使用dataset类改写数据输入
# 之前的方法中使用start:end这样的切片形式不方便,故使用dataset进行重构
from torch.utils.data import TensorDataset    # 改动
HRdataset = TensorDataset(X,Y)                # 改动
model, optim = get_model()  # get_model
# 重新写训练部分
for epoch in range(epochs):
    for i in range(num_of_batches):
        x, y = HRdataset[i*batch:i*batch+batch]   #改进的地方
        y_pred = model(x)
        loss = loss_fn(y_pred, y)
        optim.zero_grad()
        loss.backward()
        optim.step()
    # 打印出每个epoch的loss情况
    with torch.no_grad():
        print('epoch:', epoch,'loss:', loss_fn(model(X), Y).data.item())

这样的情况下就避免了两次对x、y分别进行切片的繁琐了。(可以直接运行啦)
完整代码如下:

import torch
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from torch import nn

data = pd.read_csv(r'E:\Code\pytorch\第5章\HR.csv')
data = data.join(pd.get_dummies(data.salary))
del data['salary']
data = data.join(pd.get_dummies(data.part))
del data['part']

Y_data = data.left.values.reshape(-1, 1) # 转为1维
Y = torch.from_numpy(Y_data).type(torch.float32)  # 转换成tensor
X_data = data[[c for c in data.columns if c != 'left']].values
X = torch.from_numpy(X_data).type(torch.float32)

class Model(nn.Module):
    def __init__(self):
        super().__init__()   
        self.linear_1 = nn.Linear(20, 64)
        self.linear_2 = nn.Linear(64, 64)
        self.linear_3 = nn.Linear(64, 1)  
        self.relu = nn.ReLU()
        self.sigmoid = nn.Sigmoid()
    def forward(self, input):
        x = self.linear_1(input)
        x = self.relu(x)
        x = self.linear_2(x)
        x = self.relu(x)
        x = self.linear_3(x)
        x = self.sigmoid(x)
        return x

lr = 0.0001

# 每次运行得到模型和其优化方法
def get_model():
    model = Model()
    opt = torch.optim.Adam(model.parameters(), lr=lr)
    return model, opt
    
# 定义loss
loss_fn = nn.BCELoss()
batch = 64
num_of_batches = len(data)//batch
epochs = 100

from torch.utils.data import TensorDataset   
HRdataset = TensorDataset(X,Y)              
model, optim = get_model()  
for epoch in range(epochs):
    for i in range(num_of_batches):
        x, y = HRdataset[i*batch:i*batch+batch]  
        y_pred = model(x)
        loss = loss_fn(y_pred, y)
        optim.zero_grad()
        loss.backward()
        optim.step()
    # 打印出每个epoch的loss情况
    with torch.no_grad():
        print('epoch:', epoch,'loss:', loss_fn(model(X), Y).data.item())

3.2 dataloader方法

那么又有新的问题了,这样自仍然是i*batch+batch是以固定顺序对数据进行读取的,如果不想按顺序进行运算该怎么办呢?
dataloader类:创建可以迭代的数据装载器,方便管理批次
3.1部分的dataset是dataloader的第一个参数;
batchsize是他的另一个参数,可以每次训练提供这样一个batch的数据;
shuffle也是他的一个参数,其值为True或False,看是否打乱顺序进行数据的输入;
重写训练部分代码:

from torch.utils.data import TensorDataset
from torch.utils.data import DataLoader
HR_ds = TensorDataset(X,Y)
HR_dl = DataLoader(HR_ds, batch_size=batch, shuffle=True)
model, optim = get_model()

for epoch in range(epochs):
    for x, y in HR_dl:         # 这样每次提供/返回一个batchsize的x和y
        y_pred = model(x)
        loss = loss_fn(y_pred, y)
        optim.zero_grad()
        loss.backward()
        optim.step()
    with torch.no_grad():
            print('epoch:', epoch,'loss:', loss_fn(model(X), Y).data.item())

这样就更加简洁了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

要努力的小菜鸟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值