当前位置: 首页 > news >正文

在 AMD GPU 上构建深度学习推荐模型

Deep Learning Recommendation Models on AMD GPUs — ROCm Blogs

2024 年 6 月 28 日 发布者 Phillip Dang

在这篇博客中,我们将演示如何在支持 ROCm 的 AMD GPU 上使用 PyTorch 构建一个简单的深度学习推荐模型 (DLRM)。

简介

DLRM 位于推荐系统和深度学习的交汇处,利用神经网络在庞大的数据集中预测用户与物品的交互。它是一种强大的工具,在各种领域中个性化推荐,从电子商务到内容流媒体平台。

正如 《深度学习推荐模型:个性化和推荐系统》 中讨论的那样,DLRM 具有几个组件:

  • 多个嵌入表将稀疏特征(每个特征一个)映射到密集表示。

  • 一个底部多层感知器 (MLP),将密集特征转换为与嵌入向量长度相同的密集表示。

  • 一个特征交互层,计算所有嵌入向量和处理后的密集特征之间的点积。

  • 一个顶部多层感知器 (MLP),输入交互特征与原始处理后的密集特征串联,并输出对数 (logits)。

以下图表总结了 DLRM 的架构,来自 《深度学习推荐模型:深度探究》。

Deep learning recommendation model architecture

DLRM 与其他深度学习网络的区别之一是它“在结构上以一种模仿因子分解机的方式特定地交互嵌入,通过只考虑最终 MLP 中成对嵌入之间点积产生的交叉项来显著减少模型的维度”[参考文献]。这使 DLRM 相比于其他网络如 Deep 和 Cross 大幅减少了模型的维度。

本博客强调简单性。我们将通过一个简单的数据集来预测展示广告的点击率,构建一个基本的 DLRM 架构,并为理解其内部工作原理提供坚实的基础。鼓励用户调整和扩展模型,探索更多复杂性,以适应他们的具体需求。

前提条件

  • ROCm

  • PyTorch

  • Linux 操作系统

  • An AMD GPU

确保系统识别到你的 GPU:

! rocm-smi --showproductname
================= ROCm System Management Interface ================
========================= Product Info ============================
GPU[0] : Card series: Instinct MI210
GPU[0] : Card model: 0x0c34
GPU[0] : Card vendor: Advanced Micro Devices, Inc. [AMD/ATI]
GPU[0] : Card SKU: D67301
===================================================================
===================== End of ROCm SMI Log =========================

检查是否安装了正确版本的 ROCm.

! apt show rocm-core -a 
Package: rocm-core
Version: 5.7.0.50700-63~22.04
Priority: optional
Section: devel
Maintainer: ROCm Dev Support <rocm-dev.support@amd.com>
Installed-Size: 94.2 kB
Homepage: https://github.com/RadeonOpenCompute/ROCm
Download-Size: 7030 B
APT-Manual-Installed: no
APT-Sources: http://repo.radeon.com/rocm/apt/5.7 jammy/main amd64 Packages
Description: Radeon Open Compute (ROCm) Runtime software stack

确保 PyTorch 也识别到 GPU:

import torch
print(f"number of GPUs: {torch.cuda.device_count()}")
print([torch.cuda.get_device_name(i) for i in range(torch.cuda.device_count())])
number of GPUs: 1
['AMD Radeon Graphics']

数据集

以下内容是基于原始 DLRM 论文 中介绍的,我们将使用 Criteo 数据集 来预测广告点击率 (CTR)。我们将预测用户在访问页面时点击给定广告的概率。

数据字段包含以下内容:

  • Label - 目标变量,指示广告是否被点击(1)或未被点击(0)。

  • I1-I13 - 一共13列整数特征(主要是计数特征)。

  • C1-C26 - 一共26列分类特征。这些特征的值已被哈希成32位以进行匿名化处理。

这些特征的具体语义未被披露,这在匿名化数据集中是常见的做法,以保护隐私和专有信息。为方便起见,我们已经下载了数据并将其包含在我们的代码库中。让我们安装和导入所需的库,并加载数据集。

! pip install --upgrade pip
! pip install --upgrade pandas
! pip install --upgrade scikit-learn

