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

【强化学习系列】Gym库使用——创建自己的强化学习环境2:拆解官方标准模型源码/规范自定义类+打包自定义环境

       

目录

一、 官方标准环境的获取与理解

二、根据官方环境源码修改自定义

        1.初始化__init__()

        2.重置环境 reset()

三、打包环境

        1.注册与创建自定义环境

        2.环境规范化


         在本文的早些时候,曾尝试按照自己的想法搭建自定义的基于gym强化学习环境。

        【强化学习系列】Gym库使用——创建自己的强化学习环境1:单一环境创建测试

        但由于学艺不精,在矢量化环境时遇到诸多障碍。仔细检查发现自己编写的环境存在很多不符合gym官方规范的地方,因此,索性从零重新研读官方介绍文档,从头开始解读官方标准环境源码,以帮助规范化自己搭建环境的类参数设置。

        官方文档地址:https://gymnasium.farama.org/

一、 官方标准环境的获取与理解

        通过打印 gym.envs.registry.keys() 获得的字典,就可以获得官方默认的所有可以直接调用的环境。

import gymnasium as gym# 官方支持的所有游戏环境
print(gym.envs.registry.keys())

        通过官方给出的运行和可视化代码即可,先通过“人为”(‘human’)来玩游戏。

import gymnasium as gym# 官方支持的所有游戏环境
print(gym.envs.registry.keys())# 可视化
env = gym.make("MountainCarContinuous-v0", render_mode="human")
observation, info = env.reset()for _ in range(1000):action = env.action_space.sample()  # agent policy that uses the observation and infoobservation, reward, terminated, truncated, info = env.step(action)if terminated or truncated:observation, info = env.reset()
env.close()

        下面展示一些官方游戏的可视化窗口的部分画面。只需根据最开始获得的游戏包装好的字典名,修改上述代码中环境实例化的make中第一个参数名即可,实际运行是动态的。

 

        首先从官方给出的Github地址下载好Gymnaium的源码——Gymnaium官方Github地址

        在官方文档目录的 ENVIRONMENTS 中介绍相关环境的一些基本关键信息,包括其状态动作空间、交互逻辑、奖励逻辑等。

        其中所有环境的源码保存在Github文件的 gymnaium/envs/ 目录下。

        本文选择经典环境下的山地车(Mountain Car)为源码拆解的例子。首先看起官方文档的环境介绍,其动作空间是一个三种可能的离散空间,分别对应小车的向左向右加速或不加速。

        其状态空间是一个连续的二维空间,分别是小车在x轴的位置,取值范围是(-1.2,0.6);小车速度,取值范围是(-0.07,0.07)。

        目标是让小车登顶,初始化是将小车随机放在山谷的一个位置,初始速度为0,如果小车登顶或超过200步操作,则退出游戏。

二、根据官方环境源码修改自定义

        在理解游戏逻辑的基础上,进入其源码处查看并学习其代码类编写的规范性。

        1.初始化__init__()

        首先是环境的初始化。其在传入参数上设计两个内容:一是选择环境可视化,二是设置汽车的初始速度为0。

        还可以看到其可视化模式的选择是定义了一个metadata的字典,其定义状态空间和动作空间的逻辑和我们之前无异。

        值得注意的规范细节是,对于初始化是numpy数组向量时,都需标准其定义的数据类型dtype

        总结官方环境源码初始化的内容,可以得出初始化的个关键内容——状态环境的取值范围(如所处空间的大小——游戏里的地图,到边缘就不能探索了)、实体状态属性值(如小车的速度、或者游戏里角色的血量蓝条等等)、可视化窗口的一些变量。       

        现在回到自定义环境的逻辑(参考文章——单一自定义环境测试),新的环境中状态空间是图片上的目标检测框,是一个四维的(左上右下四坐标列表)连续空间。动作空间是一个四种可能的离散空间——上扩或缩、下扩或缩。其框坐标的取值范围受到图片高宽的影响。因此初始化必须传入原图地址信息,以获取高宽范围。

        参考总结的内容,可以梳理清晰自定义环境的一些设置,状态空间上肯定超出图片高宽或者小于0的框无意义,因此很容易定义状态空间。更关键的是实体属性,在这里原始的框就是需要移动的实体,像小车会有速度一样,这里我们定义初始框包含几个实际物体对应框(虚拟的框,在状态空间环境中不存在)视为该框的属性值。同时一张图里也可能有多个框存在,如果不希望当前框和环境中其他存在的框存在高度重叠,也可以设置重叠度检查属性。

        2.重置环境 reset()

        查看官方的初始化环境函数,可以看到其对于函数传参有规范化的标准,其初始的状态控制放在options字典数据中传入,并且采取了强制关键字的模式(*后的参数需要以关键字对应方式传入)因此改进我们自定义的reset函数。

         再将真实框可视化进背景,即可运行reset得到可视化结果。

         以上可视化所有完整代码如下。

