python卷积神经网络人脸识别示例实现详解
目录
一、准备
1)使用pytorch
2)安装pytorch
3)准备训练和测试资源
二、卷积神经网络的基本结构
三、代码实现
1)导入库
2)数据预处理
3)加载数据
4)构建一个卷积神经网络
5)模型训练
6)模型测试
四、测试结果
五、模型导出
1)保存模型的状态参数
2)保存完整模型
六、总结
一、准备
1)使用pytorch
为什么建议使用pytorch来构建卷积神经网络呢?因为pytorch是基于python开发的一个神经网络工具包,它已经实现了激活函数定义、权重矩阵定义、卷积计算、正向传播、反向传播、权重矩阵更新等神经网络的基本操作,而不需要我们再去编写代码实现这些功能,只需调用相应的函数就可以搭建好我们所需的网络结构。pytorch极大方便了我们构建神经网络,加快了神经网络开发速度,我们只需要关注网络的结构层次,而不用关心所建立的网络具体训练和预测过程。
2)安装pytorch
pytorch有CPU版和GPU版,GPU版需要使用到英伟达的显卡来加快网络速度,安装过程也稍显复杂。本文重点是对python卷积神经网络示例解析,因此安装CPU版。在pycharm开发工具的终端中直接执行命令:pip install torch torchvision torchaudio,即可完成pytorch的CPU版本安装。
3)准备训练和测试资源
因为使用pytorch开发卷积神经网络实现人脸识别,pytorch对数据存放有一定要求,因此需要将相关资源放在特定的目录结构下。训练目录和测试目录结构如下图所示,在文件夹中放入相应的图片资源即可。文件路径可以自行定义,但是同一个人的照片必须放在同一个文件夹下,pytorch根据该文件夹的名称自动将相应的图片资源归于一类。


二、卷积神经网络的基本结构
一个简单的卷积神经网络包括输入层、卷积层、池化层、扁平化层和全连接层。网络的复杂度体现在卷积、池化层的大小和数量上。卷积神经网络主要用于处理有大量数据输入的情景,如图像识别是最好的例子,可以极大减少运算量。下面以一个人脸识别的实际例子,详细讲解卷积神经网络的搭建流程。

三、代码实现
1)导入库
使用PyCharm工具新建一个.py文件,在文件中导入下面需要使用到的相关库。在导入下面的库前,需要确保已经安装好了pytorch相关依赖包。
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
2)数据预处理
以下定义了一组针对图片进行预处理的方法,包括3个。第一个是将图像调整为100*100像素大小,这样我们就可以输入任何大小图片,并能保证数据输入到网络中的大小是一致的。第二个是将图像数据转换为张量格式,这时pytorch自定义的一种数据格式,可以简单理解为类似于多维向量。第三个是对图像进行归一化处理,其目的是使数据的均值为 0,标准差为 1。这样做可以加速模型的训练过程,提高模型的稳定性和收敛速度。函数参数如下:
-
mean:一个长度为 3 的列表,分别代表图像三个通道(RGB)的均值。这里[0.485, 0.456, 0.406]是在 ImageNet 数据集上统计得到的三个通道的均值。 -
std:一个长度为 3 的列表,分别代表图像三个通道(RGB)的标准差。[0.229, 0.224, 0.225]是在 ImageNet 数据集上统计得到的三个通道的标准差。
参数的取值可以直接使用上面提供的经验值。对于输入图像的每个像素RGB值 ,归一化后的像素RGB值 按照以下公式计算:

