hook函数

news2024/11/15 8:48:17

什么是hook函数

在计算机编程中,hook函数是指在特定的事件发生时被调用的函数,用于在事件发生前或后进行一些特定的操作。通常,hook函数作为回调函数被注册到事件处理器中,当事件发生时,事件处理器会自动调用相应的hook函数。

hook函数通常用于实现程序的扩展性和可定制性,允许用户在程序运行时添加自定义的操作或修改程序的行为。在很多框架和库中,hook函数被广泛应用于实现特定的功能和操作,例如在深度学习框架中,hook函数可以用于记录指标、可视化网络结构、保存模型和优化器状态等。

一些常见的hook函数包括:

  • pre-hook:在函数或方法执行前被调用,用于修改或拦截函数的输入参数或返回值。
  • post-hook:在函数或方法执行后被调用,用于修改或拦截函数的返回值。
  • exception-hook:在函数或方法抛出异常时被调用,用于处理或记录异常信息。
  • event-hook:在特定事件发生时被调用,例如程序启动、程序结束、网络连接、文件读写等。

总的来说,hook函数是一种非常有用的编程技术,可以增强程序的灵活性和可扩展性,同时也可以帮助程序员更好地理解程序的运行行为和调试程序的错误。

mmlab中hook函数

OpenMMLab 中的 Hook 机制其实是面向切面编程 (Aspect Oriented Program, AOP) 编程思想的一种体现。
在mmlab中,hook函数是指在模型训练过程中插入的一些回调函数,用于在训练过程中进行一些特定的操作,例如记录和可视化训练指标、保存模型和优化器状态等。hook函数可以通过继承mmcv.runner.Hook类来实现。

以下是一些常见的hook函数:

  1. CheckpointHook:用于保存模型和优化器状态,以便在训练过程中进行断点续训。可以使用CheckpointHook来定期保存模型和优化器状态,例如:
from mmcv.runner import CheckpointHook

checkpoint_hook = CheckpointHook(interval=1, save_optimizer=True, out_dir='checkpoints')

其中,interval参数表示保存模型和优化器状态的间隔(单位为epoch),save_optimizer参数表示是否保存优化器状态,out_dir参数表示保存路径。

  1. DistSamplerSeedHook:用于设置分布式训练中的随机种子,以保证不同进程的随机数生成一致。可以使用DistSamplerSeedHook来设置随机种子,例如:
from mmcv.runner import DistSamplerSeedHook

dist_sampler_seed_hook = DistSamplerSeedHook()
  1. EMAHook:用于计算指数移动平均值(EMA)并更新模型参数,以提高模型的鲁棒性。可以使用EMAHook来计算EMA并更新模型参数,例如:
from mmcv.runner import EMAHook

ema_hook = EMAHook(0.99, interval=1, optimizer_momentum_based=True)

其中,0.99是EMA的衰减率,interval是EMA更新的间隔(单位为epoch),optimizer_momentum_based表示是否使用优化器的动量来计算EMA。

  1. LoggerHook:用于记录和可视化训练指标,例如损失和准确率。可以使用LoggerHook来记录和可视化训练指标,例如:
from mmcv.runner import LoggerHook

logger_hook = LoggerHook(interval=10)

其中,interval参数表示记录和可视化训练指标的间隔(单位为iteration)。

除了上述hook函数外,mmlab还提供了许多其他的hook函数,例如CheckpointLoaderHookLrUpdaterHookOptimizerHook等,可以根据具体需求选择使用。这些hook函数可以方便地插入到模型训练过程中,以实现特定的功能和操作。
https://zhuanlan.zhihu.com/p/387483425
https://zhuanlan.zhihu.com/p/355272220

Hook 技术应用非常广泛,可以随便找一个简单例子来说明其用途。在软件编程的设计模式中,有一种设计模式叫做观察者设计模式,该设计模式实现的功能是:对于被观察者的一举一动,观察者都能够立即观测到,其内部实现机制可以简单通过 hook 机制实现

观察者设计模式是一种常用的设计模式,它用于实现对象间的一对多依赖关系。在观察者设计模式中,当被观察者对象的状态发生改变时,所有观察者对象都能够接收到通知并立即做出相应的响应。

