虚假人脸检测实验

2023-10-26

虚假人脸检测实验

虚假人脸识别

数据集链接
链接:https://pan.baidu.com/s/1ZY7_PqPGsxCBFerpfRW13Q?pwd=0w2r
或者https://download.csdn.net/download/weixin_50925658/88126394?spm=1001.2014.3001.5503

原理

ResNet-18是一种经典的CNN网络,是 Deep Residual Learning 团队在 2017 年提出的。它是为了解决 ImageNet 数据集上的图像分类任务而设计的,是目前最先进的图像分类模型之一。 ResNet-18 具有 18 个卷积层和 6 个全连接层,与传统的卷积神经网络相比,它在深度和广度上都有更高的分辨率和更好的性能。具体来说,它具有更大的池化层、更多的嵌入层和更密集的全连接层,可以捕捉更多的特征信息。 残差网络的核心思想是:每个附加层都应该更容易地包含原始函数作为其元素之一 ResNet沿用了VGG完整的3×3卷积层设计。 残差块里首先有2个有相同输出通道数的3×3卷积层。 每个卷积层后接一个批量规范化层和ReLU激活函数。 然后我们通过跨层数据通路,跳过这2个卷积运算,将输入直接加在最后的ReLU激活函数前。 这样的设计要求2个卷积层的输出与输入形状一样,从而使它们可以相加。 如果想改变通道数,就需要引入一个额外的1×1卷积层来将输入变换成需要的形状后再做相加运算。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qi1VNN8z-1688814001510)(./assets/image-20230705012633733.png)]

在它的训练过程采用了一种称为“无损编码”的技术,可以减少传输数据的量,从而提高效率和性能。相对于之前的图像分类网络,ResNet-18 在性能、分辨率、参数数量和泛化性能方面表现出色,特别适合处理大规模图像数据集和复杂的分类任务。

因此我们将实验数据集按照实验要求进行分类和划分后,训练一个ResNet-18网络 ,再用验证集进行测试。

步骤

数据集划分

对数据进行清洗和预处理后,将其中 500 张真实人脸和 500 张虚假人脸作为训练集,其余作为测试集

from __future__ import print_function, division
import os
import random,shutil
# 给定一个人脸数据集,其中包含1999张真实人脸,1999张虚假人脸。
# 将其中500张真实人脸和500张虚假人脸作为训练集,其余作为测试集

#数据路径
# real_face_path='./CNN_synth_testset/0_real'
# fake_face_path='./CNN_synth_testset/1_fake'
face_dataset_path='./CNN_synth_testset'

#获取文件夹下所有文件名
def listDir(path):
    file_list=os.listdir(path)
    return file_list
#创建文件夹
def mkdir(path):
    if not os.path.exists(path):
        os.makedirs(path)

#划分训练集和测试集和验证集
divided_data_path='./face_data_divided/'
def datasetDivide(divide_path):
    # 读取真实人脸和虚假人脸数据路径
    path=os.listdir(face_dataset_path)
    for doc in path:
        data=os.listdir(os.path.join(face_dataset_path,doc))
        #将人脸数据清洗
        random.shuffle(data)
        train_face_data=data[:500]
        valid_face_data=data[500:1999]
        # test_face_data=[]#
        mkdir(divide_path+'train/'+doc+'/')
        mkdir(divide_path+'validation/'+doc+'/')
        # mkdir(divide_path+'test/'+doc+'/')
        for train_face in train_face_data:
            shutil.copy(os.path.join(face_dataset_path,doc,train_face),
                        divide_path+'train/'+doc+'/'+train_face)
            
        for valid_face in valid_face_data:
            shutil.copy(os.path.join(face_dataset_path,doc,valid_face),
                        divide_path+'validation/'+doc+'/'+valid_face)
            
    print('数据集划分完成')
    
datasetDivide(divided_data_path)

在这里插入图片描述

数据预处理和超参数设置

超参数设置
import torch
import torchvision
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, models, transforms
import torch.backends.cudnn as cudnn
import numpy as np
import os

# 超参数
learning_rate = 0.001
batch_size = 4
num_epochs = 20

cudnn.benchmark = True#加速卷积神经网络的训练

