Model Fusion via Optimal Transport论文阅读+代码解析

news2024/11/16 13:33:49

论文地址点这里

一. 论文基本介绍

最近2023ICLR中的一篇论文被曝抄袭一事,而进行举报的作者就是本次要将的论文的作者之一,可以发现本篇论文的工作是非常不错的。本篇论文也是第一个从最优运输地角度考虑模型之间地融合技术,通过排列神经元而达到更好地效果。而且在本文中只要保证两个网络深度一样,那么两个网络就能够很好地融合。

二. 最优运输

详细地解读点这里
如果你对最优运输地相关概念1不是很了解,可以看一看上面这个链接地解读。
定义: 最优运输简单来说就是把A数据迁移到B。你可以理解成两堆土,从A土铲到另外一个地方,最终堆成B土。就像是以前初中学的线性规划一样的:3个城市(A, B, C)有1, 0.5, 1.5吨煤,然后要运到2个其他城市,这两个城市(C, D)分别需要2,1吨煤。然后,不同城市到不同的费用不同,让你算最优运输方案和代价。

因此,首先我们考虑有两个离散测度 μ = ∑ i = 1 n α i δ ( x ( i ) ) \mu=\sum_{i=1}^n \alpha_i \delta\left(\boldsymbol{x}^{(i)}\right) μ=i=1nαiδ(x(i)) 以及 ν = ∑ i = 1 m β i δ ( y ( i ) ) \nu=\sum_{i=1}^m \beta_i \delta\left(\boldsymbol{y}^{(i)}\right) ν=i=1mβiδ(y(i))。这里 δ ( x ) \delta(\boldsymbol{x}) δ(x)表示为离散点 x ∈ S \boldsymbol{x} \in \mathcal{S} xS以及和所有相关点 X = ( x ( 1 ) , … , x ( n ) ) ∈ S n \boldsymbol{X}=\left(\boldsymbol{x}^{(1)}, \ldots, \boldsymbol{x}^{(n)}\right) \in \mathcal{S}^n X=(x(1),,x(n))Sn的分布。权重 α = ( α 1 , … , α n ) \boldsymbol{\alpha}=\left(\alpha_1, \ldots, \alpha_n\right) α=(α1,,αn) 表示为对应的概率向量( β \boldsymbol{\beta} β类似 )。同时使用 C i j \boldsymbol{C}_{i j} Cij表示从 x ( i ) \boldsymbol{x}^{(i)} x(i) 移动到 y ( j ) \boldsymbol{y}^{(j)} y(j)的花费。 因此对于 μ \mu μ以及 ν \nu ν的最优运输可以被写为下面的线性问题: O T ( μ , ν ; C ) : = min ⁡ ⟨ T , C ⟩ OT(\mu, \nu ; \boldsymbol{C}):=\min \langle\boldsymbol{T}, \boldsymbol{C}\rangle OT(μ,ν;C):=minT,C,,其中 T ∈ R + ( n × m ) \boldsymbol{T} \in \mathbb{R}_{+}^{(n \times m)} TR+(n×m),因此 T 1 m = α , T ⊤ 1 n = β \boldsymbol{T} \mathbf{1}_m=\boldsymbol{\alpha}, \boldsymbol{T}^{\top} \mathbf{1}_n=\boldsymbol{\beta} T1m=α,T1n=β。其中 ⟨ T , C ⟩ : = tr ⁡ ( T ⊤ C ) = ∑ i j T i j C i j \langle\boldsymbol{T}, \boldsymbol{C}\rangle:=\operatorname{tr}\left(\boldsymbol{T}^{\top} \boldsymbol{C}\right)=\sum_{i j} T_{i j} C_{i j} T,C:=tr(TC)=ijTijCij表示为矩阵的内积。最优的 T ∈ R + ( n × m ) T \in \mathbb{R}_{+}^{(n \times m)} TR+(n×m)被称作是运输矩阵或者运输映射 , 而 T i j T_{i j} Tij 表示 x ( i ) \boldsymbol{x}^{(i)} x(i) y ( j ) \boldsymbol{y}^{(j)} y(j)的最佳运输大小。
Wasserstein距离: 距离度量是机器学习任务中最重要的一环。比如,常见的人工神经网络的均方误差损失函数采用的就是熟知的欧式距离。然而,在最优运输过程中,优于不同两点之间均对应不同的概率,如果直接采用欧式距离来计算运输的损失(或者说对运输的过程进行度量和评估),则会导致最终的评估结果出现较大的偏差(即忽略了原始不同点直接的概率向量定义)。

