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

pytorch-自动求导机制,构建计算图进行反向传播,需要注意inplace操作导致的报错,梯度属性变化

  • PyTorch 作为一个深度学习平台,在深度学习任务中比 NumPy 这个科学计算库强在哪里呢?一是 PyTorch 提供了自动求导机制,二是对 GPU 的支持。由此可见,自动求导 (autograd) 是 PyTorch,乃至其他大部分深度学习框架中的重要组成部分。

  • 了解自动求导背后的原理和规则,对我们写出一个更干净整洁甚至更高效的 PyTorch 代码是十分重要的。但是,现在已经有了很多封装好的 API,我们在写一个自己的网络的时候,可能几乎都不用去注意求导这些问题,因为这些 API 已经在私底下处理好了这些事情。现在我们往往只需要,搭建个想要的模型,处理好数据的载入,调用现成的 optimizer 和 loss function,直接开始训练就好了。连需要设置 requires_grad=True 的地方好像都没有。

  • torch.Tensor是这个包的核心类。如果设置 .requires_gradTrue,那么将会追踪所有对于该张量的操作。 当完成计算后通过调用 .backward(),自动计算所有的梯度, 这个张量的所有梯度将会自动积累到 .grad 属性。要阻止张量跟踪历史记录,可以调用.detach()方法将其与计算历史记录分离,并禁止跟踪它将来的计算记录

  • 为了防止跟踪历史记录(和使用内存),可以将代码块包装在with torch.no_grad():中。 在评估模型时特别有用,因为模型可能具有requires_grad = True的可训练参数,但是我们不需要梯度计算

  • 在自动梯度计算中还有另外一个重要的类Function.TensorFunction互相连接并生成一个非循环图,它表示和存储了完整的计算历史。 每个张量都有一个.grad_fn属性,这个属性引用了一个创建了TensorFunction(除非这个张量是用户手动创建的,即,这个张量的 grad_fnNone)。

  • Autograd是反向自动求导系统。概念 Autograd记录一个图表,记录创建的所有操作 执行操作时的数据,提供有向无环图 其叶子是输入张量,根是输出张量。 通过从根到叶跟踪此图,可以自动使用链式法则计算梯度

  • 计算图

    • 首先,我们先简单地介绍一下什么是计算图(Computational Graphs),以方便后边的讲解。假设我们有一个复杂的神经网络模型,我们把它想象成一个错综复杂的管道结构,不同的管道之间通过节点连接起来,我们有一个注水口,一个出水口。我们在入口注入数据的之后,数据就沿着设定好的管道路线缓缓流动到出水口,这时候我们就完成了一次正向传播。

    • 计算图通常包含两种元素,一个是 tensor,另一个是 Function。张量 tensor 不必多说,但是大家可能对 Function 比较陌生。这里 Function 指的是在计算图中某个节点(node)所进行的运算,比如加减乘除卷积等等之类的,Function 内部有 forward()backward() 两个方法,分别应用于正向、反向传播。

    • 在我们做正向传播的过程中,除了执行 forward() 操作之外,还会同时会为反向传播做一些准备,为反向计算图添加 Function 节点。在上边这个例子中,变量 b 在反向传播中所需要进行的操作是 <ExpBackward>

  • 注意:grad在反向传播过程中是累加的(accumulated),这意味着每一次运行反向传播,梯度都会累加之前的梯度,所以一般在反向传播之前需把梯度清零

  • 通过 “xiaopl” 的例子学习

    • import torch
      from torchvision.models import mobilenet_v3_small,vgg11
      from torchviz import make_dot
      # 以VGGNet11为例,前向传播
      x = torch.rand(8, 3, 224, 224)
      model = vgg11()
      y = model(x)
      # 构造图对象,3种方式
      g = make_dot(y)
      # g = make_dot(y, params=dict(model.named_parameters()))
      # g = make_dot(y, params=dict(list(model.named_parameters()) + [('x', x)]))
      # 保存图像
      # g.view()  # 生成 Digraph.gv.pdf,并自动打开
      g.render(filename='vgg11', view=False)  # 保存为 graph.pdf,参数view表示是否打开pdf
      
    • 在这里插入图片描述

    • l1 = input x w1
      l2 = l1 + w2
      l3 = l1 x w3
      l4 = l2 x l3
      loss = mean(l4)
      
    • 这个例子比较简单,涉及的最复杂的操作是求平均,但是如果我们把其中的加法和乘法操作换成卷积,那么其实和神经网络类似。我们可以简单地画一下它的计算图:

    • 在这里插入图片描述

    • 下面给出了对应的代码,我们定义了inputw1w2w3 这三个变量,其中 input 不需要求导结果。根据 PyTorch 默认的求导规则,对于 l1 来说,因为有一个输入需要求导(也就是 w1 需要),所以它自己默认也需要求导,即 requires_grad=True。在整张计算图中,只有 input 一个变量是 requires_grad=False 的。正向传播过程的具体代码如下:

      • import torch
        input = torch.ones([2, 2], requires_grad=False)
        w1 = torch.tensor(2.0, requires_grad=True)
        w2 = torch.tensor(3.0, requires_grad=True)
        w3 = torch.tensor(4.0, requires_grad=True)
        l1 = input * w1
        l2 = l1 + w2
        l3 = l1 * w3
        l4 = l2 * l3
        loss = l4.mean()
        #l1.retain_grad()  # 非叶节点张量查看需要设置
        #loss.retain_grad()
        print(w1.data, w1.grad, w1.grad_fn)
        print(l1.data, l1.grad, l1.grad_fn)
        print(loss.data, loss.grad, loss.grad_fn)
        