数据集预处理
# 数据预处理——数据增强
data_transforms = {
    'train': transforms.Compose([
        transforms.RandomHorizontalFlip(),  # 随机水平翻转
        transforms.RandomCrop(224),  # 随机裁剪
        transforms.ToTensor(),  # 转换为张量
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])  # 归一化
    ]),
    'validation': transforms.Compose([
        transforms.Resize(256),  # 缩放为256×256
        transforms.CenterCrop(224),  # 中心裁剪为224×224
        transforms.ToTensor(),  # 转换为张量,且值缩放到[0,1]
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])  # 归一化
    ]),
}

#加载数据集
data_path=divided_data_path
image_datasets = {x: datasets.ImageFolder(os.path.join(divided_data_path, x),
                                            data_transforms[x])
                    for x in ['train', 'validation']}
# print(image_datasets)
#数据的批量加载
#num_workers=0表示单线程,因为在windows不支持多线程
dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size=batch_size,shuffle=True, num_workers=0)
                for x in ['train', 'validation']}
#数据集大小
dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'validation']}
# print(dataset_sizes)
#类别名称
class_names = image_datasets['train'].classes
# print(class_names)
#GPU是否可用
device=torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print(device)

数据集可视化

import matplotlib.pyplot as plt
import numpy as np

# Get a batch of training data
inputs, classes = next(iter(dataloaders['train']))

def plot_images(images, labels, preds=None):
    """
    Plot a batch of images with their labels and predictions (if given).

    Args:
        images (tensor): A batch of images.
        labels (tensor): The true labels for each image.
        preds (tensor, optional): The predicted labels for each image. Defaults to None.
    """
    # Set up the figures
    num_images = len(images)
    cnt=0
    plt.figure(figsize=(16, 16))
    # Plot each image
    for i in range(num_images):
        cnt+=1
        plt.subplot(1, num_images, cnt)
        plt.xticks([], [])#设置x轴刻度
        plt.yticks([], [])#设置y轴刻度
        # Set the title
        if preds is not None:
            title = f"predicted: {class_names[preds[i]]}, true: {class_names[labels[i]]}\n"
            color = 'green' if preds[i] == labels[i] else 'red'
        else:
            title = f"{class_names[labels[i]]}\n"
            color = 'green'        
        plt.title(title, color=color)
        # Unnormalize the image
        image = images[i].numpy().transpose((1, 2, 0))
        mean = np.array([0.485, 0.456, 0.406])
        std = np.array([0.229, 0.224, 0.225])
        image = std * image + mean
        image = np.clip(image, 0, 1)
        plt.imshow(image)
        

    plt.show()

plot_images(inputs, classes)

在这里插入图片描述

模型构建及训练

我们定义了一个train_model函数,用于训练神经网络模型。函数接收模型(model)、损失函数(criterion)、优化器(optimizer)、学习率调整器(scheduler)和训练的轮数(num_epochs)作为参数,在该函数内部,进行模型的训练和验证,并记录训练和验证损失(loss)和准确率(accuracy)。其中我们使用tqdm库来包装我们的训练参数epoch,来显示进度条。 在训练过程我们使用了预训练模型、交叉熵损失函数、随机梯度下降法优化器以及学习率调整器,通过训练和验证来调整模型参数,最终得到一个表现较好的模型。

