【机器学习】强化学习(七)-策略梯度算法-REINFORCE 训练月球着陆器代理(智能体)...

news2024/10/7 8:23:24

285549acae05b06087097365527d8796.png

概 述

月球着陆器代理是一个模拟飞行器在月球表面着陆的环境,它有八个连续的状态变量,分别是水平坐标、垂直坐标、水平速度、垂直速度、角度、角速度、腿1触地、腿2触地。它有四个离散的动作,分别是什么都不做、发动左方向引擎、发动主引擎、发动右方向引擎。

训练月球着陆器代理的目标是使飞行器能够安全地降落在两个黄色旗帜之间的停机坪上,最小化燃料消耗和着陆时间。为了实现这个目标,我们可以用策略梯度算法来训练一个神经网络,使其输出在每个状态下执行每个动作的概率。我们可以用蒙特卡罗方法来估计每个状态-动作对的回报,即从该状态-动作对开始,按照当前策略执行到终止状态的累积折扣回报。然后,我们可以用这个回报来更新神经网络的参数,使其更倾向于选择高回报的动作,从而改进策略。

e2dc60734a92d6596816c0fb4cae7f58.png

8e08c52722b854876e0f8443c4b935c2.png

228d8c37f3bef911b43ff1a063297656.png

示例代码

这是一个使用 PyTorch 和 OpenAI Gym 的强化学习项目,目的是训练一个智能体在月球着陆器环境中完成任务。

policy_network.py 一个使用策略梯度算法的强化学习的示例,它定义了一个策略网络(PolicyNetwork)和一个智能体(Agent)的类,以及它们的相关方法.

7f99566314f541893619b3ada1795f9c.png

import torch  # 导入 PyTorch 库,用于张量运算和自动求导
import torch.nn as nn  # 导入 PyTorch 的神经网络模块,用于定义网络层和模型
import torch.optim as optim  # 导入 PyTorch 的优化器模块,用于更新模型参数
import torch.nn.functional as F  # 导入 PyTorch 的函数模块,用于激活函数和损失函数等




class PolicyNetwork(nn.Module):  # 定义一个策略网络类,继承自 nn.Module 基类
    def __init__(self, n_features, n_actions, lr):  # 定义初始化方法,接受三个参数:状态特征数,动作数,学习率
        super(PolicyNetwork, self).__init__()  # 调用父类的初始化方法


        self.layers = nn.Sequential(  # 定义一个顺序容器,包含三个全连接层和两个 ReLU 激活函数
            nn.Linear(n_features, 128),  # 第一个全连接层,输入特征数为 n_features,输出特征数为 128
            nn.ReLU(),  # 第一个 ReLU 激活函数,对上一层的输出进行非线性变换
            nn.Linear(128, 128),  # 第二个全连接层,输入和输出特征数都为 128
            nn.ReLU(),  # 第二个 ReLU 激活函数,对上一层的输出进行非线性变换
            nn.Linear(128, 256),  # 第三个全连接层,输入特征数为 128,输出特征数为 256
            nn.ReLU(),  # 第三个 ReLU 激活函数,对上一层的输出进行非线性变换
        )
        # 定义一个全连接层,输入特征数为 256,输出特征数为 n_actions,用于输出每个动作的对数值
        self.pi = nn.Linear(256, n_actions)


        if lr is not None:  # 如果学习率不为空,说明是训练模式
            # 定义一个优化器,使用 Adam 算法,传入模型的所有参数和学习率
            self.optimizer = optim.Adam(self.parameters(), lr=lr)
        self.device = "cuda" if torch.cuda.is_available(
        ) else "cpu"  # 判断是否有 GPU 可用,如果有则使用 GPU,否则使用 CPU
        self.to(self.device)  # 将模型移动到相应的设备上


    def forward(self, state: torch.Tensor):  # 定义前向传播方法,接受一个参数:状态张量
        features = self.layers(state)  # 将状态张量输入到顺序容器中,得到特征张量
        # log value for each action
        action_logs = self.pi(features)  # 将特征张量输入到全连接层中,得到每个动作的对数值张量


        # calculate the probability of logs
        # 对每个动作的对数值进行 softmax 变换,得到每个动作的概率张量,并返回
        return F.softmax(action_logs, dim=0)