import pygame
import gym
from gym import spaces
import numpy as np
from typing import Optionalclass My_Env(gym.Env):metadata = {"render_modes": ["human", "rgb_array"], "render_fps": 1}def __init__(self, render_mode: Optional[str] = None, image_path: Optional[str] = None):super(My_Env, self).__init__()# 读取当前图像信息if image_path != None:self.img = pygame.image.load(image_path)self.width, self.height = self.img.get_width(), self.img.get_height()else:self.width, self.height = 100, 100print('env need background')self.real = None  # 真实框数据# 定义框属性值self.box_num = None  # 初始预测框数量self.overlap = None  # 包含真实框个数self.box_iou = None  # 重叠度检查# 创建动作和状态空间范围self.action_space = spaces.Discrete(4)self.observation_space = spaces.Box(low=np.array([0,0,0,0],dtype=np.float32), high=np.array([self.width, self.height,self.width, self.height],dtype=np.float32), shape=(4,), dtype=np.float32)# 定义模式:人类可视化or机器人训练assert render_mode is None or render_mode in self.metadata["render_modes"]self.render_mode = render_modeself.window = None  # 可视化窗口self.clock = None   # 可视化时钟self.window_size = (600,600)  # 窗口大小self.background = None  # 背景图self.scale_x = None     # x横轴缩放比self.scale_y = None     # y竖轴缩放比def reset(self,*,seed: Optional[int] = None,options: Optional[dict] = None) :real = options['real_box']   # 真实框数据box = options['box']   # 初始框数据self.real = np.array(real, dtype=np.float32).reshape(-1, 4)self.state = np.array(box,dtype=np.float32).reshape(-1,4)   # 规范数据格式和形状if self.render_mode == 'human':self.background = pygame.transform.scale(self.img, self.window_size) # 设置背景图# 计算x和y方向的缩放比例self.scale_x = self.window_size[0]/ self.widthself.scale_y = self.window_size[1] / self.heightself.render()return self.statedef step(self, action):  # 动作序列{0:上扩, 1:上缩, 2:下扩, 3:下缩}# 根据action生成移动数组movement_np = np.zeros_like(self.state,dtype=np.float32)for i,act in enumerate(action):if act == 0:movement_np[i,1] = 10elif act == 1:movement_np[i,1] = -10elif act == 2:movement_np[i,3] = 10elif act == 3:movement_np[i,3] = -10# 移动当前状态框self.state += movement_npself.state = np.clip(self.state, self.observation_space.low, self.observation_space.high)return self.statedef render(self):# 初始化窗口和时钟if self.window is None and self.render_mode == 'human':pygame.init()pygame.display.init()self.window = pygame.display.set_mode(self.window_size)if self.clock is None and self.render_mode == 'human':self.clock = pygame.time.Clock()# 重新绘制背景,以清除上一层if self.background is not None:self.window.blit(self.background,(0,0))for real in list(self.real):rect_real = [real[0], real[1], abs(real[2]-real[0]), abs(real[3]-real[1])]# 根据x和y方向的缩放比例计算每个矩形框的新位置stretched_rectangle = [rect_real[0] * self.scale_x,  # x 坐标rect_real[1] * self.scale_y,  # y 坐标rect_real[2] * self.scale_x,  # 宽度rect_real[3] * self.scale_y  # 高度]pygame.draw.rect(self.window, (255, 0, 0), stretched_rectangle, 2)  # 绘制矩形框,线宽为2# 绘制框for box in list(self.state):rect = [box[0], box[1], abs(box[2]-box[0]), abs(box[3]-box[1])]# 根据x和y方向的缩放比例计算每个矩形框的新位置stretched_rectangle = [rect[0] * self.scale_x,  # x 坐标rect[1] * self.scale_y,  # y 坐标rect[2] * self.scale_x,  # 宽度rect[3] * self.scale_y  # 高度]pygame.draw.rect(self.window, (0, 255, 0), stretched_rectangle, 3)  # 绘制矩形框,线宽为3# 更新显示pygame.display.flip()self.clock.tick(self.metadata["render_fps"])def close(self):pygame.quit()if __name__=='__main__':# 加载本地图片image_path = './jpg/000000000025.jpg'  # 替换为你的图片路径# 加载本地框box_path = './box/000000000025.json'with open(box_path, 'r') as f:box_dict_list = json.load(f)box_list = []for box_dict in box_dict_list:box = box_dict['box']box_list.append(box)box2 = [(0,3),(1,0),(1,1),(1,2),(1,3)]box1 = [(0,0),(0,1),(1,0),(1,1),(2,1),(3,1),(4,1),(4,2),(4,3),(5,1),(5,2),(5,3),(5,4),(6,1),(6,2),(6,3),(6,4),(7,1),(7,2),(7,3),(7,4),(7,5),(8,1),(8,2),(8,3),(8,4),(8,5)]real_list = []for i in range(len(box_list)):bbox = box_list[i]wid = bbox[2]-bbox[0]hgt = bbox[3]-bbox[1]gap = 30for w in range(wid//gap):for h in range(hgt//gap):if i ==0:if (h,w) in box1:real = [bbox[0]+w*gap, bbox[1]+h*gap, bbox[0]+(w+1)*gap, bbox[1]+(h+1)*gap]real_list.append(real)elif i ==1:if (h,w) in box2:real = [bbox[0] + w * gap, bbox[1] + h * gap, bbox[0] + (w + 1) * gap, bbox[1] + (h + 1) * gap]real_list.append(real)env = My_Env(render_mode='human', image_path=image_path)state = env.reset(options={'real_box':real_list, 'box':box_list})while True:env.render()

