当前位置: 首页 > 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,本文…...

【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15

缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下&#xff1a; struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...

遍历 Map 类型集合的方法汇总

1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...

深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法

深入浅出&#xff1a;JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中&#xff0c;随机数的生成看似简单&#xff0c;却隐藏着许多玄机。无论是生成密码、加密密钥&#xff0c;还是创建安全令牌&#xff0c;随机数的质量直接关系到系统的安全性。Jav…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)

目录 1.TCP的连接管理机制&#xff08;1&#xff09;三次握手①握手过程②对握手过程的理解 &#xff08;2&#xff09;四次挥手&#xff08;3&#xff09;握手和挥手的触发&#xff08;4&#xff09;状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...

python如何将word的doc另存为docx

将 DOCX 文件另存为 DOCX 格式&#xff08;Python 实现&#xff09; 在 Python 中&#xff0c;你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是&#xff0c;.doc 是旧的 Word 格式&#xff0c;而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

Python ROS2【机器人中间件框架】 简介

销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...

React---day11

14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store&#xff1a; 我们在使用异步的时候理应是要使用中间件的&#xff0c;但是configureStore 已经自动集成了 redux-thunk&#xff0c;注意action里面要返回函数 import { configureS…...

Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信

文章目录 Linux C语言网络编程详细入门教程&#xff1a;如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket&#xff08;服务端和客户端都要&#xff09;2. 绑定本地地址和端口&#x…...

NPOI操作EXCEL文件 ——CAD C# 二次开发

缺点:dll.版本容易加载错误。CAD加载插件时&#xff0c;没有加载所有类库。插件运行过程中用到某个类库&#xff0c;会从CAD的安装目录找&#xff0c;找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库&#xff0c;就用插件程序加载进…...