YOLOv8白皮书-第Y7周:训练自己的数据集

news2024/12/28 22:55:55

本文为365天深度学习训练营中的学习记录博客
原作者:K同学啊|接辅导、项目定制

本文可以参考《YOLOv5白皮书-第Y2周:训练自己的数据集》

这次试着用YOLOv8训练自己的数据。

一、配置环境

1、官网下载源码
官网地址:【YOLOv8开源地址】
在这里插入图片描述

2、安装需要的环境
配置PyTorch环境,可以在网上搜索Pytoch安装方法。

二、准备好自己的数据
这次训练使用的数据集是水果检测数据集。
我的目录结构是这样子的:

  • 主目录

    • paper_data(自己创建一个文件夹,将数据集放到这里)
      • Annotations(放置水果检测数据集的.xml文件)
      • images(放置水果检测数据集的图片文件)
      • ImageSets
        • Main(执行split_train_val.py文件后,自动在该文件夹内生成train.txt、val.txt、test.txt、trainval.txt四个文件,分别存放训练集、验证集、测试集图片的名字)
    • split_train_val.py(划分训练集、验证集与测试集)
    • voc_label.py(获取训练集、验证集与测试集的图片路径)
    • ab.yaml(数据集及数据类别声明文件)
  • train.py(代码运行文件)

如下图片所示的目录结构:
在这里插入图片描述

Annotations文件夹存放.xml格式的文件,如下所示
在这里插入图片描述

images文件夹为存放.png 格式的图像文件,如下所示:
在这里插入图片描述

1、运行split_train _val.py 文件
ImageSets文件夹下面有个Main子文件夹,其下面存放了train.txt、val.txt、test.txt 和 trainval.txt 四个文件,它们是通过split_train val.py 文件来生成的.

split_train_val.py 文件的位置如下:
在这里插入图片描述

split_train_val.py的代码内容如下:

#导入必要的库
import os
import random
import argparse

#创建一个参数解析器
parser =argparse.ArgumentParser()

#添加命令行参数,用于指定XML文件的路径,默认为,Annotations'文件夹
parser.add_argument('--xml_path', default='Annotations', type=str, help='input xml label path')

#添加命令行参数,用于指定输出txt标签文件的路径,默认为'Imagesets/Main'文件夹
parser.add_argument('--txt_path', default='Imagesets/Main', type=str, help='output txt label path')

#解析命令行参数
opt = parser.parse_args()

#定义训练验证集和测试集的划分比例
trainval_percent=0.9   #使用全部数据
train_percent=8/9   #训练集占训练验证集的90%

#设置XML文件夹的路径,根据命令行参数指定
xmlfilepath =opt.xml_path

#设置输出txt标签文件的路径,根据命令行参数指定
txtsavepath =opt.txt_path

#获取XML文件夹中的所有XML文件列表
total_xml = os.listdir(xmlfilepath)

#如果输出txt标签文件的文件夹不存在,创建它
if not os.path.exists(txtsavepath):
    os.makedirs(txtsavepath)

#获取XML文件的总数
num = len(total_xml)

#创建一个包含所有XML文件索引的列表
list_index = range(num)

#计算训练验证集的数量
tv =int(num * trainval_percent)

#计算训练集的数量
tr =int(tv * train_percent)

#从所有XML文件索引中随机选择出训练验证集的索引
trainval=random.sample(list_index,tv)

#从训练验证集的索引中随机选择出训练集的索引
train =random.sample(trainval,tr)

#打开要写入的训练验证集、测试集、训练集、验证集的txt文件
file_trainval = open(txtsavepath + '/trainval.txt','w')
file_test = open(txtsavepath +'/test.txt','w')
file_train = open(txtsavepath +'/train.txt','w')
file_val = open(txtsavepath +'/val.txt','w')