三、打包环境

        1.注册与创建自定义环境

        为了更方便的加载环境以及为后续矢量化做准备,需要将自定义的环境打包并使用官方推荐的gymnasium.make来加载环境,这样的加载方式会帮助检查环境的合规性。

        首先新建项目文件,将所有环境代码放入一个子文件中方便修改,然后再新建一个注册环境的子文件用于测试环境能否被成功注册。

        在测试环境下(有图片和框数据的文件夹),先注册环境在创建环境。

import gymnasium as gym
import json
from gymnasium.envs.registration import register# 注册环境
register(id='detect_env-v0',entry_point='my_gym_env.detect_env:Detect_Env',
)# 加载本地图片
image_path = './jpg/000000000025.jpg'  # 替换为你的图片路径
# 加载本地框
box_path = './box/000000000025.json'
real_path = './real/000000000025.json'
with open(box_path, 'r') as f:box_dict_list = json.load(f)
box_list = []
for box_dict in box_dict_list:box = box_dict['box']box_list.append(box)
with open(real_path, 'r') as f:real_list = json.load(f)env = gym.make('detect_env-v0', render_mode='human', image_path=image_path)state = env.reset(options={'real_box':real_list, 'box':box_list})
while True:env.render()

        2.环境规范化

        运行上面的测试代码,虽然能加载出环境演示,但是make会检测环境创建源码,并对不规范报错,这方便我们进行修改规范源码。

        ① reset 报错与规范

         这里报错的原因是,在定义环境重置 reset 时,没有返回 info 信息。补一个空字典即可。

