深度学习推荐系统(二)Deep Crossing及其在Criteo数据集上的应用

news2024/11/28 12:43:20

深度学习推荐系统(二)Deep Crossing及其在Criteo数据集上的应用

在2016年, 随着微软的Deep Crossing, 谷歌的Wide&Deep以及FNN、PNN等一大批优秀的深度学习模型被提出, 推荐系统全面进入了深度学习时代, 时至今日, 依然是主流。 推荐模型主要有下面两个进展:

  • 与传统的机器学习模型相比, 深度学习模型的表达能力更强, 能够挖掘更多数据中隐藏的模式

  • 深度学习模型结构非常灵活, 能够根据业务场景和数据特点, 灵活调整模型结构, 使模型与应用场景完美契合

深度学习推荐模型,以多层感知机(MLP)为核心, 通过改变神经网络结构进行演化。

在这里插入图片描述

1 Deep Crossing模型原理

2015年由澳大利亚国立大学提出AutoRec单隐层神经网络模型,由于比较简单, 表达能力不足, 并没有真正的被应用。

在2016年,微软基于ResNet的经典DNN结构, 提出了Deep Crossing模型, 该模型完整的解决了从特征工程、稀疏向量稠密化, 多层神经网络进行优化目标拟合等一系列深度学习在推荐系统中的应用问题。

1.1 Deep Crossing模型的网络结构

为了完成端到端的训练, DeepCrossing模型要在内部网络结构中解决如下问题:

  • 离散类特征编码后过于稀疏, 不利于直接输入神经网络训练, 需要解决稀疏特征向量稠密化的问题

  • 如何解决特征自动交叉组合的问题

  • 如何在输出层中达成问题设定的优化目标

DeepCrossing分别设置了不同神经网络层解决上述问题。 模型结构如下:

在这里插入图片描述

  • Embedding层: 将稀疏的类别型特征转成稠密的Embedding向量,Embedding的维度会远小于原始的系数特征向量

    • 这里的Feature #1表示的类别特征(one-hot编码后的稀疏特征向量), Feature #2是数值型特征, 不用embedding, 直接到了Stacking层。
    • 关于Embedding层的实现, Pytorch中有实现好的层可以直接用。
  • Stacking层:这个层是把不同的Embedding特征和数值型特征拼接在一起, 形成新的包含全部特征的特征向量, 该层通常也称为连接层。

  • Multiple Residual Units层: 该层的主要结构是多层感知机, 但DeepCrossing采用了残差网络进行的连接。通过多层残差网络对特征向量各个维度充分的交叉组合, 使得模型能够抓取更多的非线性特征和组合特征信息, 增加模型的表达能力

  • Scoring层: 这个作为输出层, 为了拟合优化目标存在。 对于CTR预估二分类问题, Scoring往往采用逻辑回归, 对于多分类, 往往采用Softmax模型

总结一下:

  1. DeepCrossing的结构比较清晰和简单, 没有引入特殊的模型结构, 只是常规的Embedding+多层神经网络。但这个网络模型的出现, 有革命意义。

  2. DeepCrossing模型中没有任何人工特征工程的参与, 只需要清洗一下, 原始特征经Embedding后输入神经网络层, 自主交叉和学习。

  3. 相比于FM, FFM只具备二阶特征交叉能力的模型, DeepCrossing可以通过调整神经网络的深度进行特征之间的“深度交叉”, 这也是Deep Crossing名称的由来。

1.2 Deep Crossing模型的网络的pytorch实现

1.2.1 实现细节说明