#遍历所有XML文件的索引
for i in list_index:
    name = total_xml[i][:-4]+'\n'   #获取XML文件的名称(去掉后缀.xml),并添加换行符
    #如果该索引在训练验证集中
    if i in trainval:
        file_trainval.write(name)    #写入训练验证集txt文件
        if i in train:               #如果该索引在训练集中
            file_train.write(name)   #写入训练集txt文件
        else:
            file_val.write(name)     #否则写入验证集txt文件
    else:
        file_test.write(name)        #否则写入测试集txt文件
#关闭所有打开的文件
file_trainval.close()
file_train.close()
file_val.close()
file_test.close()

运行 split_train_val.py文件后将得到 train.txt、val.txt、test.txt 和trainval.txt 四个文件,结果如下:
在这里插入图片描述
注:如何修改数据集中训练集、验证集、测试集的比例? 请参考下图:
在这里插入图片描述
2、运行 voc label.py 文件
运行voc_label.py文件生成 train.txt、test.txt、val.txt 文件,先看看要生成的文件位置。
先看看我们要生成的文件位置:
在这里插入图片描述
要生成上面的三个文件,还需要有voc_label.py 文件,其位置如下:
在这里插入图片描述

voc_label.py的代码内容如下:

#-*- coding:utf-8 -*-

#导入必要的库
import xml.etree.ElementTree as ET
import os
from os import getcwd

#定义数据集的名称
sets =['train','val','test']

#请根据您的数据集修改这些类别名称
# 下面的两行代码,列表的里面的单词,除了首字母的大小写不一样,其他的是一样的,如果运行首字母是大写的代码,那么labels文件夹的txt文件的内容是空的,如果运行首字母是小写的代码,那么labels文件夹的txt文件的内容是有的,这很神奇,不知道原因是什么。
# classes =['Banana','Snake fruit','Dragon fruit','Pineapple']
classes = ["banana","snake fruit","dragon fruit","pineapple"]


#获取当前工作目录的绝对路径
abs_path = os.getcwd()
print(abs_path)

#定义一个函数,将边界框的坐标从绝对值转换为相对于图像大小的比例
def convert(size,box):
    dw = 1./(size[0])     #计算图像宽度的倒数
    dh = 1./(size[1])     #计算图像高度的倒数
    x = (box[0]+box[1])/2.0-1     #计算中心点的x坐标
    y = (box[2]+box[3])/2.0-1     # 计算中心点的y坐标
    w= box[1]- box[0]           # 计算边界框的宽度
    h = box[3] - box[2]         # 计算边界框的高度
    x = x * dw  # 缩放x坐标
    w = w * dw  # 缩放宽度
    y = y * dh  # 缩放y坐标
    h = h * dh  # 缩放高度
    return x, y, w, h

# 定义一个函数,将标注文件从XML格式转换为YOLO格式
def convert_annotation(image_id):
    in_file = open('./Annotations/%s.xml' % (image_id),encoding='UTF-8')  # 打开XML标注文件
    out_file = open('./labels/%s.txt'%(image_id),'w')   # 打开要写入的YOL0格式标签文件
    tree =ET.parse(in_file)     #解析XML文件
    root = tree.getroot()

    filename = root.find('filename').text  # 获取图像文件名
    filenameFormat=filename.split(".")[1]  # 获取文件格式

    size = root.find('size')  # 获取图像尺寸信息
    w = int(size.find('width').text)  # 获取图像宽度
    h = int(size.find('height').text)  #获取图像高度
    for obj in root.iter('object'):
        difficult = obj.find('difficult').text  # 获取对象的难度标志
        cls = obj.find('name').text #获取对象的类别名称
        if cls not in classes or int(difficult)== 1:
            continue
        cls_id = classes.index(cls)    # 获取类别的索引
        xmlbox = obj.find('bndbox')    # 获取边界框坐标信息
        b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text),float(xmlbox.find('ymax').text))
        b1,b2,b3,b4 = b
        # 标注越界修正
        if b2 > w:
            b2 = w
        if b4 > h:
            b4 = h
        b=(b1,b2,b3,b4)
        bb=convert((w,h),b)     #调用convert函数,将边界框坐标转换为Y0OLO格式
        out_file.write(str(cls_id)+" "+" ".join([str(a) for a in bb])+'\n')     #写入YOLO格式标签文件

    return filenameFormat