class Agent:  # 定义一个智能体类
    def __init__(self, observation_space, action_space, lr):  # 定义初始化方法,接受三个参数:观察空间大小,动作空间大小,学习率
        self.policy = PolicyNetwork(  # 创建一个策略网络对象,传入观察空间大小,动作空间大小,学习率
            n_features=observation_space, n_actions=action_space, lr=lr
        )
        self.rewards = []  # 定义一个空列表,用于存储每个时间步的奖励
        self.action_probs = []  # 定义一个空列表,用于存储每个时间步的动作概率
        self.lr = lr  # 将学习率赋值给 self.lr,用于判断是否是训练模式


        self.gamma = 0.99  # 定义一个折扣因子,用于计算累积奖励


    def choose_action(self, state):  # 定义一个选择动作的方法,接受一个参数:状态
        state = torch.tensor(state).to(
            self.policy.device)  # 将状态转换为张量,并移动到相应的设备上


        log_probs = self.policy(state)  # 将状态张量输入到策略网络中,得到每个动作的概率张量
        action_dist = torch.distributions.Categorical(
            log_probs)  # 根据概率张量创建一个分类分布对象,用于采样动作
        action = action_dist.sample()  # 从分类分布中采样一个动作


        # no calculations required during testing.
        if self.lr is not None:  # 如果学习率不为空,说明是训练模式
            action_probs: int = action_dist.log_prob(
                action).unsqueeze(0)  # 计算采样动作的对数概率,并增加一个维度
            self.action_probs.append(action_probs)  # 将动作的对数概率添加到列表中


        return action.item()  # 返回动作的数值


    def learn(self):  # 定义一个学习的方法,用于更新策略网络的参数
        G = 0  # 定义一个变量,用于存储累积奖励
        returns = []  # 定义一个空列表,用于存储每个时间步的累积奖励


        for reward in reversed(self.rewards):  # 从后向前遍历奖励列表
            G = self.gamma * G + reward  # 计算当前时间步的累积奖励,使用折扣因子和当前奖励
            returns.append(G)  # 将累积奖励添加到列表中


        returns.reverse()  # 将累积奖励列表反转,使其与时间步对应
        # 将累积奖励列表转换为张量,并移动到相应的设备上
        returns = torch.tensor(returns, dtype=torch.float,
                               device=self.policy.device)


        action_probs = torch.cat(self.action_probs)  # 将动作概率列表拼接为一个张量


        # loss = G * log pi (at | st)
        # -loss: since gradient ascent is being performed
        loss = -(returns * action_probs).sum()  # 计算损失函数,使用累积奖励和动作概率的乘积的负和


        self.policy.optimizer.zero_grad()  # 将优化器的梯度清零
        loss.backward()  # 对损失函数进行反向传播,计算梯度
        self.policy.optimizer.step()  # 对优化器进行一步更新,更新模型参数


        self.action_probs = []  # 清空动作概率列表
        self.rewards = []  # 清空奖励列表


        return loss  # 返回损失值

play.py 使用策略梯度算法来训练月球着陆器智能体的Python脚本

  • 代码首先导入了一些必要的库,如 numpy, gym, torch, tqdm 等,并从 policy_network 模块中导入了 Agent 类,该类定义了智能体的策略网络和学习算法。

  • 代码使用 argparse 库来解析命令行参数,如 epochs, lr, logdir, env, chkpt 等,这些参数可以用来控制训练的过程和结果。

  • 代码使用 SummaryWriter 来记录训练的指标,如损失和奖励,并将它们保存在 log_dir 中,方便用 TensorBoard 可视化。

  • 代码使用 gym.make() 来创建一个月球着陆器的环境,并使用 agent 对象来与环境交互,选择动作,获取奖励,更新网络参数等。

  • 代码使用 tqdm 来显示训练的进度条,以及每个回合的奖励,平均奖励和平均损失等信息。

  • 代码使用 torch.save() 来保存智能体的策略网络的状态,以便在之后加载或继续训练。

  • 代码最后使用 writer.close() 和 env.close() 来关闭 SummaryWriter 和环境对象。

# 导入numpy库,用于进行数值计算
import numpy as np
# 导入gymnasium库,用于创建和管理强化学习的环境
import gymnasium as gym
# 导入SummaryWriter类,用于记录和可视化训练过程的数据
from torch.utils.tensorboard import SummaryWriter
# 导入save函数,并重命名为torch_save,用于保存和加载模型的参数
from torch import save as torch_save
# 导入Agent类,用于定义和实现策略梯度算法的智能体
from policy_network import Agent
# 导入tqdm类,用于显示训练过程的进度条
from tqdm import tqdm
# 导入ArgumentParser类,用于解析命令行参数
from argparse import ArgumentParser
# 导入os库,用于进行文件和路径的操作
import os