在实现观察者设计模式时,可以使用hook技术来实现被观察者对象和观察者对象之间的通信。具体来说,可以将观察者对象的方法作为hook函数,注册到被观察者对象中。当被观察者对象的状态发生改变时,它会自动调用所有注册的hook函数,从而通知所有的观察者对象。

例如,假设我们要实现一个简单的观察者设计模式,用于监控一个温度传感器的温度变化。可以定义一个TemperatureSensor类作为被观察者对象,和一个Observer类作为观察者对象。在TemperatureSensor类中,可以定义一个add_observer方法,用于注册观察者对象的update方法作为hook函数。在TemperatureSensor类中,可以使用hook技术来通知所有观察者对象当前的温度值。

class TemperatureSensor:
    def __init__(self):
        self.observers = []

    def add_observer(self, observer):
        self.observers.append(observer.update)

    def remove_observer(self, observer):
        self.observers.remove(observer.update)

    def set_temperature(self, temperature):
        # 更新温度值
        self.temperature = temperature
        # 调用所有观察者对象的 update 方法
        for observer in self.observers:
            observer(self.temperature)


class Observer:
    def update(self, temperature):
        # 处理温度变化的通知
        pass

在上述代码中,TemperatureSensor类是被观察者对象,它有一个add_observer方法,用于注册观察者对象的update方法作为hook函数。Observer类是观察者对象,它有一个update方法,用于处理被观察者对象传递的温度变化通知。在TemperatureSensor类的set_temperature方法中,调用所有注册的hook函数来通知所有观察者对象当前的温度值。

因此,通过使用hook技术,可以很方便地实现观察者设计模式,从而实现对象间的一对多依赖关系,并且能够在被观察者对象的状态发生改变时自动通知所有观察者对象。

python如何实现hook函数

在Python中,可以通过定义函数或类来实现hook函数。以下是两种实现hook函数的方法:

  1. 定义函数

可以定义一个函数来实现hook函数,然后将该函数注册到事件处理器中。例如:

def my_hook(*args, **kwargs):
    # 在事件发生时执行特定的操作
    pass

# 注册函数到事件处理器中
event_handler.register(my_hook)

在上述代码中,my_hook函数是一个hook函数,可以在事件发生时执行特定的操作。通过将my_hook函数注册到事件处理器中,就可以在相应的事件发生时自动调用该函数。

  1. 定义类

可以定义一个类来实现hook函数,然后将该类实例化并注册到事件处理器中。例如:

class MyHook:
    def __init__(self, *args, **kwargs):
        pass

    def __call__(self, *args, **kwargs):
        # 在事件发生时执行特定的操作
        pass

# 实例化类并注册到事件处理器中
my_hook = MyHook()
event_handler.register(my_hook)

在上述代码中,MyHook类是一个hook函数的实现,可以在事件发生时执行特定的操作。通过实例化MyHook类并将其注册到事件处理器中,就可以在相应的事件发生时自动调用该类的__call__方法。

总的来说,Python中的hook函数实现方法可以根据具体的场景和需求来选择,可以通过定义函数或类来实现hook函数,并将其注册到事件处理器中以实现特定的功能和操作。

pytoch中的hook函数

在PyTorch中,hook函数是一种非常有用的工具,可以在模型训练过程中获取模型的中间输出结果、梯度信息等,从而进行进一步的分析和处理。PyTorch中的hook函数可以通过注册hook到模型的某一层中来实现。

具体来说,PyTorch中的hook函数可以通过register_forward_hookregister_backward_hook方法来注册到模型的某一层中。其中,register_forward_hook方法可以在模型前向传递过程中获取该层的中间输出结果,register_backward_hook方法可以在模型反向传递过程中获取该层的梯度信息。

例如,以下代码展示了如何在模型的某一层中注册hook函数:

import torch.nn as nn

