MAML-RL Pytorch 代码解读 (16) -- maml_rl/metalearner.py

2023-05-16

MAML-RL Pytorch 代码解读 (16) – maml_rl/metalearner.py

文章目录

  • MAML-RL Pytorch 代码解读 (16) -- maml_rl/metalearner.py
      • 基本介绍
        • 源码链接
        • 文件路径
      • `import` 包
      • `MetaLearner()` 类

基本介绍

在网上看到的元学习 MAML 的代码大多是跟图像相关的,强化学习这边的代码比较少。

因为自己的思路跟 MAML-RL 相关,所以打算读一些源码。

MAML 的原始代码是基于 tensorflow 的,在 Github 上找到了基于 Pytorch 源码包,学习这个包。

源码链接

https://github.com/dragen1860/MAML-Pytorch-RL

文件路径

./maml_rl/metalearner.py

import

import  torch
from    torch.nn.utils.convert_parameters import vector_to_parameters, parameters_to_vector
from    torch.distributions.kl import kl_divergence

from    maml_rl.utils.torch_utils import weighted_mean, detach_distribution, weighted_normalize
from    maml_rl.utils.optimization import conjugate_gradient

MetaLearner()

class MetaLearner:
    
    #### 这个类主要是定义如何构建一个元智能体。他会在一阶梯度下降前后采样轨迹/回合信息,计算内环损失,基于内环损失计算更新参数,执行元级别更新。
	"""
	Meta-learner

	The meta-learner is responsible for sampling the trajectories/episodes
	(before and after the one-step adaptation), compute the inner loss, compute
	the updated parameters based on the inner-loss, and perform the meta-update.

	[1] Chelsea Finn, Pieter Abbeel, Sergey Levine, "Model-Agnostic
		Meta-Learning for Fast Adaptation of Deep Networks", 2017
		(https://arxiv.org/abs/1703.03400)
	[2] Richard Sutton, Andrew Barto, "Reinforcement learning: An introduction",
		2018 (http://incompleteideas.net/book/the-book-2nd.html)
	[3] John Schulman, Philipp Moritz, Sergey Levine, Michael Jordan,
		Pieter Abbeel, "High-Dimensional Continuous Control Using Generalized
		Advantage Estimation", 2016 (https://arxiv.org/abs/1506.02438)
	[4] John Schulman, Sergey Levine, Philipp Moritz, Michael I. Jordan,
		Pieter Abbeel, "Trust Region Policy Optimization", 2015
		(https://arxiv.org/abs/1502.05477)
	"""

    #### 初始化采样器、策略、基线、折扣因子、梯度下降更新率、用于处理过长序列的价值的tau值,设备信息。
	def __init__(self, sampler, policy, baseline, gamma=0.95, fast_lr=0.5, tau=1.0, device='cpu'):
		self.sampler = sampler
		self.policy = policy
		self.baseline = baseline
		self.gamma = gamma
		self.fast_lr = fast_lr
		self.tau = tau
		self.to(device)

    #### 计算内环损失用于一阶梯度更新。内环损失是REINFORCE,用泛化优势估计计算优势。
	def inner_loss(self, episodes, params=None):
		"""
		Compute the inner loss for the one-step gradient update. The inner
		loss is REINFORCE with baseline [2], computed on advantages estimated
		with Generalized Advantage Estimation (GAE, [3]).
		"""
        
        #### 用baseline也就是人工提取的特征方式计算价值信息。用gae方法计算优势信息并归一化处理。
		values = self.baseline(episodes)
		advantages = episodes.gae(values, tau=self.tau)
		advantages = weighted_normalize(advantages, weights=episodes.mask)

        #### 设置自己的策略,参数从外部输入进来。返回每个动作的概率分布数值。如果输出动作的概率分布大于2,这说明有一列多余了,用torch.sum()求和消去这个列。最后用分维度分权重均值计算概率分布和优势的成绩的平均值。最后返回损失。
		pi = self.policy(episodes.observations, params=params)
		# return the log_prob at value
		log_probs = pi.log_prob(episodes.actions) # [200, 20, 6]
		if log_probs.dim() > 2:
			log_probs = torch.sum(log_probs, dim=2)
		loss = -weighted_mean(log_probs * advantages, weights=episodes.mask)

		return loss

	def adapt(self, episodes, first_order=False):
        
        #### 在新任务上做泛化适应,从采样的回合轨迹中获得数据,进行一阶梯度更新。对于baseline方法,采用拟合的方式获得更新的权重;通过上面一个函数的方法获得分维度分权重损失均值;采用self.fast_lr学习率,一阶优化方式获得更新的参数。最后返回参数。
		"""
		Adapt the parameters of the policy network to a new task, from
		sampled trajectories `episodes`, with a one-step gradient update [1].
		"""
		# Fit the baseline to the training episodes
		self.baseline.fit(episodes)
		# Get the loss on the training episodes
		loss = self.inner_loss(episodes)
		# Get the new parameters after a one-step gradient update
		params = self.policy.update_params(loss, step_size=self.fast_lr, first_order=first_order)

		return params

	def sample(self, tasks, first_order=False):
        
        #### 设置一个空列表的episodes用于记录信息。对于所有任务,先对所有任务重置环境,在通过self.policy策略、self.gamma折扣率和self.device设备信息进行跑episode。跑完的episode数据信息传入到train_episodes中。对train_episodes的数据信息通过一阶求导做泛化适应。将更新后的self.policy策略、self.gamma折扣率和self.device设备信息在原来任务上在进行跑episode动作。获得valid_episodes数据。最后将原来的数据和现在的数据整合成一个元组,返回。
		"""
		Sample trajectories (before and after the update of the parameters)
		for all the tasks `tasks`.
		"""
		episodes = []
		for task in tasks:
			self.sampler.reset_task(task)
			train_episodes = self.sampler.sample(self.policy, gamma=self.gamma, device=self.device)

			params = self.adapt(train_episodes, first_order=first_order)

			valid_episodes = self.sampler.sample(self.policy, params=params, gamma=self.gamma, device=self.device)
			episodes.append((train_episodes, valid_episodes))
		return episodes

	def kl_divergence(self, episodes, old_pis=None):
        
        #### 先设置kls记录KL散度数值。如果old_pis是没有None的话,则复制episodes长度的[None]并合并起来,实际就是一批任务的任务数。将episodes和old_pis里面的每一项进行解绑操作,得到训练回合信息、泛化回合信息和old_pi数值。对训练回合信息求导,得到新的参数。设置一个策略pi,如果old_pis是没有None的话,解耦合分布策略pi(这个不太明白)。获得泛化回合信息的掩码数据,如果泛化回合信息的动作数据大于2,那么就挤掉。最后通过分维度分权重均值计算新策略和老策略的KL散度,权重就是上面的掩码。最后将KL散度加到kls列表中。
		kls = []
		if old_pis is None:
			old_pis = [None] * len(episodes)

		for (train_episodes, valid_episodes), old_pi in zip(episodes, old_pis):
			params = self.adapt(train_episodes)
			pi = self.policy(valid_episodes.observations, params=params)

			if old_pi is None:
				old_pi = detach_distribution(pi)

			mask = valid_episodes.mask
			if valid_episodes.actions.dim() > 2:
				mask = mask.unsqueeze(2)
			kl = weighted_mean(kl_divergence(pi, old_pi), weights=mask)
			kls.append(kl)

		return torch.mean(torch.stack(kls, dim=0))

    #### Hessian Vector Product这个比较常用,通常用于神经网络求二阶梯度和某个向量的乘积。这里函数里面内置了一个函数,而这个内置函数才是主要的部分,然后在这个主函数里面返回的是这个小函数的入口。
	def hessian_vector_product(self, episodes, damping=1e-2):
		"""
		Hessian-vector product, based on the Perlmutter method.
		"""

        #### 内置了一个函数,用于求乘积。先求出对每个episode的KL散度,最后将KL散度数值对策略参数求一阶导数。parameters_to_vector()是torch库内部的函数,表示将求导得到的参数转变成一个向量,但是源码表示就是一个列表数据结构。grad_kl_v是转变成向量的参数和vector变量的乘积。再对grad_kl_v做一次求导操作,并转变成向量化的参数。最后得到的结果就是hessian_vector_product在加上一个很小的原来的向量的倍数,避免异常。
		def _product(vector):
			kl = self.kl_divergence(episodes)
			grads = torch.autograd.grad(kl, self.policy.parameters(),
			                            create_graph=True)
			flat_grad_kl = parameters_to_vector(grads)

			grad_kl_v = torch.dot(flat_grad_kl, vector)
			grad2s = torch.autograd.grad(grad_kl_v, self.policy.parameters())
			flat_grad2_kl = parameters_to_vector(grad2s)

			return flat_grad2_kl + damping * vector

		return _product

    #### 计算一批数据的所有的损失。
	def surrogate_loss(self, episodes, old_pis=None):
        
        #### 先用空列表初始化损失losses、KL散度kls和策略pis。如果原本的策略没有,也就是old_pis是None,那么就初始化老策略为episodes长度的空列表。
		losses, kls, pis = [], [], []
		if old_pis is None:
			old_pis = [None] * len(episodes)

        #### 对每一对episodes和old_pis解压缩,得到更新前的数据、更新后的数据和原本的策略。
		for (train_episodes, valid_episodes), old_pi in zip(episodes, old_pis):
            
            #### 用更新前的数据train_episodes做一阶求导更新,得到新的参数。
			params = self.adapt(train_episodes)

            #### 这个代码的意思是,如果老策略是不存在的(old_pi is None)那么就启动求导功能。以解压后的数据的观测信息和预设的参数作为策略,然后解耦合策略加入到pis中。
			with torch.set_grad_enabled(old_pi is None):
				pi = self.policy(valid_episodes.observations, params=params)
				pis.append(detach_distribution(pi))

                #### 解耦合策略。
				if old_pi is None:
					old_pi = detach_distribution(pi)

                #### 先通过人工特征提取的方法获得values价值,然后计算出advantages优势并进行归一化。
				values = self.baseline(valid_episodes)
				advantages = valid_episodes.gae(values, tau=self.tau)
				advantages = weighted_normalize(advantages,
				                                weights=valid_episodes.mask)

                #### 计算更新后策略的动作分布和原本策略的动作分布之差,当结果的维度大于2的时候,对第二个维度求和,也就是消去第二个为维度,然后通过指数化方法获得ratio变量。
				log_ratio = (pi.log_prob(valid_episodes.actions)
				             - old_pi.log_prob(valid_episodes.actions))
				if log_ratio.dim() > 2:
					log_ratio = torch.sum(log_ratio, dim=2)
				ratio = torch.exp(log_ratio)

                #### 对ratio乘以优势advantages的数据,然后用更新后数据的掩码权重做分维度分权重的负加权均值。最后再加入到losses列表中。将更新后数据的掩码权重赋值给mask上,并挤掉多余的维度。最后用这个mask权重和KL散度计算分维度分权重的均值,最后把计算得到的KL散度加到kls列表中。最后返回的是堆积后损失的均值,和KL散度的均值。
				loss = -weighted_mean(ratio * advantages,
				                      weights=valid_episodes.mask)
				losses.append(loss)

				mask = valid_episodes.mask
				if valid_episodes.actions.dim() > 2:
					mask = mask.unsqueeze(2)
				kl = weighted_mean(kl_divergence(pi, old_pi), weights=mask)
				kls.append(kl)

		return (torch.mean(torch.stack(losses, dim=0)), torch.mean(torch.stack(kls, dim=0)), pis)

	def step(self, episodes, max_kl=1e-3, cg_iters=10, cg_damping=1e-2, ls_max_steps=10, ls_backtrack_ratio=0.5):
        
        #### 用TRPO更新元最优化参数。
		"""
		Meta-optimization step (ie. update of the initial parameters), based
		on Trust Region Policy Optimization (TRPO, [4]).
		"""
        
        #### 先将上一个函数得到的老的损失和老的策略赋值给这个函数的old_loss和old_pis中。对老策略做自动一阶求导。再做一个二阶求导。
		old_loss, _, old_pis = self.surrogate_loss(episodes)
		grads = torch.autograd.grad(old_loss, self.policy.parameters())
		grads = parameters_to_vector(grads)

        #### 用共轭梯度方法获得步长方向。先通过hessian_vector_product得到一个正定矩阵乘以一个向量的结果,然后用共额梯度方法得到步长的方向,n维度空间就几个方向,所以是一个列表。
		# Compute the step direction with Conjugate Gradient
		# return a function
		hessian_vector_product = self.hessian_vector_product(episodes, damping=cg_damping)
		stepdir = conjugate_gradient(hessian_vector_product, grads, cg_iters=cg_iters)

        #### 计算拉格朗日乘子,用步长方向乘以一个正定矩阵和自己连乘,得到的shs再除以最大KL散度值得到拉格朗日乘子。最后将步长方向处以拉格朗日乘子得到更新步。
		# Compute the Lagrange multiplier
		shs = 0.5 * torch.dot(stepdir, hessian_vector_product(stepdir))
		lagrange_multiplier = torch.sqrt(shs / max_kl)
		step = stepdir / lagrange_multiplier

        #### 保存老的参数到old_params中。
		# Save the old parameters
		old_params = parameters_to_vector(self.policy.parameters())

        #### 做直线搜索,步长大小是1.0。在最大直线搜索迭代里面,首先将老参数减去更新量并依次赋值给self.policy.parameters()方法,即用后者承接前面的更新结果。然后用上面self.surrogate_loss()方法计算损失和KL散度。接着计算提升量improve。最后调整步长的大小。
		# Line search
		step_size = 1.0
		for _ in range(ls_max_steps):
			vector_to_parameters(old_params - step_size * step, self.policy.parameters())
			loss, kl, _ = self.surrogate_loss(episodes, old_pis=old_pis)
			improve = loss - old_loss
            
            #### 如果改进量出现负值了,且KL散度小于最大KL散度数值,那么就说明两次迭代很接近了,退出。
			if (improve.item() < 0.0) and (kl.item() < max_kl):
				break
			step_size *= ls_backtrack_ratio
            
        #### 当for语句正常遍历了容器中的所有元素后,将会执行else对应的语句;如果for语句被break语句强行结束后,则不执行else对应的语句。
		else:
			vector_to_parameters(old_params, self.policy.parameters())

    #### 将策略、基线baseline的数据和设备信息转变到'cpu'/'gpu'上面。
	def to(self, device, **kwargs):
		self.policy.to(device, **kwargs)
		self.baseline.to(device, **kwargs)
		self.device = device

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

