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

从源到目标:深度学习中的迁移学习与领域自适应实践

云边有个稻草人-CSDN博客

目录

引言

一、迁移学习概述

1.1 迁移学习的类型

1.2 迁移学习的核心思想

1.3 迁移学习的应用场景

二、领域自适应(Domain Adaptation)

2.1 领域自适应的定义

2.2 领域自适应的挑战

2.3 领域自适应的核心方法

(1)对抗训练(Adversarial Training)

(2)最大均值差异(Maximum Mean Discrepancy, MMD)

(3)自监督学习(Self-supervised Learning)

2.4 领域自适应的应用场景

三、领域自适应中的对抗训练代码示例

四、总结


引言

深度学习已经在多个领域取得了显著的突破,尤其是在计算机视觉、自然语言处理和语音识别等任务中,表现出了非常强大的能力。然而,训练深度学习模型需要大量的标注数据,这在许多应用中可能难以实现,尤其是在数据采集困难或者高标注成本的场景中。迁移学习和领域自适应正是为了解决这一问题而出现的技术,它们通过从源任务中迁移知识,帮助模型在目标任务中快速适应并提高性能。

本文将深入探讨迁移学习和领域自适应的基本概念、方法、应用,并提供代码示例,帮助读者理解并实现这些技术。同时,我们将扩展到最新的研究进展,探讨这两个技术的挑战与未来的研究方向。

一、迁移学习概述

迁移学习是一种通过借用源领域的知识来解决目标领域任务的方法,尤其适用于目标领域数据有限的情况。通过迁移学习,深度学习模型能够在标注数据少的目标任务上进行训练,利用预先训练好的源领域模型进行微调,显著加快训练速度并提高模型的性能。

1.1 迁移学习的类型

迁移学习在实际应用中有多个变种:

  1. 域间迁移(Domain Transfer)

    • 源领域和目标领域的数据相似,但数据分布有所不同。通过微调模型,迁移学习能够帮助模型适应目标领域的数据分布。
  2. 任务间迁移(Task Transfer)

    • 源领域和目标领域的任务相似,但数据和标签可能不同。迁移学习允许我们将源领域模型应用于目标任务,并进行调整以适应目标任务。
  3. 零样本学习(Zero-shot Learning)

    • 目标任务没有标签数据,迁移学习可以利用源任务的模型和无监督的方式,迁移知识进行任务学习。
1.2 迁移学习的核心思想

迁移学习的核心是通过“知识迁移”,即将源领域模型的知识转移到目标领域,来加速目标领域任务的学习。在迁移学习中,通常使用预训练模型(如ResNet、VGG等)作为基础模型,并进行微调。微调是迁移学习中常用的技术,它通过调整源任务模型的部分或全部参数,使模型适应新的目标任务。

下面是一个基于PyTorch的代码示例,展示如何加载预训练的ResNet模型并在一个新数据集上进行微调。

import torch
import torch.nn as nn
import torchvision.transforms as transforms
from torchvision import datasets, models
from torch.utils.data import DataLoader# 数据转换与增强
transform = transforms.Compose([transforms.Resize((224, 224)),transforms.ToTensor(),transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
])# 加载训练和验证数据
train_data = datasets.ImageFolder(root='data/train', transform=transform)
val_data = datasets.ImageFolder(root='data/val', transform=transform)train_loader = DataLoader(train_data, batch_size=32, shuffle=True)
val_loader = DataLoader(val_data, batch_size=32, shuffle=False)# 加载预训练的ResNet模型
model = models.resnet50(pretrained=True)# 冻结卷积层
for param in model.parameters():param.requires_grad = False# 修改全连接层以适应目标任务的类别数
num_ftrs = model.fc.in_features
model.fc = nn.Linear(num_ftrs, 2)  # 假设我们有两个类别# 移动模型到GPU
model = model.to('cuda')# 定义损失函数与优化器
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.fc.parameters(), lr=0.001, momentum=0.9)# 训练模型
for epoch in range(10):model.train()running_loss = 0.0for inputs, labels in train_loader:inputs, labels = inputs.to('cuda'), labels.to('cuda')optimizer.zero_grad()outputs = model(inputs)loss = criterion(outputs, labels)loss.backward()optimizer.step()running_loss += loss.item()print(f"Epoch {epoch+1}, Loss: {running_loss/len(train_loader)}")