import torch
import torch.nn as nn
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder, MinMaxScaler
from torch.utils.data import DataLoader, TensorDataset
from tqdm import tqdm

columns = ["label", *(f"I{i}" for i in range(1, 14)), *(f"C{i}" for i in range(1, 27))]
df = pd.read_csv("../data/dac_sample.txt", sep="\t", names=columns
).fillna(0)

预处理

我们的预处理步骤包括对稀疏和类别特征进行序数编码,并对密集和数值特征进行最小-最大缩放。

sparse_cols = ["C" + str(i) for i in range(1, 27)]
dense_cols = ["I" + str(i) for i in range(1, 14)]data = df[sparse_cols + dense_cols]
data = data.astype(str)
for feat in sparse_cols:lbe = LabelEncoder()data[feat] = lbe.fit_transform(data[feat])
mms = MinMaxScaler(feature_range=(0, 1))
data[dense_cols] = mms.fit_transform(data[dense_cols])
print(data.sample(5))
C1	C2	C3	C4	C5	C6	C7	C8	C9	C10	...	I4	I5	I6	I7	I8	I9	I10	I11	I12	I13
33714	8	289	12798	19697	23	10	2279	86	2	2505	...	0.000000	0.001729	0.013812	0.000000	0.000000	0.001027	0.000000	0.000000	0.0	0.000000
41376	8	21	6057	20081	23	5	6059	27	2	2505	...	0.011990	0.002585	0.008840	0.000795	0.001283	0.020220	0.000000	0.028846	0.0	0.000762
21202	8	62	23836	24608	41	5	2305	8	2	2933	...	0.004796	0.000136	0.002701	0.000568	0.005987	0.003633	0.166667	0.019231	0.0	0.003355
89866	8	113	42768	7421	23	11	827	48	2	2505	...	0.002398	0.000118	0.000491	0.000114	0.002138	0.002133	0.166667	0.009615	0.0	0.000152
19993	327	78	31306	11660	23	0	6837	27	2	8905	...	0.007194	0.001740	0.001105	0.002612	0.001497	0.002448	0.000000	0.038462	0.0	0.000457

我们还移除了一些类别数过多的稀疏特征,在这个数据集中大约有10,000个类别。按照Kaggle的社区讨论中的推荐,当稀疏特征的类别数超过了10,000时,模型性能的提升是微乎其微的,而且这只会不必要地增加参数的数量。

# 获取每个分类特征的类别数
num_categories = [len(data[c].unique()) for c in sparse_cols]# 只保留类别数少于10K的分类特征
indices_to_keep = [i for i, num in enumerate(num_categories) if num <= 10000]
num_categories_kept = [num_categories[i] for i in indices_to_keep]
sparse_cols_kept = [sparse_cols[i] for i in indices_to_keep]

最后,我们将数据拆分为训练集和测试集,然后将它们转换成 torch 张量并创建相应的数据加载器。

device = "cuda" if torch.cuda.is_available() else "cpu"
batch_size = 128# 拆分数据集
X_train, X_test, y_train, y_test = train_test_split(data, df["label"], test_size=0.2, random_state=42
)# 转换成张量
# 训练集
X_train_sparse = torch.tensor(X_train[sparse_cols_kept].values, dtype=torch.long).to(device
)
X_train_dense = torch.tensor(X_train[dense_cols].values, dtype=torch.float).to(device)
y_train = torch.tensor(y_train.values, dtype=torch.float).unsqueeze(1).to(device)# 测试集
X_test_sparse = torch.tensor(X_test[sparse_cols_kept].values, dtype=torch.long).to(device)
X_test_dense = torch.tensor(X_test[dense_cols].values, dtype=torch.float).to(device)
y_test = torch.tensor(y_test.values, dtype=torch.float).unsqueeze(1).to(device)# 创建训练数据的DataLoader 
train_dataset = TensorDataset(X_train_sparse, X_train_dense, y_train)
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
# 创建测试数据的DataLoader
test_dataset = TensorDataset(X_test_sparse, X_test_dense, y_test)
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)

建模

让我们为我们的DLRM设置一些超参数:

device = "cuda" if torch.cuda.is_available() else "cpu"
num_epochs = 10
lr = 3e-4
batch_size = 128
hidden_size = 32
embd_dim = 16

现在我们准备创建我们的DLRM。为了简化,底部和顶部的MLP将是一个简单的3层(输入、隐藏、输出)神经网络,并使用ReLU激活函数。

class FeatureInteraction(nn.Module):def __init__(self):super(FeatureInteraction, self).__init__()def forward(self, x):feature_dim = x.shape[1]concat_features = x.view(-1, feature_dim, 1)dot_products = torch.matmul(concat_features, concat_features.transpose(1, 2))ones = torch.ones_like(dot_products)mask = torch.triu(ones)out_dim = feature_dim * (feature_dim + 1) // 2flat_result = dot_products[mask.bool()]reshape_result = flat_result.view(-1, out_dim)return reshape_resultclass DLRM(torch.nn.Module):def __init__(self,embd_dim,num_categories,num_dense_feature,hidden_size,):super(DLRM, self).__init__()# 为每个分类特征创建具有相同嵌入维度的嵌入self.embeddings = nn.ModuleList([nn.Embedding(num_cat, embd_dim) for num_cat in num_categories])self.feat_interaction = FeatureInteraction()self.bottom_mlp = nn.Sequential(nn.Linear(in_features=num_dense_feature, out_features=hidden_size),nn.ReLU(),nn.Linear(hidden_size, embd_dim),)num_feat = (len(num_categories) * embd_dim + embd_dim)  # 包括分类特征和数值特征num_feat_interact = num_feat * (num_feat + 1) // 2  # interaction featurestop_mlp_in = (num_feat_interact + embd_dim)  # 交互特征与数值特征连接self.top_mlp = nn.Sequential(nn.Linear(in_features=top_mlp_in, out_features=hidden_size),nn.ReLU(),nn.Linear(hidden_size, 1),)def forward(self, x_cat, x_num):B = x_cat.shape[0]num_sparse_feat = x_cat.shape[1]# 查找分类特征的嵌入embed_x = torch.concat([self.embeddings[i](x_cat[:, i]).unsqueeze(1)for i in range(num_sparse_feat)])  # B, num_sparse_feat, embedding dimembed_x = embed_x.view(B, -1)  # B, num_sparse_feat * embedding dim# 获取底部的数值特征dense_x = self.bottom_mlp(x_num)  # B, embedding dim# 与嵌入连接x = torch.concat([embed_x, dense_x], dim=-1)  # B, (num_sparse_feat+1) * embedding dim# 获取二阶交互特征x = self.feat_interaction(x)  # B, n*(n+1) // 2# 与数值特征结合x = torch.concat([x, dense_x], dim=-1)# 通过顶部MLPx = self.top_mlp(x)  # B, 1return x

让我们实例化我们的模型,并定义我们的损失函数和优化器。

# 实例化模型、损失函数和优化器
model = DLRM(embd_dim=embd_dim,num_categories=num_categories_kept,num_dense_feature=len(dense_cols),hidden_size=hidden_size,
)
model.to(device)
criterion = torch.nn.BCEWithLogitsLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=lr)print(f"running on {device}")
print(sum(p.numel() for p in model.parameters()) / 1e6, "M parameters")
print(model)

输出示例:

running on cuda
2.195553 M parameters
DLRM((embeddings): ModuleList((0): Embedding(541, 16)(1): Embedding(497, 16)(2): Embedding(145, 16)(3): Embedding(12, 16)(4): Embedding(7623, 16)(5): Embedding(257, 16)(6): Embedding(3, 16)(7): Embedding(3799, 16)(8): Embedding(2796, 16)(9): Embedding(26, 16)(10): Embedding(5238, 16)(11): Embedding(10, 16)(12): Embedding(2548, 16)(13): Embedding(1303, 16)(14): Embedding(4, 16)(15): Embedding(11, 16)(16): Embedding(14, 16)(17): Embedding(51, 16)(18): Embedding(9527, 16))(feat_interaction): FeatureInteraction()(bottom_mlp): Sequential((0): Linear(in_features=13, out_features=32, bias=True)(1): ReLU()(2): Linear(in_features=32, out_features=16, bias=True))(top_mlp): Sequential((0): Linear(in_features=51376, out_features=32, bias=True)(1): ReLU()(2): Linear(in_features=32, out_features=1, bias=True))
)

