onnx 1.16 doc学习笔记四:python API-If和Scan

news2024/9/22 9:53:17

onnx作为一个通用格式,很少有中文教程,因此开一篇文章对onnx 1.16文档进行翻译与进一步解释,
onnx 1.16官方文档:https://onnx.ai/onnx/intro/index.html](https://onnx.ai/onnx/intro/index.html),
如果觉得有收获,麻烦点赞收藏关注,目前仅在CSDN发布,本博客会分为多个章节,目前尚在连载中,详见专栏链接:
https://blog.csdn.net/qq_33345365/category_12581965.html

开始编辑时间:2024/2/21;最后编辑时间:2024/2/21

这是本教程的第四篇,其余内容见上述专栏链接。


ONNX with Python

本教程的第一篇:介绍了ONNX的基本概念。

在本教程的第二篇,介绍了ONNX关于Python的API,具体涉及一个简单的线性回归例子和序列化。

本教程的第三篇,包括python API的三个部分:初始化器Initializer;属性Attributes;算子集和元数据Opset和Metadata

在本篇将继续对更多的内容进行介绍。具体介绍子图相关内容。

目录:

  • 子图:测试与循环
    • If
    • Scan

子图:测试与循环 Subgraph: test and loops

通常情况下,这些操作会被归类为控制流。一般来说,最好避免使用它们,因为它们不像矩阵操作那样高效,而且矩阵操作经过高度优化,速度更快。

If

可以使用 if 语句来实现一个test。它根据一个布尔值执行子图 A 或子图 B。这种用法不是很常见,因为一个函数通常需要批处理比较的结果。下面的示例代码:根据符号计算矩阵中所有浮点数的和,并返回 1 或 -1。

import numpy
import onnx
from onnx.helper import (
    make_node, make_graph, make_model, make_tensor_value_info)
from onnx.numpy_helper import from_array
from onnx.checker import check_model
from onnxruntime import InferenceSession

# initializers
value = numpy.array([0], dtype=numpy.float32)
zero = from_array(value, name='zero')

# Same as before, X is the input, Y is the output.
X = make_tensor_value_info('X', onnx.TensorProto.FLOAT, [None, None])
Y = make_tensor_value_info('Y', onnx.TensorProto.FLOAT, [None])

# 第一个节点:对所有轴求和。
rsum = make_node('ReduceSum', ['X'], ['rsum'])
# 第二个节点:将rsum与0比较,输出为cond
cond = make_node('Greater', ['rsum', 'zero'], ['cond'])

# 构建if正确时的图
# Input for then
then_out = make_tensor_value_info('then_out', onnx.TensorProto.FLOAT, None)
# 正确返回常数1
then_cst = from_array(numpy.array([1]).astype(numpy.float32))

# If正确时的节点,并得到图
then_const_node = make_node(
    'Constant', inputs=[],
    outputs=['then_out'],
    value=then_cst, name='cst1')

then_body = make_graph(
    [then_const_node], 'then_body', [], [then_out])

# 构建If错误时的图
else_out = make_tensor_value_info(
    'else_out', onnx.TensorProto.FLOAT, [5])
else_cst = from_array(numpy.array([-1]).astype(numpy.float32))

else_const_node = make_node(
    'Constant', inputs=[],
    outputs=['else_out'],
    value=else_cst, name='cst2')

else_body = make_graph(
    [else_const_node], 'else_body',
    [], [else_out])

# 最后If节点把两个图当成属性
if_node = onnx.helper.make_node(
    'If', ['cond'], ['Y'],
    then_branch=then_body, else_branch=else_body)

# 最后的图,使用If节点和前两个节点。
graph = make_graph([rsum, cond, if_node], 'if', [X], [Y], [zero])
onnx_model = make_model(graph)
check_model(onnx_model)

# 指定算子集
del onnx_model.opset_import[:]
opset = onnx_model.opset_import.add()
opset.domain = ''
opset.version = 15
onnx_model.ir_version = 8

# 保存模型
with open("onnx_if_sign.onnx", "wb") as f:
    f.write(onnx_model.SerializeToString())

