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

[保姆式教程]使用目标检测模型YOLO11 OBB进行旋转目标检测:训练自己的数据集(基于卫星和无人机的农业大棚数据集)

        之前写了一个基于YOLOv8做旋转目标检测(OBB)的文章,内容写得不够好,内容也有些杂乱无序。现如今YOLO已经更新到11了,数据集也集齐了无人机和卫星的农业大棚,所以这次就写一个基于YOLO11 OBB的农业大棚旋转检测。

1. 下载源码配置环境

        在https://github.com/ultralytics/ultralytics网页下载YOLO11源码,解压缩后创建虚拟环境即可,环境创建不是很难,这里就不细说了。

2. 数据集准备

2.1 数据标注

        这里我使用LabelImg2标注无人机和卫星影像,我是在一整张大幅影像上对影像中的农业大棚进行标注的,最后面使用算法将影像裁剪成合适的尺寸用于训练,后面会详细介绍整个流程。

 卫星影像中的农业大棚

无人机影像中的农业大棚

        在LabelImg2上标注好数据,LabelImg2标注是五点式,即旋转框的中心x,y坐标、旋转框的长度和宽度、旋转角度。如下图所示:

         从图中可以看到影像大小为 7176 X 5080 ,影像为RGB3通道,标注了两个旋转框,旋转框标签为默认的"dog"。

2.2 XML标注文件转DOTA格式标签文件(TXT)

       新建一个名为roxml_to_dota.py的python脚本,复制粘贴下面的代码:

# 文件名称   :roxml_to_dota.py
# 功能描述   :把rolabelimg标注的xml文件转换成dota能识别的xml文件,
#             再转换成dota格式的txt文件
#            把旋转框 cx,cy,w,h,angle,或者矩形框cx,cy,w,h,转换成四点坐标x1,y1,x2,y2,x3,y3,x4,y4
import os
import xml.etree.ElementTree as ET
import mathcls_list = ['dog']  # 修改为自己的标签def edit_xml(xml_file, dotaxml_file):"""修改xml文件:param xml_file:xml文件的路径:return:"""# dxml_file = open(xml_file,encoding='gbk')# tree = ET.parse(dxml_file).getroot()tree = ET.parse(xml_file)objs = tree.findall('object')for ix, obj in enumerate(objs):x0 = ET.Element("x0")  # 创建节点y0 = ET.Element("y0")x1 = ET.Element("x1")y1 = ET.Element("y1")x2 = ET.Element("x2")y2 = ET.Element("y2")x3 = ET.Element("x3")y3 = ET.Element("y3")# obj_type = obj.find('bndbox')# type = obj_type.text# print(xml_file)if (obj.find('robndbox') == None):obj_bnd = obj.find('bndbox')obj_xmin = obj_bnd.find('xmin')obj_ymin = obj_bnd.find('ymin')obj_xmax = obj_bnd.find('xmax')obj_ymax = obj_bnd.find('ymax')# 以防有负值坐标xmin = max(float(obj_xmin.text), 0)ymin = max(float(obj_ymin.text), 0)xmax = max(float(obj_xmax.text), 0)ymax = max(float(obj_ymax.text), 0)obj_bnd.remove(obj_xmin)  # 删除节点obj_bnd.remove(obj_ymin)obj_bnd.remove(obj_xmax)obj_bnd.remove(obj_ymax)x0.text = str(xmin)y0.text = str(ymax)x1.text = str(xmax)y1.text = str(ymax)x2.text = str(xmax)y2.text = str(ymin)x3.text = str(xmin)y3.text = str(ymin)else:obj_bnd = obj.find('robndbox')obj_bnd.tag = 'bndbox'  # 修改节点名obj_cx = obj_bnd.find('cx')obj_cy = obj_bnd.find('cy')obj_w = obj_bnd.find('w')obj_h = obj_bnd.find('h')obj_angle = obj_bnd.find('angle')cx = float(obj_cx.text)cy = float(obj_cy.text)w = float(obj_w.text)h = float(obj_h.text)angle = float(obj_angle.text)obj_bnd.remove(obj_cx)  # 删除节点obj_bnd.remove(obj_cy)obj_bnd.remove(obj_w)obj_bnd.remove(obj_h)obj_bnd.remove(obj_angle)x0.text, y0.text = rotatePoint(cx, cy, cx - w / 2, cy - h / 2, -angle)x1.text, y1.text = rotatePoint(cx, cy, cx + w / 2, cy - h / 2, -angle)x2.text, y2.text = rotatePoint(cx, cy, cx + w / 2, cy + h / 2, -angle)x3.text, y3.text = rotatePoint(cx, cy, cx - w / 2, cy + h / 2, -angle)# obj.remove(obj_type)  # 删除节点obj_bnd.append(x0)  # 新增节点obj_bnd.append(y0)obj_bnd.append(x1)obj_bnd.append(y1)obj_bnd.append(x2)obj_bnd.append(y2)obj_bnd.append(x3)obj_bnd.append(y3)tree.write(dotaxml_file, method='xml', encoding='utf-8')  # 更新xml文件# 转换成四点坐标
def rotatePoint(xc, yc, xp, yp, theta):xoff = xp - xc;yoff = yp - yc;cosTheta = math.cos(theta)sinTheta = math.sin(theta)pResx = cosTheta * xoff + sinTheta * yoffpResy = - sinTheta * xoff + cosTheta * yoffreturn str(int(xc + pResx)), str(int(yc + pResy))def totxt(xml_path, out_path):# 想要生成的txt文件保存的路径,这里可以自己修改files = os.listdir(xml_path)i = 0for file in files:tree = ET.parse(xml_path + os.sep + file)root = tree.getroot()name = file.split('.')[0]output = out_path + '\\' + name + '.txt'file = open(output, 'w')i = i + 1objs = tree.findall('object')for obj in objs:cls = obj.find('name').textbox = obj.find('bndbox')x0 = int(float(box.find('x0').text))y0 = int(float(box.find('y0').text))x1 = int(float(box.find('x1').text))y1 = int(float(box.find('y1').text))x2 = int(float(box.find('x2').text))y2 = int(float(box.find('y2').text))x3 = int(float(box.find('x3').text))y3 = int(float(box.find('y3').text))if x0 < 0:x0 = 0if x1 < 0:x1 = 0if x2 < 0:x2 = 0if x3 < 0:x3 = 0if y0 < 0:y0 = 0if y1 < 0:y1 = 0if y2 < 0:y2 = 0if y3 < 0:y3 = 0for cls_index, cls_name in enumerate(cls_list):if cls == cls_name:file.write("{} {} {} {} {} {} {} {} {} {}\n".format(x0, y0, x1, y1, x2, y2, x3, y3, cls, cls_index))file.close()# print(output)print(i)if __name__ == '__main__':# -----**** 第一步:把xml文件统一转换成旋转框的xml文件 ****-----roxml_path = r'D:\yolo11\data\origin_xml'  # labelimg2标注生成的原始xml文件路径dotaxml_path = r'D:\yolo11\data\dota_xml'  # 转换后dota能识别的xml文件路径,路径需存在,不然报错out_path = r'D:\yolo11\data\dota_txt'  # 转换后dota格式的txt文件路径,路径需存在,不然报错filelist = os.listdir(roxml_path)for file in filelist:edit_xml(os.path.join(roxml_path, file), os.path.join(dotaxml_path, file))# -----**** 第二步:把旋转框xml文件转换成txt格式 ****-----totxt(dotaxml_path, out_path)

        注意事项:小心修改文件路径,别搞错了,即