tensor(2.) None None
tensor([[2., 2.],
[2., 2.]]) None <MulBackward0 object at 0x000001B9808798B0>
tensor(40.) None <MeanBackward0 object at 0x000001B9802699D0>

  • 可以看到,变量 l1grad_fn 储存着乘法操作符 <MulBackward0>,用于在反向传播中指导导数的计算。而 w1用户自己定义的,不是通过计算得来的,所以其 grad_fn 为空;同时因为还没有进行反向传播,grad 的值也为空。接下来,我们看一下如果要继续进行反向传播,计算图应该是什么样子:

    • 在这里插入图片描述

    • 反向图也比较简单,从 loss 这个变量开始,通过链式法则,依次计算出各部分的导数。【深一点学习】BP网络,结合数学推导的代码实现_羞儿的博客-CSDN博客

    • loss.backward()
      print(w1.grad, w2.grad, w3.grad)
      print(l1.grad, l2.grad, l3.grad, l4.grad, loss.grad)
      

tensor(28.) tensor(8.) tensor(10.)
None None None None None

  • 首先我们需要注意一下的是,在之前写程序的时候我们给定的 w 们都是一个常数,利用了广播的机制实现和常数和矩阵的加法乘法,比如 w2 + l1,实际上我们的程序会自动把 w2 扩展成 [[3.0, 3.0], [3.0, 3.0]],和 l1 的形状一样之后,再进行加法计算,计算的导数结果实际上为 [[2.0, 2.0], [2.0, 2.0]],为了对应常数输入,所以最后 w2 的梯度返回为矩阵之和 8 。另外还有一个问题,虽然 w 开头的那些和我们的计算结果相符,但是为什么 l1l2l3,甚至其他的部分的求导结果都为空呢?想要解答这个问题,我们得明白什么是叶子张量。

  • 叶子张量

    • 对于任意一个张量来说,我们可以用 tensor.is_leaf 来判断它是否是叶子张量(leaf tensor)。在反向传播过程中,只有 is_leaf=True 的时候,需要求导的张量的导数结果才会被最后保留下来

    • 对于 requires_grad=False 的 tensor 来说,我们约定俗成地把它们归为叶子张量。但其实无论如何划分都没有影响,因为张量的 is_leaf 属性只有在需要求导的时候才有意义。

    • 我们真正需要注意的是当 requires_grad=True 的时候,如何判断是否是叶子张量:当这个 tensor 是用户创建的时候,它是一个叶子节点,当这个 tensor 是由其他运算操作产生的时候,它就不是一个叶子节点

    • print(input.is_leaf,w1.is_leaf,w2.is_leaf,w3.is_leaf,l1.is_leaf,l2.is_leaf,l3.is_leaf,l4.is_leaf,loss.is_leaf)
      