通过代码,我们更能理解这个模型的细节。

  • 首先, 会有embedding层。这个由于不同的类别特征会通过不同的embedding, 且每个类别的取值个数不一样, 所以有多少个类别特征就需要多少次embedding

    • 在这里,类别特征的编码其实用的LabelEncoder而不是One-hotEncoder, 我觉得原因就是LabelEncoder就类似于把每个类别下的不同取值映射到了一个字典里面去。 通过这个LabelEncoder的取值, 就可以直接拿出对应的embedding向量来。
    • Pytorch中, 实现这一层, 需要用一个ModuleDict来实现, 里面的每个值都是embedding层
    • 由于每个类别的取值不一样, 需要实现先把每个特征的取值个数记录下来, 这样是embedding的输入维度。
  • 然后就是残差层, 因为Stacking不需要特殊的层, 只需要把特征拼接即可。 残差层其实就是实现了神经网络的运算过程, 只不过稍微有点不同的是残差网络加了跳远链接

    • 残差块网络结构, 两层线性可以用两个nn.Linear来搞定, 剩下的就是跳远那部分, 在前向传播的时候加过去即可。
    • 实际应用中, 我们可能很多个这样的残差块结构, 下面代码中我们用了三个, 每一个里面神经单元的个数不一样。 所以用了ModuleList,然后加了一层Dropout层缓解过拟合, 最后一个线性层加sigmoid完成scoring层的实现。

在这里插入图片描述

1.2.2 代码实现

import torch.nn as nn
import torch.nn.functional as F
import torch

# 首先, 自定义一个残差块
class Residual_block(nn.Module):
    """
    Define Residual_block

    注意:残差块的输入输出需要一致
    """
    def __init__(self, hidden_unit, dim_stack):
        super(Residual_block, self).__init__()
        # 两个线性层   注意维度, 输出的时候和输入的那个维度一致, 这样才能保证后面的相加
        self.linear1 = nn.Linear(dim_stack, hidden_unit)
        self.linear2 = nn.Linear(hidden_unit, dim_stack)
        self.relu = nn.ReLU()

    def forward(self, x):
        orig_x = x.clone()
        x = self.relu(self.linear1(x))
        x = self.linear2(x)
        outputs = self.relu(x + orig_x)
        return outputs


# 定义deep Crossing 网络
class DeepCrossing(nn.Module):

    def __init__(self, feature_info, hidden_units, dropout=0., embed_dim=10, output_dim=1):
        """
        DeepCrossing:
            feature_info: 特征信息(数值特征, 类别特征, 类别特征embedding映射)
            hidden_units: 列表, 隐藏单元的个数(多层残差那里的)
            dropout: Dropout层的失活比例
            embed_dim: embedding维度
        """
        super(DeepCrossing, self).__init__()
        self.dense_features, self.sparse_features, self.sparse_features_map = feature_info

        # embedding层, 这里需要一个列表的形式, 因为每个类别特征都需要embedding
        self.embed_layers = nn.ModuleDict(
            {
                'embed_' + str(key): nn.Embedding(num_embeddings=val, embedding_dim=embed_dim)
                for key, val in self.sparse_features_map.items()
            }
        )

        # 统计embedding_dim的总维度
        # 一个离散型(类别型)变量 通过embedding层变为10纬
        embed_dim_sum = sum([embed_dim] * len(self.sparse_features))

        # stack layers的总维度 = 数值型特征的纬度 + 离散型变量经过embedding后的纬度
        dim_stack = len(self.dense_features) + embed_dim_sum

        # 残差层
        self.res_layers = nn.ModuleList([
            Residual_block(unit, dim_stack) for unit in hidden_units
        ])

        # dropout层
        self.res_dropout = nn.Dropout(dropout)

        # 线性层
        self.linear = nn.Linear(dim_stack, output_dim)

    def forward(self, x):
        # 1、首先得先把输入向量x分成两部分处理、因为数值型和类别型的处理方式不一样, 类别型经过embedding, 数值型是直接进入stacking。
        dense_inputs, sparse_inputs = x[:, :len(self.dense_features)], x[:, len(self.dense_features):]
        # 需要转成长张量,这个是embedding的输入要求格式
        sparse_inputs = sparse_inputs.long()
        # 2、不同的类别特征分别embedding
        sparse_embeds = [
            self.embed_layers['embed_' + key](sparse_inputs[:, i]) for key, i in
            zip(self.sparse_features_map.keys(), range(sparse_inputs.shape[1]))
        ]
        # 3、把类别型特征进行拼接,即emdedding后,转换为一行
        sparse_embed = torch.cat(sparse_embeds, axis=-1)
        # 4、数值型和类别型拼接, 这就是stacking层的任务
        stack = torch.cat([sparse_embed, dense_inputs], axis=-1)
        r = stack
        # 5、经过残差网络
        for res in self.res_layers:
            r = res(r)
        # 6、dropout减轻过拟合、sigmoid激活输出
        r = self.res_dropout(r)
        outputs = torch.sigmoid(self.linear(r))
        return outputs