from tqdm import tqdm
from torch.optim import lr_scheduler
import copy,time
def train_model(model, criterion, optimizer,scheduler,num_epochs=25):
    best_model_wts = copy.deepcopy(model.state_dict())
    best_acc = 0.0
    
    start_time = time.time()
    train_loss_history = []
    train_acc_history = []
    val_loss_history = []
    val_acc_history = []
    
    pbar=tqdm(range(num_epochs))
    for epoch in pbar:
        print(f'Epoch {epoch+1}/{num_epochs}\n{"-"*10}')
        
        # 每个 epoch 都有一个培训和验证阶段
        for phase in ['train', 'validation']:
            if phase == 'train':
                model.train()  # 将模型设置为训练模式
            else:
                model.eval()   # 将模型设置为评估模式
            
            running_loss = 0.0#记录损失
            running_corrects = 0#记录正确的个数
            
            # 包装器tqdm,用于显示进度条
            # data_loader = tqdm(dataloaders[phase], desc=f'{phase} {epoch+1}/{num_epochs}')
            
            # 迭代数据
            for inputs, labels in  dataloaders[phase]:
                inputs = inputs.to(device)
                labels = labels.to(device)

                # 清零参数梯度
                optimizer.zero_grad()

                # 前向传递
                # track history if only in train
                with torch.set_grad_enabled(phase == 'train'):
                    outputs = model(inputs)
                    _, preds = torch.max(outputs, 1)
                    loss = criterion(outputs, labels)

                    # 只有在训练阶段才进行反向传递+优化
                    # backward + optimize only if in training phase
                    if phase == 'train':
                        loss.backward()
                        optimizer.step()

                # statistics
                running_loss += loss.item() * inputs.size(0)
                running_corrects += torch.sum(preds == labels.data)
            
            # 更新学习率
            epoch_loss = running_loss / len(dataloaders[phase].dataset)
            epoch_acc = running_corrects.double() / len(dataloaders[phase].dataset)
            
            if phase == 'train':
                train_loss_history.append(epoch_loss)
                train_acc_history.append(epoch_acc)
                scheduler.step()#对优化器的学习率进行调整
            else:
                val_loss_history.append(epoch_loss)
                val_acc_history.append(epoch_acc)
                
            # print(f'{phase} loss: {epoch_loss:.4f}, acc: {epoch_acc:.4f}')
            
            pbar.set_postfix_str(f'{phase} loss: {epoch_loss:.4f}, acc: {epoch_acc:.4f}')
            # deep copy the model
            if phase == 'validation' and epoch_acc > best_acc:
                best_acc = epoch_acc
                best_model_wts = copy.deepcopy(model.state_dict())
                
    
    time_elapsed = time.time() - start_time
    print(f'Training complete in {time_elapsed // 60:.0f}m {time_elapsed % 60:.0f}s')
    print(f'Best validation accuracy: {best_acc:.4f}')
    
    # 加载最佳模型权重
    model.load_state_dict(best_model_wts)

    return model, train_loss_history, train_acc_history, val_loss_history, val_acc_history

#加载预训练模型
model_ft = models.resnet18(pretrained=True)

#替换最后一层的分类器
#数据集只有两个类别(真实人脸和虚假人脸),因此新的全连接层的输出维度为2。
num_features=model_ft.fc.in_features
model_ft.fc=nn.Linear(num_features,len(class_names))

#定义损失函数和优化器
model_ft=model_ft.to(device)
criterion=nn.CrossEntropyLoss()
optimizer=optim.SGD(model_ft.parameters(),lr=learning_rate,momentum=0.9)

#学习率调整器
exp_lr_scheduler=lr_scheduler.StepLR(optimizer,step_size=7,gamma=0.1)

#训练模型
model_ft, train_loss_history, train_acc_history, val_loss_history, val_acc_history = train_model(model_ft, criterion, optimizer, exp_lr_scheduler, num_epochs=15)

训练过程及结果可视化

#可视化训练过程
def plot_history(train_loss_history, train_acc_history, val_loss_history, val_acc_history):
    plt.figure(figsize=(15, 5))
    plt.subplot(121)
    plt.plot(train_loss_history, label='train')
    plt.plot(val_loss_history, label='validation')
    plt.xlabel('Epoch')
    plt.ylabel('Loss')
    plt.legend()
    plt.show()
    # plt.figure(figsize=(15, 5))
    # plt.subplot(122)
    # plt.plot(train_acc_history, label='train')
    # plt.plot(val_acc_history, label='validation')
    # plt.xlabel('Epoch')
    # plt.ylabel('Accuracy')
    # plt.legend()
    # plt.show()
    
    

def visualize_model(model, num_images=8):
    was_training = model.training
    model.eval()
    images_so_far = 0

    with torch.no_grad():
        for i, (inputs, labels) in enumerate(dataloaders['validation']):
            inputs = inputs.to(device)
            labels = labels.to(device)

            outputs = model(inputs)
            _, preds = torch.max(outputs, 1)

            plot_images(inputs.cpu(), preds, labels)
            images_so_far += batch_size

            if images_so_far == num_images:
                model.train(mode=was_training)
                return
        model.train(mode=was_training)
        
visualize_model(model_ft)