#获取当前工作目录
wd = getcwd()

#遍历每个数据集(train、val、test)
for image_set in sets:
    #如果labels目录不存在,创建它
    if not os.path.exists('./labels/'):
        os.makedirs('./labels/')
    #从数据集文件中获取图像ID列表
    image_ids = open('./ImageSets/Main/%s.txt'%(image_set)).read().strip().split()
    #打开要写入的文件,写入图像的文件路径和格式
    list_file =open('./%s.txt'%(image_set),'w')
    for image_id in image_ids:
        filenameFormat=convert_annotation(image_id)
        list_file.write(abs_path +'/images/%s.%s\n'%(image_id,filenameFormat)) #注意你的图片格式,如果是.jpg记得修改
    list_file.close()

运行 voc_label.py 文件,将会得到上面截图中 train.txt、test.txt、val.txt三个文件, train.txt文件内容如下:
在这里插入图片描述

3、创建 ab.yaml 文件
这个文件名是随意取的,这个可以做出改变的,ab.yaml 文件的位置如下:
在这里插入图片描述
ab.yaml 文件内容如下:

train: E:\\365-jinjieying\\YOLObaipishu\\Y7_YOLOv8_ultralytics-main\\paper_data\\train.txt     #这里需要换成绝对路径
val: E:\\365-jinjieying\\YOLObaipishu\\Y7_YOLOv8_ultralytics-main\\paper_data\\val.txt       #这里需要换成绝对路径


nc: 4   #number of classes,根据类别数目实际填写,本次训练的类别有4种

names: ["banana","snake fruit","dragon fruit","pineapple"]  #改成自己的类别

三、用自己的数据集训练模型的方法介绍

下面介绍两种方法来训练模型

1、命令行运行

命令行模版为:

yolo task=detect      mode=train       model=yolov8n.pt           args...
	      classify         predict           yolov8n-cls.yaml     args...
		  segment          val               yolov8n-seg.yaml     args...
		                   export            yolov8n.pt           format=onnx   args...

在项目工程的目录中打开CMD,并在CMD中输入以下的训练指令:

yolo task=detect mode=train model=yolov8s.yaml data=E:\365-jinjieying\YOLObaipishu\Y7_YOLOv8_ultralytics-main\paper_data\ab.yaml epochs=50 batch=4

2、自建train.py文件运行
train.py文件的代码如下:

from ultralytics import YOLO

if __name__ == '__main__':
    # Load a model
    model = YOLO("yolov8s.yaml")     # build a new model from scratch 2-ByK

    #Use the model
    model.train(data=r"E:\365-jinjieying\YOLObaipishu\Y7_YOLOv8_ultralytics-main\paper_data\ab.yaml",
                seed=0,
                epochs=200,
                batch=4,
                workers=2)

四、训练数据集
用“命令行运行”这个方法来训练数据集,本次的运行结果如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
五、训练参数设置(default.yaml)
在YOLOv8中,需要自己创建train.py文件,训练默认参数保存在 default.yaml 文件中,关键参数是可以在训练命令行 /train.py 文件中进行修改。这里就直接放配置文件。
文件路径: …\ultralytics-main\ultralytics\cfg\default.yaml

可以根据下面的代码和参数来修改训练命令行或者train.py文件里的代码和参数

#ultralytics YOLO,AGPL-3.0 许可证,由K同学啊注解
#默认的训练设置和超参数,用于中度增强 COC0 训练