UserWarning: WARN: The result returned by `env.reset()` was not a tuple of the form `(obs, info)`, where `obs` is a observation and `info` is a dictionary containing additional information. Actual type: `<class 'numpy.ndarray'>`

        ② observation_space 状态空间报错与规范

        改完后报新的错。这是说在重置环境时传入的状态空间与__init__ 中定义的状态空间形状不匹配。

UserWarning: WARN: The obs returned by the `reset()` method is not within the observation space.logger.warn(f"{pre} is not within the observation space.")

        检查环境中定义的空间必须是固定形状的,(,4)的定义会默认为(1,4),其不能自由匹配维度,但是作为图片中的目标框,其第一个维度数量是不固定的。因此一种解决方式是选择所有图片内的最大框数作为初始化状态空间第一维度,不够的地方用零填充。

# 设置最大框数
self.box_max_num = 20
# 创建动作和状态空间范围
self.action_space = spaces.Discrete(4)
self.observation_space = spaces.Box(low=np.zeros((self.box_max_num,4),dtype=np.float32),high=np.tile([self.width, self.height,self.width, self.height],(self.box_max_num,1)),shape=(self.box_max_num,4), dtype=np.float32)

# 初始传入框信息
state = np.array(box,dtype=np.float32).reshape(-1,4)   # 规范数据格式和形状# 填充零使得状态达到指定维度
self.state = np.pad(state,((0,self.box_max_num-state.shape[0]),(0,0)), mode='constant', constant_values=0)

        规范后不再报错,此时打印环境的状态检查。

        ③ step 报错与规范

        继续在加入动作空间的输入,解决step中的规范性问题。首先如果要输入动作,需要知道当前图片中实际需要操作的框的数量(不能根据状态空间判断,因为状态中框数(第一行维度)被强制设为最大框数), 因此在重置环境时就要返回当前图片的框数,作为每个框生成多少个动作的标准,在官方的规范代码中,可将这些额外信息写入info字典中返回。

info = {'box_num':state.shape[0]}
return self.state, info

        在测试代码中添加采样动作和step操作,并打印状态的变化numpy数组。注意此处环境还没有设计奖励函数,因此定义环境操作reward都是0。

env = gym.make('detect_env-v0', render_mode='human', image_path=image_path)state,info = env.reset(options={'real_box':real_list, 'box':box_list})
print(0, state)
for epid in range(50):action = [env.action_space.sample() for _ in range(info['box_num'])]state, reward, _, _, _ = env.step(action)print(epid+1, state)env.render()

         下图中,红色箭头表示右较大框的状态变化,黄色箭头代表左较小框的状态变化。此处为方便可视化,将最大框数量设为3。以20像素为步长变化检测框。

         加上具体动作打印结果可视化。

        至此,环境规范化告一段落,完整代码放在下面方便复制取走。终于可以开始后续矢量化环境操作了。

        自定义检测环境完整代码。