MAML-RL Pytorch 代码解读 (16) -- maml_rl/metalearner.py 的相关文章

  • PyTorch 中的截断反向传播(代码检查)

    我正在尝试在 PyTorch 中实现随时间截断的反向传播 对于以下简单情况K1 K2 我下面有一个实现可以产生合理的输出 但我只是想确保它是正确的 当我在网上查找 TBTT 的 PyTorch 示例时 它们在分离隐藏状态 将梯度归零以及这些
  • max_length、填充和截断参数在 HuggingFace 的 BertTokenizerFast.from_pretrained('bert-base-uncased') 中如何工作?

    我正在处理文本分类问题 我想使用 BERT 模型作为基础 然后使用密集层 我想知道这 3 个参数是如何工作的 例如 如果我有 3 个句子 My name is slim shade and I am an aspiring AI Engin
  • 推导 pytorch 网络的结构

    对于我的用例 我需要能够采用 pytorch 模块并解释模块中的层序列 以便我可以以某种文件格式在层之间创建 连接 现在假设我有一个简单的模块 如下所示 class mymodel nn Module def init self input
  • Win10 64位上CUDA 12的PyTorch安装

    我需要在我的 PC 上安装 PyTorch 其 CUDA 版本 12 0 pytorch 2 的表 https i stack imgur com X13oS png in In 火炬网站 https pytorch org get sta
  • 无法使用 torch.Tensor 创建张量

    我试图创建一个张量 如下所示 import torch t torch tensor 2 3 我收到以下错误 类型错误回溯 最近调用 最后 在 gt 1 a torch tensor 2 3 类型错误 tensor 需要 1 个位置参数 但
  • Cuda和pytorch内存使用情况

    我在用Cuda and Pytorch 1 4 0 当我尝试增加batch size 我遇到以下错误 CUDA out of memory Tried to allocate 20 00 MiB GPU 0 4 00 GiB total c
  • 如何使用 torch.stack?

    我该如何使用torch stack将两个张量与形状堆叠a shape 2 3 4 and b shape 2 3 没有就地操作 堆叠需要相同数量的维度 一种方法是松开并堆叠 例如 a size 2 3 4 b size 2 3 b torc
  • pytorch通过易失性变量反向传播错误

    我试图通过多次向后传递迭代来运行它并在每个步骤更新输入 从而最小化相对于某个目标的一些输入 第一遍运行成功 但在第二遍时出现以下错误 RuntimeError element 0 of variables tuple is volatile
  • 二维数组的按行 numpy.isin [重复]

    这个问题在这里已经有答案了 我有两个数组 A np array 3 1 4 1 1 4 B np array 0 1 5 2 4 5 2 3 5 是否可以使用numpy isin二维数组按行排列 我想检查一下是否A i j is in B
  • 通过 Conda 安装 PyTorch

    目标 使用 pytorch 和 torchvision 创建 conda 环境 Anaconda 导航器 1 8 3 python 3 6 MacOS 10 13 4 我尝试过的 在Navigator中 创建了一个新环境 尝试安装 pyto
  • RuntimeError:维度指定为 0 但张量没有维度

    我试图使用 MNIST 数据集实现简单的 NN 但我不断收到此错误 将 matplotlib pyplot 导入为 plt import torch from torchvision import models from torchvisi
  • 如何在 google colab 中运行 matlab .m 文件

    我目前正在尝试运行这个存储库https github com Fanziapril mvfnet https github com Fanziapril mvfnet这需要一个步骤 Run the Matlab ModelGeneratio
  • Model() 获得参数“nr_class”的多个值 - SpaCy 多分类模型(BERT 集成)

    您好 我正在致力于使用新的 SpaCy 模型实现多分类模型 5 类 en pytt bertbaseuncased lg 新管道的代码在这里 nlp spacy load en pytt bertbaseuncased lg textcat
  • PyTorch 教程错误训练分类器

    我刚刚开始 PyTorch 教程使用 PyTorch 进行深度学习 60 分钟闪电战我应该补充一点 我之前没有编写过任何 python 但其他语言 如 Java 现在 我的代码看起来像 import torch import torchvi
  • 下载变压器模型以供离线使用

    我有一个训练有素的 Transformer NER 模型 我想在未连接到互联网的机器上使用它 加载此类模型时 当前会将缓存文件下载到 cache 文件夹 要离线加载并运行模型 需要将 cache 文件夹中的文件复制到离线机器上 然而 这些文
  • 如何计算 CNN 第一个线性层的维度

    目前 我正在使用 CNN 其中附加了一个完全连接的层 并且我正在使用尺寸为 32x32 的 3 通道图像 我想知道是否有一个一致的公式可以用来计算第一个线性层的输入尺寸和最后一个卷积 最大池层的输入 我希望能够计算第一个线性层的尺寸 仅给出
  • pytorch 的 IDE 自动完成

    我正在使用 Visual Studio 代码 最近尝试了风筝 这两者似乎都没有 pytorch 的自动完成功能 这些工具可以吗 如果没有 有人可以推荐一个可以的编辑器吗 谢谢你 使用Pycharmhttps www jetbrains co
  • 预期设备类型为 cuda 的对象,但在 Pytorch 中获得了设备类型 cpu

    我有以下计算损失函数的代码 class MSE loss nn Module metric L1 L2 norms or cosine similarity mode training or evaluation mode def init
  • 如何计算cifar10数据的平均值和标准差

    Pytorch 使用以下值作为 cifar10 数据的平均值和标准差 变换 Normalize 0 5 0 5 0 5 0 5 0 5 0 5 我需要理解计算背后的概念 因为这些数据是 3 通道图像 我不明白什么是相加的 什么是除什么的等等
  • 将 Pytorch LSTM 的状态参数转换为 Keras LSTM

    我试图将现有的经过训练的 PyTorch 模型移植到 Keras 中 在移植过程中 我陷入了LSTM层 LSTM 网络的 Keras 实现似乎具有三种状态类型的状态矩阵 而 Pytorch 实现则具有四种状态矩阵 例如 对于hidden l