训练

接下来,让我们编写两个工具函数,一个用于模型训练,一个用于在训练集和测试集上的模型评估。

def train_one_epoch():model.train()for i, (x_sparse, x_dense, y) in enumerate(tqdm(train_loader)):x_sparse = x_sparse.to(device)x_dense = x_dense.to(device)y = y.to(device)optimizer.zero_grad()logits = model(x_sparse, x_dense)loss = criterion(logits, y)loss.backward()optimizer.step()
def evaluate(dataloader, dataname):model.eval()total_samples = 0total_loss = 0total_correct = 0with torch.no_grad():for i, (x_sparse, x_dense, y) in enumerate(tqdm(dataloader)):x_sparse = x_sparse.to(device)x_dense = x_dense.to(device)y = y.to(device)logits = model(x_sparse, x_dense)probs = torch.sigmoid(logits)predictions = (probs > 0.5).long()loss = criterion(logits, y)total_loss += loss.item() * y.shape[0]total_correct += (predictions == y).sum().item()total_samples += y.shape[0]avg_loss = total_loss / total_samplesaccuracy = total_correct / total_samples * 100print(f"{dataname} accuracy = {accuracy:0.2f}%, {dataname} avg loss = {avg_loss:.6f}")return accuracy, avg_loss

现在我们准备好训练我们的模型。

for epoch in range(num_epochs):print(f"epoch {epoch+1}")train_one_epoch()evaluate(train_loader, "train")evaluate(test_loader, "test")print()
输出结果:
epoch 1
100%|██████████| 625/625 [00:06<00:00, 92.18it/s]
100%|██████████| 625/625 [00:01<00:00, 351.70it/s]
train accuracy = 77.37%, train avg loss = 0.535811
100%|██████████| 157/157 [00:00<00:00, 354.67it/s]
test accuracy = 77.14%, test avg loss = 0.538407...epoch 10
100%|██████████| 625/625 [00:06<00:00, 98.00it/s]
100%|██████████| 625/625 [00:01<00:00, 351.16it/s]
train accuracy = 77.48%, train avg loss = 0.498510
100%|██████████| 157/157 [00:00<00:00, 352.91it/s]
test accuracy = 77.14%, test avg loss = 0.501544

推理

现在,我们已经有了一个DLRM模型,可以预测给定用户/广告组合的点击概率。由于Criteo数据集的特征语义未公开,我们无法重建代表真实用户或广告的有意义特征向量。出于说明目的,我们假设特征向量的一部分代表用户,其余的代表广告。特别是,为了简单起见,我们假设所有整数特征代表用户,所有分类特征代表广告。

假设在投放广告时,我们检索到了10个广告候选项。DLRM的任务是选择最佳广告候选项向用户展示。为了解释目的,我们假定检索到的广告候选项来自原始数据集的前10行,而用户是第一行中的用户。首先,我们创建一个数据加载器,将用户和广告特征组合起来,以供模型使用。

# 假设我们使用数据集的前10行作为广告候选项
num_ads = 10
df_c = pd.DataFrame(data.iloc[0:num_ads])
# 获取广告候选项特征
df_ads = df_c[df_c.columns[26:39]]
# 获取第一行的用户特征
df_user = df_c[df_c.columns[0:26]].iloc[0:1]
# 将用户特征复制到所有广告候选项行
df_user_rep = df_user
for i in range(num_ads-1): df_user_rep = pd.concat([df_user_rep, df_user], ignore_index=True, sort=False)
df_candidates = pd.concat([df_user_rep, df_ads], axis=1)# 将特征向量转换为张量
X_inf_sparse = torch.tensor(df_candidates[sparse_cols_kept].values, dtype=torch.long).to(device)
X_inf_dense = torch.tensor(df_candidates[dense_cols].values, dtype=torch.float).to(device)# 创建用于推理的数据加载器
y_dummy = torch.tensor([0]*num_ads, dtype=torch.float).unsqueeze(1).to(device)
inf_dataset = TensorDataset(X_inf_sparse, X_inf_dense, y_dummy)
inf_loader = DataLoader(inf_dataset, batch_size=num_ads, shuffle=True)