三. 提出的算法

正如在前面的介绍中提到的,参数平均的问题是模型参数之间缺乏一对一的对应关系。特别是对于给定的一层,两种模型的神经元之间没有直接的匹配。例如,这意味着模型A的第 p p p个神经元的行为可能与另一个模型B的第 p p p个神经元的行为非常不同(就它检测到的特征而言),相反,在功能上可能与第 p + 1 p+1 p+1个神经元非常相似。想象一下,如果我们知道神经元之间的完美匹配,那么我们就可以简单地将模型a的神经元相对于模型B的神经元排列起来。这样做之后,对神经元参数进行平均就更有意义了。匹配或赋值可以表述为一个排列矩阵,只需将参数乘以这个矩阵就可以使参数对齐。

但在实践中,对于给定的层,两种模型的神经元之间更有可能存在软对应关系,特别是当它们的数量在两种模型中不相同时。这就是最优传输的作用所在,它以传输图T的形式为我们提供了一个软对齐矩阵。换句话说,对齐问题可以重新表述为,将模型a的给定层中的神经元最优地运输到模型B的同一层中的神经元。
在这里插入图片描述
过程: 我们假设模型在 l l l层之前的神经元已经排列完成。现在我们定义两个模型在 l l l层的概率测度为: μ ( ℓ ) = ( α ( ℓ ) , X [ ℓ ] ) \mu^{(\ell)}=\left(\boldsymbol{\alpha}^{(\ell)}, \boldsymbol{X}[\ell]\right) μ()=(α(),X[]) 以及 ν ( ℓ ) = ( β ( ℓ ) , Y [ ℓ ] ) \nu^{(\ell)}=\left(\boldsymbol{\beta}^{(\ell)}, \boldsymbol{Y}[\ell]\right) ν()=(β(),Y[])。其中 X , Y \boldsymbol{X}, \boldsymbol{Y} X,Y为测量支持。

接下来,我们使用均匀分布来初始化每一层的直方图(或概率值)。在实际中,如果使用 n ( ℓ ) , m ( ℓ ) n^{(\ell)},m^{(\ell)} n(),m()表示为模型A,B在第 ℓ \ell 层的大小,那么我们可以得到 α ( ℓ ) ← 1 n ( ℓ ) / n ( ℓ ) , β ( ℓ ) ← 1 m ( ℓ ) / m ( ℓ ) \boldsymbol{\alpha}^{(\ell)} \leftarrow \boldsymbol{1}_{n^{(\ell)}} / n^{(\ell)}, \boldsymbol{\beta}^{(\ell)} \leftarrow \mathbf{1}_{m^{(\ell)}} / m^{(\ell)} α()1n()/n(),β()1m()/m()。现在,根据对齐过程,我们首先对齐当前层的传入边权值。这可以通过与前面的层传输矩阵 T ( l − 1 ) T^{(l-1)} T(l1)相乘来实现,并且通过相应列边矩阵的倒数 β ( ℓ − 1 ) \boldsymbol{\beta}^{(\ell-1)} β(1)进行归一化:
W ^ A ( ℓ , ℓ − 1 ) ← W A ( ℓ , ℓ − 1 ) T ( ℓ − 1 ) diag ⁡ ( 1 / β ( ℓ − 1 ) ) (1) \widehat{\boldsymbol{W}}_A^{(\ell, \ell-1)} \leftarrow \boldsymbol{W}_A^{(\ell, \ell-1)} \boldsymbol{T}^{(\ell-1)} \operatorname{diag}\left(1 / \boldsymbol{\beta}^{(\ell-1)}\right) \tag1 W A(,1)WA(,1)T(1)diag(1/β(1))(1)
这里可以这么解释:矩阵 T ( ℓ − 1 ) diag ⁡ ( β − ( ℓ − 1 ) ) \boldsymbol{T}^{(\ell-1)} \operatorname{diag}\left(\boldsymbol{\beta}^{-(\ell-1)}\right) T(1)diag(β(1)) m ( ℓ − 1 ) m^{(\ell-1)} m(1)个列,因此通过进行和当前权重 W A ( ℓ , ℓ − 1 ) \boldsymbol{W}_A^{(\ell, \ell-1)} WA(,1)的相乘将会产生一个凸组合。

