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

【yolov5】yolov5训练自己的数据集全流程----包含本人设计的快速数据处理脚本

关于yolo应用时能用到的脚本集合,推荐收藏:
https://chenlinwei.blog.csdn.net/article/details/127299428

1. 工程化快速yolo训练流程指定版(无讲解)

1.1 抽样数据集+xml转txt+输出量化分析

python make_dataset.py

make_dataset.py 代码见后面介绍

1.2 在训练的机器上部署yolov5项目

yolov5最新的github地址:
https://github.com/ultralytics/yolov5
没有部署的,安装后解压。

1.3 划分训练集,输出yaml文件

注意:该脚本需要在训练所在的机器下执行,否则会有路径问题。

python split_train_val.py

split_train_val.py 代码见后面介绍
输出的yaml在示例中表示为mydata.yaml

1.4 修改models内的yaml文件

可以根据自己需求复制相应的yaml然后对其进行修改,将nc修改为自己数据集的类。
例如:复制一份models/yolov5s.yaml,然后修改里面的nc参数后,命名为my_yolov5s.yaml

1.5 训练yolov5模型

输入训练的指令,根据实际情况进行修改

python train.py --cfg models/my_yolov5s.yaml --data mypath/mydata.yaml --weights yolov5s.pt --img 640 --batch-szie 32 --epochs 200

训练后,自动保存在runs/train/expxx(最后一个)

1.6 验证yolov5模型

通过测试集验证yolov5模型的得分,根据实际情况进行修改

python val.py  --data mypath/mydata.yaml --weights mypath/best.pt --batch-size 32 --img 640 

1.7 yolov5模型进行推理

用训练好的yolov5的模型对图片或视频进行推理检测,根据实际情况进行修改

python detect.py --data mypath/mydata.yaml --weights mypath/best.pt --source mysource

2. yolov5训练自己数据集详细版

2.1 标注数据集

采用labelImg进行标注:
https://github.com/heartexlabs/labelImg
下载并安装,安装过程详见README.rst
在这里插入图片描述
标注后默认会在图像目录下生成同名xml标签文件

2.2 xml转txt的介绍

labelImg自动生成的xml文件,需要转换成yolo格式的txt标签:
labelImg自动生成的xml内容介绍:

在这里插入图片描述

然后yolo的标签txt的格式:
在这里插入图片描述

每一行描述一个检测框信息,总共5个数,由空格隔开。
第一个数字代表检测目标的类别id
第二个数字至第五个数字分别表示检测框的 x_center, y_center, width, height

xml转txt的脚本:

def convert_annotation(xml_path, classes, summary_obj):flag_cls = []for _ in classes:flag_cls.append(0)# 读取xml文件,写入txt文件# print(xml_path)# 判断xml是否为空if not os.path.getsize(xml_path):print("内容为空的xml:",xml_path)txt_path = xml_path[:-3] + 'txt'  # xml文件路径with open(txt_path, 'w') as out_txt:return summary_obj, txt_pathwith open(xml_path,encoding='UTF-8') as f:xml_text = f.read()# tree = ET.parse(f)# root = tree.getroot()root = ET.fromstring(xml_text)f.close()# 获取xml参数信息outlines = []size = root.find('size')w = int(size.find('width').text)h = int(size.find('height').text)for obj in root.iter('object'):cls = obj.find('name').textif cls not in classes:print('invalid_cls:',cls)continuesummary_obj += 1cls_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))bb = convert((w,h), b)summary_cls_to_obj[cls_id] += 1flag_cls[cls_id] = 1outlines.append(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')# summaryfor idx in range(len(classes)):if flag_cls[idx] == 1:summary_cls_to_img[idx] += 1# 写入txt文件txt_path = xml_path[:-3] + 'txt'  # xml文件路径with open(txt_path, 'w') as out_txt:out_txt.writelines(outlines)return summary_obj, txt_path

2.3 制作训练数据集

2.3.1 步骤介绍

这一个操作分为3个步骤:

步骤1:抽取数据集

主要目的就是可以从大量分类好的数据集目录中按比例抽取自己所需要的数据集,例如要训练水果数据集,因此要从苹果目录,橘子目录,等多个目录提取相应数量的图像和标签,合并到一个数据集中。在抽取时,采用脚本可以设置提取的比例,数量,以及保证随机性。
对比手动操作,进入一个个目录复制粘贴相比,更加快捷。当然,如果只是对一个目录进行训练,则不需要进行数据集的抽取了。

步骤2:xml转txt(无xml生成空白txt)

步骤3:图片保存到输出文件中的image目录内,标签保存到输出目录的labels目录内,生成统计量化文件summarg.txt,可以分析。

在这里插入图片描述

2.3.2 make_dataset.py代码

