Yolov5 v7.0目标检测——详细记录环境配置、自定义数据处理、模型训练与常用错误解决方法(数据集为河道漂浮物)

news2024/11/16 19:34:31

1. Yolov5

YOLOv5是是YOLO系列的一个延伸,其网络结构共分为:input、backbone、neck和head四个模块,yolov5对yolov4网络的四个部分都进行了修改,并取得了较大的提升,在input端使用了Mosaic数据增强、自适应锚框计算、自适应图片缩放; 在backbone端使用了Focus结构与CSP结构;在neck端添加了FPN+PAN结构;在head端改进了训练时的损失函数,使用GIOU_Loss,以及预测框筛选的DIOU_nms。

YOLOv5是一种单阶段目标检测算法,该算法在YOLOv4的基础上添加了一些新的改进思路,使其速度与精度都得到了极大的性能提升。主要的改进思路如下所示:

  • input:Mosaic数据增强、自适应锚框计算、自适应图片缩放;
  • backbone:Focus结构与CSP结构;
  • neck:添加了FPN+PAN结构;
  • head:改进了训练时的损失函数,使用GIOU_Loss,以及预测框筛选的DIOU_nms。

1.1 网络结构

在这里插入图片描述yolov5的网络结构如上图所示,yolo系列的算法基本可以分为四个模块,input、neck和head。下面对着4个模块依次进行分析。

1.2 input

输入端主要对输入的图片进行预处理。该网络的输入图像大小为608×608,预处理主要是将输入图像缩放到网络的输入大小,并进行归一化等操作。在网络训练阶段,YOLOv5使用Mosaic数据增强操作提升模型的训练速度和网络的精度;并提出了一种自适应锚框计算自适应图片缩放方法。

Mosaic数据增强:Mosaic数据增强方法采用了4张图片,按照随机缩放、随机裁剪和随机排布的方式进行拼接而成,这种增强方法可以将几张图片组合成一张,这样不仅可以丰富数据集的同时极大的提升网络的训练速度,而且可以降低模型的内存需求。

自适应锚框计算:在YOLO系列算法中,针对不同的数据集,都需要设定特定长宽的Anchor。在网络训练阶段,模型在初始锚点框的基础上输出对应的预测框,计算其与真实框之间的差距,并执行反向更新操作,从而更新整个网络的参数,因此设定初始锚点框也是比较关键的一环。YOLOv5模型在每次训练时,根据数据集的名称自适应的计算出最佳的锚点框。

自适应图片缩放:传统的缩放方式都是按原始比例缩放图像并用黑色填充至目标大小,由于在实际的使用中的很多图片的长宽比不同,因此缩放填充之后,两端的黑边大小都不相同,然而如果填充的过多,则会存在大量的信息冗余,从而影响整个算法的推理速度。为了进一步提升YOLOv5算法的推理速度,该算法提出一种方法能够自适应的添加最少的黑边到缩放之后的图片中。具体的实现步骤如下所述:

  1. 根据原始图片大小与输入到网络图片大小计算缩放比例;
  2. 根据原始图片大小与缩放比例计算缩放后的图片大小;
  3. 计算黑边填充数值,该黑边数值不要求一定使图像缩放至指定大小,而是自适应模型中卷积和池化的大小。

1.3 backbone

主干网络部分主要引入了focus结构CSP结构

focus结构

Focus重要的是切片操作,如下图所示,4x4x3的图像切片后变成2x2x12的特征图。
在这里插入图片描述
在yolov5网络模型中,原始608x608x3的图像输入Focus结构,采用切片操作,先变成304x304x12的特征图,再经过一次32个卷积核的卷积操作,最终变成304x304x32的特征图。

CSP结构
yolov4网络结构中,借鉴了CSPNet的设计思路,仅仅在主干网络中设计了CSP结构。而yolov5中设计了两种CSP结构,CSP1_X结构应用于主干网络中,另一种CSP2_X结构则应用于Neck网络中。

neck

yolov5的Neck网络仍然使用了FPN+PAN结构,但是在它的基础上做了一些改进操作,yolov4的Neck结构中,采用的都是普通的卷积操作。而YOLOv5的Neck网络中,采用借鉴CSPnet设计的CSP2结构,从而加强网络特征融合能力。

head

在head部分,yolov5改进了损失函数,采用GIoU_Lossounding box的损失函数并添加了预测框筛选的DIOU_nms,这两个点并不是yolov5的原创内容,如果想深入了解可以参考相关论文,这里不再赘述。