一旦完成了这一步,我们就会专注于校准 ℓ \ell 层的神经元。我们假设我们有一个合适的地面度量矩阵 D S D_{\mathcal{S}} DS,我们可以根据 μ ( ℓ ) , ν ( ℓ ) \mu^{(\ell)}, \nu^{(\ell)} μ(),ν()以及 ℓ \ell 计算最优的传输矩阵 T ( ℓ ) \boldsymbol{T}^{(\ell)} T() T ( ℓ ) , W 2 ← O T ( μ ( ℓ ) , ν ( ℓ ) , D S ) \boldsymbol{T}^{(\ell)}, \mathcal{W}_2 \leftarrow \mathrm{OT}\left(\mu^{(\ell)}, \nu^{(\ell)}, D_{\mathcal{S}}\right) T(),W2OT(μ(),ν(),DS),其中 W 2 \mathcal{W}_2 W2表示为Wasserstein距离。现在,我们可以使用这个传输矩阵 T ( ℓ ) \boldsymbol{T}^{(\ell)} T()来重新排列模型A到模型B的神经元:
W ~ A ( ℓ , ℓ − 1 ) ← diag ⁡ ( 1 / β ( ℓ ) ) T ( ℓ ) ⊤ W ^ A ( ℓ , ℓ − 1 ) (2) \widetilde{\boldsymbol{W}}_A^{(\ell, \ell-1)} \leftarrow \operatorname{diag}\left(1 / \boldsymbol{\beta}^{(\ell)}\right) \boldsymbol{T}^{(\ell)^{\top}} \widehat{\boldsymbol{W}}_A^{(\ell, \ell-1)} \tag2 W A(,1)diag(1/β())T()W A(,1)(2)
因此,有了这种对齐,我们可以平均两层的权重,以获得融合的权重矩阵 W F ( ℓ , ℓ − 1 ) W_{\mathcal{F}}^{(\ell, \ell-1)} WF(,1),如下式:
W F ( ℓ , ℓ − 1 ) ← 1 2 ( W ~ A ( ℓ , ℓ − 1 ) + W B ( ℓ , ℓ − 1 ) ) (3) \boldsymbol{W}_{\mathcal{F}}^{(\ell, \ell-1)} \leftarrow \frac{1}{2}\left(\widetilde{\boldsymbol{W}}_A^{(\ell, \ell-1)}+\boldsymbol{W}_B^{(\ell, \ell-1)}\right) \tag3 WF(,1)21(W A(,1)+WB(,1))(3)
注意,由于输入层的顺序对两个模型是相同的,我们从第二层开始对齐。此外,最后一层,也就是输出层,神经元的顺序也是相同的。因此,最后一层的(缩放的)传输映射将等于标识。

多模型融合: 关键思想是,从融合模型的 W F ( ℓ , ℓ − 1 ) \boldsymbol{W}_{\mathcal{F}}^{(\ell, \ell-1)} WF(,1)估计开始,然后根据它对齐所有给定模型,最后返回这些对齐权重的平均值作为融合模型的最终权重。对于两个模型的情况,这相当于我们上面讨论的将融合模型初始化为模型B时的过程,即 M ^ F ← M B \widehat{M}_{\mathcal{F}} \leftarrow M_B M FMB。因为,将模型B与融合模型的这个估计对齐将得到一个等于恒等的(缩放的)传输映射。然后,式(3)将等于返回对齐权重的平均值。