class MyModel(nn.Module):
    def __init__(self):
        super(MyModel, self).__init__()
        self.conv1 = nn.Conv2d(3, 64, 3, 1, 1)
        self.conv2 = nn.Conv2d(64, 128, 3, 1, 1)
        self.fc = nn.Linear(128 * 28 * 28, 10)

    def forward(self, x):
        x = self.conv1(x)
        x = self.conv2(x)
        x = x.view(-1, 128 * 28 * 28)
        x = self.fc(x)
        return x

model = MyModel()

# 定义 hook 函数
def my_hook_fn(module, input, output):
    print(f"Module: {module}")
    print(f"Input: {input}")
    print(f"Output: {output}")

# 注册 hook 函数到模型中的某一层
layer = model.conv1
hook_handle = layer.register_forward_hook(my_hook_fn)

在上述代码中,我们定义了一个名为my_hook_fnhook函数,该函数用于在模型前向传递过程中获取该层的中间输出结果。然后,我们将该hook函数注册到模型的第一层卷积层中。通过调用register_forward_hook方法并传入my_hook_fn函数,我们可以将my_hook_fn函数注册到模型的第一层卷积层中,并返回一个hook handle,该hook handle可以用于删除该hook函数。

在训练过程中,每当模型前向传递到第一层卷积层时,my_hook_fn函数就会被调用并输出该层的中间输出结果。通过注册hook函数,我们可以方便地获取模型的中间输出结果,并进行进一步的分析和处理。
为了节省显存(内存),PyTorch会自动舍弃图计算的中间结果,所以想要获取这些数值就需要使用hook函数。hook函数在使用后应及时删除(remove),以避免每次都运行钩子增加运行负载。

这里总结一下并给出实际用法和注意点。hook方法有4种:

1、Tensor.register_hook()
2、torch.nn.Module.register_forward_hook()
3、torch.nn.Module.register_backward_hook()
4、torch.nn.Module.register_forward_pre_hook()
在这里插入图片描述

1.Tensor.register_hook(hook):对于单个张量,可以使用register_hook()方法注册一个hook。该方法将一个函数(即hook)注册到张量上,在张量被计算时调用该函数。这个函数可以用来获取张量的梯度或值,或者对张量进行其他操作。例如,以下代码演示了如何使用register_hook()方法获取张量的梯度:

import torch

x = torch.randn(2, 2, requires_grad=True)

def print_grad(grad):
    print(grad)

hook_handle = x.register_hook(print_grad)

y = x.sum()

y.backward()

hook_handle.remove()

在这个例子中,我们创建了一个包含梯度的张量x,并使用register_hook()方法注册了一个打印梯度的hook函数print_grad()。在计算y的梯度时,hook函数被调用并打印梯度。最后,我们使用hook_handle.remove()方法从张量中删除hook函数。

在这里插入图片描述

2.torch.nn.Module.register_forward_hook(hook):对于模型中的每个层,可以使用register_forward_hook()方法注册一个hook函数。这个函数将在模型的前向传递中被调用,并可以用来获取层的输出。例如,以下代码演示了如何使用register_forward_hook()方法获取模型的某一层的输出:

import torch.nn as nn

class MyModel(nn.Module):
    def __init__(self):
        super(MyModel, self).__init__()
        self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1)
        self.relu = nn.ReLU(inplace=True)
        self.conv2 = nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1)
        self.avgpool = nn.AdaptiveAvgPool2d((1, 1))

    def forward(self, x):
        x = self.conv1(x)
        x = self.relu(x)
        x = self.conv2(x)
        x = self.relu(x)
        x = self.avgpool(x)
        return x

def hook(module, input, output):
    print(output.shape)

model = MyModel()
handle = model.conv2.register_forward_hook(hook)

x = torch.randn(1, 3, 224, 224)
output = model(x)

handle.remove()


class MyModel(nn.Module):
    def __init__(self):
        super(MyModel, self).__init__()
        self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1)
        self.relu = nn.ReLU(inplace=True)
        self.conv2 = nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1)
        self.avgpool = nn.AdaptiveAvgPool2d((1, 1))

    def forward(self, x):
        x = self.conv1(x)
      