if __name__ == '__main__':

    x = torch.rand(size=(1, 5), dtype=torch.float32)
    feature_info = [
        ['I1','I2'],     # 连续性特征
        ['C1','C2','C3'],# 离散型特征
        {
         'C1': 20,
         'C2': 20,
         'C3': 20
         }
    ]

    hidden_units = [256, 128, 64, 32]
    net = DeepCrossing(feature_info, hidden_units)
    print(net)
    print(net(x))
DeepCrossing(
  (embed_layers): ModuleDict(
    (embed_C1): Embedding(20, 10)
    (embed_C2): Embedding(20, 10)
    (embed_C3): Embedding(20, 10)
  )
  (res_layers): ModuleList(
    (0): Residual_block(
      (linear1): Linear(in_features=32, out_features=256, bias=True)
      (linear2): Linear(in_features=256, out_features=32, bias=True)
      (relu): ReLU()
    )
    (1): Residual_block(
      (linear1): Linear(in_features=32, out_features=128, bias=True)
      (linear2): Linear(in_features=128, out_features=32, bias=True)
      (relu): ReLU()
    )
    (2): Residual_block(
      (linear1): Linear(in_features=32, out_features=64, bias=True)
      (linear2): Linear(in_features=64, out_features=32, bias=True)
      (relu): ReLU()
    )
    (3): Residual_block(
      (linear1): Linear(in_features=32, out_features=32, bias=True)
      (linear2): Linear(in_features=32, out_features=32, bias=True)
      (relu): ReLU()
    )
  )
  (res_dropout): Dropout(p=0.0, inplace=False)
  (linear): Linear(in_features=32, out_features=1, bias=True)
)
tensor([[0.5532]], grad_fn=<SigmoidBackward0>)

前向传播部分的逻辑:

  • 首先得先把输入向量X分成两部分处理, 因为数值型和类别型的处理方式不一样, 类别型经过embedding, 数值型是直接进入stacking。

  • 而由于Pytorch中, embedding层输入要求是long类型, 需要转一下。

    • 不熟悉embedding的可以参考Pytorch常用的函数(二)pytorch中nn.Embedding原理及使用
  • 第三行代码就是不同的类别特征分别embedding。

  • 第四行代码是把类别型特征进行拼接, 第五行代码是数值型和类别型拼接, 这就是stacking层的任务。

  • 后面就是经过残差网络, sigmoid激活输出。

1.3 总结

这里直接引用王喆老师《深度学习推荐系统》一书page63:

  • 从目前的时间节点上看,Deep Crossing模型是平淡无奇的,因为它没有引人任何诸如注意力机制、序列模型等特殊的模型结构,只是采用了常规的“Embedding+多层神经网络”的经典深度学习结构。

  • 但从历史的尺度看,DeepCrossing模型的出现是有革命意义的。Deep Crossing模型中没有任何人工特征工程的参与,原始特征经Embedding后输入神经网络层,将全部特征交叉的任务交给模型。相比之前介绍的 FM、FFM 模型只具备二阶特征交叉的能力,DeepCrossing模型可以通过调整神经网络的深度进行特征之间的“深度交叉”,这也是 Deep Crossing名称的由来。

2 Deep Crossing在Criteo数据集的应用

Criteo数据集是非常经典的点击率预估比赛。训练集4千万行,特征连续型的有13个,类别型的26个,没有提供特征名称,样本按时间排序。测试集6百万行。

数据集下载地址:https://www.kaggle.com/datasets/mrkmakr/criteo-dataset

由于数据量太大, 为了在单机上能够运行,因此做了采样,取了很少的一部分进行实验。

2.1 数据预处理