if __name__ == '__main__':# -----**** 第一步:把xml文件统一转换成旋转框的xml文件 ****-----roxml_path = r'D:\data\yolov8_obb\origin_xml'  # labelimg2标注生成的原始xml文件路径dotaxml_path = r'D:\data\yolov8_obb\dota_xml'  # 转换后dota能识别的xml文件路径,路径需存在,不然报错out_path = r'D:\data\yolov8_obb\dota_txt'  # 转换后dota格式的txt文件路径,路径需存在,不然报错filelist = os.listdir(roxml_path)for file in filelist:edit_xml(os.path.join(roxml_path, file), os.path.join(dotaxml_path, file))# -----**** 第二步:把旋转框xml文件转换成txt格式 ****-----totxt(dotaxml_path, out_path)

         下面是转换后的TXT格式的标签文件(此时的标签还不是YOLO OBB数据集的格式,还需要再转换)

2.3 标签更改

        我在标注的过程中使用的是LabelImg2软件中默认的标签名,即"dog"。在这里我使用代码将其中的标签修改为自己的标签,即"dp"。

        新建一个名为change_label.py的python文件,复制粘贴下面的代码:

import osdef replace_text_in_files(folder_path, old_text, new_text):# 遍历指定文件夹for filename in os.listdir(folder_path):# 检查文件是否是.txt文件if filename.endswith(".txt"):file_path = os.path.join(folder_path, filename)# 读取文件内容with open(file_path, 'r', encoding='utf-8') as file:file_data = file.read()# 替换文本updated_data = file_data.replace(old_text, new_text)# 写入更改后的内容with open(file_path, 'w', encoding='utf-8') as file:file.write(updated_data)# 调用函数,将'dog'替换为'dp'
replace_text_in_files(r'D:\yolo11\greenhouse\roxml_to_dota\xml_to_txt', 'dog', 'dp')

        下面是更改标签后的txtTXT文件内容:

2.4 DOTA格式标签文件转换为YOLO OBB训练所需的格式

(1)TIF格式影像(下载的卫星影像是tif格式)转换为PNG格式

        创建一个名为tif_to_png.py的python文件,复制粘贴下面的代码:

import os
import tifffile
from PIL import Image
import numpy as npdef tif2png_high_quality(tif_folder, png_folder):"""将tif文件夹中的所有tif图像转换为png图像,并尽可能保持图像质量。Args:tif_folder: 包含tif图像的文件夹路径。png_folder: 保存png图像的文件夹路径。"""if not os.path.exists(png_folder):os.makedirs(png_folder)for filename in os.listdir(tif_folder):if filename.endswith(".tif") or filename.endswith(".tiff"):tif_filepath = os.path.join(tif_folder, filename)png_filepath = os.path.join(png_folder, filename.replace(".tif", ".png").replace(".tiff", ".png"))try:# 使用tifffile库读取tif图像,可以更好地处理各种tif格式和元数据tif_image = tifffile.imread(tif_filepath)#  如果tif图像是多通道的,需要进行一些处理,例如转换为RGB图像或者分别保存每个通道if tif_image.ndim == 3 and tif_image.shape[2] > 3: #处理多波段图像,例如大于3个波段的遥感图像# 可以选择需要的波段合成RGB图像,或者保存所有波段为单独的png文件# 这里以合成RGB图像为例,假设前三个波段是RGB波段tif_image = tif_image[:,:,:3] # 取前三个波段tif_image = np.clip(tif_image, 0, 255).astype(np.uint8) # 裁剪像素值到0-255,并转换为uint8类型img = Image.fromarray(tif_image)elif tif_image.dtype == np.uint16: #16位图像处理,转换为8位img = Image.fromarray((tif_image / 256).astype(np.uint8))else: # 其他情况直接转换img = Image.fromarray(tif_image)# 使用 Pillow 库保存 png 图像, 可以指定更高的压缩质量img.save(png_filepath, "PNG", compress_level=1) # compress_level 1 表示最小压缩,质量最高print(f"已将 {tif_filepath} 转换为 {png_filepath}")except Exception as e:print(f"转换 {tif_filepath} 时出错: {e}")# 示例用法:
tif_folder = "tif_images"  # 替换为你的tif图像文件夹路径
png_folder = "png_images"  # 替换为你想保存png图像的文件夹路径
tif2png_high_quality(tif_folder, png_folder)

        设置好图像文件夹路径,将TIF图像转换为PNG格式的图像 

 (2)在项目代码目录下面创建下面的文件夹结构,然后将划分好的图像和标签文件放到相应的文件夹中 (这里我直接使用v8教程里面的图)