import pygame
import gymnasium as gym
from gymnasium import spaces
import numpy as np
from typing import Optionalclass Detect_Env(gym.Env):metadata = {"render_modes": ["human", "rgb_array"], "render_fps": 1}def __init__(self, render_mode: Optional[str] = None, image_path: Optional[str] = None):super(Detect_Env, self).__init__()# 读取当前图像信息if image_path != None:self.img = pygame.image.load(image_path)self.width, self.height = self.img.get_width(), self.img.get_height()else:self.width, self.height = 100, 100print('env need background')self.real = None  # 真实框数据# 定义框属性值self.box_num = None  # 初始预测框数量self.overlap = None  # 包含真实框个数self.box_iou = None  # 重叠度检查# 设置最大框数self.box_max_num = 3# 创建动作和状态空间范围self.action_space = spaces.Discrete(4)self.observation_space = spaces.Box(low=np.zeros((self.box_max_num,4),dtype=np.float32),high=np.tile([self.width, self.height,self.width, self.height],(self.box_max_num,1)),shape=(self.box_max_num,4), dtype=np.float32)# 定义模式:人类可视化or机器人训练assert render_mode is None or render_mode in self.metadata["render_modes"]self.render_mode = render_modeself.window = None  # 可视化窗口self.clock = None   # 可视化时钟self.window_size = (600,600)  # 窗口大小self.background = None  # 背景图self.scale_x = None     # x横轴缩放比self.scale_y = None     # y竖轴缩放比def reset(self,*,seed: Optional[int] = None,options: Optional[dict] = None) :real = options['real_box']   # 真实框数据box = options['box']   # 初始框数据self.real = np.array(real, dtype=np.float32).reshape(-1, 4)state = np.array(box,dtype=np.float32).reshape(-1,4)   # 规范数据格式和形状# 填充零使得状态达到指定维度self.state = np.pad(state,((0,self.box_max_num-state.shape[0]),(0,0)), mode='constant', constant_values=0)if self.render_mode == 'human':self.background = pygame.transform.scale(self.img, self.window_size) # 设置背景图# 计算x和y方向的缩放比例self.scale_x = self.window_size[0]/ self.widthself.scale_y = self.window_size[1] / self.heightself.render()info = {'box_num':state.shape[0]}return self.state, infodef step(self, action):  # 动作序列{0:上扩, 1:上缩, 2:下扩, 3:下缩}# 根据action生成移动数组movement_np = np.zeros_like(self.state,dtype=np.float32)for i,act in enumerate(action):if act == 0:movement_np[i,1] = 20elif act == 1:movement_np[i,1] = -20elif act == 2:movement_np[i,3] = 20elif act == 3:movement_np[i,3] = -20# 移动当前状态框self.state += movement_npself.state = np.clip(self.state, self.observation_space.low, self.observation_space.high)return np.array(self.state, dtype=np.float32),0,False,False,{}def render(self):# 初始化窗口和时钟if self.window is None and self.render_mode == 'human':pygame.init()pygame.display.init()self.window = pygame.display.set_mode(self.window_size)if self.clock is None and self.render_mode == 'human':self.clock = pygame.time.Clock()# 重新绘制背景,以清除上一层if self.background is not None:self.window.blit(self.background,(0,0))for real in list(self.real):rect_real = [real[0], real[1], abs(real[2]-real[0]), abs(real[3]-real[1])]# 根据x和y方向的缩放比例计算每个矩形框的新位置stretched_rectangle = [rect_real[0] * self.scale_x,  # x 坐标rect_real[1] * self.scale_y,  # y 坐标rect_real[2] * self.scale_x,  # 宽度rect_real[3] * self.scale_y  # 高度]pygame.draw.rect(self.window, (255, 0, 0), stretched_rectangle, 2)  # 绘制矩形框,线宽为2# 绘制框for box in list(self.state):rect = [box[0], box[1], abs(box[2]-box[0]), abs(box[3]-box[1])]# 根据x和y方向的缩放比例计算每个矩形框的新位置stretched_rectangle = [rect[0] * self.scale_x,  # x 坐标rect[1] * self.scale_y,  # y 坐标rect[2] * self.scale_x,  # 宽度rect[3] * self.scale_y  # 高度]pygame.draw.rect(self.window, (0, 255, 0), stretched_rectangle, 3)  # 绘制矩形框,线宽为3# 更新显示pygame.display.flip()self.clock.tick(self.metadata["render_fps"])def close(self):pygame.quit()

        项目文件层级结构。

        测试可视化完整代码。