task:detect  #(str)YOL0 任务,例如 detect、segment、classify、pose
mode:train   #(str)YOL0 模式,例如 train、val、predict、export、track、benchmark

# 训练设置-------------------------------------------
model:  #(str,可选)模型文件路径,例如yolov8n.pt、yolov8n.yaml
data:  #./paper data/ab.yaml #(str,可选) 数据文件路径,例如 coco128.yamldata:
epochs: 100 #(int)训练的轮次数
patience: 50 #(int)提前停止训练的等待周期数,如果没有明显的改进
batch: 1 #(int)每批处理的图像数量(-1 表示自动批处理)
imgsz: 640 #(int | list)输入图像的大小,以像素为单位,用于训练和验证模式,或以列表[w,h]形式用于预测和导出模式
save: True #(bool)保存训练检查点和预测结果
save_period: -1 #(int)每隔 x 个周期保存一个检査点(如果 <1 则禁用)
cache: False #(bool)使用缓存加载数据(True/ram、disk或False)
device: 0 #(int | str | list,可选)运行模型的设备,例如 cuda device=0 或 device=0,1,2,3 或 device=cpu
workers: 4 #(int)数据加载的工作线程数(每个 DDP 会有一个)
project: #(str,可选)项目名称
name: #(str,可选)实验名称,结果保存在project/name'目录下
exist_ok: False #(bool)是否覆盖现有的实验
pretrained: True #(bool| str)是否使用预训练模型(True 或加载权重的模型路径字符串)
optimizer: auto #(str)优化器选择,选项=[SGD、Adam、Adamax、AdamW、NAdam、RAdam、RMSProp、auto]
verbose: True #(bool)是否打印详细输出
seed: 0 #(int)随机种子,用于可重复性
deterministic: True #(bool)是否启用确定性模式
single_cls: False #(bool)是否将多类数据训练为单一类别
rect: False #(bool)如果模式='train',则进行矩形训练;如果模式='val',则进行矩形验证
cos_lr: False #(bool)是否使用余弦学习率调度器
close_mosaic: 10 #(int)在最后几个周期内禁用马赛克增强(0 表示禁用)
resume: False #(bool)是否从上次检查点恢复训练
amp: True #(bool)是否启用自动混合精度(AMP)训练,选项=[True,False],True 表示运行 AMP 检查
fraction: 1.0 #(float)训练集数据分数(默认为 1.0,使用训练集中的所有图像)
profile: False #(bool)在训练期间记录 ONNX 和 TensorRT 速度以供记录器使用
freeze: None #(int | list,可选)冻结前n层,或在训练期间冻结的层索引列表
# 分割
overlap_mask: True #(bool)训练期间是否允许蒙版重叠(仅适用于分割训练)
mask_ratio: 4 #(int)蒙版下采样比率(仅适用于分割训练)
#分类
dropout: 0.0 #(float)是否使用 dropout 正则化(仅适用于分类训练)

#验证/测试设置----------------------------------------
val: True #(boo1)训练期间是否进行验证/测试
split: val #(str)用于验证的数据集分制,例如 'val'、'test'或'train'
save_json: False #(bool)是否将结果保存为 JSON 文件
save_hybrid: False #(bool)是否保存标签的混合版本(标签 + 额外的预测)
conf    #(float,可选)用于检测的对象置信度阈值(默认 0.25 用于预测,0.001 用于验证)
iou: 0.7 #(float)NMS的交并比(IoU)阈值
max_det: 300 #(int)每张图像的最大检测数
half: False #(bool)是否使用半精度(FP16)
dnn: False #(bool)是否使用 OpenCV DNN 进行 ONNX 推理
plots: True #(bool)在训练/验证期间保存图形