定位策略: 上面我们讨论需要有一个地面度量 D S D_{\mathcal{S}} DS,这里有两种方法可以考虑:

  • 基于激活的策略 ( ψ = (\psi= (ψ= ‘acts’ ) ) ) 在这个变体中,我们对 m m m样本集进行推理, S = { x } i = 1 m S=\{\mathbf{x}\}_{i=1}^m S={x}i=1m并将所有神经元的激活存储在模型中。因此,我们认为神经元激活,连接到样本的一个向量,作为度量的支持,我们将其表示为 X k ← ACTS ⁡ ( M k ( S ) ) , Y ← ACTS ⁡ ( M F ( S ) ) \boldsymbol{X}_k \leftarrow \operatorname{ACTS}\left(M_k(S)\right), \boldsymbol{Y} \leftarrow \operatorname{ACTS}\left(M_{\mathcal{F}}(S)\right) XkACTS(Mk(S))YACTS(MF(S))。然后,如果两个模型的神经元对给定的样本集产生相似的激活输出,则认为它们是相似的。我们通过计算得到的激活向量之间的欧氏距离来测量这一点。这作为OT计算的基础度量。
  • 基于权重的策略( ψ = \psi= ψ= ‘wts’): 在这里,我们认为每个神经元的支持由传入边的权重给出(堆叠在一个向量中)。因此,一个神经元可以被认为是由权矩阵中与其对应的行表示的。因此,对这种排列类型的度量的支持由, X k [ ℓ ] ← W ^ k ( ℓ , ℓ − 1 ) , Y [ ℓ ] ← W ^ F ( ℓ , ℓ − 1 ) \boldsymbol{X}_k[\ell] \leftarrow \widehat {\boldsymbol{W}}_k^{(\ell, \ell-1)}, \boldsymbol{Y}[\ell] \leftarrow \widehat {\boldsymbol{W}}_{\mathcal{F}}^{(\ell,\ell-1)} Xk[]W k(,1)Y[]W F(,1)给出。选择这种支持的理由源于特定层的神经元激活被计算为该权重向量与前一层输出之间的内积。OT使用的地面度量是欧氏距离,就像在前面的对齐策略中一样。除了在地面度量中使用实际重量的差异,其余的程序是相同的。

算法如下:
在这里插入图片描述

三. 代码解析

论文代码点这里
在开始代码前,我将根据我自己的对文章的理解,然后使用一个简单的例子讲如何根据OT对模型进行融合的:

在这里插入图片描述
我们来看代码(为了直观理解,这里选择的是两个MLP模型并且模型大小是一样的,利用MNIST数据集进行考察的),我们首先来看参与进行融合的相关参数

def get_acts_wassersteinized_layers_modularized(args, networks, activations, eps=1e-7, train_loader=None, test_loader=None)

其中networks为一个列表,存储了两个模型的对应参数,如下:
在这里插入图片描述

activations存储的是两个模型各层经过数据集得出激活向量组:
在这里插入图片描述
这里选择得batch_size=200,因此每层为:[200,1,400] [200,1,200]等。
接下来我们来看看具体是怎么工作的,首先我们使用均匀分布初始化当前的两个概率向量mu以及nu,如下:

def _get_neuron_importance_histogram(args, layer_weight, is_conv, eps=1e-9):
    print('shape of layer_weight is ', layer_weight.shape)
    if is_conv:
        layer = layer_weight.contiguous().view(layer_weight.shape[0], -1).cpu().numpy()
    else:
        layer = layer_weight.cpu().numpy()
    
    if args.importance == 'l1':
        importance_hist = np.linalg.norm(layer, ord=1, axis=-1).astype(
                    np.float64) + eps
    elif args.importance == 'l2':
        importance_hist = np.linalg.norm(layer, ord=2, axis=-1).astype(
                    np.float64) + eps
    else:
        raise NotImplementedError

    if not args.unbalanced:
        importance_hist = (importance_hist/importance_hist.sum())
        print('sum of importance hist is ', importance_hist.sum())
    # assert importance_hist.sum() == 1.0
    return importance_hist