import gymnasium as gym
import json
from gymnasium.envs.registration import register# 注册环境
register(id='detect_env-v0',entry_point='my_gym_env.detect_env:Detect_Env',
)# 加载本地图片
image_path = './jpg/000000000025.jpg'  # 替换为你的图片路径
# 加载本地框
box_path = './box/000000000025.json'
real_path = './real/000000000025.json'
with open(box_path, 'r') as f:box_dict_list = json.load(f)
box_list = []
for box_dict in box_dict_list:box = box_dict['box']box_list.append(box)
with open(real_path, 'r') as f:real_list = json.load(f)env = gym.make('detect_env-v0', render_mode='human', image_path=image_path)state,info = env.reset(options={'real_box':real_list, 'box':box_list})
print(0, state)
for epid in range(50):action = [env.action_space.sample() for _ in range(info['box_num'])]print('action', action)state, reward, _, _, _ = env.step(action)print(epid+1, state)env.render()

相关文章:

【强化学习系列】Gym库使用——创建自己的强化学习环境2:拆解官方标准模型源码/规范自定义类+打包自定义环境

目录 一、 官方标准环境的获取与理解 二、根据官方环境源码修改自定义 1.初始化__init__() 2.重置环境 reset() 三、打包环境 1.注册与创建自定义环境 2.环境规范化 在本文的早些时候&#xff0c;曾尝试按照自己的想法搭建自定义的基于gym强化学习环境。 【强化学习系列】Gy…...

PyQt5实现按钮选择文件夹及文件夹

目录 1、选择文件夹并显示 2、选择文件 3、选择多个文件 4、设置保存文件路径 1、选择文件夹并显示 from PyQt5 import QtWidgetsdirectory QtWidgets.QFileDialog.getExistingDirectory(None, "选取文件夹", "./") # 起始路径 print(directory) 2…...

Gin渲染

HTML渲染 【示例1】 首先定义一个存放模板文件的 templates文件夹&#xff0c;然后在其内部按照业务分别定义一个 posts 文件夹和一个 users 文件夹。 posts/index.tmpl {{define "posts/index.tmpl"}} <!DOCTYPE html> <html lang"en">&…...

前端——JS基础

定义变量&#xff1a;let / var 字符串 字符串拼接&#xff1a; 字符串和数字拼&#xff1a;您.... 25 ; 这个25会转成字符串再拼接 字符串和数组拼&#xff1a;10以内的质数有&#xff1a; [2,3,5,7] > 10以内的质数有&#xff1a;2,3,5,7 字符串长度&#xff1a;leng…...

MATLAB入门教程

MATLAB安装教程可参考链接&#xff1a;matlab怎么安装 matlab安装教程-电脑软件-PHP中文网 1.MATLAB的工作环境 &#xff08;1&#xff09;命令窗(command window) 是对MATLAB进行操作的主要载体。默认情况下&#xff0c;启动MATLAB时就打开命令窗。MATLAB的所有所数…...

muduo - 概要简述

作者&#xff1a;陈硕 编程语言&#xff1a;C 架构模式&#xff1a;Reactor 代码链接&#xff1a;GitHub - chenshuo/muduo: Event-driven network library for multi-threaded Linux server in C11 设计自述&#xff1a;https://www.cnblogs.com/Solstice/archive/2010/08…...

Selenium点击元素的方法

前言 点击方法在web自动化测试中经常用到,下面就来介绍一下selenium常用和不常用的点击方法; 1、常用方法 1.1、使用 click() 方法: 这是最简单和最常用的方法。通过选中要点击的元素,然后使用 click() 方法来触发点击事件。 示例代码: element = self.driver.find_e…...