而v7.0版本最重要的更新是增加了对实例分割的支持,主要的更新了实例分割的代码,提高了分割的精度与速度。这个版本也许是Yolov5的最后一次更新了,就目前的消息,YOLOv5团队已经转向了YOLOv8的更新,因此,7.0版本大概率是YOLOv5的最终稳定版。

整个代码与数据下载地址:https://download.csdn.net/download/matt45m/89215063

2.环境安装

2.1 创建虚拟环境

我这里使用Anaconda创建虚拟环境,conda可以从清华源下载。下载自己想要的版本,这里是我用的版本:
在这里插入图片描述
安装完成之后创建环境:

conda create --name yolov5 python==3.10
activate yolov5

这里建议单独安装pytorch,torch要对应自己电脑的cuda版本进行安装,我这里使用的cuda是11.7,cudnn 8.5,单独安装torch的命令可以在torch官网可以获取:
在这里插入图片描述

conda install pytorch==2.0.0 torchvision==0.15.0 torchaudio==2.0.0 pytorch-cuda=11.7 -c pytorch -c nvidia

2.2 下载源码

在激活的环境下把源码拉取,如果拉取不了,可以直接下载源码包:
在这里插入图片描述

git clone https://github.com/ultralytics/yolov5.git

然后更改yolov5源码里面的requirements.txt文件,把这两行注掉:
在这里插入图片描述
安装所需的依赖:

cd yolov5
pip install -r requirements.txt

哪里安装过程中出错,就查看安装错误库,单独安装或者使用源码安装。

3.数据集处理

这里使用的数据是河道水面的漂浮物,数据总共有5000多张,使用的标注工具是Labelme。
在这里插入图片描述

3.1数据标注

标注的格式可以选voc或者是yolo格式,如果选择voc的格式,则要转换,这里使用的voc数据格式,标注如下:
在这里插入图片描述

在这里插入图片描述

3.2 数据转换

数据如果是xml格式,则要把数据转换成txt格式,在yolov5目录下,创建一个dataset目录,然后把标注好的数据集的数像和xml标签文件在这个目录下:
在这里插入图片描述

然后在yolov5目录下创建一个xml_txt.py文件,脚本代码如下:

import os
import glob
import argparse
import random
import xml.etree.ElementTree as ET
from PIL import Image
from tqdm import tqdm

def get_all_classes(xml_path):
    xml_fns = glob.glob(os.path.join(xml_path, '*.xml'))
    class_names = []
    for xml_fn in xml_fns:
        tree = ET.parse(xml_fn)
        root = tree.getroot()
        for obj in root.iter('object'):
            cls = obj.find('name').text
            class_names.append(cls)
    return sorted(list(set(class_names)))

def convert_annotation(img_path, xml_path, class_names, out_path):
    output = []
    im_fns = glob.glob(os.path.join(img_path, '*.jpg'))
    for im_fn in tqdm(im_fns):
        if os.path.getsize(im_fn) == 0:
            continue
        xml_fn = os.path.join(xml_path, os.path.splitext(os.path.basename(im_fn))[0] + '.xml')
        if not os.path.exists(xml_fn):
            continue
        img = Image.open(im_fn)
        height, width = img.height, img.width
        tree = ET.parse(xml_fn)
        root = tree.getroot()
        anno = []
        xml_height = int(root.find('size').find('height').text)
        xml_width = int(root.find('size').find('width').text)
        if height != xml_height or width != xml_width:
            print((height, width), (xml_height, xml_width), im_fn)
            continue
        for obj in root.iter('object'):
            cls = obj.find('name').text
            if cls not in class_names:
                continue
            cls_id = class_names.index(cls)
            # print(cls_id)
            xmlbox = obj.find('bndbox')
            xmin = int(xmlbox.find('xmin').text)
            ymin = int(xmlbox.find('ymin').text)
            xmax = int(xmlbox.find('xmax').text)
            ymax = int(xmlbox.find('ymax').text)
            cx = (xmax + xmin) / 2.0 / width
            cy = (ymax + ymin) / 2.0 / height
            bw = (xmax - xmin) * 1.0 / width
            bh = (ymax - ymin) * 1.0 / height
            anno.append('{} {} {} {} {}'.format(cls_id, cx, cy, bw, bh))
        if len(anno) > 0:
            output.append(im_fn)
            with open(im_fn.replace('.jpg', '.txt'), 'w') as f:
                f.write('\n'.join(anno))
    # random.shuffle(output)
    # train_num = int(len(output) * 0.9)
    # with open(os.path.join(out_path, 'train.txt'), 'w') as f:
    #     f.write('\n'.join(output[:train_num]))
    # with open(os.path.join(out_path, 'val.txt'), 'w') as f:
    #     f.write('\n'.join(output[train_num:]))