# 预测设置-------------------------------------------
source:    #(str,可选)图像或视频的源目录
show: False #(bool)如果可能的话是否显示结果
save_txt: False #(bool)是否将结果保存为.txt 文件
save_conf: False #(bool)是否保存带有置信度分数的结果
save_crop: False #(bool)是否保存裁剪后的带有结果的图像
show_labels: True #(bool)是否在图形中显示对象标签
show_conf: True #(bool)是否在图形中显示对象置信度分数
vid_stride: 1 #(int)视频帧率跨度
stream_buffer: False #(bool)是否缓存所有流式帧(True)或返回最新的帧(False)
line_width:    #(int, 可选)边界框的线宽,如果缺失则自动设置
visualize: False #(bool)是否可视化模型特征
augment: False #(bool)是否对预测源应用图像增强
agnostic_nms: False #(bool)是否进行类别无关的 NMS
classes:    #(int | list[int],可选)按类别筛选结果,例如 classes=0,或 classes=[0,2,3]
retina_masks: False #(bool)是否使用高分辨率分割蒙版
boxes: True #(bool)在分割预测中显示边界框

#导出设置--------------------------------------------
format: torchscript #(str)导出格式,可选项请査看 https://docs.ultralytics.com/modes/export/#export-formats
keras: False #(bool)是否使用 Kera=s
optimize: False #(bool) Torchscript: 优化为移动设备
int8: False #(bool) CoreML/TF INT8 量化
dynamic: False #(bool)ONNX/TF/TensorRT: 动态轴
simplify: False #(bool) ONNX: 简化模型
opset:    #(int,可选)ONNX: opset版本
workspace: 4 #(int)TensorRT:工作空间大小(GB)
nms: False #(bool)CoreML:添加 NMS

# 超参数---------------------------------------------
lro: 0.01 #(float) 初始学习率(例如,SGD=1E-2,Adam=1E-3)
lrf: 0.01 #(float)最终学习率(1r0 *lrf)
momentum: 0.937 #(float)SGD 动量/Adam betal
weight_decay: 0.0005 #(float) 优化器权重衰减 5e-4
warmup_epochs: 3.0 #(float)预热周期数(分数也可以)
warmup_momentum: 0.8 #(float)预热初始动量
warmup_bias_lr: 0.1 #(float)预热初始偏置 lr
box: 7.5 #(float)目标框损失增益
cls: 0.5 #(float)类别损失增益(与像素一起缩放)
dfl: 1.5 #(float)DFL 损失增益
pose: 12.0 #(float)姿势损失增益
kobj: 1.0 #(float)关键点 obj 损失增益
label_smoothing: 0.0 #(float)标签平滑化(分数)
nbs: 64 #(int)名义批次大小
hsv_h: 0.015 #(float)图像 HSV-Hue 增强(分数)
hsv_s: 0.7 #(float)图像 HSV-Saturation 增强(分数)
hsv_v: 0.4 #(float)图像 HSV-Value 增强(分数)
degrees: 0.0 #(float)图像旋转( +/- 度)
translate: 0.1 #(float)图像平移( +/- 分数)
scale: 0.5 #(float)图像缩放( +/- 增益)
shear: 0.0 #(float)图像剪切( +/- 度)
perspective: 0.0 #(float)图像透视变换( +/- 分数),范围 0-0.001
flipud: 0.0 #(float)图像上下翻转(概率)
fliplr: 0.5 #(float)图像左右翻转(概率)
mosaic: 1.0 #(float)图像马赛克增强(概率)
mixup: 0.0 #(float)图像混合增强(概率)
copy_paste: 0.0 #(float)段复制粘贴(概率)

#自定义 config.yaml----------------------------------
cfg:    #(str,可选)用于覆盖默认.yaml 的自定义配置

#跟踪器设置------------------------------------------
tracker: botsort.yaml #(str)跟踪器类型,选项=[botsort.yaml, bytetrack.yaml]

六、总结
学分如何划分训练集、验证集与测试集,及获取训练集、验证集与测试集的路径,用两种方法训练自己的数据集,并能添加代码来调整自己的训练参数。

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

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