import os
import numpy as np
import shutil
import xml.etree.ElementTree as ET
import ntpath'''
算法思想:
1. 将数据从源目录中按比例/数量,随机抽出,最后存放到2个总文件夹中(分别存放xml和jpg).
前提,源目录中必须同时存在jpg文件和xml文件
(若源目录中存在子目录,那么子目录中的文件一样会被提取出来)
2. 在传出过程中将xml文件转为txt文件更新:
1. labelImg 不需要标注的图像就不会产生xml,因此,对没有匹配到xml的jpg,会自动生成一个空的xml文件,表示无标注
2. 支持判断xml和txt两种标签, xml标签会转txt标签,txt标签会直接复制到指定目录注意:
凡是图像没有对应的标签,会自动创建空标签!
''''''
####################    输入参数设置(开始)    #################### 
'''
# org_dirs 设置说明:数组内每一个元素表示一条数据集抽离指令, 每一条抽离指令包含4个元素,分别是:
# 目录源路径,计数方式(百分比'ratio'/数值'num'),具体的值('rate':[0,1]||'num'>=0), 图像格式
#    [r'D:\dataset\02-标注数据集\102-基础数据\SITE\3-大连奥通\[HK]DLAT-hat-fire-112', 'ratio', '1', 'jpg'],org_dirs = [#dataset[r'D:\dataset\LabeledDataset\PublicDatasets\0.fire(hat,person,hat)\BASE-flames-297','ratio', '1', 'jpg'],[r'D:\dataset\LabeledDataset\FieldDatasets\MG(fire)\MG-fire-1233','ratio', '1', 'jpg'],
]# 是否需要统一输出的图像格式
is_union = False
# 若需要统一,  设置统一的图像格式
union_imgtype = 'jpg'
# 输出的目标目录,程序会在该目录下创建images和labels分别存放图像文件和txt文件
output_dir = r'D:\dataset\DLAT-11111'# 集控数据集类别
classes =['fire','Roller','hat','person','rock']# 输出量化分析summary.txt(位置在output_dir目录下)
write_summary = True'''
####################    输入参数设置(结束)    #################### 
'''# txt数据统计设置
summary_dataset=[]
summary_cls_to_img = []
summary_cls_to_obj = []
summary_img = 0
summary_obj = 0
for _ in classes:summary_cls_to_img.append(0)summary_cls_to_obj.append(0)# 按照yolo格式归一化
def convert(size, box):dw = 1.0 / size[0]dh = 1.0 / size[1]x = (box[0] + box[1]) / 2.0y = (box[2] + box[3]) / 2.0w = box[1] - box[0]h = box[3] - box[2]x = x * dww = w * dwy = y * dhh = h * dhreturn (x, y, w, h)def count_txt(txt_path):flag_cls = []for _ in classes:flag_cls.append(0)with open(txt_path, 'r',encoding='UTF-8') as f:while True:line = f.readline()if line:# 以空格为间隔,读取所有该行的数据存入数组msg = line.split(" ")if len(msg) == 5:cls_idx = line.split(' ')[0]# print("cls_idx=", cls_idx)summary_cls_to_obj[int(cls_idx)] += 1flag_cls[int(cls_idx)] = 1else:breakfor idx in range(len(classes)):if flag_cls[idx] == 1:summary_cls_to_img[idx] += 1# xml转txt(yolo)
def convert_annotation(xml_path, classes, summary_obj):flag_cls = []for _ in classes:flag_cls.append(0)# 读取xml文件,写入txt文件# print(xml_path)# 判断xml是否为空if not os.path.getsize(xml_path):print("内容为空的xml:",xml_path)txt_path = xml_path[:-3] + 'txt'  # xml文件路径with open(txt_path, 'w') as out_txt:return summary_obj, txt_pathwith open(xml_path,encoding='UTF-8') as f:xml_text = f.read()# tree = ET.parse(f)# root = tree.getroot()root = ET.fromstring(xml_text)f.close()# 获取xml参数信息outlines = []size = root.find('size')w = int(size.find('width').text)h = int(size.find('height').text)for obj in root.iter('object'):cls = obj.find('name').textif cls not in classes:print('invalid_cls:',cls)continuesummary_obj += 1# clw changecls_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))bb = convert((w,h), b)summary_cls_to_obj[cls_id] += 1flag_cls[cls_id] = 1outlines.append(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')# summaryfor idx in range(len(classes)):if flag_cls[idx] == 1:summary_cls_to_img[idx] += 1# 写入txt文件txt_path = xml_path[:-3] + 'txt'  # xml文件路径with open(txt_path, 'w') as out_txt:out_txt.writelines(outlines)return summary_obj, txt_pathif __name__ == "__main__":# copy file and convert xml to yolo# 创建目录if not os.path.exists(output_dir):os.mkdir(output_dir)output_images = os.path.join(output_dir, 'images')if not os.path.exists(output_images):os.mkdir(output_images)output_labels = os.path.join(output_dir, 'labels')if not os.path.exists(output_labels):os.mkdir(output_labels)# 遍历目录for dir in org_dirs:# create dirpath, mode, val, images_type = dirold_path = []for root, dir, files in os.walk(path):count = 1for file in files:# print("(",count,"/",len(files),")")count+=1if file[-3:] == images_type:# print(file)xml_name = file[:-3] + 'xml'txt_name =  file[:-3] + 'txt'if not (os.path.exists(os.path.join(root, xml_name)) or os.path.exists(os.path.join(root, txt_name))):# 生成空的txt文件f = open(os.path.join(root, txt_name), 'w', encoding='utf-8')f.close()old_path.append(os.path.join(root, file))if len(old_path) <= 0:print('目录:', path, '为空,跳过!\n')continue# 复制到 output_dirif mode == 'ratio':     # 按比例抽取if float(val) >=0 and float(val) <= 1:num = int(len(old_path) * float(val))else:print('提示:目录:', path, 'val=', val,',无效,跳过!\n')continueelif mode == 'num':     # 按数值抽取if int(val) > len(old_path):print('提示:目录:', path, 'val=', val,',超过目录内目标上线,默认提取目录内全部有效数据 num=',len(old_path),'\n')num = len(old_path)elif int(val) <= len(old_path) and int(val) > 0:num = int(val)else:print('提示:目录:', path, 'val=', val, ',无效,跳过!\n')continue# 打乱序列np.random.shuffle(old_path)count=0for p in old_path[:num]:count+= 1summary_img += 1# 图像复制imgname = ntpath.basename(p)shutil.copyfile(p, os.path.join(output_images,imgname))xmlpath = p[:-3] + 'xml'if os.path.exists(xmlpath):print(xmlpath)summary_obj, txt_path =convert_annotation(xmlpath, classes, summary_obj)# txt移动txt_name = imgname[:-3] + 'txt'shutil.move(txt_path, os.path.join(output_labels, txt_name))# print('目录',path,'转换复制进度:',count,'/',str(num))elif os.path.exists(xmlpath[:-3]+"txt"):txt_path = xmlpath[:-3] + 'txt'txt_name = imgname[:-3] + 'txt'shutil.copyfile(txt_path, os.path.join(output_labels, txt_name))count_txt(txt_path)dataset_status = '数据集名称:' + path + ',随机抽样(' + str(num) + '/' + str(len(old_path)) + ')\n'summary_dataset.append(dataset_status)print('目录',path,'完成数据提取!' )# 量化分析if write_summary:txt_path = os.path.join(output_dir,'summary.txt')with open(txt_path, 'w') as summary_txt:summary_txt.write('数据集抽样统计:\n')for line in summary_dataset:summary_txt.write(line)# 编写类别编号classes_line = 'classes=['for idx in range(len(classes)):cls_msg = '\''+classes[idx] + '\''classes_line += cls_msgif idx < len(classes)-1:classes_line += ','classes_line += ']\n'summary_txt.write(classes_line)summary_txt.write('\n量化分析:\n')summary_txt.write('类在图像中出现的频率统计:\n')for idx in range(len(classes)):ratio = float(summary_cls_to_img[idx] / summary_img)mes = classes[idx] + ':出现次数=' + str(summary_cls_to_img[idx]) + ',比例=' + str(round(ratio, 4)) + '\n'summary_txt.write(mes)summary_txt.write('\n类在检测框中出现的频率统计:\n')for idx in range(len(classes)):ratio = float(summary_cls_to_obj[idx] / summary_obj)mes = classes[idx] + ':出现次数=' + str(summary_cls_to_obj[idx]) + ',比例=' + str(round(ratio, 4)) + '\n'summary_txt.write(mes)print( '完成量化分析!')