# 如果当前文件是主程序,那么执行以下代码
if __name__ == "__main__":
    # 创建一个ArgumentParser对象,用于解析命令行参数
    parser = ArgumentParser()
    # 添加一个名为--epochs的参数,表示要玩的游戏的次数,默认为20000,类型为整数
    parser.add_argument(
        "--epochs", default=20_000, type=int, help="Number of games to play"
    )
    # 添加一个名为--lr的参数,表示策略网络的学习率,默认为0.0005,类型为浮点数
    parser.add_argument(
        "--lr", default=0.0005, help="Learning rate for NN Policy Network", type=float
    )
    # 添加一个名为--logdir的参数,表示记录和可视化数据的目录,默认为./plays,类型为字符串
    parser.add_argument("--logdir", default="./plays", type=str)
    # 添加一个名为--env的参数,表示要玩的游戏的环境,默认为LunarLander-v2,类型为字符串
    parser.add_argument("--env", default="LunarLander-v2", type=str)
    # 添加一个名为--chkpt的参数,表示保存和加载模型参数的文件地址,默认为./agent,类型为字符串
    parser.add_argument(
        "--chkpt",
        default="./agent",
        help="Save/Load checkpoint file address for model",
        type=str,
    )
    # 解析命令行参数,并赋值给args变量
    args = parser.parse_args()


    # 根据args.logdir和args.env拼接出完整的记录和可视化数据的目录,并赋值给log_dir变量
    log_dir = os.path.join(args.logdir, args.env)
    # 根据args.chkpt和args.env拼接出完整的保存和加载模型参数的文件地址,并赋值给chkpt变量
    chkpt = os.path.join(args.chkpt, f"{args.env}.pt")


    # 创建一个SummaryWriter对象,用于记录和可视化数据,指定log_dir为记录和可视化数据的目录
    writer = SummaryWriter(log_dir=log_dir)
    # 调用gym库的make函数,根据args.env创建一个强化学习的环境,并赋值给env变量
    env = gym.make(args.env)


    # 创建一个Agent对象,用于实现策略梯度算法,指定环境的状态空间维度,动作空间数量,和学习率,并赋值给agent变量
    agent = Agent(env.observation_space.shape[0], env.action_space.n, lr=args.lr)


    # 打印运行时的细节,包括游戏的环境,次数,记录和可视化数据的目录,和保存和加载模型参数的文件地址
    print("RunTime Details: ")
    print(f"   > Playing - {args.env} for {args.epochs} episodes")
    print(f"   > TensorBoard Logdir - {log_dir} Checkpoint File - {chkpt}")


    # 创建一个tqdm对象,用于显示训练过程的进度条,指定总数为args.epochs,描述为Playing episode
    progress_bar = tqdm(total=args.epochs, desc="Playing episode")
    # 创建一个numpy数组,用于存储每个游戏的奖励,形状为(args.epochs, 1),并赋值给episode_rewards变量
    episode_rewards = np.zeros((args.epochs, 1))
    # 创建一个numpy数组,用于存储每个游戏的损失,形状为(args.epochs, 1),并赋值给episode_losses变量
    episode_losses = np.zeros((args.epochs, 1))
    # 对于每个游戏,执行以下代码
    for epoch in range(args.epochs):
        # 初始化一个布尔变量done为False,表示游戏是否结束
        done = False
        # 调用环境的reset方法,重置环境,并返回初始的状态和信息,并赋值给obs和info变量
        obs, info = env.reset()


        # 当游戏没有结束时,执行以下代码
        while not done:
            # 调用智能体的choose_action方法,根据当前的状态选择一个动作,并赋值给action变量
            action = agent.choose_action(obs)
            # 调用环境的step方法,执行选择的动作,并返回新的状态,奖励,是否截断,是否终止,和信息,并赋值给obs, reward, truncated, terminated, info变量
            obs, reward, truncated, terminated, info = env.step(action)
            # 判断是否终止或截断,如果是,那么将done变量设为True,表示游戏结束
            done = terminated or truncated


            # 将奖励添加到智能体的rewards列表中
            agent.rewards.append(reward)


        # 计算智能体的rewards列表中的奖励之和,并赋值给episode_rewards数组的对应位置
        episode_rewards[epoch] = sum(agent.rewards)
        # 调用智能体的learn方法,根据累积奖励和动作概率更新策略网络的参数,并返回损失,并赋值给loss变量
        loss = agent.learn()
        # 将损失转换为cpu上的numpy数组,并赋值给episode_losses数组的对应位置
        episode_losses[epoch] = loss.cpu().detach().numpy()


        # 如果游戏的次数大于100,那么执行以下代码
        if epoch > 100:
            # 调用SummaryWriter对象的add_scalar方法,记录并可视化最近100个游戏的损失和奖励的均值,以及当前游戏的奖励,指定标签和步数
            writer.add_scalar(
                "Play/mean_loss", episode_losses[epoch - 100 : epoch].mean(), epoch
            )
            writer.add_scalar(
                "Play/mean_rewards", episode_rewards[epoch - 100 : epoch].mean(), epoch
            )
            writer.add_scalar("Play/episode_rewards", episode_rewards[epoch], epoch)
            # 调用SummaryWriter对象的flush方法,将数据写入文件
            writer.flush()


            # 调用tqdm对象的set_postfix_str方法,设置进度条的后缀字符串,包括当前游戏的奖励,最近100个游戏的奖励和损失的均值
            progress_bar.set_postfix_str(
                f"episode_reward - {float(episode_rewards[epoch][0]):.2f} "
                f"mean_rewards - {float(episode_rewards[epoch-100: epoch].mean()):.2f} "
                f"mean_loss - {float(episode_losses[epoch-100: epoch].mean()):.2f}"
            )


        # 调用torch_save函数,保存策略网络的参数到chkpt文件
        torch_save(agent.policy.state_dict(), chkpt)


        # 调用tqdm对象的update方法,更新进度条
        progress_bar.update(1)


    # 调用SummaryWriter对象的close方法,关闭文件
    writer.close()
    # 调用环境的close方法,关闭环境
    env.close()