import pandas as pd
from sklearn.preprocessing import MinMaxScaler, LabelEncoder
from sklearn.model_selection import train_test_split


train_df = pd.read_csv('./data/train.csv')
test_df = pd.read_csv('./data/test.csv')


print(train_df.shape)
print(test_df.shape) # 少了Label这一列
train_df.head()

在这里插入图片描述

# 将训练集和测试集进行合并,方便进行特征的预处理工作
label = train_df['Label']
del train_df['Label']

data_df = pd.concat((train_df, test_df))

del data_df['Id']

data_df.columns
Index(['I1', 'I2', 'I3', 'I4', 'I5', 'I6', 'I7', 'I8', 'I9', 'I10', 'I11',
       'I12', 'I13', 'C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7', 'C8', 'C9',
       'C10', 'C11', 'C12', 'C13', 'C14', 'C15', 'C16', 'C17', 'C18', 'C19',
       'C20', 'C21', 'C22', 'C23', 'C24', 'C25', 'C26'],
      dtype='object')
# C开头是为类别特征
sparse_feas = [col for col in data_df.columns if col[0] == 'C']

# I开头是为连续型特征
dense_feas = [col for col in data_df.columns if col[0] == 'I']
# 1、填充缺失值

# 类别特征填充为-1
data_df[sparse_feas] = data_df[sparse_feas].fillna('-1')
# 连续特征填充为0
data_df[dense_feas] = data_df[dense_feas].fillna(0)



# 2、对类别特征进行LabelEncoder编码(而非one-hot编码)
for feat in sparse_feas:
    le = LabelEncoder()
    data_df[feat] = le.fit_transform(data_df[feat])

data_df[sparse_feas].head()

在这里插入图片描述

# 3、对于连续性变量进行归一化

mms = MinMaxScaler()
data_df[dense_feas] = mms.fit_transform(data_df[dense_feas])

data_df[dense_feas].head()

在这里插入图片描述

# 处理后,再分为训练集和测试集

train = data_df[:train_df.shape[0]]
test = data_df[train_df.shape[0]:]

train['Label'] = label


# 对于训练数据集,划分为训练集及验证集
train_set, val_set = train_test_split(train, test_size = 0.2, random_state=2023)

# 统计
train_set['Label'].value_counts()
val_set['Label'].value_counts()

在这里插入图片描述

# 保存预处理后的文件,方便以后其他的推荐模型直接使用
train_set.reset_index(drop=True, inplace=True)
val_set.reset_index(drop=True, inplace=True)

train_set.to_csv('preprocessed_data/train_set.csv', index=0)
val_set.to_csv('preprocessed_data/val_set.csv', index=0)
test.to_csv('preprocessed_data/test.csv', index=0)

2.2 准备训练数据

import datetime
import pandas as pd

import torch
from torch.utils.data import TensorDataset, Dataset, DataLoader

import torch.nn as nn
import torch.nn.functional as F


# pip install torchkeras
from torchkeras import summary

from sklearn.metrics import auc, roc_auc_score, roc_curve

import warnings
warnings.filterwarnings('ignore')
# 封装为函数
def prepared_data(file_path):
    # 读入训练集,验证集和测试集
    train_set = pd.read_csv(file_path + 'train_set.csv')
    val_set = pd.read_csv(file_path + 'val_set.csv')
    test_set = pd.read_csv(file_path + 'test.csv')

    # 这里需要把特征分成数值型和离散型
    # 因为后面的模型里面离散型的特征需要embedding, 而数值型的特征直接进入了stacking层, 处理方式会不一样
    data_df = pd.concat((train_set, val_set, test_set))

    # 数值型特征直接放入stacking层
    dense_features = ['I' + str(i) for i in range(1, 14)]
    # 离散型特征需要需要进行embedding处理
    sparse_features = ['C' + str(i) for i in range(1, 27)]

    # 定义一个稀疏特征的embedding映射, 字典{key: value},
    # key表示每个稀疏特征, value表示数据集data_df对应列的不同取值个数, 作为embedding输入维度
    sparse_feas_map = {}
    for key in sparse_feas:
        sparse_feas_map[key] = data_df[key].nunique()


    feature_info = [dense_features, sparse_features, sparse_feas_map]  # 这里把特征信息进行封装, 建立模型的时候作为参数传入

    # 把数据构建成数据管道
    dl_train_dataset = TensorDataset(
        # 特征信息
        torch.tensor(train_set.drop(columns='Label').values).float(),
        # 标签信息
        torch.tensor(train_set['Label'].values).float()
    )

    dl_val_dataset = TensorDataset(
        # 特征信息
        torch.tensor(val_set.drop(columns='Label').values).float(),
        # 标签信息
        torch.tensor(val_set['Label'].values).float()
    )
    dl_train = DataLoader(dl_train_dataset, shuffle=True, batch_size=16)
    dl_vaild = DataLoader(dl_val_dataset, shuffle=True, batch_size=16)
    return feature_info,dl_train,dl_vaild,test_set