True True True True False False False False False

  • 为什么要搞出这么个叶子张量的概念出来?原因是为了节省内存(或显存)。我们来想一下,那些非叶子结点,是通过用户所定义的叶子节点的一系列运算生成的,也就是这些非叶子节点都是中间变量,一般情况下,用户不会去使用这些中间变量的导数,所以为了节省内存,它们在用完之后就被释放了

  • 我们回头看一下之前的反向传播计算图,在图中的叶子节点用绿色标出了。可以看出来,被叫做叶子,可能是因为游离在主干之外,没有子节点,因为它们都是被用户创建的,不是通过其他节点生成。对于叶子节点来说,它们的 grad_fn 属性都为空;而对于非叶子结点来说,因为它们是通过一些操作生成的,所以它们的 grad_fn 不为空

  • 通过使用 tensor.retain_grad() 就可以保留中间变量的导数:

    • print(input.requires_grad,input.is_leaf,input.grad)
      print(l1.requires_grad,l1.is_leaf,l1.grad)
      print(loss.requires_grad,loss.is_leaf,loss.grad)
      l1.retain_grad()
      loss.retain_grad()
      loss.backward()  # 重新运行,主要不要二次反向传播
      print(input.requires_grad,input.is_leaf,input.grad)
      print(l1.requires_grad,l1.is_leaf,l1.grad)
      print(loss.requires_grad,loss.is_leaf,loss.grad)
      

False True None
True False None
True False None
False True None
True False tensor([[7., 7.],
[7., 7.]])
True False tensor(1.)

  • input 其实很像神经网络输入的图像,w1, w2, w3 则类似卷积核的参数,而 l1, l2, l3, l4 可以表示4个卷积层输出,如果我们把节点上的加法乘法换成卷积操作的话。实际上这个简单的模型,很像我们平时的神经网络的简化版。

  • inplace 操作

    • inplace 指的是在不更改变量的内存地址的情况下,直接修改变量的值

    • 每次 tensor 在进行 inplace 操作时,变量 _version 就会加1,其初始值为0。在正向传播过程中,求导系统记录的 b 的 version 是0,但是在进行反向传播的过程中,求导系统发现 b 的 version 变成1了,所以就会报错了。但是还有一种特殊情况不会报错,就是反向传播求导的时候如果没用到 b 的值(比如 y=x+1, y 关于 x 的导数是1,和 x 无关),自然就不会去对比 b 前后的 version 了,所以不会报错。

    • a = torch.tensor([1.0, 3.0], requires_grad=True)
      b = a + 2
      print(b._version) # 0
      loss = (b * b).mean()
      b[0] = 1000.0
      print(b._version) # 1
      loss.backward()
      
    • 0
      1 
      RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation: [torch.FloatTensor [2]], which is output 0 of struct torch::autograd::CopySlices, is at version 1; expected version 0 instead. Hint: enable anomaly detection to find the operation that failed to compute its gradient, with torch.autograd.set_detect_anomaly(True).
      
  • 上边我们所说的情况是针对非叶子节点的,对于 requires_grad=True 的叶子节点来说,要求更加严格了,甚至在叶子节点被使用之前修改它的值都不行。这个意思通俗一点说就是你的一顿 inplace 操作把一个叶子节点变成了非叶子节点了。我们知道,非叶子节点的导数在默认情况下是不会被保存的,这样就会出问题了。举个小例子:

    • a = torch.tensor([10., 5., 2., 3.], requires_grad=True)
      print(a, a.is_leaf)   # tensor([10.,  5.,  2.,  3.], requires_grad=True) True
      a[:] = 0
      print(a, a.is_leaf)   # RuntimeError: a view of a leaf Variable that requires grad is being used in an in-place operation.
      loss = (a*a).mean()
      loss.backward()
      
    • 在进行对 a 的重新 inplace 赋值之后,表示了 a 是通过 copy operation 生成的,grad_fn 都有了,所以自然而然不是叶子节点了。本来是该有导数值保留的变量,现在成了导数会被自动释放的中间变量了,所以 PyTorch 就给你报错了。

    • 不等到你调用 backward,只要你对需要求导的叶子张量使用了这些操作,马上就会报错。那是不是需要求导的叶子节点一旦被初始化赋值之后,就不能修改它们的值了呢?我们如果在某种情况下需要重新对叶子变量赋值该怎么办呢?有办法!

    • # 方法一
      a = torch.tensor([10., 5., 2., 3.], requires_grad=True)
      print(a, a.is_leaf, id(a))
      a.data.fill_(10.)
      # 或者 a.detach().fill_(10.)
      print(a, a.is_leaf, id(a))
      loss = (a*a).mean()
      loss.backward()
      print(a.grad)
      # 方法二
      a = torch.tensor([10., 5., 2., 3.], requires_grad=True)
      print(a, a.is_leaf)
      with torch.no_grad():a[:] = 10.
      print(a, a.is_leaf)
      loss = (a*a).mean()
      loss.backward()
      print(a.grad)
      