def parse_args():
    parser = argparse.ArgumentParser('generate annotation')
    parser.add_argument('--img_path', default='dataset/Trash/images', type=str, help='input image directory')
    parser.add_argument('--xml_path', default='dataset/Trash/xml',type=str, help='input xml directory')
    parser.add_argument('--out_path',default='Trash/', type=str, help='output directory')
    args = parser.parse_args()
    return args

if __name__ == '__main__':
    args = parse_args()
    class_names = get_all_classes(args.xml_path)
    convert_annotation(args.img_path, args.xml_path, class_names, args.out_path)

运行完成之后,会在images目录下生成与图像同名的.txt文件:
在这里插入图片描述

4.数据处理

4.1 数据分割

训练之后要对数据集进行分割,一般都要分为训练集,验证集,测试集,一般按8:1:1的分法。在yolov5根目录下创建data_splitting.py脚本,脚本代码如下:

import os
import random
from shutil import move

# 指定原始目录
source_dir = 'dataset/Trash/images'

# 创建子目录:训练集、验证集和测试集
sub_dirs = ['train', 'val', 'test']
for sub_dir in sub_dirs:
    os.makedirs(os.path.join(source_dir, sub_dir), exist_ok=True)

# 收集所有.jpg和对应的.txt文件
jpg_files = {f for f in os.listdir(source_dir) if f.lower().endswith('.jpg')}
txt_files = {f[:-4] + '.txt' for f in jpg_files}  # 假设.txt文件名是去掉.jpg后缀的.jpg文件名

# 将.jpg和.txt文件映射成字典,以.jpg文件名为键
all_files = jpg_files.union(txt_files)
file_dict = {f: os.path.join(source_dir, f) for f in all_files}

# 随机打乱文件列表
random.shuffle(list(file_dict.keys()))

# 根据给定的比例分配文件到不同的目录
total_files = len(file_dict)
split1 = int(total_files * 0.8)  # 训练集的文件数量
split2 = int(total_files * 0.9)  # 验证集的文件数量

# 训练集
train_files = list(file_dict.keys())[:split1]
# 验证集
val_files = list(file_dict.keys())[split1:split2]
# 测试集
test_files = list(file_dict.keys())[split2:]

# 移动文件到相应的子目录
for files, sub_dir in ((train_files, 'train'), (val_files, 'val'), (test_files, 'test')):
    for file in files:
        source_path = file_dict[file]
        dest_dir = os.path.join(source_dir, sub_dir)
        dest_path = os.path.join(dest_dir, file)

        # 确保目标子目录中包含对应的.jpg和.txt文件
        if file.endswith('.jpg'):
            move(source_path, dest_path)  # 移动.jpg文件
            txt_file = file[:-4] + '.txt'
            if txt_file in file_dict:
                txt_source_path = file_dict[txt_file]
                move(txt_source_path, dest_dir)  # 移动对应的.txt文件

print("文件分配完成。")

运行完成之后,会下images下生成三个目录:
在这里插入图片描述
目录里面有对应的图像与txt标签文件:
在这里插入图片描述

4.2 处理数据

在dataset/Trash目录下创建一个lables文件,然后把上面生成三个目录train, val, test复制一份到labels目录里面:
在这里插入图片描述
把images下的三个目录里面的.txt文件删掉,只保留.jpg文件。
然后再把labels下的三个目录里面的.jpg文件删除掉只保留.txt文件。

4.3 创建数据配置文件

在yolov5/data目录下创建一个trash_data.yaml
添加以下内容:

path: ./dataset/Trash # dataset root dir
train: images/train # train images (relative to 'path') 128 images
val: images/val # val images (relative to 'path') 128 images
test: test

# Classes
names:
  0: trash

最终数据目录结构如下:
在这里插入图片描述

5.模型训练

5.1 模型训练

训练代码配置:

def parse_opt(known=False):
    """Parses command-line arguments for YOLOv5 training, validation, and testing."""
    parser = argparse.ArgumentParser()
    parser.add_argument("--weights", type=str, default=ROOT / "yolov5s.pt", help="initial weights path")
    parser.add_argument("--cfg", type=str, default="", help="model.yaml path")
    parser.add_argument("--data", type=str, default=ROOT / "data/coco128.yaml", help="dataset.yaml path")
    parser.add_argument("--hyp", type=str, default=ROOT / "data/hyps/hyp.scratch-low.yaml", help="hyperparameters path")
    parser.add_argument("--epochs", type=int, default=100, help="total training epochs")
    parser.add_argument("--batch-size", type=int, default=16, help="total batch size for all GPUs, -1 for autobatch")
    parser.add_argument("--imgsz", "--img", "--img-size", type=int, default=640, help="train, val image size (pixels)")
    parser.add_argument("--rect", action="store_true", help="rectangular training")
    parser.add_argument("--resume", nargs="?", const=True, default=False, help="resume most recent training")
    parser.add_argument("--nosave", action="store_true", help="only save final checkpoint")
    parser.add_argument("--noval", action="store_true", help="only validate final epoch")
    parser.add_argument("--noautoanchor", action="store_true", help="disable AutoAnchor")
    parser.add_argument("--noplots", action="store_true", help="save no plot files")
    parser.add_argument("--evolve", type=int, nargs="?", const=300, help="evolve hyperparameters for x generations")
    parser.add_argument(
        "--evolve_population", type=str, default=ROOT / "data/hyps", help="location for loading population"
    )
    parser.add_argument("--resume_evolve", type=str, default=None, help="resume evolve from last generation")
    parser.add_argument("--bucket", type=str, default="", help="gsutil bucket")
    parser.add_argument("--cache", type=str, nargs="?", const="ram", help="image --cache ram/disk")
    parser.add_argument("--image-weights", action="store_true", help="use weighted image selection for training")
    parser.add_argument("--device", default="", help="cuda device, i.e. 0 or 0,1,2,3 or cpu")
    parser.add_argument("--multi-scale", action="store_true", help="vary img-size +/- 50%%")
    parser.add_argument("--single-cls", action="store_true", help="train multi-class data as single-class")
    parser.add_argument("--optimizer", type=str, choices=["SGD", "Adam", "AdamW"], default="SGD", help="optimizer")
    parser.add_argument("--sync-bn", action="store_true", help="use SyncBatchNorm, only available in DDP mode")
    parser.add_argument("--workers", type=int, default=8, help="max dataloader workers (per RANK in DDP mode)")
    parser.add_argument("--project", default=ROOT / "runs/train", help="save to project/name")
    parser.add_argument("--name", default="exp", help="save to project/name")
    parser.add_argument("--exist-ok", action="store_true", help="existing project/name ok, do not increment")
    parser.add_argument("--quad", action="store_true", help="quad dataloader")
    parser.add_argument("--cos-lr", action="store_true", help="cosine LR scheduler")
    parser.add_argument("--label-smoothing", type=float, default=0.0, help="Label smoothing epsilon")
    parser.add_argument("--patience", type=int, default=100, help="EarlyStopping patience (epochs without improvement)")
    parser.add_argument("--freeze", nargs="+", type=int, default=[0], help="Freeze layers: backbone=10, first3=0 1 2")
    parser.add_argument("--save-period", type=int, default=-1, help="Save checkpoint every x epochs (disabled if < 1)")
    parser.add_argument("--seed", type=int, default=0, help="Global training seed")
    parser.add_argument("--local_rank", type=int, default=-1, help="Automatic DDP Multi-GPU argument, do not modify")

    # Logger arguments
    parser.add_argument("--entity", default=None, help="Entity")
    parser.add_argument("--upload_dataset", nargs="?", const=True, default=False, help='Upload data, "val" option')
    parser.add_argument("--bbox_interval", type=int, default=-1, help="Set bounding-box image logging interval")
    parser.add_argument("--artifact_alias", type=str, default="latest", help="Version of dataset artifact to use")

    # NDJSON logging
    parser.add_argument("--ndjson-console", action="store_true", help="Log ndjson to console")
    parser.add_argument("--ndjson-file", action="store_true", help="Log ndjson to file")

    return parser.parse_known_args()[0] if known else parser.parse_args()

更改yolov5/models/yolov5s.yaml文件,把nc类别改成自己数据类别数目,这里只有一个类别,所以是1:

# YOLOv5 🚀 by Ultralytics, AGPL-3.0 license