# 输出
sess = InferenceSession(onnx_model.SerializeToString(),
                        providers=["CPUExecutionProvider"])

x = numpy.ones((3, 2), dtype=numpy.float32)
res = sess.run(None, {'X': x})

print("result", res)
print()

print(onnx_model)

这个代码的核心是构建if使用的两个图,然后用着两个图构建节点,参照输出进行进一步的了解:

result [array([1.], dtype=float32)]

ir_version: 8
graph {
  node {
    input: "X"
    output: "rsum"
    op_type: "ReduceSum"
  }
  node {
    input: "rsum"
    input: "zero"
    output: "cond"
    op_type: "Greater"
  }
  node {
    input: "cond"
    output: "Y"
    op_type: "If"
    attribute {
      name: "else_branch"
      g {
        node {
          output: "else_out"
          name: "cst2"
          op_type: "Constant"
          attribute {
            name: "value"
            t {
              dims: 1
              data_type: 1
              raw_data: "\000\000\200\277"
            }
            type: TENSOR
          }
        }
        name: "else_body"
        output {
          name: "else_out"
          type {
            tensor_type {
              elem_type: 1
              shape {
                dim {
                  dim_value: 5
                }
              }
            }
          }
        }
      }
      type: GRAPH
    }
    attribute {
      name: "then_branch"
      g {
        node {
          output: "then_out"
          name: "cst1"
          op_type: "Constant"
          attribute {
            name: "value"
            t {
              dims: 1
              data_type: 1
              raw_data: "\000\000\200?"
            }
            type: TENSOR
          }
        }
        name: "then_body"
        output {
          name: "then_out"
          type {
            tensor_type {
              elem_type: 1
            }
          }
        }
      }
      type: GRAPH
    }
  }
  name: "if"
  initializer {
    dims: 1
    data_type: 1
    name: "zero"
    raw_data: "\000\000\000\000"
  }
  input {
    name: "X"
    type {
      tensor_type {
        elem_type: 1
        shape {
          dim {
          }
          dim {
          }
        }
      }
    }
  }
  output {
    name: "Y"
    type {
      tensor_type {
        elem_type: 1
        shape {
          dim {
          }
        }
      }
    }
  }
}
opset_import {
  domain: ""
  version: 15
}

在这个代码里,“else”和“then”分支都非常简单,甚至可以用一个“Where”节点替换“If”节点,这样会更快。有趣的是,当两个分支都比较大,并且跳过一个分支效率更高时,情况就变得复杂了。

Scan

根据规格描述,Scan操作似乎有些复杂:将张量的一个维度循环遍历并将其结果存储在预分配张量中,这是一种很有用的方法。以下示例实现了经典的回归问题最近邻算法。第一步是计算输入特征 X 和训练集 W 之间的成对距离:KaTeX parse error: Undefined control sequence: \norm at position 21: …X,W)=(M_{ij})=(\̲n̲o̲r̲m̲ ̲X_i-W^2_j)_{ij} . 然后使用一个 TopK 算子提取 k 个最近邻点。

注:在原教程里,此处的公式就是这样的,不保真

ONNX scan 算子可以用于迭代执行一系列操作,类似于 Python 中的 for 循环。

这个算子有些复杂,我会在更多学习后,给出更为简单的例子。

import numpy
from onnx import numpy_helper, TensorProto
from onnx.helper import (
    make_model, make_node, set_model_props, make_tensor, make_graph,
    make_tensor_value_info)
from onnx.checker import check_model

# subgraph
initializers = []
nodes = []
inputs = []
outputs = []

value = make_tensor_value_info('next_in', 1, [None, 4])
inputs.append(value)
value = make_tensor_value_info('next', 1, [None])
inputs.append(value)

value = make_tensor_value_info('next_out', 1, [None, None])
outputs.append(value)
value = make_tensor_value_info('scan_out', 1, [None])
outputs.append(value)

node = make_node(
    'Identity', ['next_in'], ['next_out'],
    name='cdistd_17_Identity', domain='')
nodes.append(node)