class MyModel(nn.Module):
    def __init__(self):
        super(MyModel, self).__init__()
        self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1)
        self.relu = nn.ReLU(inplace=True)
        self.conv2 = nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1)
        self.avgpool = nn.AdaptiveAvgPool2d((1, 1))

    def forward(self, x):
        x = self.conv1(x)


class MyModel(nn.Module):
    def __init__(self):
        super(MyModel, self).__init__()
        self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1)
        self.relu = nn.ReLU(inplace=True)
        self.conv2 = nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1)
        self.avgpool = nn.AdaptiveAvgPool2d((1, 1))

    def forward(self, x):
        x = self.conv1(x)


class MyModel(nn.Module):
    def __init__(self):
        super(MyModel, self).__init__()
        self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1)
        self.relu = nn.ReLU(inplace=True)
        self.conv2 = nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1)
        self.avgpool = nn.AdaptiveAvgPool2d((1, 1))

    def forward(self, x):
        x = self.conv1(


class MyModel(nn.Module):
    def __init__(self):
        super(MyModel, self).__init__()
        self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1)
        self.relu = nn.ReLU(inplace=True)
        self.conv2 = nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1)
        self.avgpool = nn.AdaptiveAvgPool2d((1, 1))

    def forward(self, x):
   		 pass

在这个例子中,我们定义了一个包含两个卷积层和一个全局平均池化层的模型,并使用register_forward_hook()方法在第二个卷积层上注册了一个hook函数。当模型进行前向传递时,hook函数将被调用并打印输出张量的形状。最后,我们使用handle.remove()方法从模型中删除hook函数。

在这里插入图片描述

torch.nn.Module.register_backward_hook(hook):对于模型中的每个层,可以使用register_backward_hook()方法注册一个hook函数。这个函数将在模型的反向传递中被调用,并可以用来获取梯度或其他信息。例如,以下代码演示了如何使用register_backward_hook()方法获取某一层的梯度

import torch.nn as nn

class MyModel(nn.Module):
    def __init__(self):
        super(MyModel, self).__init__()
        self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1)
        self.relu = nn.ReLU(inplace=True)
        self.conv2 = nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1)
        self.avgpool = nn.AdaptiveAvgPool2d((1, 1))

    def forward(self, x):
        x = self.conv1(x)
        x = self.relu(x)
        x = self.conv2(x)
        x = self.relu(x)
        x = self.avgpool(x)
        return x

def hook(module, grad_input, grad_output):
    print(grad_input[0].shape, grad_output[0].shape)

model = MyModel()
handle = model.conv2.register_backward_hook(hook)

x = torch.randn(1, 3, 224,
output = model(x)
output.sum().backward()

handle.remove()

在这个例子中,我们定义了一个包含两个卷积层和一个全局平均池化层的模型,并使用register_backward_hook()方法在第二个卷积层上注册了一个hook函数。当模型进行反向传递时,hook函数将被调用并打印输入梯度和输出梯度张量的形状。最后,我们使用handle.remove()方法从模型中删除hook函数。

在这里插入图片描述

  1. torch.nn.Module.register_forward_pre_hook(hook):对于模型中的每个层,可以使用register_forward_pre_hook()方法注册一个hook函数。这个函数将在模型的前向传递之前被调用,并可以用来获取输入张量或其他信息。例如,以下代码演示了如何使用register_forward_pre_hook()方法获取模型的输入张量:
import torch.nn as nn

class MyModel(nn.Module):
def init(self):
super(MyModel, self).init()
self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1)
self.relu = nn.ReLU(inplace=True)
self.conv2 = nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1)
self.avgpool = nn.AdaptiveAvgPool2d((1, 1))