接下来,我们创建一个函数,该函数返回具有最高点击概率的张量的索引。

def recommend():with torch.no_grad():for i, (x_sparse, x_dense, y) in enumerate(tqdm(inf_loader)):x_sparse = x_sparse.to(device)x_dense = x_dense.to(device)logits = model(x_sparse, x_dense)probs = torch.sigmoid(logits)print(probs)return torch.max(probs, dim=0).indices[0].item()

调用这个函数将得到最佳广告候选项的索引。

print('Best ad candidate is ad', recommend())

100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 315.29it/s]
tensor([[0.1380],[0.2414],[0.3493],[0.3500],[0.1807],[0.3009],[0.2203],[0.3639],[0.1890],[0.3702]], device='cuda:0')
Best ad candidate is ad 9

我们鼓励用户进一步探索优化和超参数调优,以提高模型性能。例如,可以尝试在底部和顶部MLP中添加更多层和隐藏单元,增加嵌入维度,或者包括正则化如dropout以防止过拟合。 

讨论

在这篇博客中,我们开发了一个仅用于教育目的的小规模模型。然而,在实际应用中,模型的规模要大得多。因此,高效地并行化这些模型以应对真实世界中的挑战是至关重要的。

对于DLRM模型,大多数模型参数来自embedding表,这使得在实际应用中很难实现数据并行性,因为我们需要在每个设备上复制这些表。因此,我们需要高效地将模型分布到多个设备上以解决内存限制的问题。另一方面,底层和顶层的MLP(多层感知器)参数较少,我们可以应用数据并行性,在不同设备上同时处理多个样本。

关于如何高效地实现DLRM模型的数据并行和模型并行的更多细节,请参阅原始论文《paper》以及Meta发布的这个开源库《repo》。

相关文章:

在 AMD GPU 上构建深度学习推荐模型

Deep Learning Recommendation Models on AMD GPUs — ROCm Blogs 2024 年 6 月 28 日 发布者 Phillip Dang 在这篇博客中&#xff0c;我们将演示如何在支持 ROCm 的 AMD GPU 上使用 PyTorch 构建一个简单的深度学习推荐模型 (DLRM)。 简介 DLRM 位于推荐系统和深度学习的交汇…...

阿里云IIS虚拟主机部署ssl证书

宝塔配置SSL证书用起来是很方便的&#xff0c;只需要在站点里就可以配置好&#xff0c;但是云虚拟主机在管理的时候是没有这个权限的&#xff0c;只提供了简单的域名管理等信息。 此处记录下阿里云&#xff08;原万网&#xff09;的IIS虚拟主机如何配置部署SSL证书。 进入虚拟…...

Python运算符列表

运算符 描述 xy&#xff0c;x—y 加、减,“"号可重载为连接符 x*y,x*&#xff0a;y&#xff0c;x/y,x&#xff05;y 相乘、求平方、相除、求余&#xff0c;“*”号可重载为重复&#xff0c;“&#xff05;"号可重载为格式化 <&#xff0c;<&#xff0c;&…...

MFC图形函数学习09——画多边形函数

这里所说的多边形是指在同一平面中由多条边构成的封闭图形&#xff0c;强调封闭二字&#xff0c;否则无法进行颜色填充&#xff0c;多边形包括凸多边形和凹多边形。 一、绘制多边形函数 原型&#xff1a;BOOL Polygon(LPPOINT lpPoints,int nCount); 参数&#x…...

GaussianDreamer: Fast Generation from Text to 3D Gaussians——点云论文阅读(11)

此内容是论文总结&#xff0c;重点看思路&#xff01;&#xff01; 文章概述 本文提出了一种快速从文本生成3D资产的新方法&#xff0c;通过结合3D高斯点表示、3D扩散模型和2D扩散模型的优势&#xff0c;实现了高效生成。该方法利用3D扩散模型生成初始几何&#xff0c;通过噪声…...

k8s篇之控制器类型以及各自的适用场景