node = make_node(
    'Sub', ['next_in', 'next'], ['cdistdf_17_C0'],
    name='cdistdf_17_Sub', domain='')
nodes.append(node)

node = make_node(
    'ReduceSumSquare', ['cdistdf_17_C0'], ['cdistdf_17_reduced0'],
    name='cdistdf_17_ReduceSumSquare', axes=[1], keepdims=0, domain='')
nodes.append(node)

node = make_node(
    'Identity', ['cdistdf_17_reduced0'],
    ['scan_out'], name='cdistdf_17_Identity', domain='')
nodes.append(node)

graph = make_graph(nodes, 'OnnxIdentity',
                   inputs, outputs, initializers)

# main graph

initializers = []
nodes = []
inputs = []
outputs = []

opsets = {'': 15, 'ai.onnx.ml': 15}
target_opset = 15  # subgraphs

# initializers
list_value = [23.29599822460675, -120.86516699239603, -144.70495899914215, -260.08772982740413,
              154.65272105889147, -122.23295157108991, 247.45232560871727, -182.83789715805776,
              -132.92727431421793, 147.48710175784703, 88.27761768038069, -14.87785569894749,
              111.71487894705504, 301.0518319089629, -29.64235742280055, -113.78493504731911,
              -204.41218591022718, 112.26561056133608, 66.04032954135549,
              -229.5428380626701, -33.549262642481615, -140.95737409864623, -87.8145187836131,
              -90.61397011283958, 57.185488100413366, 56.864151796743855, 77.09054590340892,
              -187.72501631246712, -42.779503579806025, -21.642642730674076, -44.58517761667535,
              78.56025104939847, -23.92423223842056, 234.9166231927213, -73.73512816431007,
              -10.150864499514297, -70.37105466673813, 65.5755688281476, 108.68676290979731, -78.36748960443065]
value = numpy.array(list_value, dtype=numpy.float64).reshape((2, 20))
tensor = numpy_helper.from_array(
    value, name='knny_ArrayFeatureExtractorcst')
initializers.append(tensor)

list_value = [1.1394007205963135, -0.6848101019859314, -1.234825849533081, 0.4023416340351105,
              0.17742614448070526, 0.46278226375579834, -0.4017809331417084, -1.630198359489441,
              -0.5096521973609924, 0.7774903774261475, -0.4380742907524109, -1.2527953386306763,
              -1.0485529899597168, 1.950775384902954, -1.420017957687378, -1.7062702178955078,
              1.8675580024719238, -0.15135720372200012, -0.9772778749465942, 0.9500884413719177,
              -2.5529897212982178, -0.7421650290489197, 0.653618574142456, 0.8644362092018127,
              1.5327792167663574, 0.37816253304481506, 1.4693588018417358, 0.154947429895401,
              -0.6724604368209839, -1.7262825965881348, -0.35955315828323364, -0.8131462931632996,
              -0.8707971572875977, 0.056165341287851334, -0.5788496732711792, -0.3115525245666504,
              1.2302906513214111, -0.302302747964859, 1.202379822731018, -0.38732680678367615,
              2.269754648208618, -0.18718385696411133, -1.4543657302856445, 0.04575851559638977,
              -0.9072983860969543, 0.12898291647434235, 0.05194539576768875, 0.7290905714035034,
              1.4940791130065918, -0.8540957570075989, -0.2051582634449005, 0.3130677044391632,
              1.764052391052246, 2.2408931255340576, 0.40015721321105957, 0.978738009929657,
              0.06651721894741058, -0.3627411723136902, 0.30247190594673157, -0.6343221068382263,
              -0.5108051300048828, 0.4283318817615509, -1.18063223361969, -0.02818222902715206,
              -1.6138978004455566, 0.38690251111984253, -0.21274028718471527, -0.8954665660858154,
              0.7610377073287964, 0.3336743414402008, 0.12167501449584961, 0.44386324286460876,
              -0.10321885347366333, 1.4542734622955322, 0.4105985164642334, 0.14404356479644775,
              -0.8877857327461243, 0.15634897351264954, -1.980796456336975, -0.34791216254234314]