终端输出:

RunTime Details:   > Playing - LunarLander-v2 for 20000 episodes
   > TensorBoard Logdir - ./plays\LunarLander-v2 Checkpoint File - ./agent\LunarLander-v2.pt
Playing episode:   1%|▏            | 208/20000 [00:26<51:43,  6.38it/s, episode_reward - -106.63 mean_rewards - -179.48 mean_loss - -12856.09]

play_test.py 这段代码的目的是让一个智能体(agent)在一个仿真环境(env)中玩一个叫做 LunarLander-v2 的游戏,并将游戏过程录制成视频。

这段代码的主要逻辑如下:

067a8e6032a16e87ac04e80f40dc1118.png

# 导入time库,用于获取和处理时间
import time
# 导入gymnasium库,用于创建和管理强化学习的环境
import gymnasium as gym
# 导入imageio库,用于读写图像和视频
import imageio
# 导入Agent类,用于定义和实现策略梯度算法的智能体
from policy_network import Agent
# 导入load函数,并重命名为torch_load,用于加载模型的参数
from torch import load as torch_load
# 导入ArgumentParser类,用于解析命令行参数
from argparse import ArgumentParser
# 导入os库,用于进行文件和路径的操作
import os


# 导入VideoRecorder类,用于录制视频
from gymnasium.wrappers.monitoring.video_recorder import VideoRecorder