tensor([10., 5., 2., 3.], requires_grad=True) True 2126921359984
tensor([10., 10., 10., 10.], requires_grad=True) True 2126921359984
tensor([5., 5., 5., 5.])
tensor([10., 5., 2., 3.], requires_grad=True) True
tensor([10., 10., 10., 10.], requires_grad=True) True
tensor([5., 5., 5., 5.])

  • 修改的方法有很多种,核心就是修改那个和变量共享内存,但 requires_grad=False 的版本的值,比如通过 tensor.data 或者 tensor.detach()。需要注意的是,要在变量被使用之前修改,不然等计算完之后再修改,还会造成求导上的问题,会报错的

  • 为什么 PyTorch 的求导不支持绝大部分 inplace 操作呢?从上边我们也看出来了,因为真的很 tricky。比如有的时候在一个变量已经参与了正向传播的计算,之后它的值被修改了,在做反向传播的时候如果还需要这个变量的值的话,我们肯定不能用那个后来修改的值吧,但没修改之前的原始值已经被释放掉了,我们怎么办?

    • 一种可行的办法就是在 Function 做 forward 的时候每次都开辟一片空间储存当时输入变量的值,这样无论之后它们怎么修改,都不会影响了,反正我们有备份在存着。但这样有什么问题?这样会导致内存(或显存)使用量大大增加。因为我们不确定哪个变量可能之后会做 inplace 操作,所以我们每个变量在做完 forward 之后都要储存一个备份,成本太高了。除此之外,inplace operation 还可能造成很多其他求导上的问题
  • 总之,在实际写代码的过程中,没有必须要用 inplace operation 的情况,而且支持它会带来很大的性能上的牺牲,所以 PyTorch 不推荐使用 inplace 操作,当求导过程中发现有 inplace 操作影响求导正确性的时候,会采用报错的方式提醒。但这句话反过来说就是,因为只要有 inplace 操作不当就会报错,所以如果我们在程序中使用了 inplace 操作却没报错,那么说明我们最后求导的结果是正确的,没问题的。

  • 动态图,静态图

    • 所谓动态图,就是每次当我们搭建完一个计算图,然后在反向传播结束之后,整个计算图就在内存中被释放了。静态图,每次都先设计好计算图,需要的时候实例化这个图,然后送入各种输入,重复使用,只有当会话结束的时候创建的图才会被释放
  • 静态图,每次都先设计好计算图,需要的时候实例化这个图,然后送入各种输入,重复使用,只有当会话结束的时候创建的图才会被释放。

  • 正是因为 PyTorch 的两大特性:动态图和 eager execution,所以它用起来才这么顺手,简直就和写 Python 程序一样舒服,debug 也非常方便。除此之外,我们从之前的描述也可以看出,PyTorch 十分注重占用内存(或显存)大小,没有用的空间释放很及时,可以很有效地利用有限的内存。

  • Automatic differentiation package - torch.autograd — PyTorch 1.13 documentation
    一样舒服,debug 也非常方便。除此之外,我们从之前的描述也可以看出,PyTorch 十分注重占用内存(或显存)大小,没有用的空间释放很及时,可以很有效地利用有限的内存。

  • Automatic differentiation package - torch.autograd — PyTorch 1.13 documentation