kali里面搭建docker容器

注意事项&#xff1a;kali版本&#xff0c;镜像源 &#xff08;1&#xff09;权限为管理员&#xff1a; sudo su (2) 更新软件包列表并升级已安装的软件包 apt-get update apt-get upgrade 出错了&#xff0c;应该是更新源出问题了。 &#xff08;3&#xff09;更换镜像源&am…...

WebGL系列教程八(GLSL着色器基础语法)

目录 1 前言2 基本原则3 基本数据类型4 顶点着色器和片元着色器4.1 声明4.2 初始化项目4.3 赋值 5 结构体5.1 声明5.2 赋值 6 函数6.1 基本结构6.2 自定义函数6.3 常用内置函数 7 精度8 其他9 总结 1 前言 通过前七讲&#xff0c;我们已经见过了WebGL中的部分基础语法&#xff…...

go多线程

1、简单使用&#xff08;这个执行完成&#xff0c;如果进程执行比较久&#xff0c;这里不会等待它们结束&#xff09; package mainimport "time"func main() {go func() {println("Hello, World!")}()time.Sleep(1 * time.Second) }2、wg.Add(数量)使用&…...

【话题】如何看待IBM中国研发部裁员?

&#xff08;一&#xff09;背景 在全球化的大趋势下&#xff0c;跨国公司的业务布局一直处于动态调整之中。IBM 作为全球知名的 IT 企业&#xff0c;在中国市场已经运营多年&#xff0c;其在中国的研发中心曾经为公司的全球业务发展做出了重要贡献。近年来&#xff0c;全球经…...

【C/C++】涉及string类的经典OJ编程题

【C/C】涉及string类的经典OJ编程题 一. 把字符串转化成整数&#xff08;atoi&#xff09;解法一&#xff1a;&#xff08;不用long&#xff09;完整代码&#xff1a;解法二&#xff1a;&#xff08;用long&#xff09; 二.字符串相加代码实现&#xff08;含注释&#xff09;&a…...

淘系等电商平台API接口系列:商品详情数据解析,json数据返回参考

——在成长的路上&#xff0c;我们都是同行者。这篇关于商品详情API接口的文章&#xff0c;希望能帮助到您。期待与您继续分享更多API接口的知识&#xff0c;请记得关注Anzexi58哦&#xff01; 在淘系&#xff08;如淘宝、天猫&#xff09;等电商平台中&#xff0c;商品详情数据…...

vue组件之间的数据共享

一、组件之间的关系 1.父子关系 2.兄弟关系 3.后代关系 二、父子组件之间的数据共享 1.父-->子共享数据 父组件通过v-bind属性绑定向子组件共享数据&#xff0c;子组件需要使用props接受数据。 <template><p>父组件</p><Son :msg"msg"…...

LangChain:构建强大的LLM应用的全方位框架

LangChain&#xff1a;构建强大的LLM应用的全方位框架 引言 在人工智能和大语言模型&#xff08;LLMs&#xff09;快速发展的今天&#xff0c;开发者们迫切需要一个强大而灵活的框架来简化LLM应用的开发过程。LangChain应运而生&#xff0c;它不仅提供了丰富的工具和组件&…...

自有平台自有品牌如何利用电商API接口做定价参考(多平台商品详情数据接口)

如今&#xff0c;多数自有商城自有品牌在为产品做定价时都会参考淘宝|天猫|京东等主流电商平台的商品价格以做参考&#xff0c;这一行为的好处主要有以下几点&#xff1a; 通过参考主流平台价格&#xff0c;用户更能了解目标市场中消费者对产品的接受度&#xff0c;从而制定出符…...

三万字长文Java面试题——基础篇(注:该篇博客将会一直维护 最新维护时间:2024年9月18日)