value = numpy.array(list_value, dtype=numpy.float32).reshape((20, 4))
tensor = numpy_helper.from_array(value, name='Sc_Scancst')
initializers.append(tensor)

value = numpy.array([2], dtype=numpy.int64)
tensor = numpy_helper.from_array(value, name='To_TopKcst')
initializers.append(tensor)

value = numpy.array([2, -1, 2], dtype=numpy.int64)
tensor = numpy_helper.from_array(value, name='knny_Reshapecst')
initializers.append(tensor)

# inputs
value = make_tensor_value_info('input', 1, [None, 4])
inputs.append(value)

# outputs
value = make_tensor_value_info('variable', 1, [None, 2])
outputs.append(value)

# nodes
# 这里是scan算子
node = make_node(
    'Scan', ['input', 'Sc_Scancst'], ['UU032UU', 'UU033UU'],
    name='Sc_Scan', body=graph, num_scan_inputs=1, domain='')
nodes.append(node)

node = make_node(
    'Transpose', ['UU033UU'], ['Tr_transposed0'],
    name='Tr_Transpose', perm=[1, 0], domain='')
nodes.append(node)

node = make_node(
    'Sqrt', ['Tr_transposed0'], ['Sq_Y0'],
    name='Sq_Sqrt', domain='')
nodes.append(node)

node = make_node(
    'TopK', ['Sq_Y0', 'To_TopKcst'], ['To_Values0', 'To_Indices1'],
    name='To_TopK', largest=0, sorted=1, domain='')
nodes.append(node)

node = make_node(
    'Flatten', ['To_Indices1'], ['knny_output0'],
    name='knny_Flatten', domain='')
nodes.append(node)

node = make_node(
    'ArrayFeatureExtractor',
    ['knny_ArrayFeatureExtractorcst', 'knny_output0'], ['knny_Z0'],
    name='knny_ArrayFeatureExtractor', domain='ai.onnx.ml')
nodes.append(node)

node = make_node(
    'Reshape', ['knny_Z0', 'knny_Reshapecst'], ['knny_reshaped0'],
    name='knny_Reshape', allowzero=0, domain='')
nodes.append(node)

node = make_node(
    'Transpose', ['knny_reshaped0'], ['knny_transposed0'],
    name='knny_Transpose', perm=[1, 0, 2], domain='')
nodes.append(node)

node = make_node(
    'Cast', ['knny_transposed0'], ['Ca_output0'],
    name='Ca_Cast', to=TensorProto.FLOAT, domain='')
nodes.append(node)

node = make_node(
    'ReduceMean', ['Ca_output0'], ['variable'],
    name='Re_ReduceMean', axes=[2], keepdims=0, domain='')
nodes.append(node)

# graph
graph = make_graph(nodes, 'KNN regressor', inputs, outputs, initializers)

# model
onnx_model = make_model(graph)
onnx_model.ir_version = 8
onnx_model.producer_name = 'skl2onnx'
onnx_model.producer_version = ''
onnx_model.domain = 'ai.onnx'
onnx_model.model_version = 0
onnx_model.doc_string = ''
set_model_props(onnx_model, {})

# opsets
del onnx_model.opset_import[:]
for dom, value in opsets.items():
    op_set = onnx_model.opset_import.add()
    op_set.domain = dom
    op_set.version = value

check_model(onnx_model)
with open("knnr.onnx", "wb") as f:
    f.write(onnx_model.SerializeToString())

print(onnx_model)

输出如下所示:

ir_version: 8
producer_name: "skl2onnx"
producer_version: ""
domain: "ai.onnx"
model_version: 0
doc_string: ""
graph {
  node {
    input: "input"
    input: "Sc_Scancst"
    output: "UU032UU"
    output: "UU033UU"
    name: "Sc_Scan"
    op_type: "Scan"
    attribute {
      name: "body"
      g {
        node {
          input: "next_in"
          output: "next_out"
          name: "cdistd_17_Identity"
          op_type: "Identity"
          domain: ""
        }
        node {
          input: "next_in"
          input: "next"
          output: "cdistdf_17_C0"
          name: "cdistdf_17_Sub"
          op_type: "Sub"
          domain: ""
        }
        node {
          input: "cdistdf_17_C0"
          output: "cdistdf_17_reduced0"
          name: "cdistdf_17_ReduceSumSquare"
          op_type: "ReduceSumSquare"
          attribute {
            name: "axes"
            ints: 1
            type: INTS
          }
          attribute {
            name: "keepdims"
            i: 0
            type: INT
          }
          domain: ""
        }
        node {
          input: "cdistdf_17_reduced0"
          output: "scan_out"
          name: "cdistdf_17_Identity"
          op_type: "Identity"
          domain: ""
        }
        name: "OnnxIdentity"
        input {
          name: "next_in"
          type {
            tensor_type {
              elem_type: 1
              shape {
                dim {
                }
                dim {
                  dim_value: 4
                }
              }
            }
          }
        }
        input {
          name: "next"
          type {
            tensor_type {
              elem_type: 1
              shape {
                dim {
                }
              }
            }
          }
        }
        output {
          name: "next_out"
          type {
            tensor_type {
              elem_type: 1
              shape {
                dim {
                }
                dim {
                }
              }
            }
          }
        }
        output {
          name: "scan_out"
          type {
            tensor_type {
              elem_type: 1
              shape {
                dim {
                }
              }
            }
          }
        }
      }
      type: GRAPH
    }
    attribute {
      name: "num_scan_inputs"
      i: 1
      type: INT
    }
    domain: ""
  }
  node {
    input: "UU033UU"
    output: "Tr_transposed0"
    name: "Tr_Transpose"
    op_type: "Transpose"
    attribute {
      name: "perm"
      ints: 1
      ints: 0
      type: INTS
    }
    domain: ""
  }
  node {
    input: "Tr_transposed0"
    output: "Sq_Y0"
    name: "Sq_Sqrt"
    op_type: "Sqrt"
    domain: ""
  }
  node {
    input: "Sq_Y0"
    input: "To_TopKcst"
    output: "To_Values0"
    output: "To_Indices1"
    name: "To_TopK"
    op_type: "TopK"
    attribute {
      name: "largest"
      i: 0
      type: INT
    }
    attribute {
      name: "sorted"
      i: 1
      type: INT
    }
    domain: ""
  }
  node {
    input: "To_Indices1"
    output: "knny_output0"
    name: "knny_Flatten"
    op_type: "Flatten"
    domain: ""
  }
  node {
    input: "knny_ArrayFeatureExtractorcst"
    input: "knny_output0"
    output: "knny_Z0"
    name: "knny_ArrayFeatureExtractor"
    op_type: "ArrayFeatureExtractor"
    domain: "ai.onnx.ml"
  }
  node {
    input: "knny_Z0"
    input: "knny_Reshapecst"
    output: "knny_reshaped0"
    name: "knny_Reshape"
    op_type: "Reshape"
    attribute {
      name: "allowzero"
      i: 0
      type: INT
    }
    domain: ""
  }
  node {
    input: "knny_reshaped0"
    output: "knny_transposed0"
    name: "knny_Transpose"
    op_type: "Transpose"
    attribute {
      name: "perm"
      ints: 1
      ints: 0
      ints: 2
      type: INTS
    }
    domain: ""
  }
  node {
    input: "knny_transposed0"
    output: "Ca_output0"
    name: "Ca_Cast"
    op_type: "Cast"
    attribute {
      name: "to"
      i: 1
      type: INT
    }
    domain: ""
  }
  node {
    input: "Ca_output0"
    output: "variable"
    name: "Re_ReduceMean"
    op_type: "ReduceMean"
    attribute {
      name: "axes"
      ints: 2
      type: INTS
    }
    attribute {
      name: "keepdims"
      i: 0
      type: INT
    }
    domain: ""
  }
  name: "KNN regressor"
  initializer {
    dims: 2
    dims: 20
    data_type: 11
    name: "knny_ArrayFeatureExtractorcst"
    raw_data: ",\\&\212\306K7@\333z`\345^7^\300\304\312,\006\217\026b\300Z9dWgAp\300.+F\027\343Tc@\203\330\264\255\350\216^\300\260\022\216sy\356n@\237h\263\r\320\332f\300\224\277.;\254\235`\300\336\370lV\226ob@\261\201\362|\304\021V@c,[Mv\301-\300\322\214\240\223\300\355[@)\036\262M\324\320r@nE;\211q\244=\300\021n5`<r\\\300\207\211\201\2400\215i\300H\232p\303\377\020\\@\317K[\302\224\202P@&\306\355\355^\261l\300\301/\377<N\306@\300#w\001\317\242\236a\300$fd\023!\364U\300\204\327LIK\247V\300J\211\366\022\276\227L@\262\345\254\206\234nL@f{\013\201\313ES@\234\343hU3wg\300\3370\367\305\306cE\300\336A\347;\204\2445\300f\374\242\031\347JF\300\325\2557\'\333\243S@\331\354\345{\232\3547\300\307o)\372T]m@#\005\000W\014oR\300\'\025\227\034>M$\300\310\252\022\\\277\227Q\300l_\243\036\326dP@\333kk\354\363+[@\223)\036\363\204\227S\300"
  }
  initializer {
    dims: 20
    dims: 4
    data_type: 1
    name: "Sc_Scancst"
    raw_data: "\342\327\221?\267O/\277\306\016\236\277\271\377\315>3\2575>\314\361\354>;\266\315\276W\252\320\277\221x\002\277\234\tG?FK\340\276\231[\240\277\3746\206\277\002\263\371?&\303\265\277\020g\332\277$\014\357?b\375\032\276\342.z\277\3778s?/d#\300\207\376=\277\214S\'?\261K]?\0342\304?\205\236\301>\363\023\274?\212\252\036>^&,\277\324\366\334\277Z\027\270\276[*P\277\220\354^\277\241\rf=~/\024\277\320\203\237\276*z\235?m\307\232\276\225\347\231?\263O\306\276\251C\021@ \255?\276\250(\272\277Hm;=\265Dh\277\031\024\004>\262\304T=\256\245:?\374=\277?\005\246Z\277\002\025R\276iJ\240>x\314\341?\313j\017@h\341\314>\223\216z?.:\210=6\271\271\276\231\335\232>\357b\"\277 \304\002\277QN\333>\365\036\227\277k\336\346\2744\224\316\277\026\030\306>\227\330Y\276L=e\277^\323B?]\327\252>\3000\371=\013B\343>hd\323\275\242%\272?\3709\322>(\200\023>\355Ec\277\362\031 >\275\212\375\277\213!\262\276"
  }
  initializer {
    dims: 1
    data_type: 7
    name: "To_TopKcst"
    raw_data: "\002\000\000\000\000\000\000\000"
  }
  initializer {
    dims: 3
    data_type: 7
    name: "knny_Reshapecst"
    raw_data: "\002\000\000\000\000\000\000\000\377\377\377\377\377\377\377\377\002\000\000\000\000\000\000\000"
  }
  input {
    name: "input"
    type {
      tensor_type {
        elem_type: 1
        shape {
          dim {
          }
          dim {
            dim_value: 4
          }
        }
      }
    }
  }
  output {
    name: "variable"
    type {
      tensor_type {
        elem_type: 1
        shape {
          dim {
          }
          dim {
            dim_value: 2
          }
        }
      }
    }
  }
}
opset_import {
  domain: ""
  version: 15
}
opset_import {
  domain: "ai.onnx.ml"
  version: 15
}