1. k8s中控制器介绍 在 Kubernetes 中,控制器(Controller)是集群中用于管理资源的关键组件。 它们的核心作用是确保集群中的资源状态符合用户的期望,并在需要时自动进行调整。 Kubernetes 提供了多种不同类型的控制器,每种控制器都有其独特的功能和应用场景。 2. 常见的…...

Node.js 笔记(一):express路由

代码 建立app.js文件&#xff0c;代码如下&#xff1a; const express require(express) const app express() const port 3002app.get(/,(req,res)>{res.send(hello world!)})app.listen(port,()>{console.log(sever is running on http://localhost:${port}) })问…...

bash笔记

0 $0 是脚本的名称&#xff0c;$# 是传入的参数数量&#xff0c;$1 是第一个参数&#xff0c;$BOOK_ID 是变量BOOK_ID的内容 1 -echo用于在命令窗口输出信息 -$()&#xff1a;是命令替换的语法。$(...) 会执行括号内的命令&#xff0c;并将其输出捕获为一个字符串&#xff…...

mongoDB副本集搭建-docker

MongoDB副本集搭建-docker 注&#xff1a;在进行副本集搭建前&#xff0c;请先将服务部署docker环境并正常运行。 #通过--platform指定下载镜像的系统架构 在这我用的是mongo:4.0.28版本 arm64系统架构的mongo镜像 docker pull --platformlinux/arm64 mongo:4.0.2#查看镜像是…...

Python软体中使用 Flask 或 FastAPI 搭建简单 RESTful API 服务并实现限流功能

Python软体中使用 Flask 或 FastAPI 搭建简单 RESTful API 服务并实现限流功能 引言 在现代 web 开发中,RESTful API 已成为应用程序之间进行通信的标准方式。Python 提供了多种框架来帮助开发者快速搭建 RESTful API 服务,其中 Flask 和 FastAPI 是最受欢迎的两个框架。本…...

CentOS操作系统下安装Nacos

CentOS下安装Nacos 前言 这在Centos下安装配置Nacos 下载Linux版Nacos 首先到Nacos的 Github页面&#xff0c;找到所需要安装的版本 也可以右键复制到链接&#xff0c;然后通过wget命令进行下载 wget https://github.com/alibaba/nacos/releases/download/1.3.2/nacos-ser…...

C++设计模式之适配器模式与桥接模式,装饰器模式及代理模式相似点与不同点

适配器模式、桥接模式、装饰器模式和代理模式在形式上有一些相似之处&#xff0c;因为它们都涉及到对类的功能或接口的修改、增强或转换。然而&#xff0c;它们在动机和目的上有着显著的不同。以下是对这些模式相似点和不同点的清晰说明&#xff1a; 相似点&#xff1a; 结构…...

ThreadLocal 和 Caffeine 缓存是两种不同的缓存机制,它们在用途和实现上有明显的区别

ThreadLocal 和 Caffeine 缓存是两种不同的缓存机制&#xff0c;它们在用途和实现上有明显的区别&#xff1a; ThreadLocal 缓存&#xff1a; ThreadLocal 提供了线程局部变量的功能&#xff0c;每个线程可以访问自己的局部变量&#xff0c;而不会与其他线程冲突。ThreadLocal …...

Django实现智能问答助手-进一步完善

扩展 增加问答数据库&#xff0c;通过 Django Admin 添加问题和答案。实现更复杂的问答逻辑&#xff0c;比如使用自然语言处理&#xff08;NLP&#xff09;库。使用前端框架&#xff08;如 Bootstrap&#xff09;增强用户界面 1.注册模型到 Django Admin&#xff08;admin.py…...

【Linux】开发工具make/Makefile、进度条小程序

Linux 1.make/Makefile1.什么是make和Makefile&#xff1f;2.stat命令3.Makefile单个文件的写法4.Makefile多个文件的写法 2.进度条1.回车\r、换行\n2.缓冲区3.进度条1.倒计时程序2.进度条程序 1.make/Makefile 1.什么是make和Makefile&#xff1f; 一个工程中的源文件不计其…...

深度学习三大框架对比与实战:PyTorch、TensorFlow 和 Keras 全面解析

