【强化学习系列】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.环境规范化 在本文的早些时候,曾尝试按照自己的想法搭建自定义的基于gym强化学习环境。 【强化学习系列】Gy…...
PyQt5实现按钮选择文件夹及文件夹
目录 1、选择文件夹并显示 2、选择文件 3、选择多个文件 4、设置保存文件路径 1、选择文件夹并显示 from PyQt5 import QtWidgetsdirectory QtWidgets.QFileDialog.getExistingDirectory(None, "选取文件夹", "./") # 起始路径 print(directory) 2…...

Gin渲染
HTML渲染 【示例1】 首先定义一个存放模板文件的 templates文件夹,然后在其内部按照业务分别定义一个 posts 文件夹和一个 users 文件夹。 posts/index.tmpl {{define "posts/index.tmpl"}} <!DOCTYPE html> <html lang"en">&…...
前端——JS基础
定义变量:let / var 字符串 字符串拼接: 字符串和数字拼:您.... 25 ; 这个25会转成字符串再拼接 字符串和数组拼:10以内的质数有: [2,3,5,7] > 10以内的质数有:2,3,5,7 字符串长度:leng…...

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

muduo - 概要简述
作者:陈硕 编程语言:C 架构模式:Reactor 代码链接:GitHub - chenshuo/muduo: Event-driven network library for multi-threaded Linux server in C11 设计自述:https://www.cnblogs.com/Solstice/archive/2010/08…...
Selenium点击元素的方法
前言 点击方法在web自动化测试中经常用到,下面就来介绍一下selenium常用和不常用的点击方法; 1、常用方法 1.1、使用 click() 方法: 这是最简单和最常用的方法。通过选中要点击的元素,然后使用 click() 方法来触发点击事件。 示例代码: element = self.driver.find_e…...

kali里面搭建docker容器
注意事项:kali版本,镜像源 (1)权限为管理员: sudo su (2) 更新软件包列表并升级已安装的软件包 apt-get update apt-get upgrade 出错了,应该是更新源出问题了。 (3)更换镜像源&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 前言 通过前七讲,我们已经见过了WebGL中的部分基础语法ÿ…...

go多线程
1、简单使用(这个执行完成,如果进程执行比较久,这里不会等待它们结束) package mainimport "time"func main() {go func() {println("Hello, World!")}()time.Sleep(1 * time.Second) }2、wg.Add(数量)使用&…...
【话题】如何看待IBM中国研发部裁员?
(一)背景 在全球化的大趋势下,跨国公司的业务布局一直处于动态调整之中。IBM 作为全球知名的 IT 企业,在中国市场已经运营多年,其在中国的研发中心曾经为公司的全球业务发展做出了重要贡献。近年来,全球经…...

【C/C++】涉及string类的经典OJ编程题
【C/C】涉及string类的经典OJ编程题 一. 把字符串转化成整数(atoi)解法一:(不用long)完整代码:解法二:(用long) 二.字符串相加代码实现(含注释)&a…...
淘系等电商平台API接口系列:商品详情数据解析,json数据返回参考
——在成长的路上,我们都是同行者。这篇关于商品详情API接口的文章,希望能帮助到您。期待与您继续分享更多API接口的知识,请记得关注Anzexi58哦! 在淘系(如淘宝、天猫)等电商平台中,商品详情数据…...
vue组件之间的数据共享
一、组件之间的关系 1.父子关系 2.兄弟关系 3.后代关系 二、父子组件之间的数据共享 1.父-->子共享数据 父组件通过v-bind属性绑定向子组件共享数据,子组件需要使用props接受数据。 <template><p>父组件</p><Son :msg"msg"…...
LangChain:构建强大的LLM应用的全方位框架
LangChain:构建强大的LLM应用的全方位框架 引言 在人工智能和大语言模型(LLMs)快速发展的今天,开发者们迫切需要一个强大而灵活的框架来简化LLM应用的开发过程。LangChain应运而生,它不仅提供了丰富的工具和组件&…...

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

三万字长文Java面试题——基础篇(注:该篇博客将会一直维护 最新维护时间:2024年9月18日)
🧸本篇博客重在讲解Java基础的面试题,将会实时更新,欢迎大家添加作者文末联系方式交流 📜JAVA面试题专栏:JAVA崭新面试题——2024版_dream_ready的博客-CSDN博客 📜作者首页: dream_ready-CSDN博…...
数学建模——熵权+TOPSIS+肘部法则+系统聚类
文章目录 一、起因二、代码展示 一、起因 我本科的数学建模队长找上我,让我帮她写下matlab代码,当然用的模型还是曾经打比赛的模型,所以虽然代码量多,但是写的很快,也是正逢中秋,有点时间。 当然我也没想到…...

Java | Leetcode Java题解之第403题青蛙过河
题目: 题解: 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私有化在线办公套件
一、引言 在当今数字化办公的时代,在线办公套件的需求日益增长。华为Flexus云服务器凭借其强大的性能和稳定性,为搭建OnlyOffice私有化在线办公套件提供了理想的平台。在2024年9月14日这个充满探索精神的日子里,我们开启利用华为Flexus云服务…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...

七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...
动态 Web 开发技术入门篇
一、HTTP 协议核心 1.1 HTTP 基础 协议全称 :HyperText Transfer Protocol(超文本传输协议) 默认端口 :HTTP 使用 80 端口,HTTPS 使用 443 端口。 请求方法 : GET :用于获取资源,…...
为什么要创建 Vue 实例
核心原因:Vue 需要一个「控制中心」来驱动整个应用 你可以把 Vue 实例想象成你应用的**「大脑」或「引擎」。它负责协调模板、数据、逻辑和行为,将它们变成一个活的、可交互的应用**。没有这个实例,你的代码只是一堆静态的 HTML、JavaScript 变量和函数,无法「活」起来。 …...
人工智能--安全大模型训练计划:基于Fine-tuning + LLM Agent
安全大模型训练计划:基于Fine-tuning LLM Agent 1. 构建高质量安全数据集 目标:为安全大模型创建高质量、去偏、符合伦理的训练数据集,涵盖安全相关任务(如有害内容检测、隐私保护、道德推理等)。 1.1 数据收集 描…...
uniapp 实现腾讯云IM群文件上传下载功能
UniApp 集成腾讯云IM实现群文件上传下载功能全攻略 一、功能背景与技术选型 在团队协作场景中,群文件共享是核心需求之一。本文将介绍如何基于腾讯云IMCOS,在uniapp中实现: 群内文件上传/下载文件元数据管理下载进度追踪跨平台文件预览 二…...

【Linux】Linux安装并配置RabbitMQ
目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的,需要先安…...

数据分析六部曲?
引言 上一章我们说到了数据分析六部曲,何谓六部曲呢? 其实啊,数据分析没那么难,只要掌握了下面这六个步骤,也就是数据分析六部曲,就算你是个啥都不懂的小白,也能慢慢上手做数据分析啦。 第一…...