# 保存的数据
file_path = './preprocessed_data/'

feature_info,dl_train,dl_vaild,test_set = prepared_data(file_path)

2.3 建立Deep Crossing模型

from deep_crossing import DeepCrossing

# 隐藏层
hidden_units = [256, 128, 64, 32]
# 创建DeepCrossing模型
net = DeepCrossing(feature_info, hidden_units)

summary(net, input_shape=(train_set.shape[1],))
--------------------------------------------------------------------------
Layer (type)                            Output Shape              Param #
==========================================================================
Embedding-1                                 [-1, 10]                  790
Embedding-2                                 [-1, 10]                2,520
Embedding-3                                 [-1, 10]               12,930
Embedding-4                                 [-1, 10]               10,430
Embedding-5                                 [-1, 10]                  300
Embedding-6                                 [-1, 10]                   70
Embedding-7                                 [-1, 10]               11,640
Embedding-8                                 [-1, 10]                  390
Embedding-9                                 [-1, 10]                   20
Embedding-10                                [-1, 10]                9,080
Embedding-11                                [-1, 10]                9,260
Embedding-12                                [-1, 10]               12,390
Embedding-13                                [-1, 10]                8,240
Embedding-14                                [-1, 10]                  200
Embedding-15                                [-1, 10]                8,190
Embedding-16                                [-1, 10]               11,590
Embedding-17                                [-1, 10]                   90
Embedding-18                                [-1, 10]                5,340
Embedding-19                                [-1, 10]                2,010
Embedding-20                                [-1, 10]                   40
Embedding-21                                [-1, 10]               12,040
Embedding-22                                [-1, 10]                   70
Embedding-23                                [-1, 10]                  120
Embedding-24                                [-1, 10]                7,290
Embedding-25                                [-1, 10]                  330
Embedding-26                                [-1, 10]                5,540
Linear-27                                  [-1, 256]               70,144
ReLU-28                                    [-1, 256]                    0
Linear-29                                  [-1, 273]               70,161
ReLU-30                                    [-1, 273]                    0
Linear-31                                  [-1, 128]               35,072
ReLU-32                                    [-1, 128]                    0
Linear-33                                  [-1, 273]               35,217
ReLU-34                                    [-1, 273]                    0
Linear-35                                   [-1, 64]               17,536
ReLU-36                                     [-1, 64]                    0
Linear-37                                  [-1, 273]               17,745
ReLU-38                                    [-1, 273]                    0
Linear-39                                   [-1, 32]                8,768
ReLU-40                                     [-1, 32]                    0
Linear-41                                  [-1, 273]                9,009
ReLU-42                                    [-1, 273]                    0
Dropout-43                                 [-1, 273]                    0
Linear-44                                    [-1, 1]                  274
==========================================================================
Total params: 394,836
Trainable params: 394,836
Non-trainable params: 0
--------------------------------------------------------------------------
Input size (MB): 0.000153
Forward/backward pass size (MB): 0.028061
Params size (MB): 1.506180
Estimated Total Size (MB): 1.534393
--------------------------------------------------------------------------
# 测试一下模型
for feature, label in iter(dl_train):
    out = net(feature)
    print(out)
    break

