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

TenserRT(四)在 PYTORCH 中支持更多 ONNX 算子

第四章:在 PyTorch 中支持更多 ONNX 算子 — mmdeploy 0.12.0 文档

PyTorch扩充。

PyTorch转换成ONNX:

  • PyTorch有实现。
  • PyTorch可以转化成一个或者多个ONNX算子。
  • ONNX有相应算子。

如果即没有PyTorch实现,且缺少PyTorch与ONNX的映射关系,则需要:

  • Pytorch算子
    • 组合现有算子
    • 添加TorchScript算子
    • 添加普通C++拓展算子
  • 映射方法
    • 为ATen算子添加符号函数
    • 为TorchScript算子添加符号函数
    • 封装成torch.autograd.Function并添加符号函数
  • ONNX算子
    • 使用现用ONNX算子
    • 定义新ONNX算子

不同的情况需要灵活的选用和组合这些方法。

支持 ATen 算子

算子在ATen中已经实现,ONNX也有相关算子定义,但是相关算子映射成ONNX的规则没有写。为ATen算子补充描述映射规则的符号函数。

PyTorch C++ API — PyTorch master documentation ATen是PyTorch内置的C++张量计算库,PyTorch算子在底层绝大多数计算都是用ATen实现的。

例如ONNX的Asinh https://github.com/onnx/onnx/blob/main/docs/Operators.md#Asinh 算子在ATen中有实现,但缺少映射到ONNX算子的符号函数,则需要补全符号函数,并导出一个包含该算子的ONNX模型。

获取 ATen 中算子接口定义

torch/_C/_VariableFunctions.pyi和 torch/nn/functional.pyi 两个文件可以获取函数的输入定义,这两个文件是编译pytorch时自动生成的,里面包含了ATen算子的pytorch调用接口,在torch/_C/_VariableFunctions.pyi中搜索asinh接口为

def asinh(input: Tensor, *, out: Optional[Tensor]=None) -> Tensor: ...

缺失算子为asinh,在ATen中实现的算子,在_VariableFunctions.pyi找到对应接口,需要补充对应的符号函数,使其在转场ONNX时不在报错。

添加符号函数

符号函数,看成pytorch的静态方法,将pytroch转换成ONNX模型时,pytroch算子的符号函数将被依次调用,已完成Pytorch算子到ONNX算子的转换。

def symbolic(g: torch._C.Graph, input_0: torch._C.Value, input_1: torch._C.Value, ...):

torch._C.Graph 和 torch._C.Value对应Pytorch的C++实现里的一些类。第一个参数g,表示和计算图相关内容;后面的参数input是算子输入,需要和算子的前向推理接口输入已知。对于ATen算子来说就时两个.pyi文件里的函数接口。

g有一个op方法。把pytorc算子转换成ONNX算子时,需要在符号函数中调用此方法来最终计算投图添加一个ONNX算子

def op(name: str, input_0: torch._C.Value, input_1: torch._C.Value, ...)

name:算子名称,如ONNX算子名称。

简单情况,将pytorch算子的输入用g.op()一一对应到ONNX算子上,并把g.op()的返回值作为符号函数的返回值。复杂的情况,将一个pytorch算子新建为若干个ONNX算子。

from torch.onnx import register_custom_op_symbolic
def asinh_symbolic(g, input):return g.op("custom_domain::Asinh", input)register_custom_op_symbolic('custom_ops::asinh', asinh_symbolic, 9)

asinh_symbolic就是asinh符号函数,输入参数需要按照在ATen中的定义

def asinh(input: Tensor, *, out: Optional[Tensor]=None) -> Tensor: ...

符号函数的函数体重g.op("custom_domain::Asinh", input)完成了ONNX算子的定义,第一个参数custom_domain::Asinh是算子在ONNX中的名称,之于第二个参数input,这个算子只有一个输入,主需要把符号函数的输入参数input对应过去就可以了。ONNX的custom_domain::Asinh输出和ATen的asinh的输出一直,因此直接把g.op()结果返回即可。

使用pytorch API中register_op将富含函数和原来的ATen算子绑定在一起,

register_custom_op_symbolic('custom_ops::asinh', asinh_symbolic, 9)

第一个参数custom_ops::asinh是目标ATen算子名。

第二个参数asinh_symbolic是要注册的符号函数。