# 如果当前文件是主程序,那么执行以下代码
if __name__ == "__main__":
    # 创建一个ArgumentParser对象,用于解析命令行参数
    parser = ArgumentParser()
    # 添加一个名为--env的参数,表示要玩的游戏的环境,默认为LunarLander-v2,类型为字符串
    parser.add_argument("--env", default="LunarLander-v2", type=str)
    # 添加一个名为--chkpt的参数,表示保存和加载模型参数的文件地址,默认为./agent,类型为字符串
    parser.add_argument(
        "--chkpt",
        default="./agent/",
        help="Save/Load checkpoint file address for model",
        type=str,
    )
    # 添加一个名为--render_mode的参数,表示环境的渲染模式,默认为rgb_array,类型为字符串
    parser.add_argument(
        "--render_mode", default="rgb_array", help="Render Mode for Env", type=str
    )  # human  rgb_array
    # 解析命令行参数,并赋值给args变量
    args = parser.parse_args()
    # 根据args.chkpt和args.env拼接出完整的保存和加载模型参数的文件地址,并赋值给chkpt变量
    chkpt = os.path.join(args.chkpt, f"{args.env}.pt")


    # 调用gym库的make函数,根据args.env和args.render_mode创建一个强化学习的环境,并赋值给env变量
    env = gym.make(args.env, render_mode=args.render_mode)
    # 使用 time 模块获取时间戳
    timestamp = time.time()
    # 使用 time 模块将时间戳转换为字符串
    time_str = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime(timestamp))
    # 在文件名前添加时间字符串,并赋值给new_filename变量
    new_filename = time_str + "_" + "LunarLander-v2.mp4"  
    # 创建一个 VideoRecorder 对象,指定视频文件名为new_filename,并赋值给video变量
    video = VideoRecorder(env, new_filename)
    # 创建一个Agent对象,用于实现策略梯度算法,指定环境的状态空间维度,动作空间数量,和学习率,并赋值给agent变量
    agent = Agent(env.observation_space.shape[0], env.action_space.n, lr=None)
    # 调用torch_load函数,加载chkpt文件中的模型参数,并赋值给智能体的策略网络的状态字典
    agent.policy.load_state_dict(torch_load(chkpt))
    # 调用智能体的策略网络的eval方法,将其设置为评估模式,不进行梯度计算和参数更新
    agent.policy.eval()


    # 无限循环,直到用户输入非y的值
    while True:
        # 获取用户的输入,提示是否玩游戏,赋值给play_one变量
        play_one = input("Play game - [y/N] ")
        # 如果用户输入y,那么执行以下代码
        if play_one == "y":
            # 初始化一个布尔变量done为False,表示游戏是否结束
            done = False
            # 调用环境的reset方法,重置环境,并返回初始的状态和信息,并赋值给obs和info变量
            obs, info = env.reset()
            # 当游戏没有结束时,执行以下代码
            while not done:
                # 调用环境的render方法,渲染环境,获取当前帧的图像
                env.render()  
                # 调用VideoRecorder对象的capture_frame方法,捕捉当前帧,并将其写入视频文件
                video.capture_frame()  
                # 调用智能体的choose_action方法,根据当前的状态选择一个动作,并赋值给action变量
                action = agent.choose_action(obs)
                # 调用环境的step方法,执行选择的动作,并返回新的状态,奖励,是否截断,是否终止,和信息,并赋值给obs, reward, truncated, terminated, info变量
                obs, reward, truncated, terminated, info = env.step(action)
                # 判断是否终止或截断,如果是,那么将done变量设为True,表示游戏结束
                done = truncated or terminated
            # 调用VideoRecorder对象的close方法,关闭视频文件
            video.close()  
            # 调用环境的close方法,关闭环境
            env.close()  
            # 跳出循环
            break
        # 否则,跳出循环
        else:
            break

录制的四次游戏视频:

结 语

06ed2cfc73e41585cca3f2c26d1117d8.png

策略梯度算法是一类强化学习算法的统称,它们都是基于策略梯度定理来更新策略参数的。策略梯度算法有很多种,其中一些常见的有:

  • REINFORCE:这是一种基于蒙特卡洛方法的策略梯度算法,它使用整个轨迹的回报作为动作值函数的估计,然后根据策略梯度定理更新策略参数。

  • Actor-Critic:这是一种结合了值函数和策略函数的策略梯度算法,它使用一个**演员(Actor)网络来输出策略,一个评论者(Critic)**网络来输出动作值函数,然后根据策略梯度定理和值函数的梯度更新策略参数和值函数参数。

  • TRPO:这是一种基于自然梯度的策略梯度算法,它使用一个**信任域(Trust Region)**来限制策略的更新幅度,从而保证策略的改进不会过大,导致性能下降。

  • PPO:这是一种基于比例裁剪的策略梯度算法,它使用一个**目标函数(Objective Function)**来衡量策略的改进,然后通过裁剪策略比率来避免策略的更新过大或过小,从而提高策略的稳定性和效率。