2.4 模型的训练

# 导入的这两个类可以参考
# https://blog.csdn.net/qq_44665283/article/details/130598697?spm=1001.2014.3001.5502
from AnimatorClass import Animator
from TimerClass import Timer


# 模型的相关设置
def metric_func(y_pred, y_true):
    pred = y_pred.data
    y = y_true.data
    return roc_auc_score(y, pred)


def try_gpu(i=0):
    if torch.cuda.device_count() >= i + 1:
        return torch.device(f'cuda:{i}')
    return torch.device('cpu')

# 封装为函数,方便其他推荐模型进行复用
def train_ch(net, dl_train, dl_vaild, num_epochs, lr, device):
    """⽤GPU训练模型"""
    print('training on', device)
    net.to(device)
    # 二值交叉熵损失
    loss_func = nn.BCELoss()
    optimizer = torch.optim.Adam(params=net.parameters(), lr=lr)

    animator = Animator(xlabel='epoch', xlim=[1, num_epochs],legend=['train loss', 'train auc', 'test loss', 'test auc']
                        ,figsize=(8.0, 6.0))
    timer, num_batches = Timer(), len(dl_train)
    log_step_freq = 10

    for epoch in range(1, num_epochs + 1):
        # 训练阶段
        net.train()
        loss_sum = 0.0
        metric_sum = 0.0
        step = 1

        for step, (features, labels) in enumerate(dl_train, 1):
            timer.start()
            # 梯度清零
            optimizer.zero_grad()

            # 正向传播
            predictions = net(features)
            loss = loss_func(predictions, labels.unsqueeze(1) )
            try:          # 这里就是如果当前批次里面的y只有一个类别, 跳过去
                metric = metric_func(predictions, labels)
            except ValueError:
                pass

            # 反向传播求梯度
            loss.backward()
            optimizer.step()
            timer.stop()

            # 打印batch级别日志
            loss_sum += loss.item()
            metric_sum += metric.item()

            if step % log_step_freq == 0:
                animator.add(epoch + step / num_batches,(loss_sum/step, metric_sum/step, None, None))

        # 验证阶段
        net.eval()
        val_loss_sum = 0.0
        val_metric_sum = 0.0
        val_step = 1

        for val_step, (features, labels) in enumerate(dl_vaild, 1):
            with torch.no_grad():
                predictions = net(features)
                val_loss = loss_func(predictions, labels.unsqueeze(1))
                try:
                    val_metric = metric_func(predictions, labels)
                except ValueError:
                    pass

            val_loss_sum += val_loss.item()
            val_metric_sum += val_metric.item()

            if val_step % log_step_freq == 0:
                animator.add(epoch + val_step / num_batches, (None,None,val_loss_sum / val_step , val_metric_sum / val_step))

        print(f'loss {loss_sum/len(dl_train):.3f}, auc {metric_sum/len(dl_train):.3f},'
              f' val loss {val_loss_sum/len(dl_vaild):.3f}, val auc {val_metric_sum/len(dl_vaild):.3f}')
        print(f'{num_batches * num_epochs / timer.sum():.1f} examples/sec on {str(device)}')
lr, num_epochs = 0.001, 4
train_ch(net, dl_train, dl_vaild, num_epochs, lr, try_gpu())

在这里插入图片描述

2.5 模型的预测

y_pred_probs = net(torch.tensor(test_set.values).float())
y_pred = torch.where(
    y_pred_probs>0.5,
    torch.ones_like(y_pred_probs),
    torch.zeros_like(y_pred_probs)
)
y_pred.data[:10]

2.6 模型的保存与加载

# 模型的保存与使用
torch.save(net.state_dict(), './model/net_parameter.pkl')

# 创建模型
net_clone = DeepCrossing(feature_info, hidden_units)

# 加载模型
net_clone.load_state_dict(torch.load('./model/net_parameter.pkl'))

# 进行预测
y_pred_probs = net_clone(torch.tensor(test_set.values).float())