2.4 划分数据集(训练集,测试集)

2.4.1 首先,把之前2.3生成的数据集压缩后,移动到训练模型所在的服务器内。

2.4.2 split_train_val.py脚本划分数据集

功能: 可以生成train.txt,val.txt,和test.txt,txt的文件内存放图像数据的路径。此外,脚本还可以自动生成data.yaml文件
在这里插入图片描述
train.txt内的内容
在这里插入图片描述
data.yaml的内容样式:
在这里插入图片描述

import os
import numpy as np
import shutil'''
功能说明:
1. 开启数据集文件物理划分方式(FUNC=SPLIT_DATASET)
将原图目录和标签目录按照指定的划分比例(复制/移动)到指定的输出目录,并且在指定的输出目录自动创建如下的文件结构:
例如,指定输出目录为(output_dir)
--output_dir--images--train--val--test--labels--train--val--test
注:若是需要的文件名和程序默认的不一致,可以到split_data()函数内修改默认的文件名2. 开启输出train.txt, val.txt, test.txt三个txt文件(FUNC=WRITE_TXT)
不移动源图像和标签的目录内的文件,按照指定的比例将划分后的训练集,测试集和验证集的文件路径分别输出到train.txt, val.txt, test.txt。
例如,指定输出目录为(output_dir)
--output_dir--train.txt--val.txt--test.txt3. 注意事项
3.1 标签名和图像名务必一一对应,要求所有图像统一格式,所有标签统一格式。
3.2 为提高效率,本程序不支持遍历源目录中子目录下的文件,请将所有源文件都放到一级目录,否则会出问题
'''
'''
####################    输入参数设置(开始)    #################### 
'''
# 路径
# 源图像存储的目录:
root_dir = r'/home/tc/dataset/DLAT-juge5cls-230210/'
org_images_dir = os.path.join(root_dir, 'images')
# 源标签存储的目录(图像和标签的名称必须一一对应):
org_labels_dir = os.path.join(root_dir, 'labels')
# 输出的目标路径:
output_dir = root_dir# 功能:
#FUNC = 'SPLIT_DATASET'     # 划分后移动文件
# mode = 'copy' # 当FUNC = 'SPLIT_DATASET'时才生效,选择从源目录复制到新目录
mode = 'move'   # 当FUNC = 'SPLIT_DATASET'时才生效,选择从源目录移动到新目录FUNC = 'WRITE_TXT'          # 直接输出包含路径的3个txt文件# 划分比例,依次是训练集比例,(三者之和必须等于一)
scale = [0.8, 0.19, 0.01]# 文件格式设置(默认按照yolo格式)
# 图像类型
image_type = 'jpg'
# 标签类型
label_type = 'txt'
# output --data yaml
# (yolo专属) 直接输出yolo的data参数的yaml文件(要求输出路径必须是绝对路径,否则后面训练很容易找不到路径),输出到output_dir
is_output_yaml = True
# 若输出yaml文件,必须提供类的信息
# classes=["fire","coal","hat","person","Roller"]  # class namesclasses=['fire','hat','person','roller']
'''
####################    输入参数设置(结束)    #################### 
'''def shuffle_file(org_images_dir):filenames= []# 遍历源图像目录for root, dir, files in os.walk(org_images_dir):for file in files:if file[-len(image_type):] == image_type: # 判断图像格式label_name = file[:-len(image_type)] + label_type# 判断是否存在对应标签if os.path.exists(os.path.join(org_labels_dir, label_name)):filenames.append(file)  # 保存文件名称# 打乱文件名列表np.random.shuffle(filenames)# 划分训练集、验证集,测试集if len(scale) != 3:print('划分比例设置有误,划分数组的元素量不为3,请检查')return Falseelif float(scale[0])<0 or  float(scale[1])<0 or float(scale[1])<0:print('划分比例设置有误,存在划分参数<0,请检查')return Falseelif float(scale[0]) + float(scale[1]) + float(scale[2]) != 1:print('划分比例设置有误,划分比例总和不为1,请检查')return Falsereturn True, filenamesdef split_data(train_val_test_set,mode,org_images_dir,org_labels_dir,output_dir):# 子目录文件名的设置默认按照yolo的要求,如果有差异可以修改img_label = ['images', 'labels']    # 图像目录名称和标签目录名称train_val_test = ['train','val','test']     # 子目录训练集,验证集,测试集的名称if not os.path.exists(output_dir):os.mkdir(output_dir)# 创建新目录for i in img_label:type_dir = os.path.join(output_dir, i)if not os.path.exists(type_dir):os.mkdir(type_dir)for j in train_val_test:split_dir = os.path.join(type_dir, j)if not os.path.exists(split_dir):os.mkdir(split_dir)# 移动/复制文件到新目录for i in range(len(img_label)):for j in range(len(train_val_test_set)):for k in range(len(train_val_test_set[j])):if i == 0: # imagefile_name = train_val_test_set[j][k]old_path = os.path.join(org_images_dir, file_name)else:   # labelfile_name = train_val_test_set[j][k][:-len(image_type)] + label_type# print("train_val_test_set[j][k]=", train_val_test_set[j][k])# print("file_name=", file_name)old_path = os.path.join(org_labels_dir, file_name)new_path = os.path.join(os.path.join(os.path.join(output_dir, img_label[i]), train_val_test[j]), file_name)if mode == 'copy':shutil.copyfile(old_path, new_path)elif mode == 'move':# print("old_path=",old_path)# print("new_path=",new_path)shutil.move(old_path, new_path)else:print('mode设置错误, 划分数据集取消')returnif is_output_yaml:train_line = 'train:  ' + os.path.join(os.path.join(output_dir, img_label[i]), train_val_test[0]) + '\n'val_line = 'val:  ' + os.path.join(os.path.join(output_dir, img_label[i]), train_val_test[0]) + '\n\n'nc_line = 'nc: ' + str(len(classes)) + '\n'classes_line = 'names: ['for cls in range(len(classes)):class_msg = '\'' + classes[cls] + '\''classes_line += class_msgif cls < len(classes)-1:classes_line += ','classes_line += ']'with open(os.path.join(output_dir, 'data.yaml'), 'w') as f:f.write(train_line)f.write(val_line)f.write(nc_line)f.write(classes_line)def write_txt(train_val_test_set,org_images_dir, output_dir):with open(os.path.join(output_dir, 'train.txt'), 'w') as f1,\open(os.path.join(output_dir, 'val.txt'),'w') as f2, \open(os.path.join(output_dir, 'test.txt'),'w') as f3:path_set=[]print("len(train_val_test_set)=", len(train_val_test_set))for i in range(len(train_val_test_set)):new_lines = []for j in range(len(train_val_test_set[i])):path = os.path.join(org_images_dir, train_val_test_set[i][j])+'\n'new_lines.append(path)if i==0:f1.writelines(new_lines)elif i==1:f2.writelines(new_lines)elif i==2:f3.writelines(new_lines)if is_output_yaml:train_line = 'train: ' + os.path.join(output_dir, 'train.txt') + '\n'val_line = 'val: ' + os.path.join(output_dir, 'val.txt') + '\n\n'nc_line = 'nc: ' + str(len(classes)) + '\n'classes_line = 'names: ['for cls in range(len(classes)):class_msg = '\'' + classes[cls] + '\''classes_line += class_msgif cls < len(classes)-1:classes_line += ','classes_line += ']'with open(os.path.join(output_dir, 'data.yaml'), 'w') as f:f.write(train_line)f.write(val_line)f.write(nc_line)f.write(classes_line)if __name__ == "__main__":ret,filenames = shuffle_file(org_images_dir)if ret:train = filenames[:int(len(filenames)*scale[0])]val = filenames[int(len(filenames)*scale[0]):int(len(filenames)*scale[0]+len(filenames)*scale[1])]test = filenames[int(len(filenames)*scale[0]+len(filenames)*scale[1]):]train_val_test_set = [train, val, test]if FUNC == 'SPLIT_DATASET':split_data(train_val_test_set, mode, org_images_dir, org_labels_dir, output_dir)elif FUNC == 'WRITE_TXT':write_txt(train_val_test_set, org_images_dir, output_dir)