得到得结果为:
在这里插入图片描述
因为当前得层为400,所以1/400=0.025然后填充完成,之后我们计算aligned_w:

if is_conv:
    if args.handle_skips:
        assert len(layer0_shape) == 4
        # save skip_level transport map if there is block ahead
        if layer0_shape[1] != layer0_shape[0]:
            if not (layer0_shape[2] == 1 and layer0_shape[3] == 1):
                print(f'saved skip T_var at layer {idx} with shape {layer0_shape}')
                skip_T_var = T_var.clone()
                skip_T_var_idx = idx
            else:
                print(
                    f'utilizing skip T_var saved from layer layer {skip_T_var_idx} with shape {skip_T_var.shape}')
                # if it's a shortcut (128, 64, 1, 1)
                residual_T_var = T_var.clone()
                residual_T_var_idx = idx  # use this after the skip
                T_var = skip_T_var
            print("shape of previous transport map now is", T_var.shape)
        else:
            if residual_T_var is not None and (residual_T_var_idx == (idx - 1)):
                T_var = (T_var + residual_T_var) / 2
                print("averaging multiple T_var's")
            else:
                print("doing nothing for skips")
    T_var_conv = T_var.unsqueeze(0).repeat(fc_layer0_weight_data.shape[2], 1, 1)
    aligned_wt = torch.bmm(fc_layer0_weight_data.permute(2, 0, 1), T_var_conv).permute(1, 2, 0)

else:
    if fc_layer0_weight.data.shape[1] != T_var.shape[0]:
        # Handles the switch from convolutional layers to fc layers
        # checks if the input has been reshaped
        fc_layer0_unflattened = fc_layer0_weight.data.view(fc_layer0_weight.shape[0], T_var.shape[0],
                                                           -1).permute(2, 0, 1)
        aligned_wt = torch.bmm(
            fc_layer0_unflattened,
            T_var.unsqueeze(0).repeat(fc_layer0_unflattened.shape[0], 1, 1)
        ).permute(1, 2, 0)
        aligned_wt = aligned_wt.contiguous().view(aligned_wt.shape[0], -1)
    else:
        aligned_wt = torch.matmul(fc_layer0_weight.data, T_var)

接下来我们使用激活去计算度量,如下

def process(self, coordinates, other_coordinates=None):
    print('Processing the coordinates to form ground_metric')
    if self.params.geom_ensemble_type == 'wts' and self.params.normalize_wts:
        print("In weight mode: normalizing weights to unit norm")
        coordinates = self._normed_vecs(coordinates)
        if other_coordinates is not None:
            other_coordinates = self._normed_vecs(other_coordinates)

    ground_metric_matrix = self.get_metric(coordinates, other_coordinates)

    if self.params.debug:
        print("coordinates is ", coordinates)
        if other_coordinates is not None:
            print("other_coordinates is ", other_coordinates)
        print("ground_metric_matrix is ", ground_metric_matrix)

    self._sanity_check(ground_metric_matrix)

    ground_metric_matrix = self._normalize(ground_metric_matrix)

    self._sanity_check(ground_metric_matrix)

    if self.params.clip_gm:
        ground_metric_matrix = self._clip(ground_metric_matrix)

    self._sanity_check(ground_metric_matrix)

    if self.params.debug:
        print("ground_metric_matrix at the end is ", ground_metric_matrix)

    return ground_metric_matrix

最后利用OT解出T来,并归一化,再使用T排列aligned_w:

T_var = _get_current_layer_transport_map(args, mu, nu, M0, M1, idx=idx, layer_shape=layer_shape, eps=eps, layer_name=layer0_name)
T_var, marginals = _compute_marginals(args, T_var, device, eps=eps)

if args.debug:
    if idx == (num_layers - 1):
        print("there goes the last transport map: \n ", T_var)
        print("and before marginals it is ", T_var/marginals)
    else:
        print("there goes the transport map at layer {}: \n ".format(idx), T_var)