其中,mean 和 std 分别是对应通道的均值和标准差。
transform = transforms.Compose([transforms.Resize((100, 100)), # 调整图像大小transforms.ToTensor(), # 将图像转换为张量transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) # 归一化
])
3)加载数据
使用dataset.ImageFolder()加载需要的训练图像和测试凸显数据。这里的数据路径需要注意,并没有到具体的文件名。比如在D:/zhaopian/train目录下,程序会自动读取该目录下的子文件夹,并将子文件夹中的图像数据归集到以该子文件夹命名的类别中。参数transform=transform就是调用上述第二步定义的数据预处理方法集,在读取每一张图像数据时将自动依次执行上述3个方法。并将最终转换好的数据返回。
创建数据加载器是为了便于网络训练时分批次加载数据,避免一次加载所有图像数据导致内存不足。
-
batch_size=32:指定每个批次中包含的数据样本数量。这里设置为 32,表示每次从train_dataset中取出 32 个样本组成一个批次进行训练。batch_size的选择会影响模型的训练速度和性能,较大的batch_size可以加快训练速度,但可能会导致内存不足;较小的batch_size可以增加模型的泛化能力,但训练速度会变慢。 -
shuffle=True:一个布尔值,用于指定是否在每个训练周期(epoch)开始时打乱数据集的顺序。设置为True可以增加数据的随机性,避免模型学习到数据的特定顺序,有助于提高模型的泛化能力。
train_dataset = datasets.ImageFolder(root='D:/zhaopian/train', transform=transform)
test_dataset = datasets.ImageFolder(root='D:/zhaopian/test', transform=transform)
all_samples = test_dataset.samples
print("数据集中的类别:", train_dataset.classes)# 创建数据加载器
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=32, shuffle=False)
4)构建一个卷积神经网络
自定义一个卷积神经网络类FaceCNN,继承自nn.Module。该网络包含两个卷积层,两个池化层,两个全连接层。在卷积层和全连接层之间均使用了相同的激活函数ReLU:

函数 nn.Conv2d(3, 16, kernel_size=3, padding=1) 的作用是定义一个二维卷积层,参数3表示输入的数据是3个通道,这里对应的是彩色图像的RGB三组数据,即每张图会有3个100*100的矩阵输入到该卷积层中。参数16表示该卷积层有16个卷积核,每个核的大小均是3*3(参数kernel_size=3确定的)的矩阵,这16个3*3的卷积核初始值是随机的,它的值是通过模型训练最终确定的,也就是神经网络中的权重矩阵。定义16个卷积核意味着什么呢?当一幅彩色图像输入该卷积层时,该图像有3组矩阵,每组矩阵与一个卷积核进行卷积,得到3个卷积后的矩阵,然后在将这3个卷积后的矩阵对应位置取平均值,得到一个最终的卷积均值矩阵。16个卷积核依次执行上述操作,则经过该卷积层后,会得到16个卷积均值矩阵。参数padding=1表示对输入数据进行扩充,1表示在数据四周加一行,填充的目的通常是为了保持输入和输出特征图的尺寸一致。那么,经过该卷积层后,最终会得到16个100*100的卷积均值矩阵。
函数nn.MaxPool2d(2)的作用是定义一个2*2的二维池化层,该池化层输出池中的最大值。在最大池化操作中,池化窗口会在输入特征图上滑动,对每个窗口内的元素进行操作。这里设置为 2,表示使用一个 2x2 的池化窗口。当池化窗口在特征图上滑动时,会选取每个 2x2 区域内的最大值作为该区域的输出值。此处需要注意的是,经过2*2的二维池化层后,输出的矩阵变为了50*50,因为池化层的步幅等于它的大小,这与卷积不同,卷积默认步幅为1。
函数nn.Conv2d(16, 32, kernel_size=3, padding=1) 用于定义第二个二维卷积层。在该卷积层中,前面两个参数分别是16和32,16对应的是前面的16个卷积核,因为一幅图像经过第一层卷积后会输出16组数据,所以此处第二层卷积时,输入的数据就是16组。32表示第二层卷积后输出32组50*50的矩阵。
函数nn.Linear(32 * 25 * 25, 128)的作用是定义一个全连接层,全连接层的每个神经元都与前一层的所有神经元相连接,通过对输入进行线性变换(加权求和)并加上偏置,实现从输入特征到输出特征的映射。第一个参数32 * 25 * 25=20000,表示输入数据的数量,128表示输出数据的数量。全连接层线性变换公式为:
![]()
其中, x是输入向量,W 是权重矩阵,b 是偏置向量, y是输出向量。权重矩阵W的形状为 (20000, 128), b的形状为 (128,1)。W和b都是在模型训练中需要更新的矩阵。
在建立的神经网络中还定义了前向传播函数forward(),它由开发者自行设计数据在网络中传播的方向。图像数据首先经过第一个卷积层,然后通过激活函数,再进入第一个池化层,随后依次进入第二个卷积层,第二个激活函数,第二个池化层。x = x.view(-1, 32 * 25 * 25)的作用是将得到的数据展平为一维数据。从前面的输出可知,x是一组由32个25*25矩阵组成的数据集,x.view会将该数据集整合为一个一维数组,数组的元素总量保持不变。
数据在经过展平后,进入了第一全连接层,由网络结构可知,第一个全连接层输出的是一个128个元素的数组,数据量被极大压缩了。然后再次经过激活函数,随后进入第二个全连接层,第二个全连接层输出的数组由n个元素组成,n=len(train_dataset.classes),就是我们训练模型时提供的n个人数。但需要注意的是,此处输出的结果与人脸识别并无直接关系,我们需要对该结果进行进一步处理,让它与人脸对应起来。
class FaceCNN(nn.Module):def __init__(self):super(FaceCNN, self).__init__()self.conv1 = nn.Conv2d(3, 16, kernel_size=3, padding=1) # 定义第一个二维卷积层self.relu1 = nn.ReLU() # 定义第一个激活函数self.pool1 = nn.MaxPool2d(2) # 定义第一个二维池化层self.conv2 = nn.Conv2d(16, 32, kernel_size=3, padding=1) # 定义第二个二维卷积层self.relu2 = nn.ReLU() # 定义第二个激活函数self.pool2 = nn.MaxPool2d(2) # 定义第二个二维池化层self.fc1 = nn.Linear(32 * 25 * 25, 128) # 定义第一个全连接层,展平后输出128个特征量self.relu3 = nn.ReLU() # 定义第三个激活函数self.fc2 = nn.Linear(128, len(train_dataset.classes)) # 定义第二个全连接层,展平后输出n个特征量,n为人数def forward(self, x):x = self.pool1(self.relu1(self.conv1(x)))x = self.pool2(self.relu2(self.conv2(x)))x = x.view(-1, 32 * 25 * 25)x = self.relu3(self.fc1(x))x = self.fc2(x)return x
5)模型训练
首先用自己定义卷积神经网络类实例化一个对象。然后定义一个损失函数,这里直接使用了pytorch库中提供的交叉熵损失函数对象,交叉熵损失函数(Cross-Entropy Loss)是分类问题中常用的一种损失函数,尤其适用于多分类任务。它能够有效衡量模型预测的概率分布与真实标签的概率分布之间的差异。该函数的具体实现比较复杂,如果不做算法研究,可以暂时不用管其具体实现,只需要知道在分类问题中适用该函数。
optimizer = optim.Adam(model.parameters(), lr=0.001) 这行代码在 PyTorch 中用于创建一个 Adam 优化器对象 optimizer,该优化器将用于更新模型 model 的参数。Adam(Adaptive Moment Estimation)是一种常用的优化算法,它结合了 AdaGrad 和 RMSProp 两种算法的优点。Adam 算法能够自适应地调整每个参数的学习率,同时利用梯度的一阶矩估计(均值)和二阶矩估计(方差)来更新参数。它具有收敛速度快、对不同类型的数据集和模型都有较好表现等优点,因此在深度学习中得到了广泛应用。我们同样也不需要去关心它的具体实现,PyTorch已经帮我们完成了相应的操作。其中的参数定义如下:
-
model.parameters():这是optim.Adam的第一个参数,它是一个生成器,用于返回模型model中所有需要更新的参数。在 PyTorch 中,模型的参数通常是可学习的张量,通过调用model.parameters()可以获取这些参数,优化器将根据这些参数的梯度信息来更新它们。 -
lr=0.001:lr是学习率(learning rate)的缩写,它是optim.Adam的一个重要超参数,用于控制每次参数更新的步长。学习率决定了模型在训练过程中朝着损失函数最小值前进的速度。这里将学习率设置为 0.001,表示每次更新参数时,参数的变化量是梯度乘以 0.001。如果学习率设置得过大,模型可能会跳过损失函数的最小值,导致无法收敛;如果学习率设置得过小,模型的训练速度会变得很慢。
# 初始化模型
model = FaceCNN()# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)# 训练模型
num_epochs = 20 # 训练10次
for epoch in range(num_epochs):model.train() # 将模型设置为训练模式。running_loss = 0.0for i, (images, labels) in enumerate(train_loader):optimizer.zero_grad() # 每次反向传播之前,将优化器中所有参数的梯度清零outputs = model(images) # 自动调用模型的 forward 方法loss = criterion(outputs, labels) # 计算损失值loss.backward() # 调用 loss.backward() 开始反向传播过程,计算每个可训练参数的梯度,并将这些梯度存储在参数的 .grad 属性中。optimizer.step() # 优化器会根据存储在参数 .grad 属性中的梯度,按照指定的优化算法更新模型的参数。running_loss += loss.item()
6)模型测试
模型测试的代码实现如下。测试时首先将模型设置为评估模式,在这里同样使用批量传入测试图像数据的方式。
_, predicted = torch.max(outputs.data, 1)用于找出在模型输出的结果outputs.data中,每一行数据的最大值在该行中的索引位置,torch.max 函数的第二个参数,指定了在哪个维度上进行最大值查找。这里设置为 1,表示在每一行(即每个样本)上查找最大值。需要进一步说明的是,由于我们采用批量处理的方式,outputs.data应是一个二维数组,每一行表示模型对一张图的处理结果。根据前面网络结构定义可知,若是输入3个人的人脸照片,则每一行应该有3个元素。这里取最大值,是因为模型输出的结果表征的是模型预测的概率,概率越大说明输入图像是对应人脸的概率越大。而对应的人脸在labels中表征,在本例中输入3个人的照片,则它是一个包含3个元素[0,1,2]的数组,每个值对应一个人。因此, torch.max找到最大值在每一行中的索引位置后,该位置也就表征了对应的人。
# 测试模型
model.eval() # 将模型切换到评估模式。
correct = 0
total = 0
with torch.no_grad(): # 不计算导数for index, (images, labels) in enumerate(test_loader):outputs = model(images)_, predicted = torch.max(outputs.data, 1)total += labels.size(0)correct += (predicted == labels).sum().item()labels_array = labels.numpy()predicted_array = predicted.numpy()# 计算当前批次的起始索引start_idx = index * test_loader.batch_size# 计算当前批次的结束索引end_idx = start_idx + images.size(0)# 获取当前批次的图像文件路径batch_samples = all_samples[start_idx:end_idx]# 提取图像文件名称batch_image_names = [sample[0].split('\\')[2] for sample in batch_samples]for i in range(len(predicted_array)):print(f'图名: {batch_image_names[i]}', f'实际名字: {train_dataset.classes[labels_array[i]]}',f'预测名字: {train_dataset.classes[predicted_array[i]]}')
print(f'总测试数量: {total}', f'正确识别数量: {correct}')
print(f'Test Accuracy: {100 * correct / total}%')
四、测试结果
从网络上随机下载了一些公开图片,对网路进行了训练和测试,得到结果如下。实际看神经网络的识别准确率还是比较高的。模型的完整代码和使用的资源可在这里下载。