相关文章

快捷工具(提升工作效率)

文章目录 一、notepad++设置转json1.下载插件二、截图工具(可以将截图并粘贴到窗口)1.下载安装软件:snipaste三、idea 日志控制台查找日志1.idea 安装插件:Grep console四、beyond compare 4项目工程比较工具1.浏览器下载安装。本地运行五、xampp快速部署本地mysql,tomacat1.浏…

物体检测单阶段SSD

Faster RCNN 数据增广&#xff1a;

外包干了1个月,技术明显退步。。。

有一种打工人的羡慕&#xff0c;叫做“大厂”。 真是年少不知大厂香&#xff0c;错把青春插稻秧。 但是&#xff0c;在深圳有一群比大厂员工更庞大的群体&#xff0c;他们顶着大厂的“名”&#xff0c;做着大厂的工作&#xff0c;还可以享受大厂的伙食&#xff0c;却没有大厂…

Redislnsight-v2远程连接redis

redis安装内容添加&#xff1a; Linux 下使用Docker安装redis-CSDN博客 点击添加 添加ip地址&#xff0c;密码&#xff0c;端口号 创建完成 点击查看内容&#xff1a;

python初学者知识点笔记更新

文章目录 1.main函数入口2.__init__.py 文件作用3.from .applications import server解释4.变量没有修饰&#xff0c;直接创建使用1. 内置数据类型和函数2. 类和对象3.总结 5.mod app.__module__6.集合对比区分集合类型&#xff1a;混合集合类型 7.安装包失败 1.main函数入口 …

利用react和chainlit开发大模型结果人工评测平台

项目背景 利用LLM的prompt做了个简单的服务推荐助手&#xff0c;依据用户的提问找出合适的服务项目推荐给的用户。为了测评prompt的效果&#xff0c;使用reactchainlit开发了一个简单的效果测评平台。在该平台上&#xff0c;可以模拟用户向LLM发出问题&#xff0c;并对大模型返…

阿里通义音频生成大模型 FunAudioLLM 开源

简介 近年来&#xff0c;人工智能&#xff08;AI&#xff09;技术的进步极大地改变了人类与机器的互动方式&#xff0c;特别是在语音处理领域。阿里巴巴通义实验室最近开源了一个名为FunAudioLLM的语音大模型项目&#xff0c;旨在促进人类与大型语言模型&#xff08;LLMs&…

【过题笔记】 7.15

Array Without Local Maximums 算法&#xff1a;动态规划 简要思路&#xff1a; 考虑左边的数跟当前位置的关系&#xff0c;不难想到只有三种情况&#xff1a;大于&#xff0c;小于&#xff0c;等于。 于是可以得到状态 f [ i ] [ j ] [ 0 / 1 / 2 ] f[i][j][0/1/2] f[i][j][…

数据库的管理

目录 远程连接的方式 修改数据库uuid流程 数据库的概念 关系型数据库 非关系型数据库 关系型数据和非关系型数据库优缺点 mysql的数据类型 数据库的管理 sql中的名词 sql语言的分类 1.DDL&#xff1a;创建库和表的语句 create 2.DML: 插入数据 insert 修改和更…

内存函数(C语言)

内存函数 以下函数的头文件&#xff1a;string.h 针对内存块进行处理的函数 memcpy 函数原型&#xff1a; void* memcpy(void* destination, const void* source, size_t num);目标空间地址 源空间地址num&#xff0c;被拷贝的字节个数 返回目标空间的起始地…

STM32智能医疗监测系统教程

目录 引言环境准备智能医疗监测系统基础代码实现&#xff1a;实现智能医疗监测系统 4.1 数据采集模块 4.2 数据处理与控制模块 4.3 通信与网络系统实现 4.4 用户界面与数据可视化应用场景&#xff1a;医疗监测与管理问题解决方案与优化收尾与总结 1. 引言 智能医疗监测系统通…