&#x1f9f8;本篇博客重在讲解Java基础的面试题&#xff0c;将会实时更新&#xff0c;欢迎大家添加作者文末联系方式交流 &#x1f4dc;JAVA面试题专栏&#xff1a;JAVA崭新面试题——2024版_dream_ready的博客-CSDN博客 &#x1f4dc;作者首页&#xff1a; dream_ready-CSDN博…...

数学建模——熵权+TOPSIS+肘部法则+系统聚类

文章目录 一、起因二、代码展示 一、起因 我本科的数学建模队长找上我&#xff0c;让我帮她写下matlab代码&#xff0c;当然用的模型还是曾经打比赛的模型&#xff0c;所以虽然代码量多&#xff0c;但是写的很快&#xff0c;也是正逢中秋&#xff0c;有点时间。 当然我也没想到…...

Java | Leetcode Java题解之第403题青蛙过河

题目&#xff1a; 题解&#xff1a; class Solution {public boolean canCross(int[] stones) {int n stones.length;boolean[][] dp new boolean[n][n];dp[0][0] true;for (int i 1; i < n; i) {if (stones[i] - stones[i - 1] > i) {return false;}}for (int i 1…...

828华为云征文|华为Flexus云服务器搭建OnlyOffice私有化在线办公套件

一、引言 在当今数字化办公的时代&#xff0c;在线办公套件的需求日益增长。华为Flexus云服务器凭借其强大的性能和稳定性&#xff0c;为搭建OnlyOffice私有化在线办公套件提供了理想的平台。在2024年9月14日这个充满探索精神的日子里&#xff0c;我们开启利用华为Flexus云服务…...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析

一、变量声明设计&#xff1a;let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性&#xff0c;这种设计体现了语言的核心哲学。以下是深度解析&#xff1a; 1.1 设计理念剖析 安全优先原则&#xff1a;默认不可变强制开发者明确声明意图 let x 5; …...

ES6从入门到精通:前言

ES6简介 ES6&#xff08;ECMAScript 2015&#xff09;是JavaScript语言的重大更新&#xff0c;引入了许多新特性&#xff0c;包括语法糖、新数据类型、模块化支持等&#xff0c;显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var&#xf…...

k8s从入门到放弃之Ingress七层负载

k8s从入门到放弃之Ingress七层负载 在Kubernetes&#xff08;简称K8s&#xff09;中&#xff0c;Ingress是一个API对象&#xff0c;它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress&#xff0c;你可…...

循环冗余码校验CRC码 算法步骤+详细实例计算

通信过程&#xff1a;&#xff08;白话解释&#xff09; 我们将原始待发送的消息称为 M M M&#xff0c;依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)&#xff08;意思就是 G &#xff08; x ) G&#xff08;x) G&#xff08;x) 是已知的&#xff09;&#xff0…...

Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务

通过akshare库&#xff0c;获取股票数据&#xff0c;并生成TabPFN这个模型 可以识别、处理的格式&#xff0c;写一个完整的预处理示例&#xff0c;并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务&#xff0c;进行预测并输…...

电脑插入多块移动硬盘后经常出现卡顿和蓝屏

当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时&#xff0c;可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案&#xff1a; 1. 检查电源供电问题 问题原因&#xff1a;多块移动硬盘同时运行可能导致USB接口供电不足&#x…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力

引言&#xff1a; 在人工智能快速发展的浪潮中&#xff0c;快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型&#xff08;LLM&#xff09;。该模型代表着该领域的重大突破&#xff0c;通过独特方式融合思考与非思考…...

在四层代理中还原真实客户端ngx_stream_realip_module

一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡&#xff08;如 HAProxy、AWS NLB、阿里 SLB&#xff09;发起上游连接时&#xff0c;将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后&#xff0c;ngx_stream_realip_module 从中提取原始信息…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作

一、上下文切换 即使单核CPU也可以进行多线程执行代码&#xff0c;CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短&#xff0c;所以CPU会不断地切换线程执行&#xff0c;从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...