第三个参数9表示算子集注册。

import torch
from torch.onnx import register_custom_op_symbolic#创建一个简单的神经网络层,实现forward方法,
class Model(torch.nn.Module):def __init__(self):super().__init__()def forward(self, x):return torch.asinh(x)#计算反双曲正弦值def asinh_symbolic(g, input, *, out=None):#pytorch的计算图有节点Node和边edge组成,Node表示操作(加减乘除卷积)#边表示张量间数据流关系,一个Asinh的节点,以input作为输入,输出就是Asinh(input)return g.op("Asinh", input)#将Model中的asinh操作重新绑定为asinh_symbolic,重命名该节点为“Asinh”,使用9号算法集
register_custom_op_symbolic('aten::asinh', asinh_symbolic,  9)model = Model()
input = torch.rand(1, 3, 10, 10)
torch.onnx.export(model, input, 'asinh.onnx')
#总结,就是声明一个torch.asinh的操作,该操作通过register_custom_op_symbolic注册为,9号算法集中Asinh操作

 


import onnxruntime
import torch
import numpy as npclass Model(torch.nn.Module):def __init__(self):super().__init__()def forward(self, x):return torch.asinh(x)model = Model()
input = torch.rand(1, 3, 10, 10)
torch_output = model(input).detach().numpy()#torch做了一次推理,然后转成numpy格式sess = onnxruntime.InferenceSession('asinh.onnx')
ort_output = sess.run(None, {'onnx::Asinh_0': input.numpy()})[0]
#这里的名字要和onnx中图节点的名字一致啊
assert np.allclose(torch_output, ort_output)#判断torch值和onnxruntime值一致,assert断言返回值,allclose判断两个张量是否一致

支持torcscript算子

pytorch算子无法直接满足复杂实现,需要自定义一个pytorch算子,然后转成ONNX形式。

为算子添加符号函数:

1、获取原算子的前向推理接口。#forward

2、获取目标ONNX算子的定义。#https://github.com/onnx/onnx/blob/main/docs/Operators.md

3、编写符号函数并绑定。#asinh_symbolic,register_custom_op_symbolic

使用torchscript算子

import torch
import torchvision#定义一个包含算子的模型
class Model(torch.nn.Module):def __init__(self):super().__init__()self.conv1 = torch.nn.Conv2d(3, 18, 3)#作为形变卷积的偏移张量self.conv2 = torchvision.ops.DeformConv2d(3, 3, 3)#形变卷积def forward(self, x):return self.conv2(x, self.conv1(x))

自定义 ONNX 算子