y_pred = torch.where(
    y_pred_probs>0.5,
    torch.ones_like(y_pred_probs),
    torch.zeros_like(y_pred_probs)
)
y_pred.data[:10]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/952146.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【数据分享】2000-2020年全球人类足迹数据(无需转发\免费获取)

人类足迹(Human Footprint)是生态过程和自然景观变化对生态环境造成的压力&#xff0c;是世界各国对生物多样性和生态保护的关注重点。那如何才能获取长时间跨度的人类足迹时空数据呢&#xff1f; 之前我们分享了来自于中国农业大学土地科学与技术学院的城市环境监测及建模&am…

实时语义分割网络 BiSeNet , RK1126 Npu 推理

记录下在rk1126上&#xff0c;实现 BiSeNet 网络推理. https://github.com/CoinCheung/BiSeNet ONNX 生成 onnx 模型 python tools/export_onnx.py --config configs/bisenetv2_city.py --weight-path ./checkpoints/model_final_v2_city.pth --outpath ./checkpoints/mode…

每日一题(反转链表)

每日一题&#xff08;反转链表&#xff09; 206. 反转链表 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 可以定义一个新的newhead结构体指针。再定义cur指针和next指针互相配合&#xff0c;将原链表中的节点从头到尾依次头插到newhead链表中&#xff0c;同时更…

使用爬虫代码获得深度学习目标检测或者语义分割中的图片。

问题描述&#xff1a;目标检测或者图像分割需要大量的数据&#xff0c;如果手动从网上找的话会比较慢&#xff0c;这时候&#xff0c;我们可以从网上爬虫下来&#xff0c;然后自己筛选即可。 代码如下&#xff08;不要忘记安装代码依赖的库&#xff09;&#xff1a; # -*- co…

记一次特殊的HTTP 500.30

此错误比较常见&#xff0c;网上的解决方式各种各样&#xff0c;今天遇到的情况是&#xff0c;除过配置文件别的程序集都一样&#xff0c;程序部署端口不同&#xff0c;最后检查原因竟然是appsettings配置文件 key值的格式问题&#xff08;中英文字符或者空格导致&#xff0c;粘…

【两周学会FPGA】从0到1学习紫光同创FPGA开发|盘古PGL22G开发板学习之键控流水灯(三)

本原创教程由深圳市小眼睛科技有限公司创作&#xff0c;版权归本公司所有&#xff0c;如需转载&#xff0c;需授权并注明出处 适用于板卡型号&#xff1a; 紫光同创PGL22G开发平台&#xff08;盘古22K&#xff09; 一&#xff1a;盘古22K开发板&#xff08;紫光同创PGL22G开发…

Java8实战-总结17

Java8实战-总结17 引入流流操作中间操作终端操作使用流 小结 引入流 流操作 java.util.stream.Stream中的Stream接口定义了许多操作。它们可以分为两大类。再来看一下前面的例子&#xff1a; List<String> names menu.stream() //从菜单获得流 .filter(d -> d.get…

基于Java的OA办公管理系统,Spring Boot框架,vue技术,mysql数据库,前台+后台,完美运行,有一万一千字论文。

基于Java的OA办公管理系统&#xff0c;Spring Boot框架&#xff0c;vue技术&#xff0c;mysql数据库&#xff0c;前台后台&#xff0c;完美运行&#xff0c;有一万一千字论文。 系统中的功能模块主要是实现管理员和员工的管理&#xff1b; 管理员&#xff1a;个人中心、普通员工…

etcd读写请求的执行过程

etcd读请求如何执行 首先&#xff0c;etcdctl 会对命令中的参数进行解析。在解析完请求中的参数后&#xff0c;etcdctl 会创建一个 clientv3 库对象通过gRPC API来访问 etcd server。对应流程一。 然后通过负载均衡算法选择一个etcd server节点&#xff0c;然后调用 etcd ser…

Redis之管道解读

目录 基本介绍 使用例子 管道对比 管道与原生批量命令对比 管道与事务对比 使用pipeline注意事项 基准测试 基本介绍 Redis是一种基于客户端-服务端模型以及请求/响应协议的TCP服务器。 这意味着请求通常按如下步骤处理&#xff1a; 客户端发送一个请求到服务器&am…