示意图如下所示:

在这里插入图片描述

子图由操作符Scan执行。在本例中,有一个scan输入,这意味着操作符只构建一个输出。

node = make_node(
    'Scan', ['X1', 'X2'], ['Y1', 'Y2'],
    name='Sc_Scan', body=graph, num_scan_inputs=1, domain='')

在第一步迭代中,子图接收 X1 和 X2 的第一行作为输入。它会产生两个输出:

  1. 第一个输出用于在下一轮迭代中替换 X1。
  2. 第二个输出存储在一个容器中,最终形成 Y2。

在第二步迭代中,子图的第二个输入是 X2 的第二行。

以下是用颜色简要说明这个过程:

  • 绿色表示第一轮迭代。
  • 蓝色表示第二轮迭代。

在这里插入图片描述

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

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

相关文章

$attrs

一、概念 vue官网定义如下: 包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过v-bind="$attrs"传入内部组件——在创建…

【高德地图】Android高德地图控件交互详细介绍

&#x1f4d6;第5章 与地图控件交互 ✅控件交互&#x1f9ca;缩放按钮&#x1f9ca;指南针&#x1f9ca;定位按钮&#x1f9ca;地图Logo ✅手势交互&#x1f9ca;缩放手势&#x1f9ca;滑动手势&#x1f9ca;旋转手势&#x1f9ca;倾斜手势&#x1f9ca;指定屏幕中心点的手势操…