plot_history(train_loss_history, train_acc_history, val_loss_history, val_acc_history)
主要涉及两个函数,一个是用于可视化训练过程的 plot_history() 函数,另一个是用于可视化模型的 visualize_model() 函数。
plot_history() 函数接受四个参数,分别是训练损失、训练精度、验证损失和验证精度的历史记录。该函数会将训练和验证损失随着训练轮数的增加而变化的曲线绘制在同一张图上进行对比,以便于分析模型的训练效果。最后通过 plt.show() 函数将图像展示出来。
visualize_model() 函数接受两个参数,一个是模型对象,另一个是要可视化的图片数目,默认为 8。该函数会将模型在验证集上的预测结果可视化出来。具体实现是通过一个循环遍历验证集数据集中的图片,然后将这些图片、模型的预测结果以及真实标签传递给 plot_images() 函数进行展示。在展示完指定数量的图片之后,该函数会将模型的模式切换回之前的模式,即训练模式或评估模式。
通过调用 visualize_model() 函数和 plot_history() 函数,可视化了模型的预测结果和训练过程。

训练过程
首先分析在6个Epoch内,我们看到Loss函数收敛到接近于零,无论是训练的loss还是验证集的loss,验证集上的正确率达到了100%,时间花费在14分钟左右,在GPU上进行训练
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

虚假人脸检测实验 的相关文章

  • 如何使用 cython 编译扩展?

    我正在尝试从示例页面编译一个简单的 cython 扩展here http docs cython org src userguide tutorial html在我安装了 Python 2 6 64 位版本的 Windows 7 64 位计
  • 在 Pandas 中按日期获取有效合约

    我在检测 pandas DataFrame 中的活动合约方面遇到了一些困难 假设每一行都是一个协商 对于每一行 我有两列 initial date 和 end date 我想知道的是按日期划分的活跃合约数量 到目前为止我做了一个非常低效的方
  • 从字符串到类型的词法转换

    最近 我尝试用Python存储和读取文件中的信息 遇到了一个小问题 我想从文本文件中读取类型信息 从 string 到 int 或 float 的类型转换非常有效 但从 string 到 type 的类型转换似乎是另一个问题 当然 我尝试了
  • Python 3 __getattribute__ 与点访问行为

    我读了一些关于 python 的对象属性查找的内容 这里 https blog ionelmc ro 2015 02 09 understanding python metaclasses object attribute lookup h
  • 如何使用Python将WebP图像转换为Gif?

    我已经尝试过这个 from PIL import Image im Image open this webp im save that gif gif save all True 这给了我这个错误 类型错误 不支持的操作数类型 tuple
  • 可以在 TensorFlow 中使用排名相关作为成本函数吗?

    我正在处理偶尔充满异常值的极其嘈杂的数据 因此我主要依靠相关性来衡量我的神经网络的准确性 是否可以明确使用诸如等级相关性 斯皮尔曼相关系数 之类的东西作为我的成本函数 到目前为止 我主要依赖 MSE 作为相关性的代理 我现在面临三个主要障碍
  • Python - 用逗号分割,跳过括号内的内容

    我需要用逗号分隔字符串 但我对这种情况有一个问题 TEXT EXAMPLE THIS IS A EXAMPLE BUT NOT WORKS FOR ME SECOND THIRD 我想拆分并得到 var 0 TEXT EXAMPLE THI
  • 错误:permission_manager_qt.cpp(82) 不支持的权限类型:13

    我正在开发具有内置浏览器功能的 python 代码 PyQt 5 13 import sys from PyQt5 QtCore import from PyQt5 QtGui import from PyQt5 QtWidgets imp
  • 为什么 Python 中的“pip install”会引发语法错误?

    我正在尝试使用 pip 安装软件包 我试着跑pip install从Python shell 但我得到了SyntaxError 为什么我会收到此错误 如何使用 pip 安装软件包 gt gt gt pip install selenium
  • 创建一个类似于 Tkinter 的表

    我希望创建类似于 Tkinter 中的表格的东西 但它不一定是这样的 例如 我想创建标题 Name1 Name2 Value 并在每个标题下面有几个空白行 然后 我希望稍后用我计算的值或名称的字符串值填充这些行 因此是标签 对于 Name2
  • 如何通过双击在浏览器中打开 ipynb 文件

    以前 我安装了 Canopy 当时 我只需双击 ipynb 文件并在浏览器中打开它们即可 但是 后来我需要Anaconda 一旦我安装了它 这个功能就没有了 现在我只希望能够简单地双击 ipynb 文件 然后该文件就会在 Firefox 中
  • 更改 pandas 中多个日期时间列的时区信息

    有没有一种简单的方法可以将数据帧中的所有时间戳列转换为本地 任何时区 不是逐列进行吗 您可以有选择地将转换应用于所有日期时间列 首先 选择它们select dtypes https pandas pydata org pandas docs
  • 如何使用Python的super()来更新父值?

    我对继承很陌生 之前所有关于继承和 Python 的 super 函数的讨论都有点超出我的理解 我当前使用以下代码来更新父对象的值 usr bin env python test py class Master object mydata
  • Python 中的 @staticmethod 与 @classmethod

    方法和方法有什么区别装饰的 https peps python org pep 0318 with staticmethod http docs python org library functions html staticmethod和
  • 为什么我用 beautifulSoup 刮的时候有桌子,但没有 pandas

    尝试抓取条目页面转换为制表符分隔格式 主要拉出序列和 UniProt 登录号 当我跑步时 url www signalpeptide de index php sess m listspdb bacteria s details id 10
  • 将输入发送到 python 子进程而不等待结果

    我正在尝试为一段代码编写一些基本测试 该代码通常通过 stdin 无休止地接受输入 直到给出特定的退出命令 我想检查程序是否在给出一些输入字符串时崩溃 经过一段时间来考虑处理 但似乎无法弄清楚如何发送数据而不是陷入等待我不知道的输出关心 我
  • Matplotlib Scatter - ValueError:RGBA 序列的长度应为 3 或 4

    我正在尝试为我的功能绘制图表 但不断收到此错误 ValueError RGBA sequence should have length 3 or 4 每当我只有 6 种形状时 代码就可以完美运行 但现在我将其增加到 10 种 它就不起作用了
  • Airflow Python 单元测试?

    我想为我们的 DAG 添加一些单元测试 但找不到任何单元测试 有 DAG 单元测试框架吗 有一个端到端的测试框架存在 但我猜它已经死了 https issues apache org jira browse AIRFLOW 79 https
  • Python组合目录中的所有csv文件并按日期时间排序

    我有 2 年的每日数据分成每月文件 我想将所有这些数据合并到一个按日期和时间排序的文件中 我正在使用的代码组合了所有文件 但不按顺序 我正在使用的代码 import pandas as pd import glob os import cs
  • 在 Python 模块中使用 InstaLoader

    我正在尝试使用 Instaloader 下载与主题标签相关的照片以进行图像分析 我在GitHub存储库中找到了一个全面的方法 如何在终端中执行它 但是 我需要将脚本集成到Python笔记本中 这是脚本 instaloader no vide