飞天使-python的模块与包与装饰器

文章目录 模块与包标准模块第三方模块自定义模块 高级语法切片迭代器/生成器高级模式&#xff08;闭包&#xff09;高级模式&#xff08;装饰器&#xff09; 参考视频 模块与包 标准模块 import os print(os.getcwd())import sys print(sys.argv) print(sys.platform) print(…

Three.js相机参数及Z-Fighting问题的解决方案

本主题讨论透视相机以及如何为远距离环境设置合适的视锥体。 推荐&#xff1a;用 NSDT编辑器 快速搭建可编程3D场景 透视相机是一种投影模式&#xff0c;旨在模仿人类在现实世界中看待事物的方式。 这是渲染 3D 场景最常用的投影模式。 - three.js 如果你看一下 Three.js 文档…

十四、组合模式

一、什么是组合模式 组合&#xff08;Composite Pattern&#xff09;模式的定义&#xff1a;有时又叫作整体-部分&#xff08;Part-Whole&#xff09;模式&#xff0c;它是一种将对象组合成树状的层次结构的模式&#xff0c;用来表示“整体-部分”的关系&#xff0c;使用户对单…

极限五分钟,在宝塔中用 Docker 部署升讯威在线客服系统

最近客服系统成功经受住了客户现场组织的压力测试&#xff0c;获得了客户的认可。 客户组织多名客服上线后&#xff0c;所有员工同一时间打开访客页面疯狂不停的给在线客服发消息&#xff0c;系统稳定无异常无掉线&#xff0c;客服回复消息正常。消息实时到达无任何延迟。 本文…

IDEA maven上传速度很慢、解决办法

maven上传的速度很慢&#xff0c;排除网络原因&#xff0c;需要检查配置 一、项目配置 以下针对于maven仓库不在C盘的情况&#xff1a; File | Settings | Build, Execution, Deployment | Build Tools | Maven 以IDEA为例&#xff0c;打开 File&#xff08;文件&#xff09;…

【Vue3+Ts】项目启动准备和配置项目代码规范和css样式的重置

项目启动准备 创建项目&#xff08; 使用Vite 构建工具创建项目模板&#xff09;目录介绍插件安装创建别名编译说明项目配置配置icon和标题配置项目别名配置ts.config.json检测vscode的插件是否配置 配置项目代码规范集成editorconfig配置prettier工具库ESLint检测配置 CSS样式…

软件测试/测试开发丨Selenium 高级定位 Xpath

点此获取更多相关资料 本文为霍格沃兹测试开发学社学员学习笔记分享 原文链接&#xff1a;https://ceshiren.com/t/topic/27036 一、xpath 基本概念 XPATH是一门在XML文档中查找信息的语言 XPATH使用路径表达式在XML文档中进行导航 XPATH的应用非常广泛&#xff0c;可以用于UI自…

使用Visual Studio 2022实现透明按钮和标签、POPUP样式窗体的一种工业系统的UI例程

例程实现的功能说明 1、主窗体采用POPUP样式&#xff0c;无标题栏、无菜单栏&#xff0c;适合工业类软件 2、按钮、标签使用自绘&#xff0c;实现透明样式&#xff0c;可以实现灵活的样式设计&#xff0c;更具设计感 按钮重绘函数&#xff1a;OnDrawItem()按钮样式设定&#…

微软 Turing Bletchley v3视觉语言模型更新:必应搜索图片更精准

据微软新闻稿透露&#xff0c;在推出第三代Turing Bletchley视觉语言模型后&#xff0c;微软计划逐步将其整合到Bing等相关产品中&#xff0c;以提供更出色的图像搜索体验。这款模型最初于2021年11月面世&#xff0c;并在2022年秋季开始邀请用户测试。 凭借用户的反馈和建议&am…

Spring Boot 中 Nacos 配置中心使用实战

官方参考文档 https://nacos.io/zh-cn/docs/quick-start-spring-boot.html 本人实践 1、新建一个spring boot项目 我的spirngboot版本为2.5.6 2、添加一下依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-…