随机推荐

  • 系统架构设计师论文范文

    论混合软件架构的设计 摘要 xff1a 2007年3月 xff0c 我所在的公司组织开发了一套完整的变电综合信息管理系统 xff0c 在这个项目中 xff0c 我担任系统架构设计师职务 xff0c 主要负责软件架构和网络安全体系架构设计的工
  • 计算机网络

    文章目录 隐藏 七层模型网络技术校准与协议拓扑结构网络规划与设计无线网网络接入技术网络存储技术磁盘阵列 RAID IPv6物联网云计算 七层模型 网络技术校准与协议 TCP与UDP UDP 是无连接的 xff0c TCP 是面向连接的 xf
  • linux/fs/inode.c/_bmap() and bmap()

    bmap函数的实体 用来实现文件数据块号到设备中的逻辑块号的映射 inode是文件i节点指针 xff0c block是要操作的文件数据块号 xff0c creat为创建标志 有0和1两种情况 若create为0 xff08 不置位 xff0
  • 鸿蒙OS

    文章目录 隐藏 初识鸿蒙鸿蒙开发鸿蒙的官方定义鸿蒙OS的特点鸿蒙与安卓的对比发展前景 初识鸿蒙 移动通讯技术的发展 1G xff1a 大哥大 xff0c 只能打电话 xff0c 无操作系统2G xff1a 摩托罗拉 诺基亚 xff0c 塞班
  • SpringBoot安全管理(一)

    文章目录 隐藏 SpringSecurity基本环境开启安全管理运行测试自定义用户认证源码下载 SpringSecurity Spring Security的安全管理有两个重要概念 xff0c 分别是Authentication 认证 和A
  • 系统安全分析与设计(二)

    文章目录 隐藏 各个网络层次的安全保障网络威胁与攻击防火墙 各个网络层次的安全保障 网络威胁与攻击 重放攻击 ARP 所截获的某次合法的通信数据拷贝 xff0c 出于非法的目的而被重新发送 拒绝服务 DOS 对信息或其它资源的合法访问被无条
  • 宾馆客房管理系统

    内容简介 本项目为一个宾馆客房管理系统 xff0c 用户分为两类 xff1a 系统管理员 xff1a 可以查看统计信息可以对员工进行管理 宾馆管理员 xff1a 可以查看房间信息 xff0c 管理房间可以进行业务管理 xff1a 订房退房等
  • 第十三届蓝桥杯(Web 应用开发)线上模拟赛第一题

    Bug 调试 修复网站显示问题 特别说明 第十三届蓝桥杯 xff08 Web 应用开发 xff09 线上模拟赛依托于蓝桥云课线上实验环境打造 xff0c 可能与正式比赛所使用线下环境有所不同 线上模拟赛侧重于考生了解比赛题型和体验比赛样题
  • 吃苹果的最大数目

    题目 xff1a 吃苹果的最大数目 Java代码 span class token keyword public span span class token keyword class span span class token class
  • 奇偶树:二叉树的层次遍历

    题目描述 考查 xff1a 二叉树的层次遍历 span class token keyword package span span class token namespace year2021 span class token punctu
  • Bigram 分词

    题目描述 span class token keyword public span span class token keyword class span span class token class name Solution span
  • npm 安装

    npm xff0c Node Package Manager xff0c 前端的包管理工具 Node js 内置 npm xff0c 因此要想安装 npm xff0c 直接安装 Node js 即可 下载解压 span class toke
  • CSS的使用

    目录 1 CSS基本语法 2 CSS类型 2 1 行内样式 xff08 适用范围最小 xff09 2 2 内部样式 xff08 适用范围适中 xff09 2 3 外部样式 xff08 适用范围最大 xff09 3 多种样式优先级 4 选择器
  • ubuntu shell 命令一点一点学

    这篇专门用来记录ubuntu命令 不求全面 xff0c 记录的都是自己不太熟悉的 xff0c 方便查阅而已 1 用户管理类 1 1 获取root用户密码 ubuntu安装时默认是没有设置root用户的密码的 xff0c 装好后在普通用户下可
  • <JavaScript>代码实现学生信息录入,实现增.删.改功能.

    目录 一 创建页面基本样式 二 实现添加功能 对添加按钮绑定点击后 将输入的信息渲染到页面表格 三 实现删除功能 仍然处于 34 添加 34 按钮绑定点击的函数中 四 实现修改功能 仍然处于 34 添加 34 按钮绑定点击的函数中 1 判断
  • CNI插件之bridge plugin

    CNI网络插件bridge plugin CNI网络插件bridge pluginBridge插件概念Bridge功能使用准备Kubernetes环境安装配置bridge插件安装ningx容器验证使用cnitool验证 Bridge工作原理
  • CSS基础之高度塌陷的三种解决方案

    项目场景 xff1a 相信很多小伙伴初学浮动 xff0c 在页面布局的时候可能会出现这种现象 xff0c 父元素身上没有设置高度 xff0c 想让子元素撑起父元素 xff0c 而给子元素添加浮动属性之后 xff0c 父元素的高度为0的情况
  • 正常12864模块,文字乱码问题及其解决方式

    正常12864模块 xff0c 文字乱码问题及其解决方式 先确定代码的正确性如是否有初始化函数 xff0c 是否按照了时序图去编写了代码 输出函数是否正确 如果以上没问题 xff0c 那应该就是下面这种情况了 文字的乱码问题确实和选的首地址
  • 【2021最新版】JavaOOP面试题总结(99道题含答案解析)

    文章目录 1 什么是B S架构 xff1f 什么是C S架构2 Java都有那些开发平台 xff1f 3 什么是JDK xff1f 什么是JRE 4 Java语言有哪些特点5 面向对象和面向过程的区别6 什么是数据结构 xff1f 7 Ja
  • MAML-RL Pytorch 代码解读 (16) -- maml_rl/metalearner.py

    MAML RL Pytorch 代码解读 16 maml rl metalearner py 文章目录 MAML RL Pytorch 代码解读 16 maml rl metalearner py基本介绍源码链接文件路径 96 import