通过这种方式,我们利用ResNet模型在ImageNet上预训练的知识,在新的数据集上快速进行训练,减少了训练时间并提高了目标任务的精度。

1.3 迁移学习的应用场景

迁移学习已经广泛应用于多个领域,尤其是在数据稀缺的情况下,迁移学习能大大提升模型的性能和效率:

  • 计算机视觉

    • 在图像分类、物体检测和语义分割等任务中,迁移学习能够利用大规模数据集(如ImageNet)上预训练的模型来加速模型训练,提升准确率。
  • 自然语言处理

    • BERT、GPT等预训练的自然语言处理模型通过迁移学习在各种任务(如文本分类、情感分析、问答系统等)中取得了突破性进展。
  • 语音识别

    • 语音识别模型可以通过迁移学习技术从一种语言迁移到另一种语言,甚至适应不同的口音或噪声条件。

二、领域自适应(Domain Adaptation)

2.1 领域自适应的定义

领域自适应是迁移学习的一个关键子领域,旨在解决源领域和目标领域之间数据分布的差异。当我们拥有标注的源领域数据,却在目标领域缺乏标注数据时,领域自适应通过减少这两个领域之间的分布差异,使得模型能够在目标领域上表现得更好。

通常,领域自适应的目标是让模型学会从源领域获得的知识迁移到目标领域,尽管源领域和目标领域的输入数据有很大的差异。由于目标领域的标注数据可能缺乏,领域自适应在无监督学习中扮演着重要的角色。通过减少源领域和目标领域的特征分布差异,领域自适应技术能够提升模型的泛化能力。

2.2 领域自适应的挑战

领域自适应面临着以下几个关键挑战:

  1. 分布差异(Domain Shift):源领域和目标领域的特征分布不同,甚至可能存在标签偏差。例如,源领域的数据可能来自不同的图像来源,而目标领域的数据可能包含不同的拍摄角度、不同的环境条件等。

  2. 无标注目标数据:目标领域的标注数据缺乏,导致在目标领域上无法进行直接的监督学习。我们只能依赖无监督的数据进行领域自适应。

  3. 模型的复杂性:领域自适应通常需要额外的网络组件(例如对抗网络、判别器等),使得训练过程更复杂,优化起来也更加困难。

2.3 领域自适应的核心方法

领域自适应的主要技术包括以下几种:

(1)对抗训练(Adversarial Training)

对抗训练在领域自适应中发挥着重要作用。与生成对抗网络(GAN)类似,领域自适应中的对抗训练通过使用判别器来区分源领域和目标领域的特征。训练的目标是最大化源领域和目标领域特征的共享部分,使得判别器难以区分这两个领域。

典型的领域自适应对抗训练框架是域适应对抗神经网络(DANN),其目标是通过优化源领域和目标领域特征,使得它们在特征空间中没有显著的差异。

以下是基于对抗训练的领域自适应的一个简单代码框架:

import torch
import torch.nn as nn
import torch.optim as optim
import torchvision.models as models
from torch.utils.data import DataLoader# 定义特征提取网络(例如ResNet)
class FeatureExtractor(nn.Module):def __init__(self):super(FeatureExtractor, self).__init__()self.resnet = models.resnet50(pretrained=True)self.resnet.fc = nn.Identity()  # 移除最后的全连接层def forward(self, x):return self.resnet(x)# 定义对抗网络(判别器)
class Discriminator(nn.Module):def __init__(self):super(Discriminator, self).__init__()self.fc = nn.Sequential(nn.Linear(2048, 1024),nn.ReLU(),nn.Linear(1024, 1),nn.Sigmoid())def forward(self, x):return self.fc(x)# 初始化模型
feature_extractor = FeatureExtractor().cuda()
discriminator = Discriminator().cuda()# 损失函数和优化器
criterion = nn.BCELoss()
optimizer_feat = optim.Adam(feature_extractor.parameters(), lr=0.0001)
optimizer_disc = optim.Adam(discriminator.parameters(), lr=0.0001)# 假设有两个数据加载器:train_loader和target_loader
# 训练过程
for epoch in range(10):feature_extractor.train()discriminator.train()for (source_data, _), (target_data, _) in zip(train_loader, target_loader):source_data, target_data = source_data.cuda(), target_data.cuda()# 训练判别器discriminator.zero_grad()source_features = feature_extractor(source_data)target_features = feature_extractor(target_data)source_labels = torch.ones(source_data.size(0), 1).cuda()target_labels = torch.zeros(target_data.size(0), 1).cuda()source_pred = discriminator(source_features)target_pred = discriminator(target_features)disc_loss = criterion(source_pred, source_labels) + criterion(target_pred, target_labels)disc_loss.backward()optimizer_disc.step()# 训练特征提取器(反向更新判别器)feature_extractor.zero_grad()target_pred = discriminator(target_features)feat_loss = criterion(target_pred, source_labels)  # 用源标签训练目标数据feat_loss.backward()optimizer_feat.step()print(f'Epoch [{epoch+1}/10], Discriminator Loss: {disc_loss.item()}, Feature Loss: {feat_loss.item()}')
(2)最大均值差异(Maximum Mean Discrepancy, MMD)

最大均值差异方法的目标是通过计算源领域和目标领域特征分布之间的差异,最小化源领域和目标领域之间的分布差异。通过MMD,可以最大程度地减少源领域和目标领域之间的特征分布的差异,使得模型能够更好地在目标领域上进行推断。

以下是基于MMD的一个简化代码框架:

import torch
import torch.nn as nn
import torch.optim as optimclass MMDLoss(nn.Module):def __init__(self):super(MMDLoss, self).__init__()def forward(self, source_features, target_features):# 计算源领域和目标领域的最大均值差异(MMD)mmd_loss = torch.mean(source_features) - torch.mean(target_features)return torch.abs(mmd_loss)  # 返回MMD的绝对值作为损失# 假设我们已经有源领域和目标领域的特征
source_features = torch.randn(100, 256)  # 模拟源领域特征
target_features = torch.randn(100, 256)  # 模拟目标领域特征mmd_loss_fn = MMDLoss()
loss = mmd_loss_fn(source_features, target_features)
print(f"MMD Loss: {loss.item()}")
(3)自监督学习(Self-supervised Learning)

自监督学习是一种无监督学习方法,通过让模型解决一项自设的任务,帮助模型学习到有效的特征。例如,在图像领域,模型可能会学习预测图像的旋转角度或缺失的部分,以帮助提取有用的特征。自监督学习可以作为领域自适应的预训练步骤,使得模型能够从目标领域的无标注数据中学习有效的表示。

2.4 领域自适应的应用场景

领域自适应被广泛应用于多个领域,尤其在跨域任务中表现突出。以下是领域自适应的一些典型应用:

  1. 视觉领域适应

    • 在自动驾驶系统中,车辆的感知系统需要从不同的摄像头视角、不同的光照条件下适应。在这种情况下,从合成数据(例如虚拟模拟环境)到现实世界数据的迁移是非常重要的。
  2. 跨语言迁移

    • 在自然语言处理任务中,语言模型经常需要从一个语言的文本(例如英语)迁移到另一种语言(例如中文)。通过领域自适应技术,模型可以快速适应新语言的结构和语义。
  3. 情感分析

    • 在社交媒体上,文本的情感表达方式和产品评论中的情感表达方式有所不同。通过领域自适应,情感分析模型能够从一个领域(如社交媒体)迁移到另一个领域(如产品评论),从而提高准确性。

三、领域自适应中的对抗训练代码示例

对抗训练在领域自适应中非常重要,它通过训练一个判别器来区分源领域和目标领域的特征,并通过最大化特征共享来使得判别器难以区分这两个领域的特征。

以下是一个简化的PyTorch代码示例,展示了如何使用对抗训练进行领域自适应。