(3)编写转换标注格式的代码

        创建一个名为convert_dota_to_yolo_obb.py的python文件,复制粘贴下面的代码:

import sys
# yolo11源码文件夹
sys.path.append('D:\yolo11')from ultralytics.data.converter import convert_dota_to_yolo_obb
# 上一步骤中设置的文件夹结构根目录
convert_dota_to_yolo_obb('D:\yolo11\greenhouse\data')

        由于官方源码转换代码用的是VOC数据集,所以这里我们需要修改ultralytics/data/

converter.py中的类别名,改成自己的数据集类别名。修改ultralytics/data/converter.py中的代码:先注释掉原有的class_mapping代码,然后按照原有格式写入自己的类别,我的即为:

class_mapping = {"dp": 0,
}

        转换后的YOLO OBB数据集格式的标签会保存在labels\train和labels\val中(训练需要使用的就是这两个文件夹,train_original和val_original用不到)

        转换后的OBB数据集格式的标签文件中的内容

2.5 png格式影像裁剪

       在项目代码目录下面创建下面的文件夹结构,然后将OBB格式的标签文件和对应的图像放到相应的文件夹中 (labels里面的train_original和val_original文件夹不需要,不用创建这两个文件夹,截图里面多余了)

        创建一个名为split_images.py的python文件,复制粘贴下面的代码:

from ultralytics.data.split_dota import split_test, split_trainval# 分割训练集和验证集,同时包含标签。标签需要是YOLO格式的,
# 即:0 0.332813 0.164062 0.403125 0.15 0.45 0.373437 0.379688 0.389062
#
# @param data_root str,数据根目录的路径。
# @param save_dir str,保存分割后数据集的目录路径。
# @param rates list,用于设定不同尺度分割比例的列表,例如[0.5, 1.0, 1.5]表示三个尺度。
# @param gap int,设定在数据集中间隔多少个像素进行一次分割。
split_trainval(data_root=r"D:\yolo11\datasets",save_dir=r"D:\yolo11\DOTAv1.0-split",rates=[0.5, 1.0, 1.5],  # multiscalegap=100,
)# 分割测试集,不包含标签。
#
# @param data_root str,数据根目录的路径。
# @param save_dir str,保存分割后数据集的目录路径。
# @param rates list,用于设定不同尺度分割比例的列表,例如[0.5, 1.0, 1.5]表示三个尺度。
# @param gap int,设定在数据集中间隔多少个像素进行一次分割。
split_test(data_root=r"D:\yolo11\datasets",save_dir=r"D:\yolo11\DOTAv1.0-split",rates=[0.5,1.0, 1.5],  # multiscalegap=100,

        裁剪的图像尺寸可以在split_dota里面修改,可以修改成自己需要的,比如说1280,1024,

960,768,640等等。如果设置裁剪大小为640 x 640,那么rates中的0.5代表图像大小为320 X 320,1.5代表图像大小为960 X 960。建议设置合适的多尺度图像大小用于训练和验证,这样泛化性能可能会好一些。rates可以设置为[0.3, 1.0, 1.3]。

        运行代码之后裁剪的图像和对应的标注文件会在DOTAv1.0-split文件夹中。要查看裁剪得到了多少张图像,可以直接看DOTAv1.0-split\labels里面对应的文件夹,看DOTAv1.0-split\images是难以知道的,因为images里面包含了有标签的图像和没有标签的图像。

        这里我其实有点疑惑,我原本是想把所有图像裁剪了再划分数据集,但是这里按照ultralytics里面的代码意思,似乎是先将所有的大幅影像先划分为训练影像、验证影像和测试影像,裁剪之后即是对应的数据集,但是先将所有的大幅影像先划分为训练影像、验证影像和测试影像的做法似乎不太科学,因为这样的话每个数据集中的图像差异可能比较大,这样训练得到的结果可能泛化性并不好。我觉得可能不如统一裁剪之后随机划分数据集的做法,个人目前比较粗浅的看法。。。

2.6 挑选有标签的图像

        上一步骤中裁剪得到的图像数量和标签数量是不匹配的,因为有些没有标签的图像没有舍弃掉。所有这里需要写个算法将有标签的图像挑选出来,与标签一一对应。

        创建一个名为pick_images.py的python文件,复制粘贴下面的代码:

import os
import shutil# 裁剪得到的标签的文件夹
labels_dir = r'D:\yolo11\DOTAv1.0-split\labels\train'
# 裁剪得到图像的文件夹
images_dir = r'D:\yolo11\DOTAv1.0-split\images\train'
# 存放挑选出来的图像的文件夹
pick_dir = r'D:\yolo11\DOTAv1.0-split\images\pick'# 确保 pick_dir 存在
os.makedirs(pick_dir, exist_ok=True)# 获取 labels_dir 下的所有 .txt 文件
label_files = [f for f in os.listdir(labels_dir) if f.endswith('.txt')]for label_file in label_files:# 提取文件名(不包括扩展名)base_name = os.path.splitext(label_file)[0]# 构建对应的图像文件路径image_jpg_path = os.path.join(images_dir, base_name + '.jpg')image_png_path = os.path.join(images_dir, base_name + '.png')# 检查是否存在对应的图像文件if os.path.exists(image_jpg_path):# 复制图像文件到 pick_dirshutil.copy(image_jpg_path, pick_dir)print(f"已复制 {image_jpg_path} 到 {pick_dir}")elif os.path.exists(image_png_path):# 复制图像文件到 pick_dirshutil.copy(image_png_path, pick_dir)print(f"已复制 {image_png_path} 到 {pick_dir}")else:print(f"未找到与 {label_file} 对应的图像文件")

2.7 数据集划分

        先构建好文件夹结构,文件夹结构如下(用的YOLOv8中的图,所有图像放在img文件夹下,所有txt放在dotatxt文件夹下),至于文件夹为什么是这样的结构我现在还不懂。。。

        使用下面的代码划分数据集

import os
import random
import shutilrandom.seed(42)"""
该脚本用于将给定的数据集分割成训练集和测试集。
数据集应包含图像和对应的标注文件。
脚本会按照90%训练集和10%测试集的比例进行分割,并将图像和标注文件分别复制到相应的文件夹中。
"""# 设置数据集文件夹路径和输出文件夹路径
data_folder = 'data_mouse_ro'
img_folder = 'data_mouse_ro/dataset/images'
label_folder = 'data_mouse_ro/dataset/labels'# 计算每个子集的大小
# 总文件数乘以0.9得到训练集大小,其余为测试集大小
total_files = len(os.listdir(os.path.join(data_folder, 'img')))
train_size = int(total_files * 0.9)
test_size = int(total_files - train_size)# 获取所有图像文件的文件名列表,并进行随机打乱
image_files = os.listdir(os.path.join(data_folder, 'img'))
random.shuffle(image_files)# 复制图像和标注文件到相应的子集文件夹中
# 枚举每个图像文件,根据索引决定复制到训练集还是测试集文件夹
for i, image_file in enumerate(image_files):base_file_name = os.path.splitext(image_file)[0]  # 获取文件名(不包括扩展名)image_path = os.path.join(data_folder, 'img', image_file)label_path = os.path.join(data_folder, 'dotatxt', base_file_name + '.txt')# 根据索引判断文件应复制到训练集还是测试集if i < train_size:shutil.copy(image_path, os.path.join(img_folder, 'train'))  # 复制图像到训练集shutil.copy(label_path, os.path.join(label_folder, 'train_original'))  # 复制标注到训练集else:shutil.copy(image_path, os.path.join(img_folder, 'val'))  # 复制图像到测试集shutil.copy(label_path, os.path.join(label_folder, 'val_original'))  # 复制标注到测试集

3. 模型配置

(1)新建模型配置文件my-data-obb.yaml

        在yolo11\ultralytics\cfg\datasets路径下,新建my-data-obb.yaml文件(复制粘贴其中某一个yaml文件改个名字),写入如下代码,其中参数根据自己的情况设置

# Ultralytics YOLO 🚀, AGPL-3.0 license
# COCO 2017 dataset https://cocodataset.org by Microsoft
# Documentation: https://docs.ultralytics.com/datasets/detect/coco/
# Example usage: yolo train data=coco.yaml
# parent
# ├── ultralytics
# └── datasets
#     └── coco  ← downloads here (20.1 GB)# Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..]
path: datasets # dataset root dir
train: images/train # train images (relative to 'path') 118287 images
val: images/val # val images (relative to 'path') 5000 images
test: images/val # 20288 of 40670 images, submit to https://competitions.codalab.org/competitions/20794# Classes----我的数据集类别只有一个,即dp----
names:0: dp

(2)修改模型配置文件yolo11-obb.yaml

        在yolo11\ultralytics\cfg\models\11路径下,修改yolo11-obb.yaml文件,将nc参数修改为自己的数据集类别数。我听别的博主说这里不改没有关系,会根据前面设置的my-data-obb.yaml文件修改。

4. 训练

(1)根据自己的实际情况修改yolo11\ultralytics\cfg\default.yaml文件中的训练参数

        训练参数设置

        下面是其他的参数设置

        验证、测试参数设置

        推理参数设置

       可视化参数设置

        导出参数设置

        超参数设置

(2)运行下面的代码即可开始训练(路径和参数根据自己的情况设置)

        不使用权重进行训练

from ultralytics import YOLO# Load a model
model = YOLO("/home/jun/object_detect/yolo11/ultralytics/cfg/models/11/yolo11-obb.yaml")# Train the model
train_results = model.train(data="/home/jun/object_detect/yolo11/ultralytics/cfg/datasets/my-data-obb.yaml",  # path to dataset YAMLepochs=1400,  # number of training epochsbatch=4,workers=0,amp=False,imgsz=640,  # training image sizedevice="0",  # device to run on, i.e. device=0 or device=0,1,2,3 or device=cpupretrained=False,verbose=True,optimizer="AdamW",
)# Evaluate model performance on the validation set
metrics = model.val()

        使用权重进行训练(这里就不需要模型配置文件yolo11-obb.yaml了,除非你修改了模型结构)

from ultralytics import YOLO# Load a model-----这里直接加载权重文件
model = YOLO("yolo11n-obb.pt")# Train the model
train_results = model.train(data="/home/jun/object_detect/yolo11/ultralytics/cfg/datasets/my-data-obb.yaml",  # path to dataset YAMLepochs=1400,  # number of training epochsbatch=4,workers=0,amp=False,imgsz=640,  # training image sizedevice="0",  # device to run on, i.e. device=0 or device=0,1,2,3 or device=cpupretrained=False,verbose=True,optimizer="AdamW",
)# Evaluate model performance on the validation set
metrics = model.val()

5. 验证

        在yolo11目录下创建一个名为val.py的脚本,复制粘贴下面的代码,其中的参数根据自己的情况设置

from ultralytics import YOLO# Load a model----加载自己训练好的权重
model = YOLO("yolo11n-obb.pt")# Customize validation settings
validation_results = model.val(data="my-data-obb.yaml", imgsz=640, batch=16, conf=0.25, iou=0.6, device="0")metrics.box.map  # map50-95
metrics.box.map50  # map50
metrics.box.map75  # map75
metrics.box.maps  # a list contains map50-95 of each category

6. 推理

        在yolo11目录下创建一个名为predict.py的脚本,复制粘贴下面的代码,其中的参数根据自己的情况设置

from ultralytics import YOLO# Load a model
model = YOLO("yolo11n-obb.pt")  # pretrained YOLO11n model# Run batched inference on a list of images
results = model(["image1.jpg", "image2.jpg"])  # return a list of Results objects
# results = model("path/to/your/images")  # 这里可以直接放文件夹路径,会推理完里面的全部图像# Process results list
for result in results:boxes = result.boxes  # Boxes object for bounding box outputsmasks = result.masks  # Masks object for segmentation masks outputskeypoints = result.keypoints  # Keypoints object for pose outputsprobs = result.probs  # Probs object for classification outputsobb = result.obb  # Oriented boxes object for OBB outputsresult.show()  # display to screen# result.save(filename="result.jpg")  # save to disk

        模型配置、训练、验证、推理的更多细节可以阅读ultralytics的官方文档,里面会有详细的说明。

        农业大棚无人机图像234张,卫星图像999张,两者数量不均衡,总体数量也不用够多,下次会解决这些问题。

        这只是一个篇分享经验的文章,难免有错误或者遗漏的地方,欢迎交流指正。

PS:

这里插播一下RT-DETR模型的训练代码:

from ultralytics import RTDETR# Load a COCO-pretrained RT-DETR-l model
model = RTDETR("/home/jun/yolo11/ultralytics/cfg/models/rt-detr/rtdetr-resnet50.yaml")# Display model information (optional)
model.info()# Train the model
train_results = model.train(data="/home/jun/yolo11/ultralytics/cfg/datasets/my-data.yaml",  # path to dataset YAMLepochs=1400,  # number of training epochsbatch=4,amp=False,workers=0,imgsz=640,  # training image sizedevice="0",  # device to run on, i.e. device=0 or device=0,1,2,3 or device=cpupretrained=False,verbose=True,optimizer="AdamW",
)# Evaluate model performance on the validation set
metrics = model.val()

相关文章:

[保姆式教程]使用目标检测模型YOLO11 OBB进行旋转目标检测:训练自己的数据集(基于卫星和无人机的农业大棚数据集)

之前写了一个基于YOLOv8做旋转目标检测&#xff08;OBB&#xff09;的文章&#xff0c;内容写得不够好&#xff0c;内容也有些杂乱无序。现如今YOLO已经更新到11了&#xff0c;数据集也集齐了无人机和卫星的农业大棚&#xff0c;所以这次就写一个基于YOLO11 OBB的农业大棚旋转检…...

MySQL 权限管理分配详解

MySQL 权限管理分配详解 MySQL权限系统的工作原理权限表的存取用户通过权限认证、进行权限分配的流程账号管理我们常用的授权all privileges到底有哪些权限呢&#xff1f;以及带来的安全隐患有哪些&#xff1f;创建账户的时候最好分配指定的权限&#xff0c;这样子安全也高管理…...

【期末速成】《微机原理与接口技术》知识点总结

文章目录 前言第一、二章 接口技术概述1. 接口的定义*2. 接口功能特点*3. 接口的分类*4. 接口中的传输信息及其组成5. 接口的编址与译码*6. CPU 与外设之间的数据传送方式* 第三章 总线1. 总线&#xff08;BUS&#xff09;的定义*2. 总线的标准3. 采用标准总线的优点*4. 总线的…...

华为、华三交换机纯Web下如何创关键VLANIF、操作STP参数

华为交换机WEB操作 使用的是真机S5735&#xff0c;目前主流的版本都适用&#xff08;V1R5~V2R1的就不在列了&#xff0c;版本太老了&#xff0c;界面完全不一样&#xff0c;这里调试线接的console口&#xff0c;电脑的网络接在ETH口&#xff09; 「模拟器、工具合集」复制整段内…...

【Elasticsearch】初始化默认字段及分词

1、添加分词插件 1&#xff09;在线安装 执行命令 需要指定相同的版本 bin/elasticsearch-plugin.bat install https://get.infini.cloud/elasticsearch/analysis-ik/7.17.24 2&#xff09;离线安装 将安装包解压到 /plugins 目录下 安装包可以从对应的资源处下载 启动成…...

asdf-java配置

asdf list all java 无结果 asdf list all java 显示结果 No compatible versions available 解决方案 参考 执行 cp ~/.asdf/plugins/java/data/jdk-macosx-x86_64-ga.tsv $TMPDIR/asdf-java-$(whoami).cache/releases-macosx-x86_64.tsv 在此执行 asdf list all java 就可…...

2-2-18-14 QNX系统架构之 TCP/IP 网络

阅读前言 本文以QNX系统官方的文档英文原版资料为参考&#xff0c;翻译和逐句校对后&#xff0c;对QNX操作系统的相关概念进行了深度整理&#xff0c;旨在帮助想要了解QNX的读者及开发者可以快速阅读&#xff0c;而不必查看晦涩难懂的英文原文&#xff0c;这些文章将会作为一个…...

RabbitMQ延迟消息的实现

RabbitMQ延迟队列的实现 延迟消息是什么延迟消息的实现死信交换机代码实现 延迟消息插件 延迟消息是什么 延迟消息是将消息发送到MQ中&#xff0c;消费者不会立即收到消息&#xff0c;而是过一段时间之后才会收到消息&#xff0c;进行处理。在一些业务中&#xff0c;可以用到延…...

Docker 安装 中文版 GitLab

Docker 安装系列 安装GitLab、解决服务器内存不足问题、使用域名/IP地址访问项目 1、拉取 [rootTseng ~]# docker pull twang2218/gitlab-ce-zh:latest latest: Pulling from twang2218/gitlab-ce-zh 8ee29e426c26: Pull complete 6e83b260b73b: Pull complete e26b65fd11…...

Ubuntu22.04深度学习环境安装【Anaconda+Pycharm】

anaconda可以提供多个独立的虚拟环境&#xff0c;方便我们学习深度学习&#xff08;比如复现论文&#xff09;&#xff1b; Pycharm编辑器可以高效的编写python代码&#xff0c;也是一个很不错的工具。 下面就记录下Ubuntu22.04的安装流程&#xff1a; 1.Anaconda安装 下载Ana…...

springboot整合canal

学习链接 Cannal项目地址 SpringBoot整合Canal实现数据同步到ElasticSearch - 原文地址 Spring Boot整合canal实现数据一致性解决方案解析-部署实战 Java&#xff1a;SpringBoot整合Canal实现数据同步 docker环境安装mysql、canal、elasticsearch&#xff0c;基于binlog利…...

8.在 Vue 3 中使用 OpenLayers 加载天地图示例(多种形式)

前言 OpenLayers 是一个强大的开源地图框架&#xff0c;可以轻松实现地图加载与操作。而 Vue 3 则通过 Composition API 提供了更加简洁和灵活的开发体验。本文将介绍如何在 Vue 3 中结合 OpenLayers 实现对天地图的加载&#xff0c;包括矢量地图、卫星地图以及中文和英文标记等…...

如何设置 Java 开发环境

如果你在这里&#xff0c;可能是想学习如何为 Java 开发设置环境。第一步是安装 SDK&#xff08;软件开发工具包&#xff09;&#xff0c;它是一组由硬件和软件供应商提供的工具和库。 对于 Java&#xff0c;我们使用 JDK&#xff08;Java 开发工具包&#xff09;。JDK 是一组…...

MetaGPT 安装

1. 创建环境 conda create -n metagpt python3.10 && conda activate metagpt2. 可编辑方式安装 git clone --depth 1 https://github.com/geekan/MetaGPT.git cd MetaGPT pip install -e .3. 配置 metagpt --init-config运行命令&#xff0c;在C盘位置C:\Users\325…...

石岩湿地公园的停车场收费情况

周末石岩湿地公园停车场【967个】小车停车费封顶14元价格还行&#xff0c;我还记得2020年的时候湿地公园还是10元一天封顶。现在的收费情况也是可以的&#xff0c;尤其是周末停车比工作日停车便宜还是很得民心的哈。 车型 收费标准 小车 工作日 高峰时间8:00~20:00 首小时…...

v3账号密码登录随机图片验证码

安装插件 pnpm i identify --save图形验证码组件 <template><div class"s-canvas"><!-- 图形验证码的宽和高都来自于父组件的传值&#xff0c;若父组件没有传值&#xff0c;那么就按当前子组件的默认值进行渲染 --><canvas id"s-canvas&…...

mysql8 主从复制一直失败

问题描述&#xff1a; 开启同步后从服务器一直失败&#xff0c;报错如下&#xff1a; Last_SQL_Error: Coordinator stopped because there were error(s) in the worker(s). The most recent failure being: Worker 1 failed executing transaction ANONYMOUS at source log …...

Java项目实战II基于微信小程序的消防隐患在线举报系统(开发文档+数据库+源码)

目录 一、前言 二、技术介绍 三、系统实现 四、核心代码 五、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 随着城市化进程的加快&…...

【第二十四周】从大语言模型到多模态大模型的发展

摘要 大语言模型&#xff08;Large Language Model, LLM&#xff09;是指一类基于深度学习的人工智能系统&#xff0c;它们被设计用来理解和生成自然语言。这些模型通常是在大量的文本数据上进行训练的&#xff0c;通过学习文本中的模式和结构&#xff0c;它们能够执行各种各样…...

深入理解Java的 JIT(即时编译器)

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/literature?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;…...

数据库技术文档撰写:全方位剖析

在技术的浩瀚海洋中&#xff0c;一份优秀的技术文档宛如精准的航海图。它是知识传承的载体&#xff0c;是团队协作的桥梁&#xff0c;更是产品成功的幕后英雄。然而&#xff0c;打造这样一份出色的技术文档并非易事。你是否在为如何清晰阐释复杂技术而苦恼&#xff1f;是否纠结…...

设计模式之原型模式:深入浅出讲解对象克隆

~犬&#x1f4f0;余~ “我欲贱而贵&#xff0c;愚而智&#xff0c;贫而富&#xff0c;可乎&#xff1f; 曰&#xff1a;其唯学乎” 原型模式概述 在我们的日常生活中&#xff0c;经常会遇到"复制"这样的场景。比如我们在准备文件时&#xff0c;常常会复印一份原件&a…...

centos 查看版本

在 CentOS 中&#xff0c;查看系统版本有多种方法。以下是几种常用的方法&#xff1a; 方法 1&#xff1a;使用 cat 命令查看 /etc/centos-release 文件 cat /etc/centos-release 这个文件包含了 CentOS 的版本信息。例如&#xff0c;输出可能是&#xff1a; CentOS Linux rel…...

如何本地存储中的文件路径

文章目录 1. 概念介绍2. 实现方法3. 示例代码我们在上一章回中介绍了"如何实现本地存储"相关的内容,本章回中将介绍如何实现文件存储.闲话休提,让我们一起Talk Flutter吧。 1. 概念介绍 我们在上一章回中介绍的本地存储只能存储dart语言中基本类型的数值,如果遇到…...

服务器加固

1.服务器密码复杂度 密码最小长度&#xff0c;密码复杂度策略 vim /etc/pam.d/system-auth --------------- #密码配置 #ucredit&#xff1a;大写字母个数&#xff1b;lcredit&#xff1a;小写字母个数&#xff1b;dcredit&#xff1a;数字个数&#xff1b;ocredit&#xff1a;…...

MongoDB change stream实战

什么是 Chang Stream Change Stream指数据的变化事件流&#xff0c;MongoDB从3.6版本开始提供订阅数据变更的功能。 Change Stream 是 MongoDB 用于实现变更追踪的解决方案&#xff0c;类似于关系数据库的触发器&#xff0c;但原理不完全相同&#xff1a; Change Stream 的实…...

TSWIKI知识库软件

TSWIKI 知识库软件介绍 推荐一个适合本地化部署、自托管的知识库软件 TSWIKI介绍 tswiki 是一个适合小团队、个人的知识库、资料管理的软件&#xff0c;所有数据均本地化存储。可以本地化、私有云部署&#xff0c;安装简单。在线预览。 主要功能说明 1、简化的软件依赖和安…...

【Linux课程学习】第十九弹---深入理解进程间通信---匿名管道,命名管道,多匿名管道的BUG

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;Linux课程学习 &#x1f337;追光的人&#xff0c;终会万丈光芒 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 ​ Linux学习笔记&#xff1a; https://blog.csdn.n…...

【C语言】库函数常见的陷阱与缺陷(1):字符串处理函数

目录 一、 strcpy 函数 1.1. 功能与常见用法 1.2. 陷阱与缺陷 1.3. 安全替代 1.4. 代码示例 二、strcat 函数 2.1. 功能与常见用法 2.2. 陷阱与缺陷 2.3. 安全替代 2.4. 代码示例 三、strcmp 函数 3.1. 功能与常见用法 3.2. 陷阱与缺陷 3.3. 安全替代 3.4. 代…...

Qt中的 tableView 设置 二进制 十六进制 序号表头

二 进制序号 因为QTableView的垂直表头并不支持使用委托来自定义。 相反&#xff0c;可以通过将自定义的QWidget作为QHeaderView的标签来实现这一目标。 代码&#xff1a; #include <QApplication> #include <QMainWindow> #include <QVBoxLayout> #include …...

leetCode121.买卖股票的最佳时机

题目&#xff1a; 给定一个数组prices,它的第i个元素prices[i]表示一支给定股票第i天的价格。 你只能选择某一天买入这只股票&#xff0c;并选择在未来的某一个不同的日子卖出该股票。设计一个算法来计算你所能获取的最大利润。 返回你可以从这笔交易中获取的最大利润。如果你…...

基于单片机的自限位电机正反转控制电路

【摘要】 针对减速直流电机正反转和停转控制问题,设计了正反转及自限位控制电路,编制了基于STM8S103单片机的控制电机正反转及自限位的子程序,并应用IAR软件进行仿真,搭建实验装置验证设计效果,实验结果表明所设计控制电路能够良好地控制电机正转、反转和停转,在生活实际…...

为什么使用 Token 而不是 Cookie 来管理用户认证和会话

使用 Token 而不是 Cookie 来管理用户认证和会话的原因主要有以下几点&#xff1a; 跨域问题 (Cross-Domain) Token&#xff1a;通常是存储在客户端的 localStorage 或 sessionStorage 中&#xff0c;不会自动随请求发送到服务器&#xff0c;这使得它在处理跨域请求时更加灵活…...

WIDER FACE数据集转YOLO格式

1. 引出问题 本人最近在做毕设相关内容&#xff0c;第一阶段目标是通过目标检测来统计课堂人数&#xff0c;因此需要对人脸和人头进行目标检测。模型方面没什么好说的无脑用YOLO&#xff0c;数据集方面&#xff0c;人脸部分找到了来自港中文的WIDER FACE数据集。但是解压后发现…...

机器学习概述详解

文章目录 机器学习概述详解一、引言二、机器学习基础1、机器学习定义及应用场景2、监督学习与无监督学习 三、机器学习开发流程四、使用示例1、LeNet网络结构代码示例2、AlexNet网络结构代码示例 五、总结 机器学习概述详解 一、引言 机器学习作为人工智能的一个重要分支&…...

VTK编程指南<三>:基于VTK入门程序解析来理解VTK基础知识

1、VTK入门程序 下面是一个完整的Vtk入门程序&#xff0c;我们基于这个程序来对VTK的基本知识进行一个初步了解。 #include <iostream>#include <vtkAutoInit.h> VTK_MODULE_INIT(vtkRenderingOpenGL2);// VTK was built with vtkRenderingOpenGL2 VTK_MODULE_INI…...

【UE5 C++课程系列笔记】07——使用定时器实现倒计时效果

使用定时器实现如下倒计时效果 效果 步骤 1. 新建一个Actor类&#xff0c;这里命名为“CountDownTimerActor” 2. 在头文件中先定义倒计时时间和更新剩余时间的函数方法 前向声明一个文本渲染组件 3. 在源文件中引入文本渲染组件 创建文本渲染组件并进行一些设置 实现Update…...

基于DDPM的PyTorch简单实现

基于DDPM的PyTorch简单实现 文章目录 基于DDPM的PyTorch简单实现摘要Abstract一、DDPM实现1. 获取数据集2. DDPM类3. 训练算法4. 去噪神经网络5. 实验结果与采样 总结 摘要 本周的学习与实践围绕扩散模型&#xff08;Diffusion Model&#xff09;的基础理论和实现展开&#xf…...

php laravel 学习管理系统(LMS)

Lernen LMS&#xff08;学习管理系统&#xff09;是一个综合性的在线教育平台&#xff0c;旨在为学生和导师提供灵活、高效、便捷的学习体验。该系统不仅帮助学生找到最适合自己的导师&#xff0c;还通过一系列强大的功能&#xff0c;提升了课程安排、学习管理和师生互动的效率…...

【JAVA】Java高级:数据库监控与调优:SQL调优与执行计划的分析

作为Java开发工程师&#xff0c;理解SQL调优和执行计划的分析是至关重要的。这不仅可以帮助我们提高数据库查询的效率&#xff0c;还能减少系统资源的消耗&#xff0c;提升整体应用的性能。 1. SQL调优的重要性 随着数据量的增加和用户请求的增多&#xff0c;数据库的性能问题…...

centos9升级OpenSSH

需求 Centos9系统升级OpenSSH和OpenSSL OpenSSH升级为openssh-9.8p1 OpenSSL默认为OpenSSL-3.2.2&#xff08;根据需求进行升级&#xff09; 将源码包编译为rpm包 查看OpenSSH和OpenSSL版本 ssh -V下载源码包并上传到服务器 openssh最新版本下载地址 wget https://cdn.openb…...

jeccg-boot修改密码

最近在使用jeccg-boot框架&#xff0c;遇到一个需要批量修改用户密码的问题 由于框架使用的是加密盐算法生成的密码 &#xff0c;无法直接通过数据库修改密码 例如将password字段和salt值复制过去&#xff0c;密码是不对的 查看代码发现通过user.getUsername(), user.getPasswo…...

linux 生成 nginx 的https ssl 证书详解

证书生成 1. 生成证书 会提示输入密码&#xff0c;输入两次相同密码即可。 openssl genrsa -des3 -out server.key 20482. 去除密码校验 如果想去除此输密码的步骤&#xff0c;可以执行如下命令&#xff0c;根据使用需求选择。 openssl rsa -in server.key -out server.ke…...

详细介绍vue的递归组件(重要)

递归组件在 Vue 中是一个非常强大的概念&#xff0c;尤其在渲染层级结构&#xff08;如树形结构、嵌套列表、评论系统等&#xff09;时&#xff0c;能够极大地简化代码。 什么是递归组件&#xff1f; 递归组件就是一个组件在其模板中引用自身。这种做法通常用于渲染树形结构或…...

gitlab配置调试minio

官方文档 rails console 调试 查看配置Settings.uploads.object_store加载minio clientrequire fog/awsfog_connection Fog::Storage.new(provider: AWS,aws_access_key_id: 你的MINIO_ACCESS_KEY,aws_secret_access_key: 你的MINIO_SECRET_KEY,region: <S3 region>,e…...

Docker(Nginx) 部署 uniapp

目录 一、准备工作 1.Docker安装nginx 2.安装HBuild X工具 二、HBuild X打包项目 1.在HBuild X导入项目 2.配置manifest.json 3.打包 &#xff08;1&#xff09;点击发行 &#xff08;2&#xff09;填写信息&#xff0c;点击发行 三、nginx部署uniapp 1.生成文件上传…...

Camp4-L2:LMDeploy 量化部署进阶实践

书生浦语大模型实战营第四期&#xff1a;LMDeploy 量化部署进阶实践 教程链接&#xff1a;https://github.com/InternLM/Tutorial/tree/camp4/docs/L2/LMDeploy视频链接&#xff1a;https://www.bilibili.com/video/BV18aUHY3EEG/?vd_sourceb96c7e6e6d1a48e73edafa36a36f1697…...

第二十四周学习周报

目录 摘要Abstract1. 文献阅读1.1 RNN1.2 Deep Recurrent Neural Networks1.3 实验1.4 讨论 2. AI虚拟主播生成总结 摘要 本周的主要任务是阅读了一篇关于循环神经网络的论文&#xff0c;该论文旨在探索将RNN扩展到深度RNN的不同方法。论文通过对RNN结构的理解和分析&#xff…...

深入解析 Android PMS —— APK 安装与解析全流程

文章目录 前言1. PMS 的初始化1.1 SystemServer 启动 PMS1.2 PMS 的入口方法 main1.3 PMS 构造函数1.4 扫描 APK 文件1.5 权限初始化1.6 提供对外服务 2. APK 安装机制2.1. 安装请求的触发2.2 APK 文件解析与验证2.3 签名校验2.4 权限管理2.4.1 权限声明2.4.2 权限校验与分配 2…...

RL仿真库pybullet

1. 介绍 PyBullet是一个基于Bullet Physics引擎的物理仿真Python接口&#xff0c;主要用于机器人仿真模拟。 1.1 主要特点 提供大量预设的机器人模型&#xff0c;例如URDF(统一机器人描述格式)、SDF、MJCF 格式。适用于训练和评估强化学习算法&#xff0c;提供了大量的强化学…...