大数据下使用神经网络进行年龄或性别预测(Pytorch实现)

引言

如今各类应用的推荐系统做的越来越完善,推荐主要基于用户信息的准确分析,其中性别和年龄预测通常占据重要的地位,那么如何从用户行为中准确分析出性别和年龄?传统的机器学习算法例如逻辑回归,需要人工建构特征进行输入训练,而基于神经网络的模型可以自动提取特征,对于有着大量训练数据的任务来说是一个很不错的选择。

Pytorch深度学习框架

使用Pytorch构建深度模型,基本按照以下流程展开:

  1. 模型输入(通常是与模型输出结果相关的特征数据)
  2. 模型(Pytorch中只需要构建前向传播过程)
  3. 定义损失和选择合适的优化器
  4. 训练模型,通过梯度回传不断更新模型参数

数据

由于数据的私有性,不可以公开,因此我们假设数据原型如下(假设与年龄和性别密切相关的字段数据,有昵称、偏好、其它):

昵称 偏好 其它
可爱的小花 收集的足迹信息 补充信息(e.g. 小红书打开频率更高)
王大拿 收集的足迹信息 补充信息
冷血无情 收集的足迹信息 补充信息

以上数据为应用内收集信息,需要对数据进行向量化处理,才可以作为神经网络的输入。通常有这样两种转换方式:
① 原始数据本身为数字类型数据,那么可以将其进行归一化后直接作为特征进行输入;
② 文字类数据需要做相应的转换,可以使用one-hot码或者使用word2vec转换为特征向量(个人建议,如果该做法不正确,请指出~);

数据输入网络模型通常会使用自定义的Dataloader类,通过继承Dataset类重写__init__、__getitem__以及__len__方法。

class AgePredictData(Dataset):
    def __init__(self, csv_path=None, train=True):
        # 通常初始化数据源
        self.data = pd.read_csv(csv_path, header=None)
        self.train_data = self.data.iloc[0:820000, :]  # 切分训练集 82W向量
        self.test_data = self.data.iloc[820000: 1000000, :]
        self.info = self.data.describe().shape
        self.train = train

    def test(self):
        return self.train_data if self.train else self.test_data

    def transform(self, train, index):
    	# 将数据转换为Tensor格式(以下代码是任务相关的,具体任务需要具体修改)
        if train:
            # Series to np array
            data = pd.Series.to_numpy(self.train_data.iloc[index, 0: (self.info[1] - 5)]).reshape(400)
            label = np.array([self.train_data.iloc[index, -5:]]).reshape(5)
        else:
            data = pd.Series.to_numpy(self.test_data.iloc[index, 0: (self.info[1] - 5)]).reshape(400)
            label = pd.Series.to_numpy(self.test_data.iloc[index, -5:]).reshape(5)

        data = torch.from_numpy(data).float()
        label = torch.from_numpy(label).float()
        return data, label

    def __getitem__(self, index):
    	# 获取一条输入数据
        data_, label_ = self.transform(self.train, index)
        return data_, label_

    def __info__(self):
        return self.info  # column count

    def __len__(self):
    	# 返回数据的长度
        return len(self.train_data) if self.train else len(self.test_data)

模型构建

对于一般的数据,可以直接使用全连接网络 Full Connection Network。隐藏层个数可以通过手动调整。

def add_module(self, module):
    self.add_module(str(len(self) + 1), module)


torch.nn.Module.add = add_module


def fcn(num_input_channels, num_output_channels, num_hidden):
    # Fully Connected Network, fcn
    model = nn.Sequential()
    model.add(nn.Linear(num_input_channels, num_hidden, bias=True))
    model.add(nn.Dropout(p=0.1))
    model.add(nn.ReLU6())
    model.add(nn.Linear(num_hidden, num_output_channels))
    # model.add(nn.Softmax(dim=1))
    return model

损失以及优化器的选择

net = fcn().to(device)
mse = torch.nn.MSELoss().to(device)  # 损失函数选用均方误差损失或其它损失
optimizer = torch.optim.SGD([{'params': net.parameters()}], lr=LR)  # 优化器选择随机梯度下降或其它优化器

训练模型和测试模型

def train():
	net.train()
    logging.info("start to Train ...")
    for step in range(EPOCH):        
        for i_batch, (x, y) in enumerate(train_loader):

            x = x.to(device)
            y = y.to(device)

            y_ = net(x)  # net output
            loss = mse(y_, torch.max(y, 1)[1])
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()

            if i_batch % 1000 == 0:
                print("current epoch: ", step + 1, "/", EPOCH, ", the i_batch is ", i_batch, ", the loss is %f" % loss)

        logging.warning("save model parameters to 'model/%d_net_params.pkl' " % step)
        torch.save(net.state_dict(), 'model/' + str(step) + '_net_params.pkl')  # 保存网络参数

测试结果仅仅计算了准确率。然后在模型的评价标准中,准确率并不能说明模型的好坏。

def test():
    correct = torch.zeros(1).squeeze()
    # load model
    logging.info("start to TEST, loading model ...")
    net.load_state_dict(torch.load('model/90_net_params.pkl'))
    logging.info("loaded model, calculating ...")
    for i_batch, (x, y) in enumerate(test_loader):
        x = x.to(device)
        y_ = net(x)  # .cpu().detach().squeeze().numpy()
        prediction = torch.argmax(y_, dim=1).cpu()
        labels = torch.argmax(y, dim=1)
        correct += (prediction == labels).sum().float()

    print("the test accuracy is %f" % (correct.numpy() / test_data.__len__() * 100), "%")

如果需要计算查全率查准率,可以使用sklearn工具包。
如果以上表述存在问题,欢迎留言~完整代码参见我的github。

你可能感兴趣的:(神经网络,深度学习,python,机器学习)