import torch
import torch.nn as nn
import torch.optim as optim
import torchvision.models as models
from torch.utils.data import DataLoader# 定义特征提取网络(例如ResNet)
class FeatureExtractor(nn.Module):def __init__(self):super(FeatureExtractor, self).__init__()self.resnet = models.resnet50(pretrained=True)self.resnet.fc = nn.Identity()  # 移除最后的全连接层def forward(self, x):return self.resnet(x)# 定义对抗网络(判别器)
class Discriminator(nn.Module):def __init__(self):super(Discriminator, self).__init__()self.fc = nn.Sequential(nn.Linear(2048, 1024),nn.ReLU(),nn.Linear(1024, 1),nn.Sigmoid())def forward(self, x):return self.fc(x)# 初始化模型
feature_extractor = FeatureExtractor().cuda()
discriminator = Discriminator().cuda()# 损失函数和优化器
criterion = nn.BCELoss()
optimizer_feat = optim.Adam(feature_extractor.parameters(), lr=0.0001)
optimizer_disc = optim.Adam(discriminator.parameters(), lr=0.0001)# 假设有两个数据加载器:train_loader和target_loader
# 训练过程
for epoch in range(10):feature_extractor.train()discriminator.train()for (source_data, _), (target_data, _) in zip(train_loader, target_loader):source_data, target_data = source_data.cuda(), target_data.cuda()# 训练判别器discriminator.zero_grad()source_features = feature_extractor(source_data)target_features = feature_extractor(target_data)source_labels = torch.ones(source_data.size(0), 1).cuda()target_labels = torch.zeros(target_data.size(0), 1).cuda()source_pred = discriminator(source_features)target_pred = discriminator(target_features)disc_loss = criterion(source_pred, source_labels) + criterion(target_pred, target_labels)disc_loss.backward()optimizer_disc.step()# 训练特征提取器(反向更新判别器)feature_extractor.zero_grad()target_pred = discriminator(target_features)feat_loss = criterion(target_pred, source_labels)  # 用源标签训练目标数据feat_loss.backward()optimizer_feat.step()print(f'Epoch [{epoch+1}/10], Discriminator Loss: {disc_loss.item()}, Feature Loss: {feat_loss.item()}')

这个代码展示了如何通过对抗训练来进行领域自适应。通过训练一个判别器,我们使得源领域和目标领域的特征尽可能接近,从而提高模型的领域适应能力。


四、总结

迁移学习和领域自适应是深度学习领域中解决数据稀缺和分布差异问题的重要技术。通过迁移学习,我们能够加速模型在目标任务中的学习过程,尤其是在目标任务数据不足的情况下。而领域自适应则专注于解决源领域和目标领域之间的分布差异问题,帮助模型在目标领域上获得更好的表现。

随着技术的进步,迁移学习与领域自适应在越来越多的领域中得到了广泛应用,尤其是在计算机视觉、自然语言处理和语音识别等领域。希望本文通过理论的介绍和代码示例,能够帮助您更好地理解并实践这些技术。

完——


至此结束——

我是云边有个稻草人

期待与你的下一次相遇

相关文章:

从源到目标:深度学习中的迁移学习与领域自适应实践

云边有个稻草人-CSDN博客 目录 引言 一、迁移学习概述 1.1 迁移学习的类型 1.2 迁移学习的核心思想 1.3 迁移学习的应用场景 二、领域自适应(Domain Adaptation) 2.1 领域自适应的定义 2.2 领域自适应的挑战 2.3 领域自适应的核心方法 &#…...

WebRTC与PJSIP:呼叫中心系统技术选型指南

助力企业构建高效、灵活的通信解决方案 在数字化时代,呼叫中心系统的技术选型直接影响客户服务效率和业务扩展能力。WebRTC与PJSIP作为两大主流通信技术,各有其核心优势与适用场景。本文从功能、成本、开发门槛等维度为您深度解析,助您精准匹…...

使用IDEA如何隐藏文件或文件夹

选择file -> settings 选择Editor -> File Types ->Ignored Files and Folders (忽略文件和目录) 点击号就可以指定想要隐藏的文件或文件夹...

【人工智能】数据挖掘与应用题库(1-100)