这些只是策略梯度算法的一部分,还有很多其他的策略梯度算法,如A2CA3CDDPGTD3SAC等。如果您想了解更多关于策略梯度算法的内容,您可以参考以下的资源:

  • 一篇介绍策略梯度算法原理和实现的博客文章:https://zhuanlan.zhihu.com/p/21725498

  • 一本介绍强化学习和策略梯度算法的书籍:《强化学习:原理与Python实现》

  • 一份包含策略梯度算法的代码示例的GitHub仓库:https://github.com/ShangtongZhang/reinforcement-learning-an-introduction

The End

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

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

相关文章

情人节爆品出现!单周GMV暴涨6成,直冲20K美金,节庆用品赛道迎来“爆单潮”!

2024新年钟声已经敲响&#xff0c;一大波节日爆品正在疯狂涌现&#xff0c;而这只是一个开始。 开年首月电商流量一波接一波来袭&#xff0c;下一个“消费大节”已经在来的路上&#xff01;——情人节。 节日营销热点抢量&#xff0c;宜早不宜晚。商家们纷纷开始上新节庆相关…

【详解】贪吃蛇游戏----下篇(完整源码)

目录 引入&#xff1a; 本片文章目的&#xff1a; 整个游戏的实现流程图如下&#xff1a; 游戏实现 GameRun PrintHelpInfo Pause NextIsFood printSnake EatFood NoFood KillByWall KillBySelf GameRun GameEnd 总代码&#xff1a; &#xff08;1&#xff09…

【Linux】Linux权限的概念 -- 详解

一、Linux 中的用户 Linux 下有两种用户&#xff1a; 超级用户&#xff08;root&#xff09;&#xff1a;可以在 Linux 系统下做任何事情&#xff0c;不受限制。普通用户&#xff1a;在 Linux 下做有限的事情。 超级用户的命令提示符是 “#”&#xff0c;普通用户的命令提示符…

【算法专题】动态规划综合篇

动态规划7.0 1. 最长公共子序列2. 不相交的线3. 不同的子序列4. 通配符匹配5. 正则表达式匹配6. 交错字符串7. 两个字符串的最小ASCII删除和8. 最长重复子数组 1. 最长公共子序列 题目链接 -> Leetcode -1143.最长公共子序列 Leetcode -1143.最长公共子序列 题目&#xf…

操作系统论述题+第5、6、7、8、9章的知识小点总结(尤其是选择题)

文章目录 一、操作系统论述题怎么提高内存利用率&#xff1f;怎么提高CPU利用率&#xff1f;怎么提高操作系统并发度&#xff1f;这个答案也不知道是什么问题里面的 二、操作系统5、6、7、8、9章选择题知识点第五章&#xff1a;存储器管理第六章&#xff1a;虚拟存储器第七章&a…

【笔试常见编程题03】统计回文、连续最大和、不要二、把字符串转换成整数

1. 统计回文 “回文串”是一个正读和反读都一样的字符串&#xff0c;比如“level”或者“noon”等等就是回文串。花花非常喜欢这种拥有对称美的回文串&#xff0c;生日的时候她得到两个礼物分别是字符串A和字符串B。现在她非常好奇有没有办法将字符串B插入字符串A使产生的字符串…

如何通俗解释Docker是什么?

要想弄懂Docker&#xff0c;咱们得先从“容器化”讲起。 一、容器化技术及Docker的出现 容器化&#xff0c;它是一种轻量级、可移植的软件打包方式&#xff0c;你就想象成一个快递箱子&#xff0c;里面装着你的应用和所有需要运行的环境&#xff0c;这个箱子能在任何支持容器…

promethues基础概念

promethues是一个开源的系统监控以及报警系统&#xff0c;整个zabbix的功能&#xff0c;系统&#xff0c;网络&#xff0c;设备 promethues可以兼容网络和设置被&#xff0c;容器监控&#xff0c;告警系统&#xff0c;因为他和k8s是一个项目基金开发的产品&#xff0c;天生匹配…

【漏洞复现】中移铁通禹路由器信息泄露漏洞

Nx01 产品简介 中移禹路由器支持宽带拨号、动态IP和静态IP三种上网模式,一般中国移动宽带的光猫都是智能光猫也就是光猫带路由器功能,中移禹路由器作为二级路由使用。 Nx02 漏洞描述 中移禹路由器ExportSettings处存在信息泄露漏洞&#xff0c;攻击者可以获取后台权限。 Nx03…

【机器学习】欠拟合与过拟合