深度学习框架的对比与实践 引言 在当今深度学习领域&#xff0c;PyTorch、TensorFlow 和 Keras 是三大主流框架。它们各具特色&#xff0c;分别满足从研究到工业部署的多种需求。本文将通过清晰的对比和代码实例&#xff0c;帮助你了解这些框架的核心特点以及实际应用。 1. 深…...

Leetcode206.反转链表(HOT100)

链接&#xff1a; 我的代码&#xff1a; class Solution { public:ListNode* reverseList(ListNode* head) {ListNode* p head;ListNode*res new ListNode(-1);while(p){ListNode*k res->next;res->next p;p p->next;res->next->next k;}return res->…...

怎么做好白盒测试?

白盒测试 一、什么是白盒测试&#xff1f;二、白盒测试特点三、白盒测试的设计方法1、逻辑覆盖法1、测试设计方法—语句覆盖a、用例设计如下&#xff1a;b、语句覆盖的局限性 2、测试设计方法—判定覆盖a、测试用例如下&#xff1a;b、判定覆盖的局限性 3、测试设计方法—条件覆…...

【神经网络基础】

神经网络基础 1.损失函数1.损失函数的概念2.分类任务损失函数-多分类损失:3.分类任务损失函数-二分类损失:4.回归任务损失函数计算-MAE损失5.回归任务损失函数-MSE损失6.回归任务损失函数-Smooth L1损失 2.网络优化方法1.梯度下降算法2.反向传播算法(BP算法)3.梯度下降优化方法…...

实战 | C#中使用YoloV8和OpenCvSharp实现目标检测 (步骤 + 源码)

导 读 本文主要介绍在C#中使用YoloV8实现目标检测,并给详细步骤和代码。 详细步骤 【1】环境和依赖项。 需先安装VS2022最新版,.NetFramework8.0,然后新建项目,nuget安装 YoloSharp,YoloSharp介绍: https://github.com/dme-compunet/YoloSharp 最新版6.0.1,本文…...

debian 如何进入root

debian root默认密码, 在Debian系统中&#xff0c;安装完成后&#xff0c;默认情况下root账户是没有密码的。 你可以通过以下步骤来设置或更改root密码&#xff1a; 1.打开终端。 2.输入 sudo passwd root 命令。 3.当提示输入新的root密码时&#xff0c;输入你想要的密码…...

短视频矩阵系统:智能批量剪辑、账号管理新纪元!

在当今快节奏的数字化时代&#xff0c;短视频已经成为人们获取信息和娱乐的主要途径。 然而&#xff0c;对于创作者和企业来说&#xff0c;如何高效地管理多个短视频账号并保持内容的质量和一致性&#xff0c;成为了一个令人头疼的问题。 短视频矩阵系统就是为了解决这一难题…...

【SpringMVC - 1】基本介绍+快速入门+图文解析SpringMVC执行流程

目录 1.Spring MVC的基本介绍 2.大致分析SpringMVC工作流程 3.SpringMVC的快速入门 首先大家先自行配置一个Tomcat 文件的配置 配置 WEB-INF/web.xml 创建web/login.jsp 创建com.ygd.web.UserServlet控制类 创建src下的applicationContext.xml文件 重点的注意事项和说明…...

vitepress博客模板搭建

vitepress博客搭建 个人博客技术栈更新&#xff0c;快速搭建一个vitepress自定义博客 建议去博客查看文章&#xff0c;观感更佳。原文地址 模板仓库&#xff1a; vitepress-blog-template 前言 服务器过期快一年了&#xff0c;博客也快一年没更新了&#xff0c;最近重新搭…...

Git入门图文教程 -- 深入浅出 ( 保姆级 )

01、认识一下Git&#xff01;—简介 Git是当前最先进、最主流的分布式版本控制系统&#xff0c;免费、开源&#xff01;核心能力就是版本控制。再具体一点&#xff0c;就是面向代码文件的版本控制&#xff0c;代码的任何修改历史都会被记录管理起来&#xff0c;意味着可以恢复…...

Linux编辑器 - vim

目录 一、vim 的基本概念 1. 正常/普通/命令模式(Normal mode) 2. 插入模式(Insert mode) 3. 末行模式(last line mode) 二、vim 的基本操作 三、vim 正常模式命令集 1. 插入模式 2. 移动光标 3. 删除文字 4. 复制 5. 替换 6. 撤销上一次操作 7. 更改 8. 调至指定…...