五、模型导出
在完成神经网络模型训练后,需要将训练好的模型导出,以供后续使用,具体方法有两种。
1)保存模型的状态参数
在训练后的模型下加入下列代码,则模型中的所有参数均会保存到对应的.pth文件中。
torch.save(model.state_dict(), 'model_state_dict.pth')
在重新使用模型时,需要再次实例化模型对象,然后加载保存的模型参数。因此,重新使用时我们需要知道模型的结构定义,即重写FaceCNN类。
# 加载模型的状态字典
loaded_model = FaceCNN()
loaded_model.load_state_dict(torch.load('model_state_dict.pth'))
loaded_model.eval() # 设置为评估模式
2)保存完整模型
我们也可以直接保存完整的模型文件,在重新使用时直接加载该模型即可。这种方式简单,但缺少灵活性。
# 保存整个模型
torch.save(model, 'whole_model.pth')# 加载整个模型
loaded_model = torch.load('whole_model.pth')
loaded_model.eval() # 设置为评估模式
六、总结
通过一个人脸识别示例,详细说明了利用pytorch模块搭建卷积神经网络的实现流程,并对代码进行了逐行解释。pytorch极大方便了神经网络开发,让开发人员可以不用关注网络中具体的算法实现,而更加侧重在网络模型搭建上。在本例试验测试中,模型的训练次数和网络结构参数的调整均会对图像识别的准确造成大幅度影响,仍需要通过大量测试优化网络结构参数。
相关文章:
python卷积神经网络人脸识别示例实现详解
目录 一、准备 1)使用pytorch 2)安装pytorch 3)准备训练和测试资源 二、卷积神经网络的基本结构 三、代码实现 1)导入库 2)数据预处理 3)加载数据 4)构建一个卷积神经网络 5࿰…...
以Unity6.0为例,如何在Unity中开启DLSS功能
DLSS DLSS(NVIDIA 深度学习超级采样):NVIDIA DLSS 是一套由 GeForce RTX™ Tensor Core 提供支持的神经渲染技术,可提高帧率,同时提供可与原生分辨率相媲美的清晰、高质量图像。目前最新突破DLSS 4 带来了新的多帧…...
CSDN 大模型 笔记
AI 3大范式:计算 发发 交互 L1 生成代码 复制到IDEA (22年12-23年6,7月份) L2 部分自动编程 定义class 设计interface 让其填充实现 (23年7,8月份) L3 通用任务 CRUD (24年) L4 高度自动编程 通用领域专有任务…...
Flink怎么保证Exactly - Once 语义
Exactly - Once 语义是消息处理领域中的一种严格数据处理语义,指每条数据都只会被精确消费和处理一次,既不会丢失,也不会重复。 以下从消息传递语义对比、实现方式、应用场景等方面详细介绍: 与其他消息传递语义对比 在消息传递…...
AOS安装及操作演示
文章目录 一、安装node1.1 在 macOS 上管理 Node版本1.1.1 安装 nvm1.1.2 验证 nvm 是否安装成功1.1.3 使用 nvm 安装/切换 Node.js 版本1.1.4 卸载 Node.js 版本 1.2 在 windows 上管理 Node版本1.2.1 安装 nvm-windows1.2.2 安装 Node.js 版本1.2.3 切换 Node.js 版本1.2.4 卸…...
Python 操作 MongoDB 教程
一、引言 在当今数字化时代,数据的存储和管理至关重要。传统的关系型数据库在处理一些复杂场景时可能会显得力不从心,而 NoSQL 数据库应运而生。MongoDB 作为一款开源的、面向文档的 NoSQL 数据库,凭借其高性能、高可扩展性和灵活的数据模型…...
Stability AI 联合 UIUC 提出单视图 3D 重建方法SPAR3D,可0.7秒完成重建并支持交互式用户编辑。
Stability AI 联合 UIUC 提出一种简单而有效的单视图 3D 重建方法 SPAR3D,这是一款最先进的 3D 重建器,可以从单视图图像重建高质量的 3D 网格。SPAR3D 的重建速度很快,只需 0.7 秒,并支持交互式用户编辑。 相关链接 论文…...
网易易盾接入DeepSeek,数字内容安全“智”理能力全面升级
今年农历新年期间,全球AI领域再度掀起了一波革命性浪潮,国产通用大模型DeepSeek凭借其强大的多场景理解与内容生成能力迅速“出圈”,彻底改写全球人工智能产业的格局。 作为国内领先的数字内容风控服务商,网易易盾一直致力于探索…...
自动驾驶---如何打造一款属于自己的自动驾驶系统
在笔者的专栏《自动驾驶Planning决策规划》中,主要讲解了行车的相关知识,从Routing,到Behavior Planning,再到Motion Planning,以及最后的Control,笔者都做了相关介绍,其中主要包括算法在量产上…...
局域网使用Ollama(Linux)
解决局域网无法连接Ollama服务的问题 在搭建和使用Ollama服务的过程中,可能会遇到局域网内无法连接的情况。经过排查发现,若开启了代理软件,尤其是Hiddify,会导致此问题。这一发现耗费了我数小时的排查时间,希望能给大…...
聚焦 AUTO TECH China 2025,共探汽车内外饰新未来Automotive Interiors
全球汽车产业蓬勃发展的大背景下,汽车内外饰作为汽车重要组成部分,其市场需求与技术创新不断推动着行业变革。2025年11月20日至22日,一场备受瞩目的行业盛会 ——AUTO TECH China 2025 广州国际汽车内外饰技术展览会将在广州保利世贸博览馆盛…...
Moretl 增量文件采集工具
永久免费: <下载> <使用说明> 用途 定时全量或增量采集工控机,电脑文件或日志. 优势 开箱即用: 解压直接运行.不需额外下载.管理设备: 后台统一管理客户端.无人值守: 客户端自启动,自更新.稳定安全: 架构简单,兼容性好,通过授权控制访问. 架构 技术架构: Asp…...
支持多种网络数据库格式的自动化转换工具——VisualXML
一、VisualXML软件介绍 对于DBC、ARXML……文件的编辑、修改等繁琐操作,WINDHILL风丘科技开发的总线设计工具——VisualXML,可轻松解决这一问题,提升工作效率。 VisualXML是一个强大且基于Excel表格生成多种网络数据库文件的转换工具&#…...
mysql8 用C++源码角度看客户端发起sql网络请求,并处理sql命令
MySQL 8 的 C 源码中,处理网络请求和 SQL 命令的流程涉及多个函数和类。以下是关键的函数和类,以及它们的作用: 1. do_command 函数 do_command 函数是 MySQL 服务器中处理客户端命令的核心函数。它从客户端读取一个命令并执行。这个函数在…...
四、OSG学习笔记-基础图元
前一章节: 三、OSG学习笔记-应用基础-CSDN博客https://blog.csdn.net/weixin_36323170/article/details/145514021 代码:CuiQingCheng/OsgStudy - Gitee.com 一、绘制盒子模型 下面一个简单的 demo #include<windows.h> #include<osg/Node&…...
使用vllm docker容器部署大语言模型
说明 最近deepseek比较火,我在一台4卡4090的服务器上尝试部署了一下,记录下部署步骤。 安装过程 安卓docker和nvidia-container-toolkit 安装19.03版本以上的docker-ce即可。安装步骤参考清华docker源上的安装步骤:Docker CE 软件仓库 为…...
window 安装GitLab服务器笔记
目录 视频: 资源: Linux CeneOS7: VMware: Linux无法安装 yum install vim -y 1.手动创建目录 2.下载repo PS 补充视频不可复制的代码 安装GitLab *修改root用户密码相关(我卡在第一步就直接放弃了这个操作&…...
MySQL数据库入门到大蛇尚硅谷宋红康老师笔记 基础篇 part 10
第10章_创建和管理表 DDL:数据定义语言。CREATE \ALTER\ DROP \RENAME TRUNCATE DML:数据操作语言。INSERT \DELETE \UPDATE \SELECT(重中之重) DCL:数据控制语言。COMMIT \…...
react项目引入tailwindcss不生效解决方案
根据tailwindcss官网的操作步骤下来,样式未生效,且未报错,看了挺多的资料,还是并未解决。 后面在另一个项目尝试时,报了下面的问题: Error: PostCSS plugin tailwindcss requires PostCSS 8 根据这个链接…...
Expo运行模拟器失败错误解决(xcrun simctl )
根据你的描述,问题主要涉及两个方面:xcrun simctl 错误和 Expo 依赖版本不兼容。以下是针对这两个问题的解决方案: 解决 xcrun simctl 错误 错误代码 72 通常表明 simctl 工具未正确配置或路径未正确设置。以下是解决步骤: 确保 …...
【系统架构设计师】体系结构文档化
目录 1. 说明2. 重要性3. 主要内容4. 编写原则5. 实践建议6. 例题6.1 例题1 1. 说明 1.绝大多数的体系结构都是抽象的,由一些概念上的构建组成。2.层的概念在任何程序设计语言中都不存在。3.要让系统分析员和程序员去实现体系结构,还必须将体系结构进行…...
【0403】Postgres内核 检查(procArray )给定 db 是否有其他 backend process 正在运行
文章目录 1. 给定 db 是否有其他 backend 正在运行1.1 获取 allPgXact[] 索引1.1.1 MyProc 中 databaseId 初始化实现1.2 allProcs[] 中各 databaseId 判断1. 给定 db 是否有其他 backend 正在运行 CREATE DATABASE 语句创建用户指定 数据库名(database-name)时候, 会通过 …...
前端如何判断浏览器 AdBlock/AdBlock Plus(最新版)广告屏蔽插件已开启拦截
2个月前AdBlock/AdBlock Plus疑似升级了一次 因为自己主要负责面对海外的用户项目,发现以前的检测AdBlock/AdBlock Plus开启状态方法已失效了,于是专门研究了一下。并尝试了很多方法。 已失效的老方法 // 定义一个检测 AdBlock 的函数 function chec…...
微信小程序(第一集)
app.json {// 定义小程序的所有页面路径,数组中的第一个页面是首页"pages": ["pages/index/index", // 首页"pages/logs/logs" // 日志页面],// 设置小程序的全局窗口外观(比如导航栏和背景颜色)"wind…...
flutter ListView Item复用源码解析
Flutter 的 ListView 的 Item 复用机制是其高性能列表渲染的核心,底层实现依赖于 Flutter 的渲染管线、Element 树和 Widget 树的协调机制。以下是 ListView 复用机制的源码级解析,结合关键类和核心逻辑进行分析。 1. ListView 的底层结构 ListView 的复…...
《Operating System Concepts》阅读笔记:p9-p12
《Operating System Concepts》学习第 3 天,p9-p12 总结,总计 4 页。 一、技术总结 1.interrupt interrupt具有优先级(priority)。 2.storage 指令只能在 memory 上执行,所以要执行程序,那么就要加载到内存上。 (1)RAM Gen…...
html文件怎么转换成pdf文件,2025最新教程
将HTML文件转换成PDF文件,可以采取以下几种方法: 一、使用浏览器内置功能 打开HTML文件:在Chrome、Firefox、IE等浏览器中打开需要转换的HTML文件。打印对话框:按下CtrlP(Windows)或CommandP(M…...
【SpringBoot实现全局API限频】 最佳实践
在 Spring Boot 中实现全局 API 限频(Rate Limiting)可以通过多种方式实现,这里推荐一个结合 拦截器 Redis 的分布式解决方案,适用于生产环境且具备良好的扩展性。 方案设计思路 核心目标:基于客户端标识(…...
科技查新过不了怎么办
“科技查新过不了怎么办?” “科技查新不通过的原因是什么?” 想必这些问题一直困扰着各位科研和学术的朋友们,尤其是对于查新经验不够多的小伙伴,在历经千难万险,从选择查新机构、填写线上委托单到付费,…...
设计模式-结构型-外观模式
在软件开发中,随着功能的不断迭代,系统会变得越来越复杂,模块之间的依赖关系也会越来越深。这种复杂性会导致代码难以理解、维护和扩展。而外观模式(Facade Pattern)正是为了解决这一问题而生的。 一、外观模式简介 …...