print("Ratio of trace to the matrix sum: ", torch.trace(T_var) / torch.sum(T_var))
print("Here, trace is {} and matrix sum is {} ".format(torch.trace(T_var), torch.sum(T_var)))
setattr(args, 'trace_sum_ratio_{}'.format(layer0_name), (torch.trace(T_var) / torch.sum(T_var)).item())

if args.past_correction:
    print("Shape of aligned wt is ", aligned_wt.shape)
    print("Shape of fc_layer0_weight_data is ", fc_layer0_weight_data.shape)

    t_fc0_model = torch.matmul(T_var.t(), aligned_wt.contiguous().view(aligned_wt.shape[0], -1))
else:
    t_fc0_model = torch.matmul(T_var.t(), fc_layer0_weight_data.view(fc_layer0_weight_data.shape[0], -1))

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

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

相关文章

Snort搭建以及规则编写

目录 Snort IDS Snort搭建 安装web服务,方便设置sonrt后期访问 Mysql安装 PHP安装 安装 Snort Snort配置 创建snort专用的用户和组 配置目录 配置规则 修改配置文件 规则编写 Snort IDS Snort IDS(入侵检测系统)是一个强大的网…

Airtest自定义启动器支持批量运行脚本,并兼容在AirtestIDE中使用

小编注:上期详细讲了Airtest启动器的原理,以及在最后给出了2个实现方案。本次是第2个方案的另一个实现案例,供大家学习参考。 Python v3.7.0 / Airtest: 1.1.1 / PocoUI: 1.0.78 自定义的启动器主要实现了以下功能: 将一些公共…

浙大医疗健康产业管理MBA提面经验分享

各位潜在的学弟学妹们好,很高兴和各位分享下我参加2022年浙大医疗产业管理MBA的提前批面试经验。在经过材料的撰写提交、面试备考各环节后顺利拿到优秀资格,为后面的笔试备考减轻了很大压力,回忆起去年的面试过程,我的面试以及备考…

沉睡者IT - 为你解密那些卖虚拟资源和知识付费课程的平台到底有多简单和多赚钱。

潜力博主推荐,点击上面关注博主 ↑ ↑ 上图为平台首页面截图,官方总站演示:vip.zzzz.la 备用演示:VIP.网站 1.虚拟资源平台介绍! (1)虚拟资源项目站是一个在线知识付费平台,全自动…

Nacos 中的配置文件如何实现加密传输

小伙伴们知道,Spring Cloud Config 很早就提供了配置文件的加解密功能,并且支持对称加密和非对称加密两种不同的模式。Nacos 作为分布式配置中心服务注册中心的合体,在配置文件加密这块一直差点意思,不过好在,如果你使…

公众号免费搜题系统调用方法

公众号免费搜题系统调用方法 本平台优点: 多题库查题、独立后台、响应速度快、全网平台可查、功能最全! 1.想要给自己的公众号获得查题接口,只需要两步! 2.题库: 查题校园题库:查题校园题库后台&#xf…

SQL Server 服务的启动

目录 前言: 一、进入控制面板 二、开启 SQL Server 服务 1. 找到管理工具并点击 2. 双击服务 3. 找到SQL Server 数据库服务 4. 右键点击 SQL Server 服务,选择启动 三、修改 SQL Server 服务的启动方式 1. 右键点击服务,点击属性 …

激发客户潜在需求

企业不光要看到客户的显现需求,更要挖掘客户的潜在需求,因为客户的潜在需求是可以转化为显现需求的,满足客户的潜在需求可以为企业带来更多经济效益。 前言 潜在需求是指消费者虽然有明确意识的欲望,但由于种种原因还没有明确的显…

Redis的缓存更新策略和缓存问题

1.缓存更新 1.1缓存更新策略 内存淘汰: 不需要自己维护,利用Redis的内存淘汰机制,当内存不足时自动淘汰部分数据,下次查询时更新缓存一致性 : 差维护成本:无 超时删除: 给缓存数据添加TTL时间…

零基础自学javase黑马课程第十五天