# Parameters
nc: 1 # number of classes
depth_multiple: 0.33 # model depth multiple
width_multiple: 0.50 # layer channel multiple
anchors:
  - [10, 13, 16, 30, 33, 23] # P3/8
  - [30, 61, 62, 45, 59, 119] # P4/16
  - [116, 90, 156, 198, 373, 326] # P5/32

# YOLOv5 v6.0 backbone
backbone:
  # [from, number, module, args]
  [
    [-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
    [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
    [-1, 3, C3, [128]],
    [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
    [-1, 6, C3, [256]],
    [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
    [-1, 9, C3, [512]],
    [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
    [-1, 3, C3, [1024]],
    [-1, 1, SPPF, [1024, 5]], # 9
  ]

# YOLOv5 v6.0 head
head: [
    [-1, 1, Conv, [512, 1, 1]],
    [-1, 1, nn.Upsample, [None, 2, "nearest"]],
    [[-1, 6], 1, Concat, [1]], # cat backbone P4
    [-1, 3, C3, [512, False]], # 13

    [-1, 1, Conv, [256, 1, 1]],
    [-1, 1, nn.Upsample, [None, 2, "nearest"]],
    [[-1, 4], 1, Concat, [1]], # cat backbone P3
    [-1, 3, C3, [256, False]], # 17 (P3/8-small)

    [-1, 1, Conv, [256, 3, 2]],
    [[-1, 14], 1, Concat, [1]], # cat head P4
    [-1, 3, C3, [512, False]], # 20 (P4/16-medium)

    [-1, 1, Conv, [512, 3, 2]],
    [[-1, 10], 1, Concat, [1]], # cat head P5
    [-1, 3, C3, [1024, False]], # 23 (P5/32-large)

    [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
  ]

运行命令:

python train.py --img 640 --batch 8 --epochs 150 --data ./data/trash_data.yaml --cfg ./models/yolov5s.yaml --weights yolov5s.pt
  • –img 640 #训练图像大小
  • –batch 8 #批次大小,如果GPU够大,可以改成更大,这里2的倍数,如果报显存报错,则改小
  • –epochs 150 #迭代次数
  • –data ./data/trash_data.yaml #数据配置文件
  • –cfg ./models/yolov5s.yaml #模型配置文件
  • –weights yolov5s.pt #第一次运动会下载这个权重文件,如果下载其间报错,可以手动下载放到指定目录,然后指定模型路径

手动模型下载地址

在这里插入图片描述
开始训练:
在这里插入图片描述

5.2 训练结果

训练完成之后,会在yolov5/run目录下看找到训练的结果:
在这里插入图片描述
可以看到验证结果:
在这里插入图片描述

7.常见错误解决

7.1 解决错误:RuntimeError: result type Float can‘t be cast to the desired output type __int64

原因:
原因是新版本的torch无法自动执行转换,旧版本torch可以。

解决方法:
将utils/loss.py中gain = torch.ones(7, device=targets.device)改为gain = torch.ones(7, device=targets.device).long()即可。

7.2 AttributeError: module ‘numpy‘ has no attribute ‘float‘

原因:
这是numpy版本过高的原因,降低numpy版本就可以

解决方法:

pip uninstall numpy
pip install numpy==1.23.5

7.3 AssertionError:Label class 1 exceeds nc=1 in yolo/dataset.ymal Possible class labels are 0-0

原因:
这是因为训练类型只有一个的原因。

解决方法:
找到train.py文件中这一行代码,注释掉。

assert mlc < nc, f'Label class {mlc} exceeds nc={nc} in {data}. Possible class labels are 0-{nc - 1}'

注释后:

#assert mlc < nc, f'Label class {mlc} exceeds nc={nc} in {data}. Possible class labels are 0-{nc - 1}'

assert nf > 0 or not augment, f’{prefix}No labels found in {cache_path}, can not start training. {HELP_URL}’
AssertionError: train: No labels found in

7.4 No labels found in (Done) 或者 Exception: Dataset not found

原因:
这是数据目录没有对上的原因。就是代码无法找到lables目录里面的文件。

解决方法:
​数据集详细参考4.3节的格式。

7.5 Could not run ‘torchvision::nms’ with arguments from the ‘CUDA’ backend (Done)

原因:

因为CUDA与torch版本不匹配造成的,当前版本:

环境、工具版本
CUDA11.3
torch1.13.1+cu116
torchvision0.14.1

解决方法:
降低torch版本解决。

pip install torch==1.9.0+cu111 torchvision==0.10.0+cu111 torchaudio===0.9.0 -f https://download.pytorch.org/whl/torch_stable.html -i https://pypi.douban.com/simple

更换版本后的各个环境工具版本:

环境、工具版本
CUDA11.3
torch1.9.0+cu111
torchvision0.10.0+cu111

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

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

相关文章

鸿蒙云函数调试坑点

如果你要本地调试请使用 const {payload, action} event.body/** 本地调试不需要序列化远程需要序列化 */ // const {payload, action} JSON.parse(event.body) const {payload, action} event.body 注意: 只要修改云函数&#xff0c;必须上传云函数 如果使用 const {pay…

牛客NC98 判断t1树中是否有与t2树完全相同的子树【simple 深度优先dfs C++/Java/Go/PHP】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/4eaccec5ee8f4fe8a4309463b807a542 思路 深度优先搜索暴力匹配 思路和算法这是一种最朴素的方法——深度优先搜索枚举 s 中的每一个节点&#xff0c;判断这个点的子树是否和 t 相等。如何判断一个节点的子树是否…

HTTP/1.1,HTTP/2.0和HTTP/3.0 各版本协议的详解(2024-04-24)

1、HTTP介绍 HTTP 协议有多个版本&#xff0c;目前广泛使用的是 HTTP/1.1 和 HTTP/2&#xff0c;以及正在逐步推广的 HTTP/3。 HTTP/1.1&#xff1a;支持持久连接&#xff0c;允许多个请求/响应通过同一个 TCP 连接传输&#xff0c;减少了建立和关闭连接的消耗。 HTTP/2&#…

基于STM32和阿里云的智能台灯(STM32+ESP8266+MQTT+阿里云+语音模块)

一、主要完成功能 1、冷光模式和暖光模式两种灯光 主要支持冷光和暖光模式两种&#xff0c;可以通过语音模块或手机app远程切换冷暖光 2、自动模式和手动模式 主要支持手动模式和自动两种模式&#xff08;app或语音助手切换&#xff09; (1)自动模式&#xff1a;根据环境光照…

vscode 使用文件模板功能来添加版权信息

vscode 新建文件的时候&#xff0c;自动填充作者及版权信息 无需使用插件&#xff0c;操作如下&#xff1a; 选择 “首选项(Preferences)”。在搜索框中输入 “file template” 或者 “文件模板”&#xff0c;然后选择相关的设置项。 {"C_Cpp.clang_format_fallbackSt…

[lesson58]类模板的概念和意义

类模板的概念和意义 类模板 一些类主要用于存储和组织数据元素 类中数据组织的方式和数据元素的具体类型无关 如&#xff1a;数组类、链表类、Stack类、Queue类等 C中将模板的思想应用于类,使得类的实现不关注数据元素的具体类型,而只关注类所需要实现的功能。 C中的类模板…

Docker 开启远程安全访问

说明 如果你的服务器是公网IP&#xff0c;并且开放了docker的远程访问&#xff0c;如果没有进行保护是非常危险的&#xff0c;任何人都可以向你的docker中推送镜像、运行实例。我曾开放过阿里云服务器中docker的远程访问权限&#xff0c;在没有开启保护的状态下&#xff0c;几…

企业微信hook接口协议,根据手机号搜索联系人

根据手机号搜索联系人 参数名必选类型说明uuid是String每个实例的唯一标识&#xff0c;根据uuid操作具体企业微信 请求示例 {"uuid":"3240fde0-45e2-48c0-90e8-cb098d0ebe43","phoneNumber":"1357xxxx" } 返回示例 {"data&q…

抖音 小程序 获取手机号 报错 getPhoneNumber:fail auth deny

这是因为 当前小程序没有获取 手机号的 权限 此能力仅支持小程序通过试运营期后可用&#xff0c;默认获取权限&#xff0c;无需申请&#xff1b; https://developer.open-douyin.com/docs/resource/zh-CN/mini-app/develop/guide/open-capabilities/acquire-phone-number-acqu…

用斐波那契数列感受算法的神奇(21亿耗时0.2毫秒)

目录 一、回顾斐波那契数列 二、简单递归方法 &#xff08;一&#xff09;解决思路 &#xff08;二&#xff09;代码展示 &#xff08;三&#xff09;性能分析 三、采用递归HashMap缓存 &#xff08;一&#xff09;解决思路 &#xff08;二&#xff09;代码展示 &…

深度学习系列65:数字人openHeygen详解

1. 主流程分析 从inference.py函数进入&#xff0c;主要流程包括&#xff1a; 1&#xff09; 使用cv2获取视频中所有帧的列表&#xff0c;如下&#xff1a; 2&#xff09;定义Croper。核心代码为69行&#xff1a;full_frames_RGB, crop, quad croper.crop(full_frames_RGB)。…

公开课学习——基于索引B+树精准建立高性能索引

文章目录 遇到慢查询怎么办&#xff1f;—— 创建索引联合索引的底层的数据存储结构长什么样&#xff1f; mysql脑图 阿里开发手册 遇到慢查询怎么办&#xff1f;—— 创建索引 不用索引的话一个一个找太慢了&#xff0c;用索引就快的多。 假如使用树这样的结构建立索引&#x…

Spring - 3 ( 12000 字 Spring 入门级教程 )

一&#xff1a;Spring Web MVC入门 1.1 响应 在我们前⾯的代码例子中&#xff0c;都已经设置了响应数据, Http 响应结果可以是数据, 也可以是静态页面&#xff0c;也可以针对响应设置状态码, Header 信息等. 1.2 返回静态页面 创建前端页面 index.html(注意路径) html代码 …

frp 实现 http / tcp 内网穿透(穿透 wordpress )

frp 实现 http / tcp 内网穿透&#xff08;穿透 wordpress &#xff09; 1. 背景简介与软件安装2. 服务端配置2.1 配置文件2.2 wordpress 配置文件2.3 frps 自启动 3.客户端配置3.1 配置文件3.2 frpc 自启动 同步发布在个人笔记frp 实现 http / tcp 内网穿透&#xff08;穿透 w…

HZNUCTF -- web

HZNUCTF第五届校赛实践赛初赛 Web方向 WriteUp-CSDN博客 ezssti 下载文件 访问 /login 可由源代码中看到 Eval 函数 &#xff0c;可以任意命令执行 按照格式&#xff0c;可执行命令 POST &#xff1a;name{{.Eval "env"}} 可以得到flag &#xff08;尝试ls 只能列出…

就业班 第三阶段(负载均衡) 2401--4.19 day3

二、企业 keepalived 高可用项目实战 1、Keepalived VRRP 介绍 keepalived是什么keepalived是集群管理中保证集群高可用的一个服务软件&#xff0c;用来防止单点故障。 ​ keepalived工作原理keepalived是以VRRP协议为实现基础的&#xff0c;VRRP全称Virtual Router Redundan…

微软发布Phi-3 Mini,性能媲美GPT-3.5、Llama-3,可在手机端运行

前言 微软发布了最新版的Phi系列小型语言模型(SLM) - Phi-3。这个系列包括3个不同参数规模的版本&#xff1a;Phi-3 Mini (38亿参数)、Phi-3 Small (70亿参数)和Phi-3 Medium (140亿参数)。 Phi系列模型是微软研究团队开发的小规模参数语言模型。从第一代Phi-1到第二代Phi-2&…

kubebuilder(3)实现operator

在前面的文章我们已经了解了operator项目的基本结构。现在我们来写一点简单的代码&#xff0c;然后把我们的crd和operator部署到k8s集群中。 需求 这是一个真实的需求&#xff0c;只不过做了简化。 在开发公司自己的paas平台&#xff0c;有一个需求是&#xff0c;用户在发版…

【Linux高性能服务器编程】两种高性能并发模式剖析——领导者/追随者模式

hello &#xff01;大家好呀&#xff01; 欢迎大家来到我的Linux高性能服务器编程系列之两种高性能并发模式介绍&#xff0c;在这篇文章中&#xff0c;你将会学习到高效的创建自己的高性能服务器&#xff0c;并且我会给出源码进行剖析&#xff0c;以及手绘UML图来帮助大家来理解…

RK3588S和ARM阵列服务器在虚拟化云平台的应用

RK3588是瑞芯微2021年底推出的首款高端8nm旗舰芯片&#xff0c;而RK3588S 则是针对消费端市场在RK3588基础上缩减了部分外围接口&#xff0c;CPU、GPU和NPU等主要参数得到了保留&#xff0c;主要应用范围为高端ARM平板、ARM笔电产品&#xff0c;会议平板类、ARM服务器、智能机器…