RocketMQ源码学习笔记:Producer发送消息流程

这是本人学习的总结&#xff0c;主要学习资料如下 马士兵教育rocketMq官方文档 目录 1、Overview2、验证消息3、查找路由4、选择消息发送队列4.1、选择队列的策略4.2、源码阅读4.2.1、轮询规避4.2.2、故障延迟规避4.2.2.1、计算规避时间4.2.2.2、选择队列 4.2.3、ThreadLocal的…

正运动控制器:EtherCAT总线初始化

1、EtherCAT总线初始化的目的 运动控制器的EtherCAT 总线接口可用于连接 EtherCAT 伺服驱动器和 EtherCAT 扩展模块&#xff0c;无论连接什么模块&#xff0c; EtherCAT 总线都需要编写一段 EtherCAT 总线初始化程序来进行电机和 EtherCAT 扩展模块的使能。使能之后的应用与脉…

QT多线程下,信号槽分别在什么线程中执行,如何控制?

可以通过connect的第五个参数进行控制信号槽执行时所在的线程 connect有几种连接方式&#xff0c;直接连接、队列连接和 自动连接 直接连接&#xff08;Qt::DirectConnection&#xff09;&#xff1a;信号槽在信号发出者所在的线程中执行 队列连接&#xff08;Qt::QueuedConn…

LeetCode-返回链表倒数第K个节点、链表的回文结构,相交链表

一、返回链表倒数第k个节点 . - 力扣&#xff08;LeetCode&#xff09; 本体思路参展寻找中间节点的方法&#xff0c;寻找中间节点是定义快慢指针&#xff0c;快指针每次走两步&#xff0c;慢指针每次走一步&#xff0c;当快指针为空或者快指针的下一个节点是空时&#xff0c;…

vue实现提交时对不同板块的表单内容进行校验

需求 1、需要对第一个红色框框板块内所有带星号的地方进行校验&#xff0c;并将提示语显示到对应的输入框下面&#xff0c;如图&#xff1a; 2、第二个红色框框板块中&#xff0c;点击 “添加相关人员” 能实现对多人的添加功能&#xff0c;并且能绑定相对应的校验规则 3、在…

linux进行redis的安装并使用RDB进行数据迁移

现在有两台电脑&#xff0c;分别是A&#xff0c;B&#xff0c;现在我要把A电脑上的redis的数据迁移到B电脑上&#xff0c;B电脑上是没有安装redis的 1.找到A电脑的redis的版本 1.先启动A电脑的redis&#xff0c;一般来说&#xff0c;都是直接在linux的控制台输入&#xff1a;re…

数据结构与算法(1):递归函数的设计技巧

1.前言 哈喽小伙伴们大家好哦~从今天开始笔者就要开始正式学习数据结构与算法了&#xff0c;在这里写知识博客既是做一些学习笔记&#xff0c;又相当于给大家做知识分享咯&#xff0c;希望大家一起加油哦&#xff01; 2.正文 2.1递归的引入 在正式讲解递归之前&#xff0c;…

创建鸿蒙手机模拟器(HarmonyOS Emulator)

文 | Promise Sun 一.前提条件&#xff1a; 鸿蒙项目开发需要使用模拟器进行开发测试&#xff0c;但目前想在DevEco Studio开发工具中使用模拟器就必须到华为官网进行报名申请&#xff0c;参加“鸿蒙模拟器&#xff08;HarmonyOS Emulator&#xff09;Beta活动申请”。 申请审…

中间件的理解

内容来源于学习网站整理。【一看就会】什么是前端开发的中间件&#xff1f;_哔哩哔哩_bilibili 每日八股文~白话说mq&#xff0c;消息中间件_哔哩哔哩_bilibili 例如&#xff1a; 1&#xff09;两个人打电话&#xff0c;中间的通信网络就是中间件。 2&#xff09;菜鸟驿站&…