1、涉及变化快慢的问题可以考虑使用导数来分析。 答案:对 2、导数的几何意义是曲线在某点处切线的斜率。 答案:对 3、函数在某点的左导数存在,则导数就存在。 答案:错 4、关于梯度下降算法,下列说法错误的是( ) 错误:梯度下降算法能找到函数精确的最小值。 5、正…...

腾讯云大模型知识引擎驱动的DeepSeek满血版医疗顾问大模型搭建实战

文章目录 1. 引言2. 什么是腾讯云大模型知识引擎(LKE)?核心优势功能特点应用场景 3. 模型搭建过程3.1 注册登录产品3.2 创建应用3.3 配置模型3.4 配置角色指令3.5 配置欢迎语3.6 配置知识库3.7 配置工作流3.8 启用联网搜索3.9 发布模型 4. 问…...

大白话页面加载速度优化的工具与实践案例

大白话页面加载速度优化的工具与实践案例 优化工具 Chrome开发者工具:这是个超好用的浏览器自带工具。就像你给车做检查的一套工具一样,能帮你查看页面加载的各种情况。比如说,你能在“Network”(网络)选项里看到每个…...

【JAVA面试题】什么是面向对象?谈谈你对面向对象的理解。

【JAVA面试题】什么是面向对象?谈谈你对面向对象的理解 在 Java 面试中,面向对象 是一个高频考点。它不仅是一种编程思想,更是现代软件开发的核心方法论。本文将从 面向对象的概念、与面向过程的对比、以及 面向对象的三大特性(封…...

解锁责任链模式:Java 实战与应用探秘

系列文章目录 后续补充~~~ 文章目录 一、责任链模式基础入门1.1 责任链模式的定义1.2 核心角色剖析1.2.1 抽象处理者(Handler)1.2.2 具体处理者(ConcreteHandler)1.2.3 客户端(Client) 1.3 类图结构展示 二…...

华为 Open Gauss 数据库在 Spring Boot 中使用 Flyway

db-migration:Flyway、Liquibase 扩展支持达梦(DM)、南大通用(GBase 8s)、OpenGauss 等国产数据库。部分数据库直接支持 Flowable 工作流。 开源代码仓库 Github:https://github.com/mengweijin/db-migrat…...

汽车电子电控软件开发中因复杂度提升导致的架构恶化问题

针对汽车电子电控软件开发中因复杂度提升导致的架构恶化问题,建议从以下方向进行架构优化和开发流程升级,以提升灵活性、可维护性和扩展性: 一、架构设计与模块化优化 分层架构与模块解耦 采用AUTOSAR标准的分层架构(应用层、运行…...

VMware Ubuntu 共享目录

在VMware中挂载Ubuntu共享目录需要以下步骤,分为设置共享文件夹和在Ubuntu中挂载两部分: 一、VMware 设置共享文件夹 关闭Ubuntu虚拟机 在配置前,建议先关闭虚拟机(若已运行需关闭,部分VMware版本支持热添加&#xff0…...

Linux安装jdk,node,mysql,redis

准备工作: 1.安装VMware软件,下载CentOs7镜像文件,在VMware安装CentOs7 2.宿主机安装Xshell用来操作linux 3. .宿主机安装Xftp用来在宿主机和虚拟机的linux传输文件 案例1:在 /home/soft文件夹解压缩jdk17,并配置环…...

Excel工作圈小工具一个集合了大量Excel功能的绿色工具软件

​Excel工作圈小工具 一个集合了大量Excel功能的绿色工具软件,可以大大加强生产效率~ 软件虽然看起来比较简陋,但功能却是十分丰富。无需联网即可运行,而且兼容WPS和MS office各版本。 以下是软件的功能详细截图。 总的来说功能挺丰富&#…...

DeepSeek实操教程(清华、北大)

文末清华大学及北京大学DeepSeek下载地址 1. 地址 2. 提示词 模板:我要(做)xxx,要给xxx用,希望达到xxx效果,但担心xxx问题 3. 软件联动 基本原则:Deepseek生成内容,以其它软件…...

模拟退火算法浅尝

简介 其是模拟物理退火过程而演升出的算法,物理退火过程包含加温过程,等温过程,冷却过程。 模拟退火(SA) 初始设定为高温状态,看作是在解空间进行广域搜,处于低温状态时,看作是在解空间中作局部领域搜索…...

React:B站评论demo,实现列表渲染、删除按钮显示和功能实现、导航栏渲染切换及高亮显示、评论区的排序

功能要求: 1、渲染评论列表 2、删除评论功能:只显示自己评论的删除按钮;点击删除按钮,删除当前评论,列表中不再显示。 3、渲染导航Tab(最新 | 最热)和其 高亮实现 4、评论排序功能实现&…...

支持IPD项目管理的9大系统,哪款工具能有效提高项目控制能力

本文介绍了以下9大系统: 1.Worktile; 2. 腾讯敏捷开发平台(TAPD); 3. 简道云(Jiandaoyun); 4. 蓝鲸智云(BlueWhale); 5. 轻流(Qingflow&#xff0…...

4070Super安装GPU版本pytorch记录

一些啐啐念。 安装LLaMA-Factory时遇到pytorch安装成CPU版本。网上找了一圈攻略,都是下载龟速。挂梯子也一样。最后在尝试用pytorch官网的生成的命令进行安装时,突然奇想,直接把安装日志显示的下载链接复制到浏览器下载,发现可以满…...

SpringBoot 端口配置

在Spring Boot中,配置应用程序的监听端口有多种方式。以下是常见的几种方法: 1. 通过 application.properties 或 application.yml 文件配置 application.properties server.port8081application.yml server:port: 8081如果没有显式配置 server.port…...

Linux网络相关概念和重要知识(1)(网络协议、网络通信)

目录 1.网络协议 (1)网络的起源 (2)为什么需要协议 (3)协议分层及其设计的解耦 (4)OSI定义的七层网络模型 ①分层及其功能 ②TCP/IP协议 ③传输层协议(TCP和UDP&a…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...

7.4.分块查找

一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...

uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖

在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?

论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...

cf2117E

原题链接&#xff1a;https://codeforces.com/contest/2117/problem/E 题目背景&#xff1a; 给定两个数组a,b&#xff0c;可以执行多次以下操作&#xff1a;选择 i (1 < i < n - 1)&#xff0c;并设置 或&#xff0c;也可以在执行上述操作前执行一次删除任意 和 。求…...

C# SqlSugar:依赖注入与仓储模式实践

C# SqlSugar&#xff1a;依赖注入与仓储模式实践 在 C# 的应用开发中&#xff0c;数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护&#xff0c;许多开发者会选择成熟的 ORM&#xff08;对象关系映射&#xff09;框架&#xff0c;SqlSugar 就是其中备受…...

有限自动机到正规文法转换器v1.0

1 项目简介 这是一个功能强大的有限自动机&#xff08;Finite Automaton, FA&#xff09;到正规文法&#xff08;Regular Grammar&#xff09;转换器&#xff0c;它配备了一个直观且完整的图形用户界面&#xff0c;使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

AI,如何重构理解、匹配与决策?

AI 时代&#xff0c;我们如何理解消费&#xff1f; 作者&#xff5c;王彬 封面&#xff5c;Unplash 人们通过信息理解世界。 曾几何时&#xff0c;PC 与移动互联网重塑了人们的购物路径&#xff1a;信息变得唾手可得&#xff0c;商品决策变得高度依赖内容。 但 AI 时代的来…...

Vue ③-生命周期 || 脚手架

生命周期 思考&#xff1a;什么时候可以发送初始化渲染请求&#xff1f;&#xff08;越早越好&#xff09; 什么时候可以开始操作dom&#xff1f;&#xff08;至少dom得渲染出来&#xff09; Vue生命周期&#xff1a; 一个Vue实例从 创建 到 销毁 的整个过程。 生命周期四个…...

springboot 日志类切面,接口成功记录日志,失败不记录

springboot 日志类切面&#xff0c;接口成功记录日志&#xff0c;失败不记录 自定义一个注解方法 import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/***…...