随机推荐

  • SpringBoot 集成SpringBatch 批处理框架

    SpringBatch 核心组件简介 1 JobRepository 用来注册Job容器 设置数据库相关属性 2 JobLauncher 用来启动Job的接口 3 Job 我们要实际执行的任务 包含一个或多个 4 Step 即步骤 包括 I
  • 自然语言处理实战项目18-NLP模型训练中的Logits与损失函数的计算应用项目

    大家好 我是微学AI 今天给大家介绍一下 自然语言处理实战项目18 NLP模型训练中的Logits与损失函数的计算应用项目 在NLP模型训练中 Logits常用于计算损失函数并进行优化 损失函数的计算是用来衡量模型预测结果与真实标签之间的差
  • QQkey后门

    今天凌晨收到 LX2222 的举报反馈被盗号 发布的加速器盗取账号信息 https www 52pojie cn thread 785555 1 1 html 我们着手分析一下看看软件确实发现了问题 被添加了盗取QQkey的后门 通过拿到Q
  • SQL查询语句之查询数据

    目录 1 基本查询语句 2 单表查询 2 1 查询所有字段 1 列出表中的所有字段 2 使用 查询所有字段 2 2 查询指定字段 2 3 查询指定记录 2 4 带 in 关键字的查询 2 5 带 between and 的范围查询 2 6
  • HTML中Table表格的使用与漂亮的表格模板

    1 表格标记 表格是网页中十分重要的组成元素 表格用来存储数据 包含标题 表头 行和单元格 在HTML语言中 表格标记使用符号 table 表示 定义表格光使用 table 是不够的 还需要定义表格中的行 列 标题等内容 标记 说明 表格标
  • Vue2 项目里,使用 Element 的 dialog 里嵌套 tabs,导致关闭 dialog 时浏览器卡死问题

    Vue2 项目里 使用 Element 的 dialog 里嵌套 tabs 导致关闭 dialog 时浏览器卡死问题 解决办法 给 tab 添加 v if 绑定 dialog 的 visible sync
  • 如何查看awr/statspack报表,来定位系统的问题

    author skate time 2010 03 25 如何查看awr statspack报表 来定位系统的问题 数据库的性能指标一般都有什么 只有定好指标才能判定系统的性能 性能参考指标一般有如下几个 1 响应时间 平均每事务的响应时间
  • QT 使用QLibrary加载动态库

    简介 使用QLibraryi可以在程序运行时加载动态链接库 一个QLibrary的实例作用于一个单一的共享库上 QLibrary提 供了一种平台无关的方式访问库中的函数 可以在构建QLibrary的实例时将要加载的库文件传入 也可以在创建
  • python/元组、列表、字典

    Python 的元组与列表类似 不同之处在于元组的元素不能修改 元组使用小括号 列表使用方括号 字典使用 下面用一个实例来体验一下 s list input r 创建一个字典 for i in s r i r get i 0 1 看下文解释
  • 引爆点--读书有感

    有个理念一直在我心里 都说流行都是轮回 如何去让产品抓住流行趋势 究竟是什么造就了流行 如何去学习 看看周围的世界吧 它看上去似乎雷打不动 无法改变 但只要你找准位置 轻轻一触 它就可能倾斜 书籍理念 个别人物法则 附着力因素法则和环境威力
  • 单片机控制直流电机(风扇)电路详解

    单片机引脚为什么无法直接控制电机或风扇 我们在使用单片机去控制 5V的直流电机或者散热风扇时 可能会有一种疑惑 51单片机的引脚电压为 5V 为什么不直接用单片机引脚去驱动电机或者风扇 实际上单片机的控制引脚 不管是51单片机或者stm32
  • Linux安装python显示“软件包python没有可安装候选”

    在Linux中安装python时 调用 sudo apt get install python 命令出现以下问题 sudo apt get install python sudo lyx 的密码 正在读取软件包列表 完成 正在分析软件包的依
  • java中public/private/protected的具体区别

    java中public private protected的具体区别 public public表明该数据成员 成员函数是对所有用户开放的 所有用户都可以直接进行调用 private private表示私有 私有的意思就是除了class自己
  • 深度学习——更深层次的神经网络

    一个深层次的CNN网络结构 这里使用的卷积层全都是3 3的小型滤波器 特点是随着层的加深 通道数变大 卷积层的通道数从前面的层开始按顺序以16 16 32 32 64 64的方式增加 此外 插入了池化层 以逐渐减小中间数据的空间大小 并且
  • C++ 字符串

    C 提供了以下两种类型的字符串表示形式 C 风格字符串 C 引入的 string 类类型 C 风格字符串 C 风格的字符串起源于 C 语言 并在 C 中继续得到支持 字符串实际上是使用 null 字符 0 终止的一维字符数组 因此 一个以
  • OpenMV的单颜色识别讲解

    OpenMV的官方教程 寻找色块 single color rgb565 blob tracking示例讲解 视频讲解 需要提前看的文章 程序烧录 颜色阈值设置 目录 threshold index和thresholds解析 固定代码部分
  • Vue记住滚动条位置 scrollBehavior + debounce

    Vue记住滚动条位置 1 先给占位符加一层缓存 2 在路由上加一个源信息meta 记录滚动条的top值 3 使用 scrollBehavior 4 给页面添加事件监听 使用前端路由 当切换到新路由时 想要页面滚到顶部 或者是保持原先的滚动位
  • 浅谈 js运行机制 、宏观任务、微观任务

    今天我们谈一下我对js 运行机制 和宏观任务 微观任务的理解 js运行机制有同步运行和异步运行 js是单线程运行模式在进入任务当中如果是同步任务 那么就直接被主线程运行 如果是异步任务 那么就进入任务队列中进行等待运行 直到主线程任务执行完
  • 二叉树基础

    文章目录 一 树的基础 1 树的概念 2 非树 3 树的相关概念 image 20220402143804166 https img blog csdnimg cn img convert a8bbb6f8483be3ca9edd9e354
  • 虚假人脸检测实验

    虚假人脸检测实验 虚假人脸识别 数据集链接 链接 https pan baidu com s 1ZY7 PqPGsxCBFerpfRW13Q pwd 0w2r 或者https download csdn net download weixi