#定义一个包含算子的模型
class Model(torch.nn.Module):def __init__(self):super().__init__()self.conv1 = torch.nn.Conv2d(3, 18, 3)#作为形变卷积的偏移张量self.conv2 = torchvision.ops.DeformConv2d(3, 3, 3)#形变卷积点https://pytorch.org/vision/stable/ops.htmldef forward(self, x):return self.conv2(x, self.conv1(x))
#@parse_args装饰器,torchscripp算子的符号函数要求标注出么米一个输入参数的数据类型,
#v表示torch库中的value类型,一般用于标注张量
#i表示int类型
#f表示float
#none表示该数据为空。
#可以在torch.onny.symbolic_helper.py中查看
@parse_args("v", "v", "v", "v", "v", "i", "i", "i", "i", "i", "i", "i", "i", "none")
def symbolic(g,input,#张量vweight,#张量voffset,#张量vmask,#张量vbias,#张量vstride_h, stride_w, #int ipad_h, pad_w,dil_h, dil_w,n_weight_grps,n_offset_grps,use_mask):#以查询到的DeformConv2d算子输入参数作为符号函数的输入#custom是命名空间,以区别官方的算子#只使用input和offset来构造ONNX算子return g.op("custom::deform_conv2d", input, offset)#只是简单的例子,如何定义一个onnx中的deform节点,所以不做具体实现。
from torch.onnx import register_custom_op_symbolic
register_custom_op_symbolic("torchvision::deform_conv2d", symbolic, 9)model = Model()
input = torch.rand(1, 3, 10, 10)
torch.onnx.export(model, input, 'dcn.onnx')

 使用torch.autograd.Function

为 PyTorch 添加 C++ 拓展

//my_add.cpp
#include <torch/torch.h>torch::Tensor my_add(torch::Tensor a, torch::Tensor b)//torch::Tensor就是c++中torch张量
{return 2 * a + b;
}PYBIND11_MODULE(my_lib, m)//PYBIND11_MODULE为C++提供python调用接口。这里的my_lib是将来要在python中导入的模块名
{m.def("my_add", my_add);//my_add是python调用的接口名称,这里的接口名称与c++函数名称不一定要一样,但是这一命名辨识度比较高。
}
python setup.py develop
#编译文件

用 torch.autograd.Function 封装底层调用

import torch
import my_lib
#Function类本身是pytorch的一个可导函数,只需要实现前向推理和反向传播实现。
class MyAddFunction(torch.autograd.Function):#pytorch自动调用该函数,合适的执行前向和反向计算。@staticmethoddef forward(ctx, a, b):#forward函数中调用c++函数,my_lib是库名,my_add函数名,这两个名字是在#PYBIND11_MODULE中定义的。return my_lib.my_add(a, b)#对模型部署来说,function类有个很好的性质:如果定义了symbolic静态方法,#该function在执行torch.onnx.export()时就可以根据symbolic中定义的规则,#转换成ONNX算子,这个symbolic就是前面提到的符号函数,只是这里的名称必须是symbolic而已。@staticmethoddef symbolic(g, a, b):#g.op()只需要根据ONNX算子定义的规则把输入参数填入即可#ONNX中把新建常量当成一个算子来看待,尽管这个算子并不会以节点形式出现在ONNX模型的可视化结果里。two = g.op("Constant", value_t=torch.tensor([2]))#常量算子,把pytorch张量值传入value_t参数a = g.op('Mul', a, two)#乘法return g.op('Add', a, b)#加法
my_add = MyAddFunction.apply#apply是torch.autograd.Function的方法,这个方法完成了Function在前向推理或者反向传播的调度。
#在使用Function的派生类做推理时,不应该显示的调用forward,而应该调用apply方法。class MyAdd(torch.nn.Module):#把my_add封装成一个神经网络中的计算层。def __init__(self):super().__init__()def forward(self, a, b):return my_add(a, b)

测试算子

import torch
import my_lib
#Function类本身是pytorch的一个可导函数,只需要实现前向推理和反向传播实现。
class MyAddFunction(torch.autograd.Function):#pytorch自动调用该函数,合适的执行前向和反向计算。@staticmethoddef forward(ctx, a, b):#forward函数中调用c++函数,my_lib是库名,my_add函数名,这两个名字是在#PYBIND11_MODULE中定义的。return my_lib.my_add(a, b)#对模型部署来说,function类有个很好的性质:如果定义了symbolic静态方法,#该function在执行torch.onnx.export()时就可以根据symbolic中定义的规则,#转换成ONNX算子,这个symbolic就是前面提到的符号函数,只是这里的名称必须是symbolic而已。@staticmethoddef symbolic(g, a, b):#g.op()只需要根据ONNX算子定义的规则把输入参数填入即可#ONNX中把新建常量当成一个算子来看待,尽管这个算子并不会以节点形式出现在ONNX模型的可视化结果里。two = g.op("Constant", value_t=torch.tensor([2]))#常量算子,把pytorch张量值传入value_t参数a = g.op('Mul', a, two)#乘法return g.op('Add', a, b)#加法
my_add = MyAddFunction.apply#apply是torch.autograd.Function的方法,这个方法完成了Function在前向推理或者反向传播的调度。
#在使用Function的派生类做推理时,不应该显示的调用forward,而应该调用apply方法。class MyAdd(torch.nn.Module):#把my_add封装成一个神经网络中的计算层。def __init__(self):super().__init__()def forward(self, a, b):return my_add(a, b)model = MyAdd()
input = torch.rand(1, 3, 10, 10)
torch.onnx.export(model, (input, input), 'my_add.onnx')
torch_output = model(input, input).detach().numpy()import onnxruntime
import numpy as np
sess = onnxruntime.InferenceSession('my_add.onnx')
ort_output = sess.run(None, {'a.1': input.numpy(), 'b.1': input.numpy()})[0]assert np.allclose(torch_output, ort_output)

 总结

  • ATen是pytorch的C++张量库,~\Lib\site-packages\torch\_C\_VariableFunctions.pyi 和~\\Lib\site-packages\torch\nn可以知道ATen算子的python接口定义。
  • register_op可以为ATen算子补充注册符号函数。
  • register_custom_op_symbolic可以为TorchScript算子补充注册符号函数
  • 在Pytorch里添加C++扩展,#include <torch/torch.h> 、PYBIND11_MODULE(my_lib, m)、setup
  • torch.autograd.Function封装一个自定义的pytorch算子
  • symbolic编写符号函数。
  • g.op()把一个pytorch算子映射成一个或者多个ONNX算子。

相关文章:

TenserRT(四)在 PYTORCH 中支持更多 ONNX 算子

第四章&#xff1a;在 PyTorch 中支持更多 ONNX 算子 — mmdeploy 0.12.0 文档 PyTorch扩充。 PyTorch转换成ONNX&#xff1a; PyTorch有实现。PyTorch可以转化成一个或者多个ONNX算子。ONNX有相应算子。 如果即没有PyTorch实现&#xff0c;且缺少PyTorch与ONNX的映射关系&…...

前端高级面试题-浏览器

1 事件机制 事件触发三阶段 document 往事件触发处传播&#xff0c;遇到注册的捕获事件会触发 传播到事件触发处时触发注册的事件 从事件触发处往 document 传播&#xff0c;遇到注册的冒泡事件会触发 事件触发⼀般来说会按照上⾯的顺序进⾏&#xff0c;但是也有特例&#x…...

Mongodb 多文档聚合操作处理方法三(聚合管道)

聚合 聚合操作处理多个文档并返回计算结果。您可以使用聚合操作来&#xff1a; 将多个文档中的值分组在一起。 对分组数据执行操作以返回单个结果。 分析数据随时间的变化。 要执行聚合操作&#xff0c;您可以使用&#xff1a; 聚合管道 单一目的聚合方法 Map-reduce 函…...

Zabbix分布式监控配置和使用

目录 1 Zabbix监控的配置流程2 添加主机组3 添加模板4 添加主机5 配置图形6 配置大屏7 新建监控项7.1 简介7.2 添加监控项7.3 查看数据7.4 图表 8 新建触发器8.1 概述8.2 添加触发器8.3 显示触发器状态 1 Zabbix监控的配置流程 在Zabbix-Web管理界面中添加一个主机&#xff0c;…...

XCTF_very_easy_sql

简单的进行sql注入测试后发现不简单尝试一下按照提示 结合这句提示应该是内部访问&#xff0c;所以采用的手段应该是ssrf顺便看看包 唯一值得关注的是set-cookie说回ssrf唯一能使用的方式应该是Gopher协议找到了一个POST的python脚本 import urllib.parsepayload ""…...

[React]useMemoizedFn和useCallback对比

useMemoizedFn文档地址&#xff1a;https://ahooks.js.org/zh-CN/hooks/use-memoized-fn hooks组件内什么时候会更新自定义函数 在 React 中&#xff0c;自定义的 Hooks 内部的函数在以下常见的几种情况下会被重新赋值&#xff0c;导致更新引用&#xff1a; 组件重新渲染&…...

计算机毕设 深度学习人体跌倒检测 -yolo 机器视觉 opencv python

文章目录 0 前言1.前言2.实现效果3.相关技术原理3.1卷积神经网络3.1YOLOV5简介3.2 YOLOv5s 模型算法流程和原理4.数据集处理3.1 数据标注简介3.2 数据保存 5.模型训练 6 最后 0 前言 &#x1f525; 这两年开始毕业设计和毕业答辩的要求和难度不断提升&#xff0c;传统的毕设题…...

完全背包

动态规划解题步骤 : 动态规划问题一般从三个步骤进行考虑。 步骤一:集合和集合的状态 所谓的集合&#xff0c;就是一些方案的集合。 用 g[i][j] 表示从前 i 种物品中进行选择&#xff0c;且总体积不大于 j 的各个选法获得的价值的集合。注意&#xff1a;g[i][j] 不是一个数…...

【软件测试】webdriver常用API演示(Java+IDEA+chrome浏览器)

1.元素定位方法 对象的定位应该是自动化测试的核心&#xff0c;要想操作一个对象&#xff0c;首先应该识别这个对象。一个对象就是一个人一样&#xff0c;他会有各种的特征&#xff08;属性&#xff09;&#xff0c;如比我们可以通过一个人的身份证号&#xff0c;姓名&#xf…...

Linux安装MySQL 8.1.0

MySQL是一个流行的开源关系型数据库管理系统&#xff0c;本教程将向您展示如何在Linux系统上安装MySQL 8.1.0版本。请按照以下步骤进行操作&#xff1a; 1. 下载MySQL安装包 首先&#xff0c;从MySQL官方网站或镜像站点下载MySQL 8.1.0的压缩包mysql-8.1.0-linux-glibc2.28-x…...

多线程面试相关的一些问题

面试题 1. 常见的锁策略相关的面试题 2. CAS相关的面试题 3. Synchronized 原理相关的面试题 4. Callable 接口相关的面试题 1. 常见的锁策略 乐观锁 vs 悲观锁 悲观锁: 总是假设最坏的情况&#xff0c;每次去拿数据的时候都认为别人会修改&#xff0c;所以每次在拿数据的时候都…...

【使用维纳滤波进行信号分离】基于维纳-霍普夫方程的信号分离或去噪维纳滤波器估计(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

Vue+axios如何解决跨域

1、为什么会产生跨域&#xff1f; 出于浏览器的同源策略限制。 同源策略&#xff08;Sameoriginpolicy&#xff09;是一种约定&#xff0c;是浏览器的一种安全机…...

网络安全系统中的守护者:如何借助威胁情报 (TI) 提高安全性

在这篇哈巴尔网站上的推文中&#xff0c;我们将解释 TI 缩写背后的含义、为什么需要它、Positive Technologies 收集哪些网络威胁数据以及如何帮助企业预防网络威胁。我们将以四种情况为例&#xff0c;说明公司如何使用 PT Threat Intelligence Feeds 来发现恶意活动并预防攻击…...

并发编程 - CompletableFuture

文章目录 Pre概述FutureFuture的缺陷类继承关系功能概述API提交任务的相关API结果转换的相关APIthenApplyhandlethenRunthenAcceptthenAcceptBoththenCombinethenCompose 回调方法的相关API异常处理的相关API获取结果的相关API DEMO实战注意事项 Pre 每日一博 - Java 异步编程…...

IPIDEA参展ChinaJoy!探索未来创新科技的峰会之旅

中国最大的国际数码互动娱乐展会ChinaJoy即将于7月28日在上海举行&#xff0c;届时将聚集全球来自22个国家和地区的领先科技公司、创业者和技术专家&#xff0c;为参观者呈现一系列引人入胜的展览和活动。而IPIDEA作为参展商之一&#xff0c;将为参观者带来一场关于数字科技的奇…...

2023最新ChatGPT商业运营版网站源码+支持ChatGPT4.0+GPT联网+支持ai绘画(Midjourney)+支持Mind思维导图生成

本系统使用Nestjs和Vue3框架技术&#xff0c;持续集成AI能力到本系统&#xff01; 支持GPT3模型、GPT4模型Midjourney专业绘画&#xff08;全自定义调参&#xff09;、Midjourney以图生图、Dall-E2绘画Mind思维导图生成应用工作台&#xff08;Prompt&#xff09;AI绘画广场自定…...

轮趣科技教育版ros小车键盘控制运动

我之前买的ros小车是单独买的底板&#xff0c;以为随便一个树莓派就可以&#xff0c;因为我以前有一个树莓派3B&#xff0c;后来买了单独的小车之后&#xff0c;发现只能使用树莓派4B&#xff0c;然后又单独买了一个树莓派4B&#xff0c;给装上镜像&#xff0c;安装ros-melodic…...

深入理解Python中的os.chdir()方法

深入理解Python中的os.chdir()方法 1. 简介 在Python中&#xff0c;os.chdir()方法用于改变当前的工作目录。工作目录是指当前正在执行的脚本所在的目录。通过使用os.chdir()方法&#xff0c;我们可以在脚本执行过程中切换到不同的目录。 在编写Python脚本时&#xff0c;我们…...

【Golang 接口自动化02】使用标准库net/http发送Post请求

目录 写在前面 发送Post请求 示例代码 源码分析 Post请求参数解析 响应数据解析 验证 发送Json/XMl Json请求示例代码 xml请求示例代码 总结 资料获取方法 写在前面 上一篇我们介绍了使用 net/http 发送get请求&#xff0c;因为考虑到篇幅问题&#xff0c;把Post单…...

【华为云物联网】如何实现在 MQTT.fx 上模拟数据间隔上传一次,并按设定系数变动数据

虽然 MQTT.fx 本身不支持定时循环脚本发送消息,但可以通过以下方式 实现在 MQTT.fx 上模拟设备参数每隔 1 分钟上传一次,并按设定系数变动数据: ✅ 推荐方式:使用 Python 脚本+MQTT.fx 联动观察 你将用 Python 自动发送数据,MQTT.fx 订阅对应主题观察是否发送成功。 🧩…...

从零开始的数据结构教程(七) 回溯算法

&#x1f504; 标题一&#xff1a;回溯核心思想——走迷宫时的“穷举回头”策略 回溯算法 (Backtracking) 是一种通过探索所有可能的候选解来找出所有的解或某些解的算法。它就像你在一个复杂的迷宫中寻找出路&#xff1a;当你遇到一个岔路口时&#xff0c;你会选择一条路继续…...

CentOS-stream-9 Zabbix的安装与配置

一、Web环境搭建部署Zabbix时&#xff0c;选择合适的MariaDB、PHP和Nginx版本非常重要&#xff0c;以确保兼容性和最佳性能。以下是建议版本&#xff1a;Zabbix 6.4 MariaDB&#xff1a;官方文档推荐使用MariaDB 10.3或更高版本。对于CentOS Stream 9&#xff0c;建议使用Maria…...

回归任务损失函数对比曲线

回归任务损失函数曲线可视化对比 本节将可视化对比均方误差&#xff08;MSE&#xff09;、平均绝对误差&#xff08;MAE&#xff09;、Huber损失函数三种常见回归任务损失函数的曲线&#xff0c;帮助理解它们在不同误差区间的表现差异。 1. 导入所需库 我们需要用到 numpy 进…...

Linux --进度条小程序更新

这里使用随机数来模拟下载量&#xff0c;来实现一个下载进度更新的小程序 main.c 的代码&#xff0c;其中downlod这个函数使用的是函数指针&#xff0c;如果有多个进度条函数可以传入进行多样化的格式下载显示&#xff0c;还需要传入一个下载总量&#xff0c;每次"下载以…...

MySQL访问控制与账号管理:原理、技术与最佳实践

MySQL的安全体系建立在精细的访问控制和账号管理机制上。本文基于MySQL 9.3官方文档&#xff0c;深入解析其核心原理、关键技术、实用技巧和行业最佳实践。 一、访问控制核心原理&#xff1a;双重验证机制 连接验证 (Connection Verification) 客户端发起连接时&#xff0c;MyS…...

跨平台开发框架electron

桌面端开发框架有很多&#xff0c;比如C#的WPF和Winform&#xff0c;Dart的Flutter,JS的Electron&#xff0c;Rust的Tauri。 目前应用比较广的是Electron&#xff0c;比如我们常见的开发工具VsCode&#xff0c;就是基于Electron开发的。 所以这篇文章我们就来聊聊Electron。 简…...

核心机制三:连接管理(三次握手)

核心机制一:确认应答 > 实现可靠传输的核心 接受方给发送方返回"应答报文"(ack) 1)发送方能够感知到对方是否收到 2)如果对方没有收到,发送方采取措施 序号按照字节编排 (连续递增) 确认序号按照收到数据的最后一个字节序号 1 核心机制二:超时重传 > 产生丢包…...

如何保护网络免受零日漏洞攻击?

零日漏洞&#xff08;Zero-Day Vulnerability&#xff09;是指软件或系统中尚未被厂商发现或修补的安全漏洞。这个名称中的“零日”意味着&#xff0c;从漏洞被发现到厂商发布修复补丁的时间是零天&#xff0c;也就是说&#xff0c;黑客可以利用这个漏洞进行攻击&#xff0c;而…...

华为计试——刷题

判断两个IP是否属于同一子网 题目&#xff1a;给定一个子网掩码和两个 IP 地址&#xff0c;判断这两个 IP 地址是否在同一个子网中。 思路&#xff1a;首先&#xff0c;判断这个 IP 地址和子网掩码格式是否正确&#xff0c;不正确输出 ‘1’&#xff0c;进而结束&#xff1b;…...