相关文章:

pytorch-自动求导机制,构建计算图进行反向传播,需要注意inplace操作导致的报错,梯度属性变化

PyTorch 作为一个深度学习平台&#xff0c;在深度学习任务中比 NumPy 这个科学计算库强在哪里呢&#xff1f;一是 PyTorch 提供了自动求导机制&#xff0c;二是对 GPU 的支持。由此可见&#xff0c;自动求导 (autograd) 是 PyTorch&#xff0c;乃至其他大部分深度学习框架中的重…...

【Project】项目管理软件学习笔记

一、前言使用Project制定项目计划步骤大致如下&#xff1a;以Project2013为例&#xff0c;按照上图步骤指定项目计划。二、实施2.1 创建空白项目点击文件——新建——空白项目&#xff0c;即完成了空白项目的创建&#xff0c;在此我把该项目保存为60mm项目管理.mpp&#xff0c;…...

【算法设计-分治思想】快速幂与龟速乘

文章目录1. 快速幂2. 龟速乘3. 快速幂取模4. 龟速乘取模5. 快速幂取模优化1. 快速幂 算法原理&#xff1a; 计算 311&#xff1a; 311 (35)2 x 335 (32)2 x 332 3 x 3仅需计算 3 次&#xff0c;而非 11 次 计算 310&#xff1a; 310 (35)235 (32)2 x 332 3 x 3仅需计算…...

Kafka(十一) 如何保证数据的不重复和不丢失

数据不丢失 1&#xff09;从生产端&#xff1a;acks -1&#xff0c;&#xff08;ack应答机制&#xff09;从生产端到节点端&#xff0c;当所有isr集合里的节点备份完毕后返回成功&#xff1b; 2&#xff09;从节点端&#xff1a;每个partition至少需要一个isr节点&#xff0…...

解决树莓派 bullseye (11) 系统无法通过 xrdp 远程连接的问题

我手上有一台树莓派 4B&#xff0c;使用官方镜像烧录器烧录老版本操作系统 buster (10) 时可以正常通过 Windows 远程桌面连接上&#xff0c;但换成最新的 bullseye (11) 系统后却无法正常连接远程桌面。 问题复现&#xff1a; 使用官方镜像烧录器烧录&#xff0c;配置用户名为…...

微信公众号历史作品定向采集

最近有遇到微信公众号历史作品采集的需求,这里做一下记录, 登录自己注册好的的微信公众号后台进入创作界面,点击右上角的引用: 弹出如下界面: 选择查找公众号文章,输入要查找的公众号: 回车: 同时就可以打开F12开始抓包,选择公众号点击进入: appmsg?action=li…...

Vue学习笔记(3)

3.1 计算属性和监视属性 3.1.1 计算属性 计算属性是一种计算值的方式&#xff0c;可以根据其他属性的值来动态地计算新的属性值。计算属性可以缓存计算结果&#xff0c;当依赖的属性发生改变时&#xff0c;才会重新计算。在Vue中&#xff0c;可以使用computed选项来定义计算属…...