2.5 修改训练配置文件:

打开yolov5项目内的models目录:
在这里插入图片描述
例如,训练yolov5s模型,就修改models/yolov5s.yaml的配置文件。
可以根据自己需求复制相应的yaml然后对其进行修改,将nc修改为自己数据集的类,修改后的文件重新命名

在这里插入图片描述

2.6 开始训练:

在yolov5的目录内,输入:

python train.py --data mydatset.yaml --weights yolov5s.pt --cfg models/myyolov5s.yaml --batch-size 16 --epochs 200 

训练指令的参数可以在train.py内看到:
在这里插入图片描述
其中:

--weights 输入训练所用的预训练模型
--cfg 模型配置文件yaml,原型在models内的yolov5().yaml,根据自己的数据集修改
--data 数据集相关的配置文件yaml,原型在data目录内,修改yaml内部的路径为自己数据集的路径
--epochs 训练迭代次数
--device 训练模型指定的显卡ID
--batch-size 每次迭代训练的batch数量,具体数据与所用显卡的显存相关
--img 模型中输入的尺寸

相关文章:

【yolov5】yolov5训练自己的数据集全流程----包含本人设计的快速数据处理脚本

关于yolo应用时能用到的脚本集合&#xff0c;推荐收藏&#xff1a; https://chenlinwei.blog.csdn.net/article/details/127299428 1. 工程化快速yolo训练流程指定版&#xff08;无讲解&#xff09; 1.1 抽样数据集xml转txt输出量化分析 python make_dataset.pymake_dataset…...