过拟合&#xff1a;模型在训练数据上表现良好对不可见数据的泛化能力差。 欠拟合&#xff1a;模型在训练数据和不可见数据上泛化能力都很差。 欠拟合常见解决办法&#xff1a; &#xff08;1&#xff09;增加新特征&#xff0c;可以考虑加入特征组合、高次特征&#xff0c;以…

【Mac】windows PC用户转用Mac 配置笔记

win转mac使用的一些配置笔记&#xff1b;感觉mac在UI上还是略胜一筹&#xff0c;再配合在win上的操作习惯就体验更好了&#xff0c;对日常办公需求的本人足以。 优化设置 主要 操作优化 AltTab&#xff1a; win 习惯查看全部活动的alt键&#xff0c;对比cmdtab多了可以预览&…

【qt】switchBtn

方法1 在qtdesigner中设置按钮图标的三个属性&#xff0c;normal off 、normal on和checkabletrue。 from PyQt5.QtWidgets import * from PyQt5.QtGui import * from PyQt5.QtCore import * from PyQt5 import uic from switchBtn import Ui_Dialogclass Test(QDialog, Ui_…

手敲Mybatis(17章)-二级缓存功能,感受装饰器的魅力

1.目的 本节主要是讲Mybatis的二级缓存&#xff0c;一级缓存是会话SqlSession级别的&#xff0c;二级缓存是Mapper级别的这个大家都知道&#xff0c;一级缓存主要是同一个SqlSession实例才可以缓存&#xff0c;那么出现commit等其他情况可能清除缓存&#xff0c;我想要再发起的…

ABB机器人单周和连续运行模式切换的配置方法

ABB机器人单周和连续运行模式切换的配置方法 有朋友反映:示教器上已经选择了“连续”模式,在通过PLC远程控制ABB机器人启动时,机器人的运行模式会从“连续”自动切换到“单周”, 那么哪里可以设置该选项呢,大家可以参考以下内容: 用户可以在快速设置栏设置机器人运行的运…

Q-Bench:一种用于低级别视觉通用基础模型的基准测试

1. 引言 多模态大语言模型&#xff08;Multi-modality Large Language Models&#xff0c;后续简称多模态大模型&#xff09;能够提供强大的通用级别视觉感知/理解能力&#xff0c;甚至可以通过自然语言与人类进行无缝对话和互动。虽然多模态大模型的这些能力已经在多个视觉语…

解析PreMaint在石油化工设备预测性维护领域的卓越表现

石油化工行业一直在寻找能够确保设备高效运行的先进维护解决方案。在这个领域&#xff0c;PreMaint以其卓越的性能和创新的技术引起了广泛关注。 一、为何选择预测性维护&#xff1f; 传统的维护方法&#xff0c;基于固定的时间表&#xff0c;无法灵活应对设备的真实运行状况。…

金融行业现场故障处理实录

KL银行现场服务记录—HA故障 服务时间 2019年9月10日星期二 14&#xff1a;40 到2019年9月11日星期三 0&#xff1a;30 服务内容 排查redhat RHEL 6.4 一个节点cman启动故障。 &#xff08;1&#xff09;、查看系统日志&#xff1b; &#xff08;2&#xff09;、查看ha日志…

编程大侦探林浩然的“神曲奇遇记”

编程大侦探林浩然的“神曲奇遇记” The Coding Detective Lin Haoran’s “Divine Comedy Adventures” 在我们那所充满活力与创新精神的高职学院中&#xff0c;林浩然老师无疑是众多教师中最独特的一颗星。这位身兼程序员与心理分析专家双重身份的大咖&#xff0c;不仅能在电脑…

APPium简介及安装

1 APPium简介 1. 什么是APPium&#xff1f; APPium是一个开源测试自动化框架&#xff0c;适用于原生、混合或移动Web应用程序的自动化测试工具。 APPium使用WebDriver协议驱动iOS、Android等应用程序。 2. APPium的特点 支持多平台&#xff08;Android、iOS等&#xff09; …

浅谈楼房老旧的配电设备加装电能管理系统的方案

摘要&#xff1a;文章通过对大楼配电设备现状及电能管理系统的需求分析&#xff0c;提出了在大楼老旧配电设备中加装 电能管理系统的方法&#xff0c;包括方案配置、计量点选择、终端改造、数据通信、报表格式等。旨在供无计量 管理系统或仅有电力监控系统的配电系统中加装电能…