Marshmallow 库

文章目录Marshmallow 库介绍使用序列化反序列化参数介绍schema参数fields 参数钩子函数内置验证器Meta 属性Marshmallow 库 介绍 marshmallow是一个用来将复杂的orm对象与python原生数据类型之间相互转换的库&#xff0c;简而言之&#xff0c;就是实现object -> dict&#…...

【BN层的作用】论文阅读 | How Does Batch Normalization Help Optimization?

前言&#xff1a;15年Google提出Batch Normalization&#xff0c;成为深度学习最成功的设计之一&#xff0c;18年MIT团队将原论文中提出的BN层的作用进行了一一反驳&#xff0c;重新揭示BN层的意义 2015年Google团队论文&#xff1a;【here】 2018年MIT团队论文&#xff1a;【h…...

re.sub()用法的详细介绍

一、前言 在字符串数据处理的过程中&#xff0c;正则表达式是我们经常使用到的&#xff0c;python中使用的则是re模块。下面会通过实际案例介绍 re.sub() 的详细用法&#xff0c;该函数主要用于替换字符串中的匹配项。 二、函数原型 首先从源代码来看一下该函数原型&#xf…...

【Python数据挖掘入门】2.2文本分析-中文分词(jieba库cut方法/自定义词典load_userdict/语料库分词)

中文分词就是将一个汉字序列切分成一个一个单独的词。例如&#xff1a; 另外还有停用词的概念&#xff0c;停用词是指在数据处理时&#xff0c;需要过滤掉的某些字或词。 一、jieba库 安装过程见&#xff1a;https://blog.csdn.net/momomuabc/article/details/128198306 ji…...

Meta利用视觉信息来优化3D音频模型,未来将用于AR/VR

我们知道&#xff0c;Meta为了给AR眼镜打造智能助手&#xff0c;专门开发了第一人称视觉模型和数据集。与此同时&#xff0c;该公司也在探索一种将视觉和语音融合的AI感知方案。相比于单纯的语音助手&#xff0c;同时结合视觉和声音数据来感知环境&#xff0c;可进一步增强智能…...

openlayers加载离线地图并实现深色地图

问题背景 我们自己一直使用的openlayergeoserver自己发布的地图&#xff0c;使用的是矢量地图。但是由于政府地图大都使用为天地图&#xff0c;所以需要将geoserver的矢量地图更改为天地图&#xff0c;并且依旧是搭配openlayers来使用。 解决步骤 一&#xff1a;加载离线地图&a…...

socket,tcp,http三者之间的区别和原理

目录 一、OSI模型也称七层网络模型 1、TCP/IP连接 1.1三次握手与四次挥手的简单理解&#xff1a;&#xff08;面试重点&#xff09; 1.2面试考题&#xff1a;如果已经建立了连接&#xff0c;但是客户端突然出现故障了怎么办&#xff1f; 1.3 socket、tcp、http三者之间有什…...

红日(vulnstack)1 内网渗透ATTCK实战

环境准备 靶机链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;sx22 攻击机系统&#xff1a;kali linux 2022.03 网络配置&#xff1a; win7配置&#xff1a; kali配置&#xff1a; kali 192.168.1.108 192.168.111.129 桥接一块&#xff0c;自定义网卡4 win7 1…...

ik 分词器怎么调用缓存的词库

IK 分词器是一个基于 Java 实现的中文分词器&#xff0c;它支持在分词时调用缓存的词库。 要使用 IK 分词器调用缓存的词库&#xff0c;你需要完成以下步骤&#xff1a; 创建 IK 分词器实例 首先&#xff0c;你需要创建一个 IK 分词器的实例。可以通过以下代码创建一个 IK 分…...

ROS1/2机器人操作系统与时间Time的不解之缘

时间对于机器人操作系统非常重要。所有机器人类的编程中所涉及的变量如果需要在网络中传输都需要这个数据结构的时间戳。宏观上&#xff0c;ROS1、ROS2各版本都有官方支持的时间节点。ROS时钟--支持时间倒计时小工具效果如下&#xff1a;如果要部署机器人操作系统&#xff0c;R…...