def forward(self, x):
    x = self.conv1(x)
    x = self.relu(x)
    x = self.conv2(x)
    x = self.relu(x)
    x = self.avgpool(x)
    [return x](poe://www.poe.com/_api/key_phrase?phrase=return%20x&prompt=Tell%20me%20more%20about%20return%20x.)
def hook(module, input):
print(input[0].shape)

model = MyModel()
handle = model.conv1.register_forward_pre_hook(hook)

x = torch.randn(1, 3, 224, 224)
output = model(x)

handle.remove()

在这个例子中,我们定义了一个包含两个卷积层和一个全局平均池化层的模型,并使用register_forward_pre_hook()方法在第一个卷积层上注册了一个hook函数。当模型进行前向传递时,hook函数将被调用并打印输入张量的形状。最后,我们使用handle.remove()方法从模型中删除hook函数。

需要注意的是,hook函数应该尽可能快地执行,以避免对模型的计算时间造成过多的影响。此外,如果注册了太多的hook函数,会导致额外的内存占用和计算负担。因此,应该仔细考虑何时需要注册hook函数,并在使用后及时删除它们。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/464856.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

QtDAY 2

代码&#xff1a; 头文件&#xff1a; #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QDebug> #include <QString> #include <QTextToSpeech>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : …

【Hello Network】网络编程套接字(二)

作者&#xff1a;小萌新 专栏&#xff1a;网络 作者简介&#xff1a;大二学生 希望能和大家一起进步 本篇博客简介&#xff1a;简单介绍网络的基础概念 网络编程套接字&#xff08;二&#xff09; 简单的TCP网络程序服务端创建套接字服务端绑定服务器监听服务端获取连接服务端处…

Qt Quick Qml-Rectangle案例

Qt Quick - Qml 1.Rectangle //组件 IShadow.qml import QtQuick import QtQuick.ControlsItem {id:rootanchors.fill: parentanchors.margins: -4property color color: "#999999"property int radius: 4Rectangle{width: root.widthheight: root.heightanchors.ce…

原型图都可以用什么软件做?分享这9款给你

设计师在进行原型设计师时&#xff0c;会使用原型图软件&#xff0c;从产生想法到向开发人员提交项目。无论是构建基本线框还是功能齐全的原型&#xff0c;原型图软件都可以为你节省大量的时间和精力。 如果你是这个领域的新手或者想更新你的原型图软件包&#xff0c;请快速看…

iOS App的生命周期

App的生命周期 App从启动到退出的过程中&#xff0c;iOS应用程序不断从系统接收各种事件&#xff0c;如&#xff1a;用户点击了屏幕、用户点击了Home键&#xff0c;并对这些事件进行响应。接受事件是UIApplication对象的工作&#xff0c;但是&#xff0c;响应事件就需要由程序…

Dubbo详解

一、基础知识 1、 RPC RPC【Remote Procedure Call】是指远程过程调用&#xff0c;是一种进程间通信方式&#xff0c;他是一种技术的思想&#xff0c;而不是规范。它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数&#xff0c; 而不用程序员显式编码…

【unity细节】—(Can‘t add script)脚本文件无法拖拽到对象的问题

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 秩沅 原创 收录于专栏&#xff1a;unity细节和bug ⭐关于脚本文件无法拖拽到对象的问题⭐ 文章目录 ⭐关于脚本文件无法拖拽到对象的…

分治算法(Divide and Conquer)

本文已收录于专栏 《算法合集》 一、简单释义 1、分治算法 字面上的解释是“分而治之”&#xff0c;就是把一个复杂的问题拆分成两个或更多的相同或相似的子问题&#xff0c;再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解&#xff0c;原问题的解即子问题的…

什么是FAQ页面?如何设计一个优秀的FAQ页面?

随着互联网技术的迅猛发展&#xff0c;越来越多的企业开始将在线客户支持服务作为一种重要的业务方式&#xff0c;以提供更好的服务体验。然而&#xff0c;在线客户支持服务除了提供实时的沟通方式外&#xff0c;一个功能齐全、易于使用的FAQ页面也是必不可少的&#xff0c;这可…

Go 语言进阶与依赖管理

作者&#xff1a;非妃是公主 专栏&#xff1a;《Golang》 博客主页&#xff1a;https://blog.csdn.net/myf_666 个性签&#xff1a;顺境不惰&#xff0c;逆境不馁&#xff0c;以心制境&#xff0c;万事可成。——曾国藩 文章目录 一、语言进阶1. 并发和并行2. 协程(Goroutine…

软件or硬件?硬件的前途到底在哪里?

一、硬件明明比软件更难&#xff0c;国内的硬件技术也不如软件&#xff0c;为什么硬件工程师待遇还不如软件&#xff1f; 1、不需要太高层次的硬件设计&#xff0c;比如大部分小家电企业&#xff0c;简单的电子产品企业&#xff0c;单片机简单外围设计就够了&#xff0c;单片机…

java网络编程——NIO架构

目录 1.什么是NIO 2.NIO结构 3.基于NIO下的聊天系统实现 4.Netty 1.什么是NIO NIO&#xff1a;java non-blocking IO&#xff0c;同步非阻塞IO。 BIO是阻塞IO&#xff0c;即每一个事件都需要分配一个进程给他&#xff0c;如果客户端没有连接上&#xff0c;则一直阻塞等待…

Java基础--->并发部分(1)

文章目录 线程基本概念线程的创建方式线程调度-------常用的方法线程的生命周期和状态并发编程的根本原因Java内存模型(JMM)多线程核心的根本问题volatile关键字保障原子性synchronized和ReentrantLock的区别 线程基本概念 ​ 进程是程序的一次执行过程&#xff0c;是系统运行程…

【Linux】1.4 基本权限

文章目录 一、shell 命令以及运行原理二、Linux 权限的概念三、Linux 权限管理01.文件类型和访问权限&#xff08;事物属性&#xff09;02.文件访问的分类&#xff08;人&#xff09;①用户分类②角色划分 03.文件权限值的表现方法04.文件访问权限的相关设置方法&#xff08;a.…

STC8H8K64U单片机-看门狗配置与讲解

1、看门狗寄存器讲解 &#xff08;bit7&#xff09;WDT_FLAG&#xff1a;看门狗溢出标志&#xff0c;看门狗发生溢出时&#xff0c;硬件自动将此位置1&#xff0c;需要软件清零 &#xff08;bit5&#xff09;EN_WDT&#xff1a;看门狗使能位 0&#x…

被优化了怎么办?他苦学仨月拿到11koffer

网上有个段子叫做“生活就是起起落落落落落落”。人生在世&#xff0c;本就不易&#xff0c;再加上最近大环境影响&#xff0c;各行各业都在内卷&#xff0c;身为芸芸众生的一员&#xff0c;我们也难免受到影响&#xff0c;面临福利裁剪、降薪、甚至被优化的风险。 大环境我们…

面了20家大厂,发现这样介绍项目经验,显得项目很牛...

我在刚刚开始面试的时候&#xff0c;也遇到了这个问题&#xff0c;也是我第一个思考的问题&#xff0c;如何介绍自己的项目&#xff0c;既可以比较全面的让面试官了解这个项目&#xff0c;同时&#xff0c;也不会让面试官觉得废话太多。经过这么多的面试&#xff0c;我发现&…

JavaWeb+JSP+路径问题+跳转(HTML|Servlet|JSP)|这一篇就够了(超详细)

&#x1f648;作者简介&#xff1a;练习时长两年半的Java up主 &#x1f649;个人主页&#xff1a;老茶icon &#x1f64a; ps:点赞&#x1f44d;是免费的&#xff0c;却可以让写博客的作者开兴好久好久&#x1f60e; &#x1f4da;系列专栏&#xff1a;Java全栈&#xff0c;计…

ChatGPT真能取代程序员吗,看看它怎么解释SQL注入漏洞的问题

本文首发自「慕课网」&#xff0c;想了解更多IT干货内容&#xff0c;程序员圈内热闻&#xff0c;欢迎关注"慕课网"&#xff01; 作者&#xff1a;Beerus|慕课网讲师 背景 本周在《Web安全渗透测试》课程的QQ群中&#xff0c;有同学提问了一个关于网上一个关于SQL注入…

大淘宝技术斩获NTIRE 2023视频质量评价比赛冠军(内含夺冠方案)

近日&#xff0c;CVPR NTIRE 2023 Quality Assessment of Video Enhancement Challenge比赛结果公布&#xff0c;来自大淘宝音视频技术团队的同学组成「TB-VQA」队伍&#xff0c;从37支队伍中脱颖而出&#xff0c;拿下该比赛&#xff08;唯一赛道&#xff09;冠军。此次夺冠是团…