leaflet 加载CSV数据,显示图形(代码示例046)

第046个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+leaflet中加载CSV文件,将图形显示在地图上。 直接复制下面的 vue+openlayers源代码,操作2分钟即可运行实现效果; 注意如果OpenStreetMap无法加载,请加载其他来练习 文章目录 示例效果配置方式示例源代码(共74…...

百趣代谢组学资讯:槟榔的基因组为雌雄同株植物的性别决定提供见解

文章标题&#xff1a;The genome of Areca catechu provides insights into sex determination of monoecious plants 发表期刊&#xff1a;New Phytologist 影响因子&#xff1a;10.323 作者单位&#xff1a;海南大学 百趣生物提供服务&#xff1a;植物激素高通量靶标定…...

SSO单点登录 - 多系统,单一位置登录,实现多系统同时登录 学习笔记

(1)单点登录 多系统的前提下&#xff0c;单一位置的登录&#xff0c;会实现多系统同时登录的一种技术。 常出现在互联网应用和企业级平台中 如&#xff1a;京东 单点登录一般是用于互相授信的系统&#xff0c;实现单一位置登录&#xff0c;全系统有效的。 注意&#xff1a…...

图解LeetCode——剑指 Offer 32 - III. 从上到下打印二叉树 III

一、题目 请实现一个函数按照之字形顺序打印二叉树&#xff0c;即&#xff1a;第一行按照从左到右的顺序打印&#xff0c;第二层按照从右到左的顺序打印&#xff0c;第三行再按照从左到右的顺序打印&#xff0c;其他行以此类推。 二、示例 2.1> 示例1 提示&#xff1a; …...

【快排与归并排序算法】

作者&#xff1a;指针不指南吗 专栏&#xff1a;算法篇 &#x1f43e;或许会很慢&#xff0c;但是不可以停下&#x1f43e; 文章目录一、快速排序 ( Quick Sort )二、归并排序 ( Merge Sort )总结一、快速排序 ( Quick Sort ) 1.思路 找出一个分界点&#xff0c;随机的调整区间…...

面试官问我:说说你对JMM内存模型的理解?为什么需要JMM?

点个关注&#xff0c;必回关 随着CPU和内存的发展速度差异的问题&#xff0c;导致CPU的速度远快于内存&#xff0c;所以现在的CPU加入了高速 缓存&#xff0c;高速缓存一般可以分为L1、L2、L3三级缓存。基于上面的例子我们知道了这导致了缓存一致 性的问题&#xff0c;所以加入…...

工程管理系统源码之提高工程项目管理软件的效率

高效的工程项目管理软件不仅能够提高效率还应可以帮你节省成本提升利润 在工程行业中&#xff0c;管理不畅以及不良的项目执行&#xff0c;往往会导致项目延期、成本上升、回款拖后&#xff0c;最终导致项目整体盈利下降。企企管理云业财一体化的项目管理系统&#xff0c;确保…...

SpringBoot集成xxl-job实现

SpringBoot集成xxl-job实现 一、xxl-job介绍 xxl-job是一个分布式任务调度平台&#xff0c;核心设计目标是开发迅速、学习简单、轻量级、易扩展。源码&#xff1a;下载地址编译环境&#xff1a;Maven3、Jdk1.8、MySQL5.7 二、调度中心 初始化调度数据库&#xff0c;执行指定…...

欧几里得度量和余弦度量的可取消生物识别方案

欧几里得度量和余弦度量的可取消生物识别方案 便捷的生物识别数据是一把双刃剑&#xff0c;在为生物识别认证系统的繁荣铺平道路的同时&#xff0c;也带来了个人隐私问题。为了缓解这种担忧&#xff0c;提出了各种生物特征模板保护方案来保护生物特征模板免于信息泄露。现有提案…...

平板作为主机扩展屏的实现

网上有许多教程使用平板作为电脑的拓展屏&#xff0c;但是多数都是需要在电脑和平板上都装上服务器和客户端的软件才行&#xff0c;而且有些系统还没有对应的软件。 那有没有一种方法只需要在主机上运行一个软件&#xff0c;而平板上只需要扫个码就行呢&#xff1f; 答案是当然…...

HTTP和HTTPS有什么区别?如何实现网站的HTTPS?

细心的朋友会发现&#xff0c;我们在浏览网站时&#xff0c;有的网址以http开头&#xff0c;而有的网站却以https开头&#xff0c;那这两者之间有什么区别吗&#xff1f;http的网站如何能变成https呢&#xff1f;本文中科三方针对这个问题做下简单介绍。 什么是http&#xff1…...

Rockstar Games遭黑客攻击,《侠盗猎车手6》90个开发视频外泄

当地时间9月19日&#xff0c;视频游戏开发商Rockstar Games证实&#xff0c;其 热门游戏《侠盗猎车手6》&#xff08;Grand Theft Auto&#xff09;开发片段遭到黑客大规模窃取 &#xff0c;这一泄露事件立即在游戏圈迅速传播。 据报道&#xff0c; 上周末黑客至少泄露了90个游…...

RabbitMQ-客户端源码之AMQPImpl+Method

AMQPImpl类包括AMQP接口&#xff08;public class AMQImpl implements AMQP&#xff09;主要囊括了AMQP协议中的通信帧的类别。 这里以Connection.Start帧做一个例子。 public static class Connection {public static final int INDEX 10;public static class Startextends…...

雅思经验(7)

我发现雅思阅读要命的不是难度&#xff0c;而是时间的把控。考试时间是总共一小时&#xff0c;但是要写三篇文章&#xff0c;之后总共40道题目&#xff0c;也就是说每篇文章平均是13.3道。但是他们很多人说&#xff0c;如果誊写答案需要花掉3、4分钟每篇&#xff0c;也就是说真…...

Ubuntu20.04 用 `hwclock` 或 `timedatectl` 设置RTC硬件时钟为本地时区

Ubuntu20.04用 hwclock 或 timedatectl 设置硬件时区为本地时区 可以用hwclock命令 sudo hwclock --localtime --systohc&#x1f446;效果等同&#x1f447; , --localtime的简写是-l ; --systohc的简写是-w sudo hwclock -l -w也可以用timedatectl命令 &#x1f446;效果等…...

大学物理·第15章【量子物理】

黑体 斯特藩玻耳兹曼定律 维恩定律 光电效应 在光照射下 &#xff0c;电子从金属表面逸出的现象&#xff0c;叫光电效应. 逸出的电子&#xff0c;叫光电子 经典理论&#xff1a; 光电流值与入射光强成正比截止频率&#xff08;红限&#xff09;v0对某种金属来说&#xff0c;只有…...

2010-2019年290个地级市经济发展与城市绿化数据

2010-2019年290个地级市经济发展与城市绿化数据 1、时间&#xff1a;2010-2019年 2、来源&#xff1a;城市统计NJ&#xff0c;缺失情况与NJ一致 3、范围&#xff1a;290个地级市 4、指标&#xff1a; 综合经济&#xff1a;地区生产总值、人均地区生产总值、地区生产总值增…...

【CSS 布局】-多列布局

一、两列布局 两列布局&#xff1a;一列定宽(也有可能由子元素决定宽度)&#xff0c;一列自适应的布局。 创建一个父盒子&#xff0c;和子盒子 <div class"container clearfix"><div class"left ">定宽</div><div class"right…...

从C语言向C++过渡

文章目录前言1.命名空间1.域的概念2.命名空间的使用2.C输入&输出3.缺省参数1.概念2.分类3.注意事项4.函数重载5.引用1.概念2.使用注意事项3.引用使用场景4.指针和引用的区别6.内联函数7.auto关键字8.nullptr前言 C被成为带类的C,本文由C语言向C过度&#xff0c;将会初步介…...

Matter 研讨会回顾(第三期)|乐鑫 Matter 免开发方案与证书服务介绍

1 月 17 日&#xff0c;乐鑫举办了以“乐鑫 Matter 免开发方案与证书服务介绍”为主题的第三期 Matter 线上研讨会&#xff0c;介绍乐鑫开箱即用的 ESP-ZeroCode 模组及其免开发 Matter 方案&#xff0c;以及证书生成和预配置相关服务。欢迎观看研讨会的视频回放了解详情。&…...

函数栈帧的创建和销毁——“C”

各位CSDN的uu们你们好呀&#xff0c;今天小雅兰来为大家介绍一个知识点——函数栈帧的创建和销毁。其实这个知识点&#xff0c;我们很早之前就要讲&#xff0c;但是因为我的一系列原因&#xff0c;才一直拖到了现在&#xff0c;那么&#xff0c;话不多说&#xff0c;让我们一起…...

腾讯云对象存储+企业网盘 打通数据链“最后一公里

对云厂商和企业用户来说&#xff0c;随着数据规模的快速增长&#xff0c;企业除了对存储功能和性能的要求不断增加&#xff0c;也越来越注重数据分发的效率。在传统数据分发的过程中&#xff0c;数据管理员往往需要先在存储桶下载对应的客户方案/交付资料&#xff0c;再使用微信…...

在浏览器输入url到发起http请求,这过程发生了什么

当用户输入url&#xff0c;操作系统会将输入事件传递到浏览器中&#xff0c;在这过程中&#xff0c;浏览器可能会做一些预处理&#xff0c;比如 Chrome 会根据历史统计来预估所输入字符对应的网站&#xff0c;例如输入goog&#xff0c;根据之前的历史发现 90% 的概率会访问「ww…...

PyTorch学习笔记:nn.ReLU——ReLU激活函数

PyTorch学习笔记&#xff1a;nn.ReLU——ReLU激活函数 torch.nn.ReLU(inplaceFalse)功能&#xff1a;逐元素应用ReLU函数对数据进行激活 函数方程&#xff1a; ReLU(x)(x)max⁡(0,x)ReLU(x)(x)^\max(0,x) ReLU(x)(x)max(0,x) 输入&#xff1a; inplace&#xff1a;是否改变输…...

同步线程

↵ 由于这节内容资料比较少&#xff0c;所以以下内容总结自Qt官方文献&#xff0c;在文章最后会给出相应链接。 线程的目的是允许并行运行&#xff0c;但有时线程必须停止等待其他线程。例如&#xff0c;如果两个线程尝试访问同一个变量&#xff0c;这样的话结果是未定义的。强…...

服务端返回内容跨域CORS之后,也在chrome/edge浏览器里显示出响应信息

由于浏览器的同源策略&#xff0c;服务端返回的内容跨域&#xff0c;且没有允许跨域CORS的请求头之后&#xff0c;浏览器无法显示出服务端返回的信息&#xff0c;不方便问题排查。比如&#xff1a;Access to XMLHttpRequest at http://localhost:6001/service-app/query/common…...

DHCP中继及配置

为什么需要DHCP Relay&#xff1f;产生背景解决方案DHCP Relay工作原理DHCP Relay配置实现产生背景 随着网络规模的扩大&#xff0c;网络中就会出现用户处于不同网段的情况。 这个时候客户A和客户B要请求IP地址时&#xff0c;首先会发送DHCP Discover广播包&#xff0c;这个广…...

中国社科院与美国杜兰大学金融管理硕士,让我们相遇在春暖花开时

在芸芸众生中&#xff0c;能拥有志同道合的朋友是一件多么幸运的事。人们常说&#xff1a;你是谁&#xff0c;就会遇见谁。走过半生才知道&#xff0c;看似命中注定的遇见谁、发生的事&#xff0c;其实都取决于自己。只有自己足够优秀&#xff0c;才能遇到更优秀的别人。在这个…...

MySQL---单表查询、多表查询

一、单表查询 素材&#xff1a; 表名&#xff1a;worker-- 表中字段均为中文&#xff0c;比如 部门号 工资 职工号 参加工作 等 CREATE TABLE worker ( 部门号 int(11) NOT NULL, 职工号 int(11) NOT NULL, 工作时间 date NOT NULL, 工资 float(8,2) NOT NULL, 政治面貌 v…...

展示型网站设计/网络营销组合策略

2019独角兽企业重金招聘Python工程师标准>>> 尝试了很长时间&#xff0c;也试过很多办法&#xff0c;比如在之前使用的ubuntu中&#xff0c;我使用chmod -R 777 /var/www/* 为这个目录下面的所有文件赋777权限&#xff0c;我在fedora 15试了一下&#xff0c;完全不行…...

网站案例演示/seo官网优化

前言 2021春季社招正在火热招聘当中&#xff0c;很多人都挂在了技术知识掌握还是不够广&#xff0c;不够深&#xff0c;甚至连一些基础的问题都只能模模糊糊的回答出来。你说&#xff0c;这跳槽不是跳了个寂寞吗&#xff1f; 其实&#xff0c;根本原因还是对于自己的技术栈掌…...

1号网站建设 高端网站建设/四川网站seo

题目链接&#xff1a;http://poj.org/problem?id2955 题意&#xff1a;求相互匹配的括号个数。 一道简单的区间dp&#xff0c;按常规的套路来写就可以了。 #include <iostream> #include <cstring> #include <string> using namespace std; int dp[110][110…...

衡阳网站建设衡阳千度网络/友链对网站seo有帮助吗

“微软实现企业信息系统远程客户端的安全技术及应用-石家庄站活动”召开在即&#xff01;热忱期待您的光临&#xff01;感谢您对本次活动的热情参与&#xff01; 城 市&#xff1a;石家庄 时 间&#xff1a;2005年11月16日 13&#xff1a;30-17&#xff1a…...

网站建设外包行业/企业推广是什么职业

XSS又叫CSS (Cross Site Script) ,跨站脚本攻击。恶意攻击者往Web页面里插入恶意html代码&#xff0c;当用户浏览该页之时&#xff0c;嵌入当中Web里面的html代码会被运行&#xff0c;从而达到恶意攻击用户的特殊目的。 from:http://www.incapsula.com/blog/world-largest-site…...

陕西省建设造价协会网站/优化营商环境条例全文

上一次在面试官&#xff1a;来说说MySQL的常见优化方案……中说到 MySQL 性能优化的方案很多&#xff0c;因此它可以全面地考查一个程序员的经验是否丰富。当然对于这个问题的回答也是可深可浅&#xff0c;不同的岗位对此问题的要求也是不同的。MySQL 可以引申出更多的面试问题…...