Spring Security使用基本认证(Basic Auth)保护REST API

基本认证概述 基本认证&#xff08;Basic Auth&#xff09;是保护REST API最简单的方式之一。它通过在HTTP请求头中携带Base64编码过的用户名和密码来进行身份验证。由于基本认证不使用cookie&#xff0c;因此没有会话或用户登出的概念&#xff0c;这意味着每次请求都必须包含…...

MySQL —— explain 查看执行计划与 MySQL 优化

文章目录 explain 查看执行计划explain 的作用——查看执行计划explain 查看执行计划返回信息详解表的读取顺序&#xff08;id&#xff09;查询类型&#xff08;select_type&#xff09;数据库表名&#xff08;table&#xff09;联接类型&#xff08;type&#xff09;可用的索引…...

出海第一步:搞定业务系统的多区域部署

出海的企业越来越多&#xff0c;他们不约而同开始在全球范围内部署应用程序。这样做的原因有很多&#xff0c;例如降低延迟&#xff0c;改善用户体验&#xff1b;满足一些国家或地区的数据隐私法规与合规要求&#xff1b;通过在全球范围内部署应用程序来提高容灾能力和可用性&a…...

二手手机回收小程序,一键便捷高效回收

随着科技的不断升级&#xff0c;智能手机也在快速进行更新换代&#xff0c;出现了大量的闲置手机&#xff0c;这为二手手机市场提供了巨大的发展空间&#xff01; 经过手机回收市场的快速发展&#xff0c;二手手机回收已经成为了消费者的新选择&#xff0c;既能够减少手机的浪…...

阿里 网站备案核验单/网站怎么做出来的

下载地址 https://www.consul.io/downloads windows上安装consul 下载完成后解压只有一个consul.exe文件&#xff0c;双击运行&#xff0c;查看版本号信息 开发模式启动 可以通过以下地址访问consul的首页 http://localhost:8500/ui/dc1/services...

网站模板后台怎么做/百度seo排名培训优化

jenkins默认的邮件通知 我先讲解下&#xff0c;默认的。 jenkins默认就有一个邮件通知&#xff0c;只是太简单的&#xff0c;不能个性化或者说定制化。 设置系统管理员邮件地址 邮件通知 ①SMTP服务器&#xff1a;如果你使用的是公司邮箱&#xff0c;那么就询问你自己公司里的运…...

石家庄网站建设平台有哪些/百度推广怎么才能效果好

文章目录套接字相关接口&#xff08;一&#xff09;创建套接字socket&#xff08;二&#xff09;套接字地址&#xff08;三&#xff09;命名套接字bind&#xff08;四&#xff09;创建监听队列&#xff08;套接字队列&#xff09;listen&#xff08;五&#xff09;接收连接acce…...

团队做网站的收获/58黄页网推广公司

今天来点数据吧&#xff0c; 不过我觉得收集数据确实是枯燥无味的工作&#xff0c; 我看资料的时候&#xff0c; 经理过来问你今天打的电话好少哟。。。无语&#xff0c;本来拿了一百份&#xff0c; 不过到现在统计了80份&#xff0c; 实在坚持不下去了&#xff0c; 算了&#…...

网站开发工作安排/公司网站建设流程

题目&#xff1a;有n 个人围城一圈每次从1数起数到3就把那个人提出圈子&#xff0c;最后只保留一个人。输入&#xff1a; 输入人数字符串输出&#xff1a;把最后一个人所保留位置返回出来。比如你输入11 的话即有11个人 [1,2,3,4,5,6,7,8,9,10,11] 。返回的是7.如果输入”123a”…...

怎么创建视频号/深圳优化公司统高粱seo

如果你想查看更多 Jmeter 常用函数可以在这篇文章找找哦 https://www.cnblogs.com/poloyy/p/13291704.htm 作用 执行 BeanShell 脚本&#xff0c;并返回结果 语法格式 ${__BeanShell(123*456,name)} 参数讲解 字段含义是否必传BeanShellBeanShell 脚本yesVariable Name存储脚本…...