无线传感器网络简单介绍

&#xff08;本文为简单介绍&#xff0c;内容来源自网络&#xff09; 无线传感器网络&#xff08;Wireless Sensor Networks&#xff09;是一种创新的传感器网络架构&#xff0c;具有广泛的应用前景和潜力。与传统的有限传感器网络不同&#xff0c;无线传感器网络克服了节点数…

在苹果电脑MAC上安装Windows10(双系统安装的详细图文步骤教程)

在苹果电脑MAC上安装Windows10&#xff08;双系统安装的详细图文步骤教程&#xff09; 一、准备工作准备项1&#xff1a;U盘作为系统安装盘准备项2&#xff1a;您需要安装的系统镜像 二、启动转换助理步骤1&#xff1a;找到启动转换助理步骤2&#xff1a;启动转换助理步骤3&…

基于springboot+vue的安康旅游网站(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

【Java EE初阶二十】http的简单理解(一)

1. 初识http HTTP 最新的版本应该是 HTTP/3.0&#xff0c;目前大规模使用的版本 HTTP/1.1&#xff1b; 下面来简单说明一下使用 HTTP 协议的场景: 1、浏览器打开网站 (基本上) 2、手机 APP 访问对应的服务器 (大概率) 前面的 TCP与UDP 和http不同&#xff0c;HTTP 的报文格式&a…

基于Embedding召回和DSSM双塔模型

文章目录 基于Embedding召回介绍基于Embedding召回算法分类I2I召回U2I召回 DSSM模型DSSM双塔模型层次 基于Embedding召回介绍 基于embedding的召回是从内容文本信息和用户查询的角度出发&#xff0c;利用预训练的词向量模型或深度学习模型&#xff0c;将文本信息转换成向量进行…

【PyQt】15-让控件支持拖拽工作

文章目录 前言一、控件的拖拽-setAcceptDrops()1.1 代码1.2 运行结果 总结 前言 允许控件的拖拽操作&#xff0c;后续可以升级为拖拽图片之类的。hasHtml()、hasUrls()、hasImage() 一、控件的拖拽-setAcceptDrops() 比如把A放到B&#xff0c;需要两步 B—setAcceptDrops(Tru…

Hudi程序导致集群RPC偏高问题分析

1、背景 Hudi程序中upsert操作频繁&#xff0c;过多的删除和回滚操作,导致集群RPC持续偏高 2、描述 hudi采用的是mvcc设计&#xff0c;提供了清理工具cleaner来把旧版本的文件分片删除&#xff0c;默认开启了清理功能&#xff0c;可以防止文件系统的存储空间和文件数量的无限…

【自然语言处理】:实验5,司法阅读理解

清华大学驭风计划课程链接 学堂在线 - 精品在线课程学习平台 (xuetangx.com) 代码和报告均为本人自己实现&#xff08;实验满分&#xff09;&#xff0c;只展示主要任务实验结果&#xff0c;如果需要详细的实验报告或者代码可以私聊博主 有任何疑问或者问题&#xff0c;也欢…

配置redis-cell 控流插件

1.下载绑定资源也可以到git上下载 https://gitee.com/dianjinshi/springboot-nginx.git 2.创建文件夹 mkdir redis-cell 3.上传到linux上并进入文件夹解压 4.拷贝 docker cp libredis_cell.so redis:/usr/local/etc/redis 5.重启redis docker restart redis 6.进入redis…

六、回归与聚类算法 - 欠拟合和过拟合

目录 1、定义 2、原因及解决方法 2.1 正则化 线性回归欠拟合与过拟合线性回归的改进 - 岭回归分类算法&#xff1a;逻辑回归模型保存与加载无监督学习&#xff1a;K-means算法 1、定义 2、原因及解决方法 2.1 正则化

【Emgu CV教程】7.3、图像锐化之手搓代码实现直方图均衡化

文章目录 一、介绍1.写在前面2.彩色图像直方图均衡化函数 二、举例 一、介绍 1.写在前面 上一篇文章介绍的是直方图均衡化&#xff0c;使用Emgu CV的EqualizeHist()函数。它对于背景和前景都太亮或者太暗的图像非常有用&#xff0c;而且计算速度非常快&#xff0c;简单又好用…

NXP实战笔记(七):S32K3xx基于RTD-SDK在S32DS上配置ICU输入捕获

目录 1、概述 2、输入捕获SDK配置 2.1、SAIC中断方式 2.2、IPWM或者IPM 1、概述 输入捕获&#xff0c;可以抓取高电平时间、低电平时间、占空比、周期、边沿检测与回调函数、边沿计数&#xff08;ABZ解码&#xff09;、时间戳、唤醒中断。 记录一下根据Emios模块实现上述部分…

论文精读--word2vec

word2vec从大量文本语料中以无监督方式学习语义知识&#xff0c;是用来生成词向量的工具 把文本分散嵌入到另一个离散空间&#xff0c;称作分布式表示&#xff0c;又称为词嵌入&#xff08;word embedding&#xff09;或词向量 Abstract We propose two novel model architec…

LeetCode 热题 100 | 二叉树(终)

目录 1 二叉树小结 1.1 模式一 1.2 模式二 2 236. 二叉树的最近公共祖先 3 124. 二叉树中的最大路径和 菜鸟做题&#xff08;返校版&#xff09;&#xff0c;语言是 C 1 二叉树小结 菜鸟碎碎念 通过对二叉树的练习&#xff0c;我对 “递归” 有了一些肤浅的理解。…

适用于 Windows 10、11 的 5 款最佳免费文件恢复软件

最好的免费文件恢复软件是什么&#xff1f; 如今&#xff0c;人们通常将数据保存在硬盘或云备份上。除此之外&#xff0c;您还可以将重要数据存储在 USB 或其他电子设备上。 但是&#xff0c;如果您遇到存储设备故障、存储设备逻辑故障或意外删除&#xff0c;您可能会丢失文件…

Android控件WebView实现完整截图

最近总能看到好多APP都支持文章和网页的长截图&#xff0c;出于好奇研究了一下&#xff0c;分享给大家。 网上有好多的例子&#xff0c;其中好多都是已经过时的就不在复述了&#xff0c;我发现有一种还是比较通用的方法。 //android 5.0 之后需要开启浏览器的整体缓存才能截取…

后端程序员入门react笔记(四)-综合运用,写一个小demo

样式模块化 有时候我们会遇到这样的问题&#xff0c;有两个css对一个class声明了样式&#xff0c;这样的话后引入的css会覆盖前面的css样式&#xff0c;导致样式冲突&#xff0c;那么我们怎么解决这种问题呢&#xff0c;我们可以使用样式的模块化&#xff0c;我们起名一个inde…

关于HashMap的面试问题(26问面试题)

文章目录 关于HashMap的面试问题1、HashMap的底层实现2、HashMap的数组的元素类型3、为什么要使用数组&#xff1f;4、HashMap的数组的初始化长度5、HashMap的映射关系的存储索引index如何计算6、HashMap 为什么使用 &按位与运算代替%模运算&#xff1f;7、为什么要使用has…