华为OD机试真题2022(JAVA)

华为机试题库已换 →→→ 华为OD机试2023&#xff08;JAVA&#xff09; 以下题目为旧版题库&#xff0c;供大家课外消遣 基础题&#xff1a; 序号题目分值1查找众数及中位数1002出错的或电路1003连续字母长度1004分班1005计算面积1006最远足迹1007判断一组不等式是否满足约束…...

【3】MyBatis+Spring+SpringMVC+SSM整合一套通关

三、SpringMVC 1、SpringMVC简介 1.1、什么是MVC MVC是一种软件架构的思想&#xff0c;将软件按照模型、视图、控制器来划分 M&#xff1a;Model&#xff0c;模型层&#xff0c;指工程中的JavaBean&#xff0c;作用是处理数据 JavaBean分为两类&#xff1a; 一类称为实体…...

20道前端高频面试题(附答案)

ES6新特性 1.ES6引入来严格模式变量必须声明后在使用函数的参数不能有同名属性, 否则报错不能使用with语句 (说实话我基本没用过)不能对只读属性赋值, 否则报错不能使用前缀0表示八进制数,否则报错 (说实话我基本没用过)不能删除不可删除的数据, 否则报错不能删除变量delete p…...

android EditText设置后缀

有两种实现方案。 方案一&#xff1a;是自己写一个TextWatcher。 方案二&#xff1a;是重写TextView的getOffsetForPosition方法&#xff0c;返回一个计算好的offset。 我在工作时&#xff0c;使用的是方案一。在离职之后&#xff0c;我还是对这个问题耿耿于怀&#xff0c;所以…...

prometheus+cadvisor监控docker

官方解释 cAdvisor&#xff08;ContainerAdvisor&#xff09;为容器用户提供了对其运行容器的资源使用和性能特性的了解。它是一个正在运行的守护程序&#xff0c;用于收集、聚合、处理和导出有关正在运行的容器的信息。具体来说&#xff0c;它为每个容器保存资源隔离参数、历史…...

正演(1): 二维声波正演模拟程序(中心差分)Python实现

目录 1、原理&#xff1a; 1&#xff09;二维声波波动方程: ​编辑 2&#xff09;收敛条件&#xff08;不是很明白&#xff09; 3&#xff09;雷克子波 4&#xff09;二维空间衰减函数 5&#xff09;边界吸收条件 (不是很明白。。) 2、编程实现 1&#xff09;参数设置&…...

珠海数据智能监控器+SaaS平台 轻松实现SMT生产管控

数据智能监控器 兼容市面上99%的SMT设备 直接读取设备生产数据与状态&#xff0c;如&#xff1a;计划产出、实际产出、累计产出、停机、节拍、线利用率、直通率、停产时间、工单状态、OEE…… 产品功能价值 ◎ OEE不达标报警&#xff0c;一手掌握生产效能 ◎ 首检/巡检/成…...

习题22对前面21节的归纳总结

笨方法学python --习题22 Vi---Rum 于 2021-01-12 14:16:10 发布 python 习题22 这节内容主要是归纳总结 ex1.py 第一次学习 1.print&#xff1a;打印 2.# &#xff1a;是注释的意思&#xff0c;井号右边的内容不再执行 3.end"":,在句子结尾加上这个就不会再换行…...

使用Vite快速构建前端React项目

一、Vite简介 Vite是一种面向现代浏览器的一个更轻、更快的前端构建工具,能够显著提升前端开发体验。除了Vite外,前端著名的构建工具还有Webpack和Gulp。目前,Vite已经发布了Vite3,Vite全新的插件架构、丝滑的开发体验,可以和Vue3完美结合。 相比Webpack和Gulp等构建工具…...