零基础自学javase黑马课程第十五天 ✨欢迎关注🖱点赞🎀收藏⭐留言✒ 🔮本文由京与旧铺原创,csdn首发! 😘系列专栏:java学习 💻首发时间:🎞2022年11月21日&…

【案例设计】配置与批量化处理外部 Texture 导入格式转换

开发平台:Unity 2020 版本以上 编程平台:Visual Studio 2020 版本 编程语言:CSharp   前言 Unity 开发者不仅是要求在面对开发需求上有着预见性的目光与能力去应对各种功能实现。更加注重的是通过各个项目的开发类型与过程,总结…

计算机体系结构:不同改进方案的性价比计算

题目内容 某一计算机用于商业外贸的事务处理,有大量的字符串操作。由于这种事务处理很普遍,有较大的市场,故而设计人员决定在下一代此类计算机的CPU中加入字符串操作的功能。经测试应用软件调查发现,字符串操作的使用占整个程序运…

进程切换及一些常见概念(面试必问)

目录前言一、竞争性1、什么是进程的竞争性?2、为什么进程间存在竞争性?二、独立性#这里先简单了解三、并行四、并发五、优先级队列六、进程切换寄存器1. 函数返回值2. 进程上下文数据总结前言 在不同的进程在处理机上切换的过程中,我们需要学…

碳酸钙/GPC3单克隆抗体介导阿霉素二氧化硅纳米粒/DOX-GNRs@mSiO2-HA-RGD纳米制备方法

小编在这里整理了碳酸钙/GPC3单克隆抗体介导阿霉素二氧化硅纳米粒/DOX-GNRsmSiO2-HA-RGD纳米制备方法,来看! 碳酸钙阿霉素二氧化硅纳米颗粒制备方法: 包括以下步骤: 将含有钙离子的乙醇溶液与含有氨水与盐酸阿霉素的水溶液混合,…

【Jupyter】远程连接Jupyter服务器

远程连接Jupyter 步骤一 配置Jupyter https://blog.csdn.net/MYRLibra/article/details/109599531 https://blog.csdn.net/weixin_40641725/article/details/114636779 安装 conda activate abc #激活虚拟环境 pip install jupyter #安装 jupyter notebook --generate-conf…

Webservice接口-WSDL文档【Webservice】

WSDL是一个用于精确描述Web服务的文档,WSDL文档是一个遵循WSDL-XML模式的XML文档。WSDL 文档将Web服务定义为服务访问点或端口的集合。在 WSDL 中,由于服务访问点和消息的抽象定义已从具体的服务部署或数据格式绑定中分离出来,因此可以对抽象…

python使用flask实现前后端分离通过前端修改数据库数据【全栈开发基础】

文章目录🚎前言:🛺工具🚓截图🚕数据库截图🚙前端截图🚘代码🚲增加🍕前端 HTML🍟后端 python🛴 删除🍕前端 HTML🍟后端 pyt…

AMM 套利者

AMM 套利者 理由 以太坊和其他支持 EVM 的区块链上有很多 AMM。其中许多 AMM 是 UniswapV2 的分叉项目或与 UniswapV2 具有相同的接口。这些 AMM 的列表: Uniswap V2(以太坊)寿司交换(以太坊)煎饼掉期(BSC)MDEX(BSC/heco) ... 一旦相同代币…

SpiderPool - 云原生容器网络 IPAM 插件

SpiderPool 来源于容器网络落地实践的经验积累,是「Daocloud 道客」开源的原生容器网络 IPAM 插件(github:https://github.com/spidernet-io/spiderpool),主要用于搭配 Underlay CNI 实现容器云平台精细化的管理和分配…

策略验证_指标买点分析技法_运用boll布林线指标选择买点

写在前面: 1. 本文中提到的“股票策略校验工具”的具体使用操作请查看该博文; 2. 文中知识内容来自书籍《同花顺炒股软件从入门到精通》 3. 本系列文章是用来学习技法,文中所得内容都仅仅只是作为演示功能使用 目录 解说 策略代码 结果 解…