人工智能高等数学--人工智能需要的数学知识_微积分_线性代数_概率论_最优化---人工智能工作笔记0024

然后我们看一下人工智能中需要的数学知识 数学知识是重要的,对于理解人工智能底层原理来说很重要,但是工作中 工作中一般都不会涉及的自己写算法之类的,只是面试,或者理解底层原理的时候需要 然后看一下人工智能需要哪些数学知识 这里需要微积分 线性代数 概率论 最优化的知识…...

阿里大数据之路总结

一、数据采集 二、数据同步 2.1、数据同步方式&#xff1a; 数据同步的三种方式&#xff1a;直连方式、数据文件同步、数据库日志解析方式 关系型数据库的结构化数据&#xff1a;MYSQL、Oracle、DB2、SQL Server非关系型数据库的非结构化数据&#xff08;数据库表形式存储&am…...

ABAP中Literals的用法(untyped literal vs. typed literal)

1. 什么是Literals ? Literals的字面意思即“文字”。其实&#xff0c;Literals就是在ABAP代码中直接指定的一个字符串&#xff0c;但注意哦&#xff0c;这个字符串并不意味着其类型一定是string哦。 要弄清这个概念&#xff0c;就要清楚ABAP对于Literals 的定义和处理方式。…...

tensorflow1.14.0安装教程

1首先电脑安装好Anaconda3&#xff08;Anaconda介绍、安装及使用教程 - 知乎 (zhihu.com)&#xff0c;&#xff09; 蟒蛇 |全球最受欢迎的数据科学平台 (anaconda.com) 2打开Anaconda Prompt&#xff08;本人更新win11后&#xff0c;主菜单不再显示&#xff0c;那么我们可以打…...

WordPress defcon/如何进行seo

【一】range()函数 在python中可以使用range()函数来产生一系列数字 for w in range(1,11): print(w) 输出&#xff1a; 1 2 3 4 5 6 7 8 9 10 #注意&#xff1a;这里的到10就结束了&#xff0c;不包括11 【二】list()函数 如果将range()作为参数传递给list()函数&#xff0c;那…...

wordpress增加内链/网页设计首页制作

EditText继承关系&#xff1a;View-->TextView-->EditTextEditText的属性很多&#xff0c;这里介绍几个&#xff1a;android:hint"请输入数字&#xff01;"//设置显示在控件上的提示信息android:numeric"integer"//设置只能输入整数&#xff0c;如果…...

网站站内交换链接怎么做/刷钻业务推广网站

现有一表&#xff0c;其内容既有中文也有英文字符&#xff0c;但在统计该字段内容中最大长度时&#xff0c;由于len&#xff08;&#xff09;函数统计的是字符而不是字节&#xff0c;使得得到的长度无法达到统一标准。请问如何解决这样的问题。表的内容如下&#xff1a; table…...

三合一网站选什么系统/深圳全网营销型网站

C中的格式化输出变参函数一、C中的格式化输出变参函数二、应用示例一、C中的格式化输出变参函数 C中的格式化输出变参函数有&#xff1a; int vprintf(const char *format,va_list ap); // 格式化字符串标准输出 int vfprintf(FILE *stream,const char *format,va_list ap); /…...

wordpress gettermby/搜索引擎优化的七个步骤

转载 http://blog.csdn.net/kakashi8841/article/details/17686791 Uni2D生成了一个自定义的表格用于保存你资源的唯一ID的引用。这个表格用于更新资源。比如&#xff0c;当你导入一个texture&#xff0c;Uni2D将检查这个表格&#xff0c;从而判断是否有atlas需要被更新。 为了…...

网站风险怎么解决方案/手机百度快照

案例一&#xff1a;去除集合里面的重复元素 package cn.itcast_04;import java.util.ArrayList;/** ArrayList去除集合中字符串的重复值(字符串的内容相同)* * 分析&#xff1a;* A:创建集合对象* B:添加多个字符串元素(包含内容相同的)* C:创建新集合* D:遍历旧集合,获…...