first commit

This commit is contained in:
hatcher committed 2026-07-17 18:55:31 +08:00
1 parent ae53e9eac5
commit 91cbd01126
514 files changed
+55625 -2203

No files matched your search

+1 -1
View File
@@ -2,7 +2,7 @@
<module type="PYTHON_MODULE" version="4"> <module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager"> <component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" /> <content url="file://$MODULE_DIR$" />
<orderEntry type="jdk" jdkName="Python 3.6 (py36pt18)" jdkType="Python SDK" /> <orderEntry type="jdk" jdkName="Python 3.6 (py36pt15)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
</component> </component>
<component name="PyDocumentationSettings"> <component name="PyDocumentationSettings">
+1 -1
View File
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.6 (py36pt18)" project-jdk-type="Python SDK" /> <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.6 (py36pt15)" project-jdk-type="Python SDK" />
</project> </project>
Vendored Executable
+24
View File
@@ -0,0 +1,24 @@
{
// 使用 IntelliSense 了解相关属性。
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python: Remote Attach",
"type": "python",
"request": "attach",
"connect": {
"host": "172.16.0.254",
"port": 22
},
"pathMappings": [
{
"localRoot": "${workspaceFolder}",
"remoteRoot": "."
}
],
"justMyCode": true
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 MiB

File renamed without changes.
+50
View File
@@ -0,0 +1,50 @@
import os
from PIL import Image
import matplotlib.pyplot as plt
import numpy as np
#from scipy.misc import imread,imresize
import cv2,argparse
parser1 = argparse.ArgumentParser(description="CUI")
parser1.add_argument("root", default='/data1/Hatcher/model/project/data_MPKFNet/rawdata/竹林嘴-3月3日候鸟视频.mp4', type=str,
help='root.')
parser1.add_argument("imgsize", default='640', type=str,
help='imgsize')
args = parser1.parse_args()
filepath = args.root
imageSize = int(args.imgsize)
pathDir = os.listdir(filepath)
R_channel = 0
G_channel = 0
B_channel = 0
for idx in range(len(pathDir)):
filename = pathDir[idx]
print(filename)
img = cv2.imread(os.path.join(filepath, filename))
img = cv2.resize(img,(imageSize,imageSize))/ 255.0
R_channel = R_channel + np.sum(img[:, :, 0])
G_channel = G_channel + np.sum(img[:, :, 1])
B_channel = B_channel + np.sum(img[:, :, 2])
num = len(pathDir) * 512 * 512 # 这里(512,512)是每幅图片的大小,所有图片尺寸都一样
R_mean = R_channel / num
G_mean = G_channel / num
B_mean = B_channel / num
R_channel = 0
G_channel = 0
B_channel = 0
for idx in range(len(pathDir)):
filename = pathDir[idx]
print(filename)
img = cv2.imread(os.path.join(filepath, filename))
img = cv2.resize(img, (imageSize, imageSize)) / 255.0
R_channel = R_channel + np.sum((img[:, :, 0] - R_mean) ** 2)
G_channel = G_channel + np.sum((img[:, :, 1] - G_mean) ** 2)
B_channel = B_channel + np.sum((img[:, :, 2] - B_mean) ** 2)
R_var = np.sqrt(R_channel / num)
G_var = np.sqrt(G_channel / num)
B_var = np.sqrt(B_channel / num)
print("R_mean is %f, G_mean is %f, B_mean is %f" % (R_mean, G_mean, B_mean))
print("R_var is %f, G_var is %f, B_var is %f" % (R_var, G_var, B_var))
View File
File mode changed.
View File
File mode changed.
+1 -1
View File
@@ -44,7 +44,7 @@ from Dcl.models.LoadModel import MainModel
from Dcl.DclConfig import LoadConfig, load_data_transformers from Dcl.DclConfig import LoadConfig, load_data_transformers
from Dcl.util.test_tool import set_text, save_multi_img, cls_base_acc from Dcl.util.test_tool import set_text, save_multi_img, cls_base_acc
os.environ['CUDA_VISIBLE_DEVICES'] = '6' #os.environ['CUDA_VISIBLE_DEVICES'] = '6'
devices = torch.device('cuda' if torch.cuda.is_available() else 'cpu') devices = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
class DclInference: class DclInference:
+37
View File
@@ -0,0 +1,37 @@
import os
import cv2
import shutil
from tqdm import tqdm
anno_pathRoot = "/data/DataManagement/Project/CAS_ProjectBird/CDB_ProjectBird/Annotations_Original/"
image_pathRoot = anno_pathRoot.replace("/Annotations_Original/","/JPEGImages_Original/")
w = 1024
h = 768
def DetResizeForTrain(anno_pathRoot,image_pathRoot,w,h):
annoResultPath = anno_pathRoot.replace("/Annotations_Original/","/Annotations/")
annoJPEGPath = anno_pathRoot.replace("/JPEGImages_Original/", "/JPEGImages/")
for anno in tqdm(os.listdir(anno_pathRoot)):
anno = GEN_Annotations(anno.replace(".xml", ".jpg"))
dom = xml.dom.minidom.parse(os.path.join(anno_pathRoot, xmls))
size = dom.getElementsByTagName("size")
# print(size[0].getElementsByTagName('width')[0].childNodes[0].data)
width = size[0].getElementsByTagName('width')[0].childNodes[0].data
height = size[0].getElementsByTagName('height')[0].childNodes[0].data
depth = size[0].getElementsByTagName('depth')[0].childNodes[0].data
anno.set_size(int(w), int(h), int(depth))
objects = dom.getElementsByTagName("object")
for object in objects:
bndbox = object.getElementsByTagName('bndbox')[0]
xmin = bndbox.getElementsByTagName('xmin')[0]
ymin = bndbox.getElementsByTagName('ymin')[0]
xmax = bndbox.getElementsByTagName('xmax')[0]
ymax = bndbox.getElementsByTagName('ymax')[0]
xmin_data = int(xmin.childNodes[0].data)*(w/width)
ymin_data = int(ymin.childNodes[0].data)*(h/height)
xmax_data = int(xmax.childNodes[0].data)*(w/width)
ymax_data = int(ymax.childNodes[0].data)*(h/height)
label_name = object.getElementsByTagName('name')[0].childNodes[0].data
anno.add_pic_attr(label=label_name, xmin=xmin_data, xmax=xmax_data, ymin=ymin_data, ymax=ymax_data)
anno.savefile(os.path.join(annoResultPath, xmls))
image = cv2.imread
+273
View File
@@ -0,0 +1,273 @@
# -*- coding:utf-8 -*-
import cv2,os,torch,argparse
import queue
import time
import threading
from System_I import Check_start_fordataselect,Density,Detection_Y5,Fine_grained,Fine_grained_T,shishi,save_sigle_image,RealDeal
from common import global_para as gp
r_db = None
import torch.multiprocessing as multiprocessing
import sort.sort as SORT
from imatovideo import images_to_video
from multiprocessing import Array
class DetFineVid():
def __init__(self, VideoPath,SavePath):
super(DetFineVid,self).__init__()
# name
self.VideoPath = VideoPath
self.VideoResultSavePathroot = "/data1/Hatcher/model/project/data_MPKFNet/result_vedio/"
self.VideoName = os.path.basename(self.VideoPath).split(".")[0]
self.VideoResultSavePath = os.path.join(self.VideoResultSavePathroot,"{}.avi".format(self.VideoName))
self.SavePath = os.path.join(SavePath,self.VideoName)
if not os.path.exists(self.SavePath):
os.makedirs(self.SavePath)
self.root = "/home/wanghc/output_jiankong"
self.DensityClass = Density(gp.devices, self.root)
self.DetectionClass = Detection_Y5(gp.devices, self.root)
self.Fine_grianedClass = Fine_grained_T(gp.devices)
self.FineRestartFlag = True
self.numrestart = 0
def conVideo(self):
images_to_video( self.SavePath,self.VideoResultSavePath)
def StartRec(self):
t1 = time.time()
cap = cv2.VideoCapture(self.VideoPath)
t2 = time.time()
print("capture is ",(t2-t1)*1000)
num_detection = 0
num_cuntupian=0
SortRestart = SORT.Sort(max_age=gp.max_age,
min_hits=gp.min_hits,
iou_threshold=gp.sortiou_threshold)
realtimedeal = RealDeal("check_start",self.DetectionClass,self.Fine_grianedClass,self.DensityClass)
if cap.isOpened():
res, frame = cap.read()
if res:
shapex = frame.shape[1]
shapey = frame.shape[0]
gp.radioShowX = shapex / gp.radioShowX
gp.radioShowY = shapey / gp.radioShowY
gp.radioShowtext = gp.radioShowX
if frame.shape[1] == 3840:
gp.fontScale = 3
elif frame.shape[1] == 2560:
gp.fontScale = 1
else:
gp.fontScale = 1
for i in range(20):
res, frame = cap.read()
print("skip{}".format(i))
num_image = 0
while True:
if cap.isOpened():
res, frame = cap.read()
if res:
closed = False
failCnt = 0
num_image += 1
data_today = 8
print(num_detection)
# if num_detection <12974:
# a=0
# num_detection+=1
# continue
#cv2.imwrite("./test.jpg",frame)
if (int(data_today) > 1) & (int(data_today) < 20):
if (0xFF == ord('q')):
print("restart")
self.FineRestartFlag = True
self.numrestart = 0
SortRestart = SORT.Sort(max_age=gp.max_age,
min_hits=gp.min_hits,
iou_threshold=gp.sortiou_threshold)
if self.FineRestartFlag :
realtimedeal.realtimerestart(frame,num_image=num_image,num_detection=num_detection,SortRestart = SortRestart)
self.numrestart += 1
if self.numrestart >= 5:
self.numrestart = 0
self.FineRestartFlag = False
FirstDetFineResult = realtimedeal.getrestartresult(gp.IndexMax)
print("µÚÒ»´Îʶ±ðÄ¿±êÊýÁ¿ ",len(FirstDetFineResult))
gp.SortLabel_Index = FirstDetFineResult
# SortRealTime = SORT.Sort(max_age=gp.max_age,
# min_hits=gp.min_hits,
# iou_threshold=gp.sortiou_threshold)
else:
tm1 = time.time()
#frame = cv2.imread("./test.jpg")
img_show,num_image = realtimedeal.realtime(frame,num_image=num_image,num_detection=num_detection,SortRestart = SortRestart)
tm2 = time.time()
if gp.DebugPrint_flag:
print("main1 time is ", (tm2 - tm1) * 1000)
# cv2.imshow("AI-ECO", img_show)
# #cv2.imwrite("../data_MPKFNet/RTSP3/" + "{}.jpg".format(time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))),img_show)
# if cv2.waitKey(1) & 0xFF == ord('r'):
# break
save_path =os.path.join(self.SavePath,"{}.jpg".format(str(num_detection).zfill(6)))
cv2.imwrite(save_path,img_show)
tm3 = time.time()
if gp.DebugPrint_flag:
print("main2 time is ", (tm3 - tm2) * 1000)
else:
print("time is out")
if (num_detection >1000000) :
# save_image = save_sigle_image(frame)
# save_image.start()
# num_detection=0
num_detection = 0
num_detection+=1
num_cuntupian+=1
else:
break
def commanddeal():
SavePath = "/data1/Hatcher/model/project/data_MPKFNet/result/"
print("starting ",gp.VideoPath)
DFS = DetFineVid(gp.VideoPath,SavePath)
DFS.StartRec()
DFS.conVideo()
def filedeal(rootPath): #deal all file in a folder
SavePath = "/data3/DEMO/images/"
i = 0
for video_path in os.listdir(rootPath):
if i == 1:
print("111")
# print("starting deal {}".format(str(video_path)))
# VideoPath = os.path.join(rootPath,video_path)
# DFS = DetFineVid(VideoPath,SavePath)
# DFS.StartRec()
# DFS.conVideo()
P = multiprocessing.Process(target=func,args=(video_path,SavePath,rootPath))
P.start()
P.join()
#globalInit()
i += 1
def func(video_path,SavePath,rootPath):
print("starting deal {}".format(str(video_path)))
VideoPath = os.path.join(rootPath, video_path)
DFS = DetFineVid(VideoPath, SavePath)
DFS.StartRec()
DFS.conVideo()
def globalInit(): #deal all file in a folder
parser1 = argparse.ArgumentParser(description="CUI")
parser1.add_argument("--video_num", default='/data1/Hatcher/model/project/data_MPKFNet/rawdata/PYH-DEMO.mp4',
type=str,
help='Video name.')
parser1.add_argument("--GPU", default='6', type=str,
help='GPU.')
parser1.add_argument("--thresh", default=0.4, type=float,
help='GPU.')
parser1.add_argument("--red", default=0, type=int,
help='red.')
parser1.add_argument("--add", default=0, type=str,
help='add.')
args = parser1.parse_args()
# print(args)
gp.root = "/home/gyd/output1"
# os.environ['CUDA_VISIBLE_DEVICES'] = '0'
os.environ['CUDA_VISIBLE_DEVICES'] = args.GPU
gp.devices = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
gp.camera_address = args.add
gp.VideoPath = args.video_num
gp.red_flag = args.red
gp.detect_thresh = args.thresh
# fine_thresh2 = torch.tensor(fine_thresh2).cuda()
gp.birdIndex = 99999
# birdIndex = torch.tensor(birdIndex).cuda()
gp.is_ex_bird = False # Ä¿±ê¼ì²â±ê־λ£¬Ã¿¸öÒ»Ãë¼ì²âÒ»´ÎÄ¿±ê¼ì²â£¬Èç¹ûÓÐÄñ£¬ÔòÖÃΪTrue£¬ÎªTrueµÄʱºò˵Ã÷£¬ ´¦Àí30sµÄÏ̻߳¹ÔÚ¼ÌÐø£¬Ö±µ½±ê־λ±äΪÁËFalseÔÙ¿ªÆôеÄÏß³Ì
gp.Density_thread_flag = False # ÃܶȹÀ¼ÆÏ̱߳ê־λ£¬ÎªTrue˵Ã÷¿ªÆôÁËÃܶȹÀ¼ÆỊ̈߳¬´¦ÀíÍê750֡Ϊֹ£¬±ê־λ±êΪFalse£¬
gp.Detection_thread_flag = False # Ä¿±ê¼ì²âºÍϸÁ£¶Èʶ±ðÏ̱߳ê־λ£¬ÎªTrue˵Ã÷¿ªÆôÁËÃܶȹÀ¼ÆỊ̈߳¬´¦ÀíÍê750֡Ϊֹ£¬±ê־λ±êΪFalse£¬
gp.Vedio_thread_flag = False # ´æ´¢ÊÓÆµÏ̱߳ê־룬´æ´¢30s
gp.SaveImage_thread_flag = False # ±£´æÔ­Í¼Ï̱߳ê־룬´æ´¢30ÕÅԭͼ
gp.ALL_thread_flag = False # ËùÓÐÏ̵߳ıê־룬µ¥¶À¿ªÉèÒ»¸öỊ̈߳¬¼à¿ØËùÓÐÏß³ÌÊÇ·ñ¶¼½áÊø£¬Èç¹û¶¼½áÊø£¬ÔòÖÃΪFalse£¬ºóÐøÌí¼ÓÏ̹߳ÜÀí£¬¿ÉÒÔ·ÅÔÚÕâÀïÃæ
gp.ShowAllNumFlag = False
gp.DebugPrint_flag = False # ´òÓ¡±ê־λ
gp.num_count_old = 0
gp.boxes_fine = None
gp.labels_fine = None
gp.showThresh = 25
gp.destory_image = False
gp.Camera_device = args.video_num # ÉãÏñÍ·±àºÅ£¬0001
gp.image_time = None # µ±Ç°´¦ÀíµÄ30ÊÓÆµµÄ±àºÅ
gp.ImgDealQueue = [] # 750Ö¡ÊÓÆµ£¬»º´æ¿Õ¼ä
gp.img_show = None
# event = threading.Event()
gp.eventDensity = threading.Event()
gp.eventDetection = threading.Event()
gp.eventSaveimage = threading.Event()
gp.max_age = 2
gp.min_hits = 3
gp.sortiou_threshold = 0.3
gp.Finerestartboxes = []
gp.IndexMax = 0
gp.radioShowX = 2560.0
gp.radioShowY = 1440.0
gp.radioShowtext = gp.radioShowX
gp.SortLabel_Index = None # ±êÇ©ºÍË÷Òý¶ÔÓ¦¹ØÏµ[[4,1],[3,2]]
gp.SortLabel_Indexpre = [] # ±êÇ©ºÍË÷ÒýµÄ¶ÔÓ¦¹ØÏµ£¬ÓÃÔÚ×·×Ù¹ý³ÌÖÐгöÏÖµÄÄ¿±ê£¬[[label,Index,Count]]
# Detection2 = Detection(devices,root)
gp.FineCountThresh = 5
gp.img_show = None
gp.Fine_thresh = 0.4
# DetWeight = "/data1/Hatcher/model/Detection/yolov5/runs/train/exp21/weights/best.pt"
# FineWeight = "/data/Hatcher/data/weigth/areaproject/resnet50-PYH-3-20.7/_42522_PYH-3/best.pth"
gp.DetWeight = "/data1/Hatcher/model/Detection/yolov5/runs/train/KunMingCuiHu-Fish2/weights/best.pt"
gp.FineWeight = "/data/Hatcher/data/weigth/areaproject/resnet50-DianChiFish-3-3-0.7/_4289_DianChiFish-4/best.pth"
# DetWeight = "/data1/Hatcher/model/Detection/yolov5/runs/train/BeijingCuiHu-Bird26/weights/best.pt"
# FineWeight = "/data/Hatcher/data/weigth/areaproject/resnet50-cui90_1model0.7/_42111_CUI-94-1/best.pth"
# BHG_chineseName = ["kong", '白鹤', '白头鹤','白枕鹤']#["kong","鲫鱼","麦穗鱼","鳑鲏"]
gp.BHG_chineseName = ["kong", "鲫鱼", "麦穗鱼", "鳑鲏"]
# BHG_chineseName = ['Kong', '白额雁', '白骨顶', '苍鹭', '苍鹭', '白秋沙鸭', '白腰草鹬', '斑头雁', '斑嘴鸭', '苍鹭', '赤膀鸭', '赤颈鸭', '苍鹭', '大麻鳽',
# '豆雁', '反嘴鹬', '凤头鸊鷉', '凤头麦鸡', '凤头潜鸭', '黑鹳', '黑水鸡', '红嘴鸥', '鸿雁', '灰鹤', '灰雁', '绿翅鸭', '绿头鸭', '琵嘴鸭',
# '普通鸬鹚', '普通秋沙鸭', '翘鼻麻鸭', '鹊鸭', '扇尾沙锥', '小白额雁', '小天鹅', '针尾鸭', '苍鹭', '暗绿绣眼鸟', '八哥', '白腹鹞', '白鹡鸰',
# '白眼潜鸭', '草鹭', '池鹭', '戴胜', '黑翅长脚鹬', '黑鸢', '红隼', '花脸鸭', '环颈雉', '灰头绿啄木鸟', '灰头麦鸡', '矶鹬', '栗苇鳽',
# '罗纹鸭', '牛背鹭', '普通翠鸟', '雀鹰', '喜鹊', '苍鹭', '鸳鸯', '棕背伯劳', '红胸秋沙鸭', '普通燕鸥', '小白额燕鸥', '丘鹬', '凤头蜂鹰',
# '大天鹅', '大鸨', '小田鸡', '山斑鸠', '帆背潜鸭', '日本松雀鹰', '普通鵟', '松雀鹰', '毛脚鵟', '灰斑鸠', '白头鹞', '白尾鹞', '白眉鸭',
# '白鹈鹕', '红头潜鸭', '苍鹰', '蒙古银鸥', '西方秧鸡', '赤嘴潜鸭', '阔嘴鹬', '雕鸮', '鹌鹑', '鹗', '黄苇鳽', '黑颈鹤', '小䴙䴘', '赤麻鸭']
# BHG_chineseName =["kong","绿头鸭","斑嘴鸭","灰雁","鸿雁","kong","小鷿鷈"]
gp.FineClassNum = 4
gp.color_show = (255, 255, 255)
gp.color_box = (255, 0, 0)
gp.NoneLabel = "鱼" # "鹤类"
gp.fine_thresh1 = 6000
gp.fine_thresh2 = 10000
gp.fontScale = 1
torch.zero_(gp.Species)
if __name__ == '__main__':
multiprocessing.set_start_method("spawn")
rootPath = "/data3/DEMO/video/PYH/"
filedeal(rootPath)
#commanddeal()
+176
View File
@@ -0,0 +1,176 @@
# -- coding: utf-8 --
# @Author : Calvin
# @Email : 934055521@qq.com
# @File : xld.py
# @use :
# @Software: PyCharm
# @Time : 27/5/2022 3:32 PM
"""
python3 FinegrainedIdentificationDatasetGenerate.py
-rp /data/DataManagement/Project/004_kunmingcuihu/0003_20220507_800/CAS_KMCuihuBird/CMB_KMCuihuBird
-blp /data/DataManagement/Project/004_kunmingcuihu/0003_20220507_800/CAS_KMCuihuBird/CMB_KMCuihuBird/birdList/KMCuihuBird.xlsx
"""
import os
import shutil
import argparse
import random
import pandas as pd
import numpy as np
import cv2
from tqdm import tqdm
BHG_chineseName = ['bird', 'Anser_albifrons', 'Fulica_atra', 'Egretta_garzetta', 'Platalea_leucorodia', 'Mergellus_albellus', 'Tringa_ochropus', 'Anser_indicus', 'Anas_zonorhyncha', 'Ardea_cinerea', 'Mareca_strepera', 'Mareca_penelope', 'Ardea_alba', 'Botaurus_stellaris', 'Anser_fabalis', 'Recurvirostra_avosetta', 'Podiceps_cristatus', 'Vanellus_vanellus', 'Aythya_fuligula', 'Ciconia_nigra', 'Gallinula_chloropus', 'Chroicocephalus_ridibundus', 'Anser_cygnoides', 'Grus_grus', 'Anser_anser', 'Anas_crecca', 'Anas_platyrhynchos', 'Spatula_clypeata', 'Phalacrocorax_carbo', 'Mergus_merganser', 'Tadorna_tadorna', 'Bucephala_clangula', 'Gallinago_gallinago', 'Anser_erythropus', 'Cygnus_columbianus', 'Anas_acuta', 'Ardea_intermedia', 'Zosterops_simplex', 'Acridotheres_cristatellus', 'Circus_spilonotus', 'Motacilla_alba', 'Aythya_nyroca', 'Ardea_purpurea', 'Ardeola_bacchus', 'Upupa_epops', 'Himantopus_himantopus', 'Milvus_migrans', 'Falco_tinnunculus', 'Sibirionetta_formosa', 'Phasianus_colchicus', 'Picus_canus', 'Vanellus_cinereus', 'Actitis_hypoleucos', 'Ixobrychus_cinnamomeus', 'Mareca_falcata', 'Bubulcus_coromandus', 'Alcedo_atthis', 'Accipiter_nisus', 'Pica_serica', 'Nycticorax_nycticorax', 'Aix_galericulata', 'Lanius_schach', 'Mergus_serrator', 'Sterna_hirundo', 'Sternula_antillarum', 'Scolopax_rusticola', 'Pernis_ptilorhynchus', 'Cygnus_cygnus', 'Otis_tarda', 'Zapornia_pusilla', 'Streptopelia_orientalis', 'Aythya_valisineria', 'Accipiter_gularis', 'Buteo_japonicus', 'Accipiter_virgatus', 'Buteo_lagopus', 'Streptopelia_decaocto', 'Circus_aeruginosus', 'Circus_cyaneus', 'Spatula_querquedula', 'Pelecanus_onocrotalus', 'Aythya_ferina', 'Accipiter_gentilis', 'Larus_cachinnans', 'Rallus_aquaticus', 'Netta_rufina', 'Calidris_falcinellus', 'Bubo_bubo', 'Coturnix_japonica', 'Pandion_haliaetus', 'Ixobrychus_sinensis', 'Grus_nigricollis', 'Tachybaptus_ruficollis', 'Tadorna_ferruginea', 'Leucogeranus_leucogeranus', 'Grus_monacha', 'Antigone_vipio', 'Cyanopica_cyanus', 'Passer_montanus', 'Hirundo_rustica']
#####################################
Number_last = 0
LabelSpecies = []
DataNOlineFeed = []
WrongImages = []
DataSpeciesClassier = dict()
#####################################
def parse():
arg = argparse.ArgumentParser()
arg.add_argument('--root_path', '-rp', default='/data/DataManagement/Project/CAS_ProjectBird/CMB_ProjectBird0615/', type=str)
arg.add_argument('--division_ratio', '-dr', default='0.7', type=float)
arg.add_argument('--bird_list_path', '-blp', default='/data/DataManagement/Project/CAS_ProjectBird/CMB_ProjectBird0615/birdList/ProjectBirdList.xlsx')
args = arg.parse_args()
return args
if __name__ == '__main__':
args = parse()
dataset_txt_path = os.path.join(args.root_path, 'DatasetTxt')
species_txt_path = f'{args.root_path}/DatasetTxt/Species.txt'
dataset_spectrum_path = f'{args.root_path}/OrginalData'
dataset_allspectrum_path = f'{args.root_path}/FinalData/data'
dataset_allspectrum_path_train = f'{args.root_path}/FinalData/train'
dataset_allspectrum_path_test = f'{args.root_path}/FinalData/test'
dataset_allspectrum_txt_path = f'{args.root_path}/FinalData/anno/all.txt'
if not os.path.exists(dataset_txt_path):
os.makedirs(dataset_txt_path)
# for data in tqdm(os.listdir(dataset_spectrum_path), ncols=80, ascii=True, desc="OrginalData images path"):
# # for data in os.listdir(dataset_spectrum_path):
# for image in os.listdir(os.path.join(dataset_spectrum_path, data)):
# try:
# im = cv2.imread(os.path.join(dataset_spectrum_path, data, image))
# except:
# WrongImages.append(os.path.join(dataset_spectrum_path, data, image))
# os.remove(os.path.join(dataset_spectrum_path, data, image))
# tqdm.write('Wrong images are {:}'.format(WrongImages))
bird_list = pd.read_excel(args.bird_list_path, usecols=['拉丁名'])
bird_list = np.array(bird_list.stack()).tolist()
for num, data in tqdm(enumerate(bird_list), ncols=80, ascii=True, desc="writing species.txt"):
# for num, data in enumerate(bird_list):
with open(species_txt_path, 'a') as f:
filename = data
file_final_name = data + ' ' + str(num)
f.write(file_final_name)
f.write('\n')
for speices in tqdm(os.listdir(dataset_spectrum_path), ncols=80, ascii=True, desc="writing species.txt"):
# for speices in os.listdir(dataset_spectrum_path):
for data in os.listdir(os.path.join(dataset_spectrum_path, speices)):
if data.split('___')[0] != speices:
os.rename(os.path.join(dataset_spectrum_path, speices, data), os.path.join(dataset_spectrum_path, speices, '{:}___{:}'.format(speices, data)))
tqdm.write('The pictures naming is done!')
with open(species_txt_path, 'r') as file:
Data = file.readlines()
for line in Data:
line = line.strip('\n')
species = line.split(' ')[0]
Number = line.split(' ')[1]
#Judge Number
if Number != Number_last:
DataSpeciesClassier[species] = Number
Number_last = Number
tqdm.write(str(DataSpeciesClassier))
tqdm.write('The species have been obtained')
# transfer single files to all files
if not os.path.exists(dataset_allspectrum_path):
os.makedirs(dataset_allspectrum_path)
if not os.path.exists(dataset_allspectrum_path_train):
os.makedirs(dataset_allspectrum_path_train)
if not os.path.exists(dataset_allspectrum_path_test):
os.makedirs(dataset_allspectrum_path_test)
for data in tqdm(os.listdir(dataset_spectrum_path), ncols=80, ascii=True, desc="transfer single files"):
# for data in os.listdir(dataset_spectrum_path):
for file in os.listdir(os.path.join(dataset_spectrum_path, data)):
shutil.copy(os.path.join(dataset_spectrum_path, data, file), dataset_allspectrum_path)
tqdm.write('Transfer single files to all files is done')
# generate the all.txt
if not os.path.exists('/'.join(dataset_allspectrum_txt_path.split('/')[:-1])):
os.makedirs('/'.join(dataset_allspectrum_txt_path.split('/')[:-1]))
for data in tqdm(os.listdir(dataset_allspectrum_path), ncols=80, ascii=True, desc="transfer single files"):
# for data in os.listdir(dataset_allspectrum_path):
with open(dataset_allspectrum_txt_path, 'a') as f:
file_new_name = data.split('___')[0]
# file_new_name = data
# file_new_name = '_'.join(file_new_name.split('_')[:-1])
num = DataSpeciesClassier[file_new_name]
file_final_name = data + ' ' + num
f.write(file_final_name)
f.write('\n')
tqdm.write('Generate the all.txt is done')
# Spilit dataset
DataPath = dataset_allspectrum_txt_path
# delete file_txt
if os.path.exists(DataPath.replace(os.path.basename(DataPath), 'train.txt')) :
os.remove(DataPath.replace(os.path.basename(DataPath), 'train.txt'))
if os.path.exists(DataPath.replace(os.path.basename(DataPath), 'test.txt')):
os.remove(DataPath.replace(os.path.basename(DataPath), 'test.txt'))
with open(DataPath, 'r')as f:
Data = f.readlines()
LabelSpecies = []
for RowData in Data:
RowData = RowData.strip()
# find picture-label
RowLabels = RowData.split(' ')[1]
DataNOlineFeed.append(RowData.split(' '))
if RowLabels not in LabelSpecies:
LabelSpecies.append(RowLabels)
print(LabelSpecies)
tqdm.write("classes num of Dataset is : {:}".format(len(LabelSpecies)))
for Labels in tqdm(LabelSpecies, ncols=80, ascii=True, desc="transfer single files"):
# for Labels in LabelSpecies:
Num = 0
TrainData = []
TestData = []
TotalData = []
for SpeciesData in DataNOlineFeed:
if Labels == SpeciesData[1]:
Num += 1
TotalData.append(SpeciesData)
TrainNum = int(Num * args.division_ratio)
TestNum = Num - TrainNum
random.shuffle(TotalData)
with open(DataPath.replace(os.path.basename(DataPath), 'train.txt'), 'a') as f:
for i in range(TrainNum):
f.write(' '.join(TotalData[i]) + '\n')
label_classname = "{}.{}".format(str(Labels).zfill(4),BHG_chineseName[int(Labels)])
soursepathTrain = os.path.join(dataset_spectrum_path,label_classname)
destpathTrain = os.path.join(dataset_allspectrum_path_train,label_classname)
if not os.path.exists(destpathTrain):
os.makedirs(destpathTrain)
image_name = TotalData[i][0]
shutil.copy(os.path.join(soursepathTrain,str(image_name)),os.path.join(destpathTrain,str(image_name)))
with open(DataPath.replace(os.path.basename(DataPath), 'test.txt'), 'a') as f:
for i in range(TrainNum, Num):
f.write(' '.join(TotalData[i]) + '\n')
label_classname = "{}.{}".format(str(Labels).zfill(4), BHG_chineseName[int(Labels)])
soursepathTest = os.path.join(dataset_spectrum_path, label_classname)
destpathTest = os.path.join(dataset_allspectrum_path_test, label_classname)
if not os.path.exists(destpathTest):
os.makedirs(destpathTest)
image_name = TotalData[i][0]
shutil.copy(os.path.join(soursepathTest, str(image_name)), os.path.join(destpathTest, str(image_name)))
Regular → Executable
+24 -14
View File
@@ -1,30 +1,40 @@
import os,argparse,torch import os,argparse,torch
from System_I import Detection_Y5 from System_I import Detection_Y5,Fine_grained_T
from tqdm import tqdm from tqdm import tqdm
#os.environ['CUDA_VISIBLE_DEVICES'] = "1"
if __name__ == '__main__': if __name__ == '__main__':
parser1 = argparse.ArgumentParser(description="AILabel") parser1 = argparse.ArgumentParser(description="AILabel")
parser1.add_argument("--RawPath", default='/data/DataManagement/Project/001_cuihu/0012_20220517_RTSP/imagesAILabel', type=str, parser1.add_argument("--RawPath", default='/data/DataManagement/Project/006_huanghekou/0006_20220621/Raw_images/imagesAILabel', type=str,
help='RawPath.') help='RawPath.')
parser1.add_argument("--GPU", default="1", type=str, parser1.add_argument("--GPU", default="4", type=str,
help='GPU.') help='GPU.')
parser1.add_argument("--thresh", default=0.4, type=float, parser1.add_argument("--thresh", default=0.4, type=float,
help='thresh.') help='thresh.')
parser1.add_argument("--Weight", default="/data/Hatcher/data/Detection_weigth/BJCHKMCH-Bird-1-4/weights/best.pt", type=str,
help='Weight.')
args = parser1.parse_args() args = parser1.parse_args()
os.environ['CUDA_VISIBLE_DEVICES'] = args.GPU os.environ['CUDA_VISIBLE_DEVICES'] = args.GPU#"1"
devices = torch.device('cuda:{}'.format(str(int(args.GPU))) if torch.cuda.is_available() else 'cpu') try:
if "imagesAILabel" not in args.RawPath:
exit()
else:
os.system("sudo chmod 777 -R {}".format(str(args.RawPath).replace("imagesAILabel","")))
except:
exit()
#devices = torch.device('cuda:{}'.format(str(int(args.GPU))) if torch.cuda.is_available() else 'cpu')
devices = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
if not os.path.exists(args.RawPath.replace("imagesAILabel","NoResult")): if not os.path.exists(args.RawPath.replace("imagesAILabel","NoResult")):
os.makedirs(args.RawPath.replace("imagesAILabel","NoResult")) os.makedirs(args.RawPath.replace("imagesAILabel","NoResult"))
if not os.path.exists(args.RawPath.replace("imagesAILabel","YesResult")): if not os.path.exists(args.RawPath.replace("imagesAILabel","JPEGImages")):
os.makedirs(args.RawPath.replace("imagesAILabel","YesResult")) os.makedirs(args.RawPath.replace("imagesAILabel","JPEGImages"))
if not os.path.exists(args.RawPath.replace("imagesAILabel","LabelXML")): if not os.path.exists(args.RawPath.replace("imagesAILabel","Annotations")):
os.makedirs(args.RawPath.replace("imagesAILabel","LabelXML")) os.makedirs(args.RawPath.replace("imagesAILabel","Annotations"))
Detection = Detection_Y5(device=devices,root=" ", detect_thresh=args.thresh,DetWeight=args.Weight) if not os.path.exists(args.RawPath.replace("imagesAILabel", "BrokenImage")):
os.makedirs(args.RawPath.replace("imagesAILabel", "BrokenImage"))
Detection = Detection_Y5(device=devices,root=" ", detect_thresh=args.thresh)
FineGrained = Fine_grained_T(device=devices)
imagepaths = os.listdir(args.RawPath) imagepaths = os.listdir(args.RawPath)
for imagepath in tqdm(imagepaths): for imagepath in tqdm(imagepaths):
imagepath = os.path.join(args.RawPath,imagepath) imagepath = os.path.join(args.RawPath,imagepath)
Detection.AIlabel(imagepath) Detection.AIlabelFine(imagepath,FineGrained)
+44
View File
@@ -0,0 +1,44 @@
import os,argparse,torch
from System_I import Detection_Y5,Fine_grained_T
from tqdm import tqdm
#os.environ['CUDA_VISIBLE_DEVICES'] = "1"
if __name__ == '__main__':
parser1 = argparse.ArgumentParser(description="AILabel")
parser1.add_argument("--RawPath", default='/data/DataManagement/Project/temp/OrginalData', type=str,
help='RawPath.')
parser1.add_argument("--GPU", default="2", type=str,
help='GPU.')
parser1.add_argument("--thresh", default=0.4, type=float,
help='thresh.')
args = parser1.parse_args()
os.environ['CUDA_VISIBLE_DEVICES'] = args.GPU#"1"
try:
if "imagesAILabel" not in args.RawPath:
exit()
else:
os.system("sudo chmod 777 -R {}".format(str(args.RawPath).replace("imagesAILabel","")))
except:
exit()
#devices = torch.device('cuda:{}'.format(str(int(args.GPU))) if torch.cuda.is_available() else 'cpu')
devices = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
Detection = Detection_Y5(device=devices, root=" ", detect_thresh=args.thresh)
FineGrained = Fine_grained_T(device=devices)
for RawPaths in os.listdir(args.RawPath):
RawPath = os.path.join(args.RawPath,RawPaths,"imagesAILabel")
if not os.path.exists(RawPath.replace("imagesAILabel","NoResult")):
os.makedirs(RawPath.replace("imagesAILabel","NoResult"))
if not os.path.exists(RawPath.replace("imagesAILabel","JPEGImages")):
os.makedirs(RawPath.replace("imagesAILabel","JPEGImages"))
if not os.path.exists(RawPath.replace("imagesAILabel","Annotations")):
os.makedirs(RawPath.replace("imagesAILabel","Annotations"))
if not os.path.exists(RawPath.replace("imagesAILabel", "BrokenImage")):
os.makedirs(RawPath.replace("imagesAILabel", "BrokenImage"))
imagepaths = os.listdir(RawPath)
for imagepath in tqdm(imagepaths):
imagepath = os.path.join(args.RawPath,imagepath)
Detection.AIlabelFine(imagepath,FineGrained)
+66
View File
@@ -0,0 +1,66 @@
import os,argparse,torch
from System_I import Detection_Y5,Fine_grained_T,Fine_grained_mmclsonnx
from tqdm import tqdm
#os.environ['CUDA_VISIBLE_DEVICES'] = "1"
"""###
输入:/根目录/imagesAI
-------文件夹1
------NoResult 存放无结果图片
------BrokenImage 存放损坏图片
------imagesAILabel 存放待处理图片
------Annotations 存放识别结果xml标签文件
------JPEGImages 备份原图原图
------result 存放可视化结果图片
-------文件夹2
------NoResult 存放无结果图片
------BrokenImage 存放损坏图片
------imagesAILabel 存放待处理图片
------Annotations 存放识别结果xml标签文件
------JPEGImages 备份原图原图
------result 存放可视化结果图片
###"""
if __name__ == '__main__':
parser1 = argparse.ArgumentParser(description="AILabel")
parser1.add_argument("--RawPath", default='/data5/student/Hatcher/test/imagesAI', type=str,
help='RawPath.')
parser1.add_argument("--GPU", default="2", type=str,
help='GPU.') #本参数在该工程中不起作用,请修改common.py文件种的全局参数
parser1.add_argument("--thresh", default=0.4, type=float,
help='thresh.')
args = parser1.parse_args()
os.environ['CUDA_VISIBLE_DEVICES'] = args.GPU#"1"
try:
if "imagesAI" not in args.RawPath:
exit()
else:
os.system("sudo chmod 777 -R {}".format(str(args.RawPath).replace("imagesAI","")))
except:
exit()
#devices = torch.device('cuda:{}'.format(str(int(args.GPU))) if torch.cuda.is_available() else 'cpu')
devices = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
Detection = Detection_Y5(device=devices, root=" ", detect_thresh=args.thresh)
FineGrained = Fine_grained_mmclsonnx(device=devices)
for RawPaths in os.listdir(args.RawPath):
RawPath = os.path.join(args.RawPath,RawPaths,"imagesAILabel")
if not os.path.exists(RawPath.replace("imagesAILabel","NoResult")):
os.makedirs(RawPath.replace("imagesAILabel","NoResult"))
if not os.path.exists(RawPath.replace("imagesAILabel","JPEGImages")):
os.makedirs(RawPath.replace("imagesAILabel","JPEGImages"))
if not os.path.exists(RawPath.replace("imagesAILabel","Annotations")):
os.makedirs(RawPath.replace("imagesAILabel","Annotations"))
if not os.path.exists(RawPath.replace("imagesAILabel", "BrokenImage")):
os.makedirs(RawPath.replace("imagesAILabel", "BrokenImage"))
if not os.path.exists(RawPath.replace("imagesAILabel", "result")):
os.makedirs(RawPath.replace("imagesAILabel", "result"))
imagepaths = os.listdir(RawPath)
for imagepath in tqdm(imagepaths):
imagepath = os.path.join(RawPath,imagepath)
Detection.AIlabelFine(imagepath,FineGrained)
+61
View File
@@ -0,0 +1,61 @@
import os
import argparse
import torch
from System_zwq import Detection_Y5, Fine_grained_T
from tqdm import tqdm
#os.environ['CUDA_VISIBLE_DEVICES'] = "1"
def oneFolder():
RawPath = os.path.join(args.RawPath, "imagesAILabel")
os.system("sudo chmod 777 -R {}".format(str(args.RawPath)))
if not os.path.exists(RawPath.replace("imagesAILabel", "NoResult")):
os.makedirs(RawPath.replace("imagesAILabel", "NoResult"))
if not os.path.exists(RawPath.replace("imagesAILabel", "JPEGImages")):
os.makedirs(RawPath.replace("imagesAILabel", "JPEGImages"))
if not os.path.exists(RawPath.replace("imagesAILabel", "Annotations")):
os.makedirs(RawPath.replace("imagesAILabel", "Annotations"))
if not os.path.exists(RawPath.replace("imagesAILabel", "BrokenImage")):
os.makedirs(RawPath.replace("imagesAILabel", "BrokenImage"))
imagepaths = os.listdir(RawPath)
for imagepath in tqdm(imagepaths, ncols=120, ascii=True, desc=RawPath + " images"):
imagepath = os.path.join(RawPath, imagepath)
Detection.AIlabelFine(imagepath, FineGrained)
def manyFolder():
for RawPaths in tqdm(os.listdir(args.RawPath), ncols=120, ascii=True, desc="bird folders"):
# for RawPaths in os.listdir(args.RawPath):
RawPath = os.path.join(args.RawPath, RawPaths, "imagesAILabel")
# os.system("sudo chmod 777 -R {}".format(str(os.path.join(args.RawPath, RawPaths))))
if not os.path.exists(RawPath.replace("imagesAILabel", "NoResult")):
os.makedirs(RawPath.replace("imagesAILabel", "NoResult"))
if not os.path.exists(RawPath.replace("imagesAILabel", "JPEGImages")):
os.makedirs(RawPath.replace("imagesAILabel", "JPEGImages"))
if not os.path.exists(RawPath.replace("imagesAILabel", "Annotations")):
os.makedirs(RawPath.replace("imagesAILabel", "Annotations"))
if not os.path.exists(RawPath.replace("imagesAILabel", "BrokenImage")):
os.makedirs(RawPath.replace("imagesAILabel", "BrokenImage"))
imagepaths = os.listdir(RawPath)
for imagepath in tqdm(imagepaths, ncols=120, ascii=True, desc=RawPaths + " images"):
# for imagepath in tqdm(imagepaths):
imagepath = os.path.join(RawPath, imagepath)
Detection.AIlabelFine(imagepath, FineGrained)
if __name__ == '__main__':
parser1 = argparse.ArgumentParser(description="AILabel")
parser1.add_argument("RawPath", default='/data5/PartDataset/003 PYH/0014 20230411/', type=str, help='RawPath.')
parser1.add_argument("--GPU", default="7", type=str, help='GPU.')
parser1.add_argument("--thresh", default=0.4, type=float, help='thresh.')
args = parser1.parse_args()
# os.environ['CUDA_VISIBLE_DEVICES'] = "7" #args.GPU # "1"
devices = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
Detection = Detection_Y5(device=devices, root=" ", detect_thresh=args.thresh)
FineGrained = Fine_grained_T(device=devices)
oneFolder()
# manyFolder()
+1 -1
View File
@@ -27,7 +27,7 @@ from vediotoima import vedio_img
from imatovideo import images_to_video,images_to_video_big from imatovideo import images_to_video,images_to_video_big
from moviepy.editor import * from moviepy.editor import *
import os import os
os.environ['CUDA_VISIBLE_DEVICES'] = '3' #os.environ['CUDA_VISIBLE_DEVICES'] = '3'
def parse_args(): def parse_args():
+13
View File
@@ -0,0 +1,13 @@
"""
FInename---->0001.Finename
"""
import os
from tqdm import tqdm
BHG_chineseName = ['bird', 'Anser_albifrons', 'Fulica_atra', 'Egretta_garzetta', 'Platalea_leucorodia', 'Mergellus_albellus', 'Tringa_ochropus', 'Anser_indicus', 'Anas_zonorhyncha', 'Ardea_cinerea', 'Mareca_strepera', 'Mareca_penelope', 'Ardea_alba', 'Botaurus_stellaris', 'Anser_fabalis', 'Recurvirostra_avosetta', 'Podiceps_cristatus', 'Vanellus_vanellus', 'Aythya_fuligula', 'Ciconia_nigra', 'Gallinula_chloropus', 'Chroicocephalus_ridibundus', 'Anser_cygnoides', 'Grus_grus', 'Anser_anser', 'Anas_crecca', 'Anas_platyrhynchos', 'Spatula_clypeata', 'Phalacrocorax_carbo', 'Mergus_merganser', 'Tadorna_tadorna', 'Bucephala_clangula', 'Gallinago_gallinago', 'Anser_erythropus', 'Cygnus_columbianus', 'Anas_acuta', 'Ardea_intermedia', 'Zosterops_simplex', 'Acridotheres_cristatellus', 'Circus_spilonotus', 'Motacilla_alba', 'Aythya_nyroca', 'Ardea_purpurea', 'Ardeola_bacchus', 'Upupa_epops', 'Himantopus_himantopus', 'Milvus_migrans', 'Falco_tinnunculus', 'Sibirionetta_formosa', 'Phasianus_colchicus', 'Picus_canus', 'Vanellus_cinereus', 'Actitis_hypoleucos', 'Ixobrychus_cinnamomeus', 'Mareca_falcata', 'Bubulcus_coromandus', 'Alcedo_atthis', 'Accipiter_nisus', 'Pica_serica', 'Nycticorax_nycticorax', 'Aix_galericulata', 'Lanius_schach', 'Mergus_serrator', 'Sterna_hirundo', 'Sternula_antillarum', 'Scolopax_rusticola', 'Pernis_ptilorhynchus', 'Cygnus_cygnus', 'Otis_tarda', 'Zapornia_pusilla', 'Streptopelia_orientalis', 'Aythya_valisineria', 'Accipiter_gularis', 'Buteo_japonicus', 'Accipiter_virgatus', 'Buteo_lagopus', 'Streptopelia_decaocto', 'Circus_aeruginosus', 'Circus_cyaneus', 'Spatula_querquedula', 'Pelecanus_onocrotalus', 'Aythya_ferina', 'Accipiter_gentilis', 'Larus_cachinnans', 'Rallus_aquaticus', 'Netta_rufina', 'Calidris_falcinellus', 'Bubo_bubo', 'Coturnix_japonica', 'Pandion_haliaetus', 'Ixobrychus_sinensis', 'Grus_nigricollis', 'Tachybaptus_ruficollis', 'Tadorna_ferruginea', 'Leucogeranus_leucogeranus', 'Grus_monacha', 'Antigone_vipio', 'Cyanopica_cyanus', 'Passer_montanus', 'Hirundo_rustica']
rootPath = "/data/DataManagement/Project/CAS_ProjectBird/CMB_ProjectBird0615/OrginalData"
os.system("sudo chmod 777 -R {}".format(rootPath))
for path in tqdm(os.listdir(rootPath),ncols=80, ascii=True, desc="change name"):
source = os.path.join(rootPath,path)
dest = os.path.join(rootPath,"{}.{}".format(str(BHG_chineseName.index(path)).zfill(4),str(path)))
os.rename(source,dest)
+1 -1
View File
@@ -36,7 +36,7 @@ def GYD_RedCameraDeal (root,DetectionCalss,Fine_grainedClass):
if __name__ == '__main__': if __name__ == '__main__':
os.environ['CUDA_VISIBLE_DEVICES'] = '4' #os.environ['CUDA_VISIBLE_DEVICES'] = '4'
devices = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') devices = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
root = "/data1/Hatcher/ftp" root = "/data1/Hatcher/ftp"
Detection1 = Detection_S(devices, root) Detection1 = Detection_S(devices, root)
+1763
View File
File diff suppressed because it is too large. Load diff
+38
View File
@@ -0,0 +1,38 @@
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(
['NewDetAiLabelFine.py'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='NewDetAiLabelFine',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)
+1717
View File
File diff suppressed because it is too large. Load diff
Executable
+21
View File
@@ -0,0 +1,21 @@
import os
in_path = "/data/DataManagement/Project/001_cuihu/CAS_CuihuBird/CDB_Cuihubird/ImageSets/Main/test.txt"
out_path = "/data/DataManagement/Project/001_cuihu/CAS_CuihuBird/CDB_Cuihubird/ImageSets/Main/test1.txt"
def change(in_path,out_path):
new = []
f = open(in_path,'r')
lines = f.readlines()
for line in lines:
line = line.strip('\n')
line = "./images/{}.jpg".format(line)+" "+"./Annotations/{}.xml".format(line)+"\n"
new.append(line)
# while(line):
# line = f.readline().replace("\n","")
# line = "./images/{}".format(line) + " " + "./Annotations/{}".format(line) +"\n"
# print(line)
# new.append(line)
handle = open(out_path, 'a')
handle.writelines(new)
if __name__ == '__main__':
change(in_path,out_path)
+26
View File
@@ -0,0 +1,26 @@
import os
import tqdm
import cv2
from PIL import Image
result_path = "E:/2021.10.15-wettrain/results/"
GT_path = "E:/2021.10.15-wettrain/result_GT/"
image_path ="E:/2021.10.15-wettrain/images/"
image = []
for j in range(14):
img = []
for i in range(60):
img.append(Image.open("/data/DataManagement/Project/001_cuihu/CAS_CuihuBird/CDB_Cuihubird/images/train/0010700285.jpg").resize((1024,768)))
image.append(img)
def long_pic_paste(image):
image_result = Image.new(image[0][0].mode, ( 1024 * 60,14 * 768), 0xffffff)
for j in range(14):
for i in range(60):
print(j," ",i)
image_result.paste(image[j][i], (i*1024, j*768))
#image_result.resize((65500,8591))
image_result.save("./result.jpg")
if __name__ == '__main__':
long_pic_paste(image)
+899 -618
View File
File diff suppressed because it is too large. Load diff
Executable
+1708
View File
File diff suppressed because it is too large. Load diff
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+546 -117
View File
@@ -1,18 +1,31 @@
# This file contains modules common to various models # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
"""
Common modules
"""
import json
import math import math
import platform
import warnings
from collections import OrderedDict, namedtuple
from copy import copy
from pathlib import Path from pathlib import Path
import sys
sys.path.append("..") import cv2
import numpy as np import numpy as np
import pandas as pd
import requests import requests
import torch import torch
import torch.nn as nn import torch.nn as nn
import yaml
from PIL import Image from PIL import Image
from torch.cuda import amp
from Y5.utils.datasets import letterbox from utils.dataloaders import exif_transpose, letterbox
from Y5.utils.general import non_max_suppression, make_divisible, scale_coords, xyxy2xywh from utils.general import (LOGGER, check_requirements, check_suffix, check_version, colorstr, increment_path,
from Y5.utils.plots import color_list, plot_one_box make_divisible, non_max_suppression, scale_coords, xywh2xyxy, xyxy2xywh)
from utils.plots import Annotator, colors, save_one_box
from utils.torch_utils import copy_attr, time_sync
def autopad(k, p=None): # kernel, padding def autopad(k, p=None): # kernel, padding
@@ -22,15 +35,10 @@ def autopad(k, p=None): # kernel, padding
return p return p
def DWConv(c1, c2, k=1, s=1, act=True):
# Depthwise convolution
return Conv(c1, c2, k, s, g=math.gcd(c1, c2), act=act)
class Conv(nn.Module): class Conv(nn.Module):
# Standard convolution # Standard convolution
def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True): # ch_in, ch_out, kernel, stride, padding, groups def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True): # ch_in, ch_out, kernel, stride, padding, groups
super(Conv, self).__init__() super().__init__()
self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g, bias=False) self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g, bias=False)
self.bn = nn.BatchNorm2d(c2) self.bn = nn.BatchNorm2d(c2)
self.act = nn.SiLU() if act is True else (act if isinstance(act, nn.Module) else nn.Identity()) self.act = nn.SiLU() if act is True else (act if isinstance(act, nn.Module) else nn.Identity())
@@ -38,14 +46,62 @@ class Conv(nn.Module):
def forward(self, x): def forward(self, x):
return self.act(self.bn(self.conv(x))) return self.act(self.bn(self.conv(x)))
def fuseforward(self, x): def forward_fuse(self, x):
return self.act(self.conv(x)) return self.act(self.conv(x))
class DWConv(Conv):
# Depth-wise convolution class
def __init__(self, c1, c2, k=1, s=1, act=True): # ch_in, ch_out, kernel, stride, padding, groups
super().__init__(c1, c2, k, s, g=math.gcd(c1, c2), act=act)
class DWConvTranspose2d(nn.ConvTranspose2d):
# Depth-wise transpose convolution class
def __init__(self, c1, c2, k=1, s=1, p1=0, p2=0): # ch_in, ch_out, kernel, stride, padding, padding_out
super().__init__(c1, c2, k, s, p1, p2, groups=math.gcd(c1, c2))
class TransformerLayer(nn.Module):
# Transformer layer https://arxiv.org/abs/2010.11929 (LayerNorm layers removed for better performance)
def __init__(self, c, num_heads):
super().__init__()
self.q = nn.Linear(c, c, bias=False)
self.k = nn.Linear(c, c, bias=False)
self.v = nn.Linear(c, c, bias=False)
self.ma = nn.MultiheadAttention(embed_dim=c, num_heads=num_heads)
self.fc1 = nn.Linear(c, c, bias=False)
self.fc2 = nn.Linear(c, c, bias=False)
def forward(self, x):
x = self.ma(self.q(x), self.k(x), self.v(x))[0] + x
x = self.fc2(self.fc1(x)) + x
return x
class TransformerBlock(nn.Module):
# Vision Transformer https://arxiv.org/abs/2010.11929
def __init__(self, c1, c2, num_heads, num_layers):
super().__init__()
self.conv = None
if c1 != c2:
self.conv = Conv(c1, c2)
self.linear = nn.Linear(c2, c2) # learnable position embedding
self.tr = nn.Sequential(*(TransformerLayer(c2, num_heads) for _ in range(num_layers)))
self.c2 = c2
def forward(self, x):
if self.conv is not None:
x = self.conv(x)
b, _, w, h = x.shape
p = x.flatten(2).permute(2, 0, 1)
return self.tr(p + self.linear(p)).permute(1, 2, 0).reshape(b, self.c2, w, h)
class Bottleneck(nn.Module): class Bottleneck(nn.Module):
# Standard bottleneck # Standard bottleneck
def __init__(self, c1, c2, shortcut=True, g=1, e=0.5): # ch_in, ch_out, shortcut, groups, expansion def __init__(self, c1, c2, shortcut=True, g=1, e=0.5): # ch_in, ch_out, shortcut, groups, expansion
super(Bottleneck, self).__init__() super().__init__()
c_ = int(c2 * e) # hidden channels c_ = int(c2 * e) # hidden channels
self.cv1 = Conv(c1, c_, 1, 1) self.cv1 = Conv(c1, c_, 1, 1)
self.cv2 = Conv(c_, c2, 3, 1, g=g) self.cv2 = Conv(c_, c2, 3, 1, g=g)
@@ -58,41 +114,86 @@ class Bottleneck(nn.Module):
class BottleneckCSP(nn.Module): class BottleneckCSP(nn.Module):
# CSP Bottleneck https://github.com/WongKinYiu/CrossStagePartialNetworks # CSP Bottleneck https://github.com/WongKinYiu/CrossStagePartialNetworks
def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion
super(BottleneckCSP, self).__init__() super().__init__()
c_ = int(c2 * e) # hidden channels c_ = int(c2 * e) # hidden channels
self.cv1 = Conv(c1, c_, 1, 1) self.cv1 = Conv(c1, c_, 1, 1)
self.cv2 = nn.Conv2d(c1, c_, 1, 1, bias=False) self.cv2 = nn.Conv2d(c1, c_, 1, 1, bias=False)
self.cv3 = nn.Conv2d(c_, c_, 1, 1, bias=False) self.cv3 = nn.Conv2d(c_, c_, 1, 1, bias=False)
self.cv4 = Conv(2 * c_, c2, 1, 1) self.cv4 = Conv(2 * c_, c2, 1, 1)
self.bn = nn.BatchNorm2d(2 * c_) # applied to cat(cv2, cv3) self.bn = nn.BatchNorm2d(2 * c_) # applied to cat(cv2, cv3)
self.act = nn.LeakyReLU(0.1, inplace=True) self.act = nn.SiLU()
self.m = nn.Sequential(*[Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n)]) self.m = nn.Sequential(*(Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n)))
def forward(self, x): def forward(self, x):
y1 = self.cv3(self.m(self.cv1(x))) y1 = self.cv3(self.m(self.cv1(x)))
y2 = self.cv2(x) y2 = self.cv2(x)
return self.cv4(self.act(self.bn(torch.cat((y1, y2), dim=1)))) return self.cv4(self.act(self.bn(torch.cat((y1, y2), 1))))
class CrossConv(nn.Module):
# Cross Convolution Downsample
def __init__(self, c1, c2, k=3, s=1, g=1, e=1.0, shortcut=False):
# ch_in, ch_out, kernel, stride, groups, expansion, shortcut
super().__init__()
c_ = int(c2 * e) # hidden channels
self.cv1 = Conv(c1, c_, (1, k), (1, s))
self.cv2 = Conv(c_, c2, (k, 1), (s, 1), g=g)
self.add = shortcut and c1 == c2
def forward(self, x):
return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x))
class C3(nn.Module): class C3(nn.Module):
# CSP Bottleneck with 3 convolutions # CSP Bottleneck with 3 convolutions
def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion
super(C3, self).__init__() super().__init__()
c_ = int(c2 * e) # hidden channels c_ = int(c2 * e) # hidden channels
self.cv1 = Conv(c1, c_, 1, 1) self.cv1 = Conv(c1, c_, 1, 1)
self.cv2 = Conv(c1, c_, 1, 1) self.cv2 = Conv(c1, c_, 1, 1)
self.cv3 = Conv(2 * c_, c2, 1) # act=FReLU(c2) self.cv3 = Conv(2 * c_, c2, 1) # optional act=FReLU(c2)
self.m = nn.Sequential(*[Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n)]) self.m = nn.Sequential(*(Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n)))
# self.m = nn.Sequential(*[CrossConv(c_, c_, 3, 1, g, 1.0, shortcut) for _ in range(n)])
def forward(self, x): def forward(self, x):
return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), dim=1)) return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), 1))
class C3x(C3):
# C3 module with cross-convolutions
def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5):
super().__init__(c1, c2, n, shortcut, g, e)
c_ = int(c2 * e)
self.m = nn.Sequential(*(CrossConv(c_, c_, 3, 1, g, 1.0, shortcut) for _ in range(n)))
class C3TR(C3):
# C3 module with TransformerBlock()
def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5):
super().__init__(c1, c2, n, shortcut, g, e)
c_ = int(c2 * e)
self.m = TransformerBlock(c_, c_, 4, n)
class C3SPP(C3):
# C3 module with SPP()
def __init__(self, c1, c2, k=(5, 9, 13), n=1, shortcut=True, g=1, e=0.5):
super().__init__(c1, c2, n, shortcut, g, e)
c_ = int(c2 * e)
self.m = SPP(c_, c_, k)
class C3Ghost(C3):
# C3 module with GhostBottleneck()
def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5):
super().__init__(c1, c2, n, shortcut, g, e)
c_ = int(c2 * e) # hidden channels
self.m = nn.Sequential(*(GhostBottleneck(c_, c_) for _ in range(n)))
class SPP(nn.Module): class SPP(nn.Module):
# Spatial pyramid pooling layer used in YOLOv3-SPP # Spatial Pyramid Pooling (SPP) layer https://arxiv.org/abs/1406.4729
def __init__(self, c1, c2, k=(5, 9, 13)): def __init__(self, c1, c2, k=(5, 9, 13)):
super(SPP, self).__init__() super().__init__()
c_ = c1 // 2 # hidden channels c_ = c1 // 2 # hidden channels
self.cv1 = Conv(c1, c_, 1, 1) self.cv1 = Conv(c1, c_, 1, 1)
self.cv2 = Conv(c_ * (len(k) + 1), c2, 1, 1) self.cv2 = Conv(c_ * (len(k) + 1), c2, 1, 1)
@@ -100,21 +201,70 @@ class SPP(nn.Module):
def forward(self, x): def forward(self, x):
x = self.cv1(x) x = self.cv1(x)
return self.cv2(torch.cat([x] + [m(x) for m in self.m], 1)) with warnings.catch_warnings():
warnings.simplefilter('ignore') # suppress torch 1.9.0 max_pool2d() warning
return self.cv2(torch.cat([x] + [m(x) for m in self.m], 1))
class SPPF(nn.Module):
# Spatial Pyramid Pooling - Fast (SPPF) layer for YOLOv5 by Glenn Jocher
def __init__(self, c1, c2, k=5): # equivalent to SPP(k=(5, 9, 13))
super().__init__()
c_ = c1 // 2 # hidden channels
self.cv1 = Conv(c1, c_, 1, 1)
self.cv2 = Conv(c_ * 4, c2, 1, 1)
self.m = nn.MaxPool2d(kernel_size=k, stride=1, padding=k // 2)
def forward(self, x):
x = self.cv1(x)
with warnings.catch_warnings():
warnings.simplefilter('ignore') # suppress torch 1.9.0 max_pool2d() warning
y1 = self.m(x)
y2 = self.m(y1)
return self.cv2(torch.cat((x, y1, y2, self.m(y2)), 1))
class Focus(nn.Module): class Focus(nn.Module):
# Focus wh information into c-space # Focus wh information into c-space
def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True): # ch_in, ch_out, kernel, stride, padding, groups def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True): # ch_in, ch_out, kernel, stride, padding, groups
super(Focus, self).__init__() super().__init__()
self.conv = Conv(c1 * 4, c2, k, s, p, g, act) self.conv = Conv(c1 * 4, c2, k, s, p, g, act)
# self.contract = Contract(gain=2) # self.contract = Contract(gain=2)
def forward(self, x): # x(b,c,w,h) -> y(b,4c,w/2,h/2) def forward(self, x): # x(b,c,w,h) -> y(b,4c,w/2,h/2)
return self.conv(torch.cat([x[..., ::2, ::2], x[..., 1::2, ::2], x[..., ::2, 1::2], x[..., 1::2, 1::2]], 1)) return self.conv(torch.cat((x[..., ::2, ::2], x[..., 1::2, ::2], x[..., ::2, 1::2], x[..., 1::2, 1::2]), 1))
# return self.conv(self.contract(x)) # return self.conv(self.contract(x))
class GhostConv(nn.Module):
# Ghost Convolution https://github.com/huawei-noah/ghostnet
def __init__(self, c1, c2, k=1, s=1, g=1, act=True): # ch_in, ch_out, kernel, stride, groups
super().__init__()
c_ = c2 // 2 # hidden channels
self.cv1 = Conv(c1, c_, k, s, None, g, act)
self.cv2 = Conv(c_, c_, 5, 1, None, c_, act)
def forward(self, x):
y = self.cv1(x)
return torch.cat((y, self.cv2(y)), 1)
class GhostBottleneck(nn.Module):
# Ghost Bottleneck https://github.com/huawei-noah/ghostnet
def __init__(self, c1, c2, k=3, s=1): # ch_in, ch_out, kernel, stride
super().__init__()
c_ = c2 // 2
self.conv = nn.Sequential(
GhostConv(c1, c_, 1, 1), # pw
DWConv(c_, c_, k, s, act=False) if s == 2 else nn.Identity(), # dw
GhostConv(c_, c2, 1, 1, act=False)) # pw-linear
self.shortcut = nn.Sequential(DWConv(c1, c1, k, s, act=False), Conv(c1, c2, 1, 1,
act=False)) if s == 2 else nn.Identity()
def forward(self, x):
return self.conv(x) + self.shortcut(x)
class Contract(nn.Module): class Contract(nn.Module):
# Contract width-height into channels, i.e. x(1,64,80,80) to x(1,256,40,40) # Contract width-height into channels, i.e. x(1,64,80,80) to x(1,256,40,40)
def __init__(self, gain=2): def __init__(self, gain=2):
@@ -122,11 +272,11 @@ class Contract(nn.Module):
self.gain = gain self.gain = gain
def forward(self, x): def forward(self, x):
N, C, H, W = x.size() # assert (H / s == 0) and (W / s == 0), 'Indivisible gain' b, c, h, w = x.size() # assert (h / s == 0) and (W / s == 0), 'Indivisible gain'
s = self.gain s = self.gain
x = x.view(N, C, H // s, s, W // s, s) # x(1,64,40,2,40,2) x = x.view(b, c, h // s, s, w // s, s) # x(1,64,40,2,40,2)
x = x.permute(0, 3, 5, 1, 2, 4).contiguous() # x(1,2,2,64,40,40) x = x.permute(0, 3, 5, 1, 2, 4).contiguous() # x(1,2,2,64,40,40)
return x.view(N, C * s * s, H // s, W // s) # x(1,256,40,40) return x.view(b, c * s * s, h // s, w // s) # x(1,256,40,40)
class Expand(nn.Module): class Expand(nn.Module):
@@ -136,170 +286,449 @@ class Expand(nn.Module):
self.gain = gain self.gain = gain
def forward(self, x): def forward(self, x):
N, C, H, W = x.size() # assert C / s ** 2 == 0, 'Indivisible gain' b, c, h, w = x.size() # assert C / s ** 2 == 0, 'Indivisible gain'
s = self.gain s = self.gain
x = x.view(N, s, s, C // s ** 2, H, W) # x(1,2,2,16,80,80) x = x.view(b, s, s, c // s ** 2, h, w) # x(1,2,2,16,80,80)
x = x.permute(0, 3, 4, 1, 5, 2).contiguous() # x(1,16,80,2,80,2) x = x.permute(0, 3, 4, 1, 5, 2).contiguous() # x(1,16,80,2,80,2)
return x.view(N, C // s ** 2, H * s, W * s) # x(1,16,160,160) return x.view(b, c // s ** 2, h * s, w * s) # x(1,16,160,160)
class Concat(nn.Module): class Concat(nn.Module):
# Concatenate a list of tensors along dimension # Concatenate a list of tensors along dimension
def __init__(self, dimension=1): def __init__(self, dimension=1):
super(Concat, self).__init__() super().__init__()
self.d = dimension self.d = dimension
def forward(self, x): def forward(self, x):
return torch.cat(x, self.d) return torch.cat(x, self.d)
class NMS(nn.Module): class DetectMultiBackend(nn.Module):
# Non-Maximum Suppression (NMS) module # YOLOv5 MultiBackend class for python inference on various backends
conf = 0.25 # confidence threshold def __init__(self, weights='yolov5s.pt', device=torch.device('cpu'), dnn=False, data=None, fp16=False):
iou = 0.45 # IoU threshold # Usage:
classes = None # (optional list) filter by class # PyTorch: weights = *.pt
# TorchScript: *.torchscript
# ONNX Runtime: *.onnx
# ONNX OpenCV DNN: *.onnx with --dnn
# OpenVINO: *.xml
# CoreML: *.mlmodel
# TensorRT: *.engine
# TensorFlow SavedModel: *_saved_model
# TensorFlow GraphDef: *.pb
# TensorFlow Lite: *.tflite
# TensorFlow Edge TPU: *_edgetpu.tflite
from models.experimental import attempt_download, attempt_load # scoped to avoid circular import
def __init__(self): super().__init__()
super(NMS, self).__init__() w = str(weights[0] if isinstance(weights, list) else weights)
pt, jit, onnx, xml, engine, coreml, saved_model, pb, tflite, edgetpu, tfjs = self.model_type(w) # get backend
w = attempt_download(w) # download if not local
fp16 &= (pt or jit or onnx or engine) and device.type != 'cpu' # FP16
stride, names = 32, [f'class{i}' for i in range(1000)] # assign defaults
if data: # assign class names (optional)
with open(data, errors='ignore') as f:
names = yaml.safe_load(f)['names']
def forward(self, x): if pt: # PyTorch
return non_max_suppression(x[0], conf_thres=self.conf, iou_thres=self.iou, classes=self.classes) model = attempt_load(weights if isinstance(weights, list) else w, device=device)
stride = max(int(model.stride.max()), 32) # model stride
names = model.module.names if hasattr(model, 'module') else model.names # get class names
model.half() if fp16 else model.float()
self.model = model # explicitly assign for to(), cpu(), cuda(), half()
elif jit: # TorchScript
LOGGER.info(f'Loading {w} for TorchScript inference...')
extra_files = {'config.txt': ''} # model metadata
model = torch.jit.load(w, _extra_files=extra_files)
model.half() if fp16 else model.float()
if extra_files['config.txt']:
d = json.loads(extra_files['config.txt']) # extra_files dict
stride, names = int(d['stride']), d['names']
elif dnn: # ONNX OpenCV DNN
LOGGER.info(f'Loading {w} for ONNX OpenCV DNN inference...')
check_requirements(('opencv-python>=4.5.4',))
net = cv2.dnn.readNetFromONNX(w)
elif onnx: # ONNX Runtime
LOGGER.info(f'Loading {w} for ONNX Runtime inference...')
cuda = torch.cuda.is_available()
check_requirements(('onnx', 'onnxruntime-gpu' if cuda else 'onnxruntime'))
import onnxruntime
providers = ['CUDAExecutionProvider', 'CPUExecutionProvider'] if cuda else ['CPUExecutionProvider']
session = onnxruntime.InferenceSession(w, providers=providers)
meta = session.get_modelmeta().custom_metadata_map # metadata
if 'stride' in meta:
stride, names = int(meta['stride']), eval(meta['names'])
elif xml: # OpenVINO
LOGGER.info(f'Loading {w} for OpenVINO inference...')
check_requirements(('openvino',)) # requires openvino-dev: https://pypi.org/project/openvino-dev/
from openvino.runtime import Core
ie = Core()
if not Path(w).is_file(): # if not *.xml
w = next(Path(w).glob('*.xml')) # get *.xml file from *_openvino_model dir
network = ie.read_model(model=w, weights=Path(w).with_suffix('.bin'))
executable_network = ie.compile_model(model=network, device_name="CPU")
output_layer = next(iter(executable_network.outputs))
meta = Path(w).with_suffix('.yaml')
if meta.exists():
stride, names = self._load_metadata(meta) # load metadata
elif engine: # TensorRT
LOGGER.info(f'Loading {w} for TensorRT inference...')
import tensorrt as trt # https://developer.nvidia.com/nvidia-tensorrt-download
check_version(trt.__version__, '7.0.0', hard=True) # require tensorrt>=7.0.0
Binding = namedtuple('Binding', ('name', 'dtype', 'shape', 'data', 'ptr'))
logger = trt.Logger(trt.Logger.INFO)
with open(w, 'rb') as f, trt.Runtime(logger) as runtime:
model = runtime.deserialize_cuda_engine(f.read())
bindings = OrderedDict()
fp16 = False # default updated below
for index in range(model.num_bindings):
name = model.get_binding_name(index)
dtype = trt.nptype(model.get_binding_dtype(index))
shape = tuple(model.get_binding_shape(index))
data = torch.from_numpy(np.empty(shape, dtype=np.dtype(dtype))).to(device)
bindings[name] = Binding(name, dtype, shape, data, int(data.data_ptr()))
if model.binding_is_input(index) and dtype == np.float16:
fp16 = True
binding_addrs = OrderedDict((n, d.ptr) for n, d in bindings.items())
context = model.create_execution_context()
batch_size = bindings['images'].shape[0]
elif coreml: # CoreML
LOGGER.info(f'Loading {w} for CoreML inference...')
import coremltools as ct
model = ct.models.MLModel(w)
else: # TensorFlow (SavedModel, GraphDef, Lite, Edge TPU)
if saved_model: # SavedModel
LOGGER.info(f'Loading {w} for TensorFlow SavedModel inference...')
import tensorflow as tf
keras = False # assume TF1 saved_model
model = tf.keras.models.load_model(w) if keras else tf.saved_model.load(w)
elif pb: # GraphDef https://www.tensorflow.org/guide/migrate#a_graphpb_or_graphpbtxt
LOGGER.info(f'Loading {w} for TensorFlow GraphDef inference...')
import tensorflow as tf
def wrap_frozen_graph(gd, inputs, outputs):
x = tf.compat.v1.wrap_function(lambda: tf.compat.v1.import_graph_def(gd, name=""), []) # wrapped
ge = x.graph.as_graph_element
return x.prune(tf.nest.map_structure(ge, inputs), tf.nest.map_structure(ge, outputs))
gd = tf.Graph().as_graph_def() # graph_def
with open(w, 'rb') as f:
gd.ParseFromString(f.read())
frozen_func = wrap_frozen_graph(gd, inputs="x:0", outputs="Identity:0")
elif tflite or edgetpu: # https://www.tensorflow.org/lite/guide/python#install_tensorflow_lite_for_python
try: # https://coral.ai/docs/edgetpu/tflite-python/#update-existing-tf-lite-code-for-the-edge-tpu
from tflite_runtime.interpreter import Interpreter, load_delegate
except ImportError:
import tensorflow as tf
Interpreter, load_delegate = tf.lite.Interpreter, tf.lite.experimental.load_delegate,
if edgetpu: # Edge TPU https://coral.ai/software/#edgetpu-runtime
LOGGER.info(f'Loading {w} for TensorFlow Lite Edge TPU inference...')
delegate = {
'Linux': 'libedgetpu.so.1',
'Darwin': 'libedgetpu.1.dylib',
'Windows': 'edgetpu.dll'}[platform.system()]
interpreter = Interpreter(model_path=w, experimental_delegates=[load_delegate(delegate)])
else: # Lite
LOGGER.info(f'Loading {w} for TensorFlow Lite inference...')
interpreter = Interpreter(model_path=w) # load TFLite model
interpreter.allocate_tensors() # allocate
input_details = interpreter.get_input_details() # inputs
output_details = interpreter.get_output_details() # outputs
elif tfjs:
raise Exception('ERROR: YOLOv5 TF.js inference is not supported')
self.__dict__.update(locals()) # assign all variables to self
def forward(self, im, augment=False, visualize=False, val=False):
# YOLOv5 MultiBackend inference
b, ch, h, w = im.shape # batch, channel, height, width
if self.pt: # PyTorch
y = self.model(im, augment=augment, visualize=visualize)[0]
elif self.jit: # TorchScript
y = self.model(im)[0]
elif self.dnn: # ONNX OpenCV DNN
im = im.cpu().numpy() # torch to numpy
self.net.setInput(im)
y = self.net.forward()
elif self.onnx: # ONNX Runtime
im = im.cpu().numpy() # torch to numpy
y = self.session.run([self.session.get_outputs()[0].name], {self.session.get_inputs()[0].name: im})[0]
elif self.xml: # OpenVINO
im = im.cpu().numpy() # FP32
y = self.executable_network([im])[self.output_layer]
elif self.engine: # TensorRT
assert im.shape == self.bindings['images'].shape, (im.shape, self.bindings['images'].shape)
self.binding_addrs['images'] = int(im.data_ptr())
self.context.execute_v2(list(self.binding_addrs.values()))
y = self.bindings['output'].data
elif self.coreml: # CoreML
im = im.permute(0, 2, 3, 1).cpu().numpy() # torch BCHW to numpy BHWC shape(1,320,192,3)
im = Image.fromarray((im[0] * 255).astype('uint8'))
# im = im.resize((192, 320), Image.ANTIALIAS)
y = self.model.predict({'image': im}) # coordinates are xywh normalized
if 'confidence' in y:
box = xywh2xyxy(y['coordinates'] * [[w, h, w, h]]) # xyxy pixels
conf, cls = y['confidence'].max(1), y['confidence'].argmax(1).astype(np.float)
y = np.concatenate((box, conf.reshape(-1, 1), cls.reshape(-1, 1)), 1)
else:
k = 'var_' + str(sorted(int(k.replace('var_', '')) for k in y)[-1]) # output key
y = y[k] # output
else: # TensorFlow (SavedModel, GraphDef, Lite, Edge TPU)
im = im.permute(0, 2, 3, 1).cpu().numpy() # torch BCHW to numpy BHWC shape(1,320,192,3)
if self.saved_model: # SavedModel
y = (self.model(im, training=False) if self.keras else self.model(im)).numpy()
elif self.pb: # GraphDef
y = self.frozen_func(x=self.tf.constant(im)).numpy()
else: # Lite or Edge TPU
input, output = self.input_details[0], self.output_details[0]
int8 = input['dtype'] == np.uint8 # is TFLite quantized uint8 model
if int8:
scale, zero_point = input['quantization']
im = (im / scale + zero_point).astype(np.uint8) # de-scale
self.interpreter.set_tensor(input['index'], im)
self.interpreter.invoke()
y = self.interpreter.get_tensor(output['index'])
if int8:
scale, zero_point = output['quantization']
y = (y.astype(np.float32) - zero_point) * scale # re-scale
y[..., :4] *= [w, h, w, h] # xywh normalized to pixels
if isinstance(y, np.ndarray):
y = torch.tensor(y, device=self.device)
return (y, []) if val else y
def warmup(self, imgsz=(1, 3, 640, 640)):
# Warmup model by running inference once
warmup_types = self.pt, self.jit, self.onnx, self.engine, self.saved_model, self.pb
if any(warmup_types) and self.device.type != 'cpu':
im = torch.zeros(*imgsz, dtype=torch.half if self.fp16 else torch.float, device=self.device) # input
for _ in range(2 if self.jit else 1): #
self.forward(im) # warmup
@staticmethod
def model_type(p='path/to/model.pt'):
# Return model type from model path, i.e. path='path/to/model.onnx' -> type=onnx
from export import export_formats
suffixes = list(export_formats().Suffix) + ['.xml'] # export suffixes
check_suffix(p, suffixes) # checks
p = Path(p).name # eliminate trailing separators
pt, jit, onnx, xml, engine, coreml, saved_model, pb, tflite, edgetpu, tfjs, xml2 = (s in p for s in suffixes)
xml |= xml2 # *_openvino_model or *.xml
tflite &= not edgetpu # *.tflite
return pt, jit, onnx, xml, engine, coreml, saved_model, pb, tflite, edgetpu, tfjs
@staticmethod
def _load_metadata(f='path/to/meta.yaml'):
# Load metadata from meta.yaml if it exists
with open(f, errors='ignore') as f:
d = yaml.safe_load(f)
return d['stride'], d['names'] # assign stride, names
class autoShape(nn.Module): class AutoShape(nn.Module):
# input-robust model wrapper for passing cv2/np/PIL/torch inputs. Includes preprocessing, inference and NMS # YOLOv5 input-robust model wrapper for passing cv2/np/PIL/torch inputs. Includes preprocessing, inference and NMS
img_size = 640 # inference size (pixels)
conf = 0.25 # NMS confidence threshold conf = 0.25 # NMS confidence threshold
iou = 0.45 # NMS IoU threshold iou = 0.45 # NMS IoU threshold
classes = None # (optional list) filter by class agnostic = False # NMS class-agnostic
multi_label = False # NMS multiple labels per box
classes = None # (optional list) filter by class, i.e. = [0, 15, 16] for COCO persons, cats and dogs
max_det = 1000 # maximum number of detections per image
amp = False # Automatic Mixed Precision (AMP) inference
def __init__(self, model): def __init__(self, model, verbose=True):
super(autoShape, self).__init__() super().__init__()
if verbose:
LOGGER.info('Adding AutoShape... ')
copy_attr(self, model, include=('yaml', 'nc', 'hyp', 'names', 'stride', 'abc'), exclude=()) # copy attributes
self.dmb = isinstance(model, DetectMultiBackend) # DetectMultiBackend() instance
self.pt = not self.dmb or model.pt # PyTorch model
self.model = model.eval() self.model = model.eval()
def autoshape(self): def _apply(self, fn):
print('autoShape already enabled, skipping... ') # model already converted to model.autoshape() # Apply to(), cpu(), cuda(), half() to model tensors that are not parameters or registered buffers
self = super()._apply(fn)
if self.pt:
m = self.model.model.model[-1] if self.dmb else self.model.model[-1] # Detect()
m.stride = fn(m.stride)
m.grid = list(map(fn, m.grid))
if isinstance(m.anchor_grid, list):
m.anchor_grid = list(map(fn, m.anchor_grid))
return self return self
@torch.no_grad()
def forward(self, imgs, size=640, augment=False, profile=False): def forward(self, imgs, size=640, augment=False, profile=False):
# Inference from various sources. For height=720, width=1280, RGB images example inputs are: # Inference from various sources. For height=640, width=1280, RGB images example inputs are:
# filename: imgs = 'data/samples/zidane.jpg' # file: imgs = 'data/images/zidane.jpg' # str or PosixPath
# URI: = 'https://github.com/ultralytics/yolov5/releases/download/v1.0/zidane.jpg' # URI: = 'https://ultralytics.com/images/zidane.jpg'
# OpenCV: = cv2.imread('image.jpg')[:,:,::-1] # HWC BGR to RGB x(720,1280,3) # OpenCV: = cv2.imread('image.jpg')[:,:,::-1] # HWC BGR to RGB x(640,1280,3)
# PIL: = Image.open('image.jpg') # HWC x(720,1280,3) # PIL: = Image.open('image.jpg') or ImageGrab.grab() # HWC x(640,1280,3)
# numpy: = np.zeros((720,1280,3)) # HWC # numpy: = np.zeros((640,1280,3)) # HWC
# torch: = torch.zeros(16,3,720,1280) # BCHW # torch: = torch.zeros(16,3,320,640) # BCHW (scaled to size=640, 0-1 values)
# multiple: = [Image.open('image1.jpg'), Image.open('image2.jpg'), ...] # list of images # multiple: = [Image.open('image1.jpg'), Image.open('image2.jpg'), ...] # list of images
p = next(self.model.parameters()) # for device and type t = [time_sync()]
p = next(self.model.parameters()) if self.pt else torch.zeros(1, device=self.model.device) # for device, type
autocast = self.amp and (p.device.type != 'cpu') # Automatic Mixed Precision (AMP) inference
if isinstance(imgs, torch.Tensor): # torch if isinstance(imgs, torch.Tensor): # torch
return self.model(imgs.to(p.device).type_as(p), augment, profile) # inference with amp.autocast(autocast):
return self.model(imgs.to(p.device).type_as(p), augment, profile) # inference
# Pre-process # Pre-process
n, imgs = (len(imgs), imgs) if isinstance(imgs, list) else (1, [imgs]) # number of images, list of images n, imgs = (len(imgs), list(imgs)) if isinstance(imgs, (list, tuple)) else (1, [imgs]) # number, list of images
shape0, shape1, files = [], [], [] # image and inference shapes, filenames shape0, shape1, files = [], [], [] # image and inference shapes, filenames
for i, im in enumerate(imgs): for i, im in enumerate(imgs):
if isinstance(im, str): # filename or uri f = f'image{i}' # filename
im, f = Image.open(requests.get(im, stream=True).raw if im.startswith('http') else im), im # open if isinstance(im, (str, Path)): # filename or uri
im.filename = f # for uri im, f = Image.open(requests.get(im, stream=True).raw if str(im).startswith('http') else im), im
files.append(Path(im.filename).with_suffix('.jpg').name if isinstance(im, Image.Image) else f'image{i}.jpg') im = np.asarray(exif_transpose(im))
im = np.array(im) # to numpy elif isinstance(im, Image.Image): # PIL Image
im, f = np.asarray(exif_transpose(im)), getattr(im, 'filename', f) or f
files.append(Path(f).with_suffix('.jpg').name)
if im.shape[0] < 5: # image in CHW if im.shape[0] < 5: # image in CHW
im = im.transpose((1, 2, 0)) # reverse dataloader .transpose(2, 0, 1) im = im.transpose((1, 2, 0)) # reverse dataloader .transpose(2, 0, 1)
im = im[:, :, :3] if im.ndim == 3 else np.tile(im[:, :, None], 3) # enforce 3ch input im = im[..., :3] if im.ndim == 3 else np.tile(im[..., None], 3) # enforce 3ch input
s = im.shape[:2] # HWC s = im.shape[:2] # HWC
shape0.append(s) # image shape shape0.append(s) # image shape
g = (size / max(s)) # gain g = (size / max(s)) # gain
shape1.append([y * g for y in s]) shape1.append([y * g for y in s])
imgs[i] = im # update imgs[i] = im if im.data.contiguous else np.ascontiguousarray(im) # update
shape1 = [make_divisible(x, int(self.stride.max())) for x in np.stack(shape1, 0).max(0)] # inference shape shape1 = [make_divisible(x, self.stride) if self.pt else size for x in np.array(shape1).max(0)] # inf shape
x = [letterbox(im, new_shape=shape1, auto=False)[0] for im in imgs] # pad x = [letterbox(im, shape1, auto=False)[0] for im in imgs] # pad
x = np.stack(x, 0) if n > 1 else x[0][None] # stack x = np.ascontiguousarray(np.array(x).transpose((0, 3, 1, 2))) # stack and BHWC to BCHW
x = np.ascontiguousarray(x.transpose((0, 3, 1, 2))) # BHWC to BCHW x = torch.from_numpy(x).to(p.device).type_as(p) / 255 # uint8 to fp16/32
x = torch.from_numpy(x).to(p.device).type_as(p) / 255. # uint8 to fp16/32 t.append(time_sync())
# Inference with amp.autocast(autocast):
with torch.no_grad(): # Inference
y = self.model(x, augment, profile)[0] # forward y = self.model(x, augment, profile) # forward
y = non_max_suppression(y, conf_thres=self.conf, iou_thres=self.iou, classes=self.classes) # NMS t.append(time_sync())
# Post-process # Post-process
for i in range(n): y = non_max_suppression(y if self.dmb else y[0],
scale_coords(shape1, y[i][:, :4], shape0[i]) self.conf,
self.iou,
self.classes,
self.agnostic,
self.multi_label,
max_det=self.max_det) # NMS
for i in range(n):
scale_coords(shape1, y[i][:, :4], shape0[i])
return Detections(imgs, y, files, self.names) t.append(time_sync())
return Detections(imgs, y, files, t, self.names, x.shape)
class Detections: class Detections:
# detections class for YOLOv5 inference results # YOLOv5 detections class for inference results
def __init__(self, imgs, pred, files, names=None): def __init__(self, imgs, pred, files, times=(0, 0, 0, 0), names=None, shape=None):
super(Detections, self).__init__() super().__init__()
d = pred[0].device # device d = pred[0].device # device
gn = [torch.tensor([*[im.shape[i] for i in [1, 0, 1, 0]], 1., 1.], device=d) for im in imgs] # normalizations gn = [torch.tensor([*(im.shape[i] for i in [1, 0, 1, 0]), 1, 1], device=d) for im in imgs] # normalizations
self.imgs = imgs # list of images as numpy arrays self.imgs = imgs # list of images as numpy arrays
self.pred = pred # list of tensors pred[0] = (xyxy, conf, cls) self.pred = pred # list of tensors pred[0] = (xyxy, conf, cls)
self.names = names # class names self.names = names # class names
self.files = files # image filenames self.files = files # image filenames
self.times = times # profiling times
self.xyxy = pred # xyxy pixels self.xyxy = pred # xyxy pixels
self.xywh = [xyxy2xywh(x) for x in pred] # xywh pixels self.xywh = [xyxy2xywh(x) for x in pred] # xywh pixels
self.xyxyn = [x / g for x, g in zip(self.xyxy, gn)] # xyxy normalized self.xyxyn = [x / g for x, g in zip(self.xyxy, gn)] # xyxy normalized
self.xywhn = [x / g for x, g in zip(self.xywh, gn)] # xywh normalized self.xywhn = [x / g for x, g in zip(self.xywh, gn)] # xywh normalized
self.n = len(self.pred) self.n = len(self.pred) # number of images (batch size)
self.t = tuple((times[i + 1] - times[i]) * 1000 / self.n for i in range(3)) # timestamps (ms)
self.s = shape # inference BCHW shape
def display(self, pprint=False, show=False, save=False, render=False, save_dir=''): def display(self, pprint=False, show=False, save=False, crop=False, render=False, labels=True, save_dir=Path('')):
colors = color_list() crops = []
for i, (img, pred) in enumerate(zip(self.imgs, self.pred)): for i, (im, pred) in enumerate(zip(self.imgs, self.pred)):
str = f'image {i + 1}/{len(self.pred)}: {img.shape[0]}x{img.shape[1]} ' s = f'image {i + 1}/{len(self.pred)}: {im.shape[0]}x{im.shape[1]} ' # string
if pred is not None: if pred.shape[0]:
for c in pred[:, -1].unique(): for c in pred[:, -1].unique():
n = (pred[:, -1] == c).sum() # detections per class n = (pred[:, -1] == c).sum() # detections per class
str += f"{n} {self.names[int(c)]}{'s' * (n > 1)}, " # add to string s += f"{n} {self.names[int(c)]}{'s' * (n > 1)}, " # add to string
if show or save or render: if show or save or render or crop:
for *box, conf, cls in pred: # xyxy, confidence, class annotator = Annotator(im, example=str(self.names))
for *box, conf, cls in reversed(pred): # xyxy, confidence, class
label = f'{self.names[int(cls)]} {conf:.2f}' label = f'{self.names[int(cls)]} {conf:.2f}'
plot_one_box(box, img, label=label, color=colors[int(cls) % 10]) if crop:
img = Image.fromarray(img.astype(np.uint8)) if isinstance(img, np.ndarray) else img # from np file = save_dir / 'crops' / self.names[int(cls)] / self.files[i] if save else None
crops.append({
'box': box,
'conf': conf,
'cls': cls,
'label': label,
'im': save_one_box(box, im, file=file, save=save)})
else: # all others
annotator.box_label(box, label if labels else '', color=colors(cls))
im = annotator.im
else:
s += '(no detections)'
im = Image.fromarray(im.astype(np.uint8)) if isinstance(im, np.ndarray) else im # from np
if pprint: if pprint:
print(str.rstrip(', ')) print(s.rstrip(', '))
if show: if show:
img.show(self.files[i]) # show im.show(self.files[i]) # show
if save: if save:
f = Path(save_dir) / self.files[i] f = self.files[i]
img.save(f) # save im.save(save_dir / f) # save
print(f"{'Saving' * (i == 0)} {f},", end='' if i < self.n - 1 else ' done.\n') if i == self.n - 1:
LOGGER.info(f"Saved {self.n} image{'s' * (self.n > 1)} to {colorstr('bold', save_dir)}")
if render: if render:
self.imgs[i] = np.asarray(img) self.imgs[i] = np.asarray(im)
if crop:
if save:
LOGGER.info(f'Saved results to {save_dir}\n')
return crops
def print(self): def print(self):
self.display(pprint=True) # print results self.display(pprint=True) # print results
print(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {tuple(self.s)}' % self.t)
def show(self): def show(self, labels=True):
self.display(show=True) # show results self.display(show=True, labels=labels) # show results
def save(self, save_dir='results/'): def save(self, labels=True, save_dir='runs/detect/exp'):
Path(save_dir).mkdir(exist_ok=True) save_dir = increment_path(save_dir, exist_ok=save_dir != 'runs/detect/exp', mkdir=True) # increment save_dir
self.display(save=True, save_dir=save_dir) # save results self.display(save=True, labels=labels, save_dir=save_dir) # save results
def render(self): def crop(self, save=True, save_dir='runs/detect/exp'):
self.display(render=True) # render results save_dir = increment_path(save_dir, exist_ok=save_dir != 'runs/detect/exp', mkdir=True) if save else None
return self.display(crop=True, save=save, save_dir=save_dir) # crop results
def render(self, labels=True):
self.display(render=True, labels=labels) # render results
return self.imgs return self.imgs
def __len__(self): def pandas(self):
return self.n # return detections as pandas DataFrames, i.e. print(results.pandas().xyxy[0])
new = copy(self) # return copy
ca = 'xmin', 'ymin', 'xmax', 'ymax', 'confidence', 'class', 'name' # xyxy columns
cb = 'xcenter', 'ycenter', 'width', 'height', 'confidence', 'class', 'name' # xywh columns
for k, c in zip(['xyxy', 'xyxyn', 'xywh', 'xywhn'], [ca, ca, cb, cb]):
a = [[x[:5] + [int(x[5]), self.names[int(x[5])]] for x in x.tolist()] for x in getattr(self, k)] # update
setattr(new, k, [pd.DataFrame(x, columns=c) for x in a])
return new
def tolist(self): def tolist(self):
# return a list of Detections objects, i.e. 'for result in results.tolist():' # return a list of Detections objects, i.e. 'for result in results.tolist():'
x = [Detections([self.imgs[i]], [self.pred[i]], self.names) for i in range(self.n)] r = range(self.n) # iterable
for d in x: x = [Detections([self.imgs[i]], [self.pred[i]], [self.files[i]], self.times, self.names, self.s) for i in r]
for k in ['imgs', 'pred', 'xyxy', 'xyxyn', 'xywh', 'xywhn']: # for d in x:
setattr(d, k, getattr(d, k)[0]) # pop out of list # for k in ['imgs', 'pred', 'xyxy', 'xyxyn', 'xywh', 'xywhn']:
# setattr(d, k, getattr(d, k)[0]) # pop out of list
return x return x
def __len__(self):
return self.n # override len(results)
def __str__(self):
self.print() # override print(results)
return ''
class Classify(nn.Module): class Classify(nn.Module):
# Classification head, i.e. x(b,c1,20,20) to x(b,c2) # Classification head, i.e. x(b,c1,20,20) to x(b,c2)
def __init__(self, c1, c2, k=1, s=1, p=None, g=1): # ch_in, ch_out, kernel, stride, padding, groups def __init__(self, c1, c2, k=1, s=1, p=None, g=1): # ch_in, ch_out, kernel, stride, padding, groups
super(Classify, self).__init__() super().__init__()
self.aap = nn.AdaptiveAvgPool2d(1) # to x(b,c1,1,1) self.aap = nn.AdaptiveAvgPool2d(1) # to x(b,c1,1,1)
self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g) # to x(b,c2,1,1) self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g) # to x(b,c2,1,1)
self.flat = nn.Flatten() self.flat = nn.Flatten()
+46 -77
View File
@@ -1,36 +1,25 @@
# This file contains experimental modules # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
"""
Experimental modules
"""
import math
import numpy as np import numpy as np
import torch import torch
import torch.nn as nn import torch.nn as nn
from models.common import Conv
from Y5.models.common import Conv, DWConv from utils.downloads import attempt_download
from Y5.utils.google_utils import attempt_download
class CrossConv(nn.Module):
# Cross Convolution Downsample
def __init__(self, c1, c2, k=3, s=1, g=1, e=1.0, shortcut=False):
# ch_in, ch_out, kernel, stride, groups, expansion, shortcut
super(CrossConv, self).__init__()
c_ = int(c2 * e) # hidden channels
self.cv1 = Conv(c1, c_, (1, k), (1, s))
self.cv2 = Conv(c_, c2, (k, 1), (s, 1), g=g)
self.add = shortcut and c1 == c2
def forward(self, x):
return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x))
class Sum(nn.Module): class Sum(nn.Module):
# Weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 # Weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070
def __init__(self, n, weight=False): # n: number of inputs def __init__(self, n, weight=False): # n: number of inputs
super(Sum, self).__init__() super().__init__()
self.weight = weight # apply weights boolean self.weight = weight # apply weights boolean
self.iter = range(n - 1) # iter object self.iter = range(n - 1) # iter object
if weight: if weight:
self.w = nn.Parameter(-torch.arange(1., n) / 2, requires_grad=True) # layer weights self.w = nn.Parameter(-torch.arange(1.0, n) / 2, requires_grad=True) # layer weights
def forward(self, x): def forward(self, x):
y = x[0] # no weight y = x[0] # no weight
@@ -44,92 +33,72 @@ class Sum(nn.Module):
return y return y
class GhostConv(nn.Module):
# Ghost Convolution https://github.com/huawei-noah/ghostnet
def __init__(self, c1, c2, k=1, s=1, g=1, act=True): # ch_in, ch_out, kernel, stride, groups
super(GhostConv, self).__init__()
c_ = c2 // 2 # hidden channels
self.cv1 = Conv(c1, c_, k, s, None, g, act)
self.cv2 = Conv(c_, c_, 5, 1, None, c_, act)
def forward(self, x):
y = self.cv1(x)
return torch.cat([y, self.cv2(y)], 1)
class GhostBottleneck(nn.Module):
# Ghost Bottleneck https://github.com/huawei-noah/ghostnet
def __init__(self, c1, c2, k=3, s=1): # ch_in, ch_out, kernel, stride
super(GhostBottleneck, self).__init__()
c_ = c2 // 2
self.conv = nn.Sequential(GhostConv(c1, c_, 1, 1), # pw
DWConv(c_, c_, k, s, act=False) if s == 2 else nn.Identity(), # dw
GhostConv(c_, c2, 1, 1, act=False)) # pw-linear
self.shortcut = nn.Sequential(DWConv(c1, c1, k, s, act=False),
Conv(c1, c2, 1, 1, act=False)) if s == 2 else nn.Identity()
def forward(self, x):
return self.conv(x) + self.shortcut(x)
class MixConv2d(nn.Module): class MixConv2d(nn.Module):
# Mixed Depthwise Conv https://arxiv.org/abs/1907.09595 # Mixed Depth-wise Conv https://arxiv.org/abs/1907.09595
def __init__(self, c1, c2, k=(1, 3), s=1, equal_ch=True): def __init__(self, c1, c2, k=(1, 3), s=1, equal_ch=True): # ch_in, ch_out, kernel, stride, ch_strategy
super(MixConv2d, self).__init__() super().__init__()
groups = len(k) n = len(k) # number of convolutions
if equal_ch: # equal c_ per group if equal_ch: # equal c_ per group
i = torch.linspace(0, groups - 1E-6, c2).floor() # c2 indices i = torch.linspace(0, n - 1E-6, c2).floor() # c2 indices
c_ = [(i == g).sum() for g in range(groups)] # intermediate channels c_ = [(i == g).sum() for g in range(n)] # intermediate channels
else: # equal weight.numel() per group else: # equal weight.numel() per group
b = [c2] + [0] * groups b = [c2] + [0] * n
a = np.eye(groups + 1, groups, k=-1) a = np.eye(n + 1, n, k=-1)
a -= np.roll(a, 1, axis=1) a -= np.roll(a, 1, axis=1)
a *= np.array(k) ** 2 a *= np.array(k) ** 2
a[0] = 1 a[0] = 1
c_ = np.linalg.lstsq(a, b, rcond=None)[0].round() # solve for equal weight indices, ax = b c_ = np.linalg.lstsq(a, b, rcond=None)[0].round() # solve for equal weight indices, ax = b
self.m = nn.ModuleList([nn.Conv2d(c1, int(c_[g]), k[g], s, k[g] // 2, bias=False) for g in range(groups)]) self.m = nn.ModuleList([
nn.Conv2d(c1, int(c_), k, s, k // 2, groups=math.gcd(c1, int(c_)), bias=False) for k, c_ in zip(k, c_)])
self.bn = nn.BatchNorm2d(c2) self.bn = nn.BatchNorm2d(c2)
self.act = nn.LeakyReLU(0.1, inplace=True) self.act = nn.SiLU()
def forward(self, x): def forward(self, x):
return x + self.act(self.bn(torch.cat([m(x) for m in self.m], 1))) return self.act(self.bn(torch.cat([m(x) for m in self.m], 1)))
class Ensemble(nn.ModuleList): class Ensemble(nn.ModuleList):
# Ensemble of models # Ensemble of models
def __init__(self): def __init__(self):
super(Ensemble, self).__init__() super().__init__()
def forward(self, x, augment=False): def forward(self, x, augment=False, profile=False, visualize=False):
y = [] y = [module(x, augment, profile, visualize)[0] for module in self]
for module in self:
y.append(module(x, augment)[0])
# y = torch.stack(y).max(0)[0] # max ensemble # y = torch.stack(y).max(0)[0] # max ensemble
# y = torch.stack(y).mean(0) # mean ensemble # y = torch.stack(y).mean(0) # mean ensemble
y = torch.cat(y, 1) # nms ensemble y = torch.cat(y, 1) # nms ensemble
return y, None # inference, train output return y, None # inference, train output
def attempt_load(weights, map_location=None): def attempt_load(weights, device=None, inplace=True, fuse=True):
# Loads an ensemble of models weights=[a,b,c] or a single model weights=[a] or weights=a # Loads an ensemble of models weights=[a,b,c] or a single model weights=[a] or weights=a
from models.yolo import Detect, Model
model = Ensemble() model = Ensemble()
for w in weights if isinstance(weights, list) else [weights]: for w in weights if isinstance(weights, list) else [weights]:
attempt_download(w) ckpt = torch.load(attempt_download(w), map_location='cpu') # load
ckpt = torch.load(w, map_location=map_location) # load ckpt = (ckpt.get('ema') or ckpt['model']).to(device).float() # FP32 model
model.append(ckpt['ema' if ckpt.get('ema') else 'model'].float().fuse().eval()) # FP32 model model.append(ckpt.fuse().eval() if fuse else ckpt.eval()) # fused or un-fused model in eval mode
# Compatibility updates # Compatibility updates
for m in model.modules(): for m in model.modules():
if type(m) in [nn.Hardswish, nn.LeakyReLU, nn.ReLU, nn.ReLU6, nn.SiLU]: t = type(m)
m.inplace = True # pytorch 1.7.0 compatibility if t in (nn.Hardswish, nn.LeakyReLU, nn.ReLU, nn.ReLU6, nn.SiLU, Detect, Model):
elif type(m) is Conv: m.inplace = inplace # torch 1.7.0 compatibility
m._non_persistent_buffers_set = set() # pytorch 1.6.0 compatibility if t is Detect and not isinstance(m.anchor_grid, list):
delattr(m, 'anchor_grid')
setattr(m, 'anchor_grid', [torch.zeros(1)] * m.nl)
elif t is Conv:
m._non_persistent_buffers_set = set() # torch 1.6.0 compatibility
elif t is nn.Upsample and not hasattr(m, 'recompute_scale_factor'):
m.recompute_scale_factor = None # torch 1.11.0 compatibility
if len(model) == 1: if len(model) == 1:
return model[-1] # return model return model[-1] # return model
else: print(f'Ensemble created with {weights}\n')
print('Ensemble created with %s\n' % weights) for k in 'names', 'nc', 'yaml':
for k in ['names', 'stride']: setattr(model, k, getattr(model[0], k))
setattr(model, k, getattr(model[-1], k)) model.stride = model[torch.argmax(torch.tensor([m.stride.max() for m in model])).int()].stride # max stride
return model # return ensemble assert all(model[0].nc == m.nc for m in model), f'Models have different class counts: {[m.nc for m in model]}'
return model # return ensemble
+32 -31
View File
@@ -1,58 +1,59 @@
# Default YOLOv5 anchors for COCO data # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
# Default anchors for COCO data
# P5 ------------------------------------------------------------------------------------------------------------------- # P5 -------------------------------------------------------------------------------------------------------------------
# P5-640: # P5-640:
anchors_p5_640: anchors_p5_640:
- [ 10,13, 16,30, 33,23 ] # P3/8 - [10,13, 16,30, 33,23] # P3/8
- [ 30,61, 62,45, 59,119 ] # P4/16 - [30,61, 62,45, 59,119] # P4/16
- [ 116,90, 156,198, 373,326 ] # P5/32 - [116,90, 156,198, 373,326] # P5/32
# P6 ------------------------------------------------------------------------------------------------------------------- # P6 -------------------------------------------------------------------------------------------------------------------
# P6-640: thr=0.25: 0.9964 BPR, 5.54 anchors past thr, n=12, img_size=640, metric_all=0.281/0.716-mean/best, past_thr=0.469-mean: 9,11, 21,19, 17,41, 43,32, 39,70, 86,64, 65,131, 134,130, 120,265, 282,180, 247,354, 512,387 # P6-640: thr=0.25: 0.9964 BPR, 5.54 anchors past thr, n=12, img_size=640, metric_all=0.281/0.716-mean/best, past_thr=0.469-mean: 9,11, 21,19, 17,41, 43,32, 39,70, 86,64, 65,131, 134,130, 120,265, 282,180, 247,354, 512,387
anchors_p6_640: anchors_p6_640:
- [ 9,11, 21,19, 17,41 ] # P3/8 - [9,11, 21,19, 17,41] # P3/8
- [ 43,32, 39,70, 86,64 ] # P4/16 - [43,32, 39,70, 86,64] # P4/16
- [ 65,131, 134,130, 120,265 ] # P5/32 - [65,131, 134,130, 120,265] # P5/32
- [ 282,180, 247,354, 512,387 ] # P6/64 - [282,180, 247,354, 512,387] # P6/64
# P6-1280: thr=0.25: 0.9950 BPR, 5.55 anchors past thr, n=12, img_size=1280, metric_all=0.281/0.714-mean/best, past_thr=0.468-mean: 19,27, 44,40, 38,94, 96,68, 86,152, 180,137, 140,301, 303,264, 238,542, 436,615, 739,380, 925,792 # P6-1280: thr=0.25: 0.9950 BPR, 5.55 anchors past thr, n=12, img_size=1280, metric_all=0.281/0.714-mean/best, past_thr=0.468-mean: 19,27, 44,40, 38,94, 96,68, 86,152, 180,137, 140,301, 303,264, 238,542, 436,615, 739,380, 925,792
anchors_p6_1280: anchors_p6_1280:
- [ 19,27, 44,40, 38,94 ] # P3/8 - [19,27, 44,40, 38,94] # P3/8
- [ 96,68, 86,152, 180,137 ] # P4/16 - [96,68, 86,152, 180,137] # P4/16
- [ 140,301, 303,264, 238,542 ] # P5/32 - [140,301, 303,264, 238,542] # P5/32
- [ 436,615, 739,380, 925,792 ] # P6/64 - [436,615, 739,380, 925,792] # P6/64
# P6-1920: thr=0.25: 0.9950 BPR, 5.55 anchors past thr, n=12, img_size=1920, metric_all=0.281/0.714-mean/best, past_thr=0.468-mean: 28,41, 67,59, 57,141, 144,103, 129,227, 270,205, 209,452, 455,396, 358,812, 653,922, 1109,570, 1387,1187 # P6-1920: thr=0.25: 0.9950 BPR, 5.55 anchors past thr, n=12, img_size=1920, metric_all=0.281/0.714-mean/best, past_thr=0.468-mean: 28,41, 67,59, 57,141, 144,103, 129,227, 270,205, 209,452, 455,396, 358,812, 653,922, 1109,570, 1387,1187
anchors_p6_1920: anchors_p6_1920:
- [ 28,41, 67,59, 57,141 ] # P3/8 - [28,41, 67,59, 57,141] # P3/8
- [ 144,103, 129,227, 270,205 ] # P4/16 - [144,103, 129,227, 270,205] # P4/16
- [ 209,452, 455,396, 358,812 ] # P5/32 - [209,452, 455,396, 358,812] # P5/32
- [ 653,922, 1109,570, 1387,1187 ] # P6/64 - [653,922, 1109,570, 1387,1187] # P6/64
# P7 ------------------------------------------------------------------------------------------------------------------- # P7 -------------------------------------------------------------------------------------------------------------------
# P7-640: thr=0.25: 0.9962 BPR, 6.76 anchors past thr, n=15, img_size=640, metric_all=0.275/0.733-mean/best, past_thr=0.466-mean: 11,11, 13,30, 29,20, 30,46, 61,38, 39,92, 78,80, 146,66, 79,163, 149,150, 321,143, 157,303, 257,402, 359,290, 524,372 # P7-640: thr=0.25: 0.9962 BPR, 6.76 anchors past thr, n=15, img_size=640, metric_all=0.275/0.733-mean/best, past_thr=0.466-mean: 11,11, 13,30, 29,20, 30,46, 61,38, 39,92, 78,80, 146,66, 79,163, 149,150, 321,143, 157,303, 257,402, 359,290, 524,372
anchors_p7_640: anchors_p7_640:
- [ 11,11, 13,30, 29,20 ] # P3/8 - [11,11, 13,30, 29,20] # P3/8
- [ 30,46, 61,38, 39,92 ] # P4/16 - [30,46, 61,38, 39,92] # P4/16
- [ 78,80, 146,66, 79,163 ] # P5/32 - [78,80, 146,66, 79,163] # P5/32
- [ 149,150, 321,143, 157,303 ] # P6/64 - [149,150, 321,143, 157,303] # P6/64
- [ 257,402, 359,290, 524,372 ] # P7/128 - [257,402, 359,290, 524,372] # P7/128
# P7-1280: thr=0.25: 0.9968 BPR, 6.71 anchors past thr, n=15, img_size=1280, metric_all=0.273/0.732-mean/best, past_thr=0.463-mean: 19,22, 54,36, 32,77, 70,83, 138,71, 75,173, 165,159, 148,334, 375,151, 334,317, 251,626, 499,474, 750,326, 534,814, 1079,818 # P7-1280: thr=0.25: 0.9968 BPR, 6.71 anchors past thr, n=15, img_size=1280, metric_all=0.273/0.732-mean/best, past_thr=0.463-mean: 19,22, 54,36, 32,77, 70,83, 138,71, 75,173, 165,159, 148,334, 375,151, 334,317, 251,626, 499,474, 750,326, 534,814, 1079,818
anchors_p7_1280: anchors_p7_1280:
- [ 19,22, 54,36, 32,77 ] # P3/8 - [19,22, 54,36, 32,77] # P3/8
- [ 70,83, 138,71, 75,173 ] # P4/16 - [70,83, 138,71, 75,173] # P4/16
- [ 165,159, 148,334, 375,151 ] # P5/32 - [165,159, 148,334, 375,151] # P5/32
- [ 334,317, 251,626, 499,474 ] # P6/64 - [334,317, 251,626, 499,474] # P6/64
- [ 750,326, 534,814, 1079,818 ] # P7/128 - [750,326, 534,814, 1079,818] # P7/128
# P7-1920: thr=0.25: 0.9968 BPR, 6.71 anchors past thr, n=15, img_size=1920, metric_all=0.273/0.732-mean/best, past_thr=0.463-mean: 29,34, 81,55, 47,115, 105,124, 207,107, 113,259, 247,238, 222,500, 563,227, 501,476, 376,939, 749,711, 1126,489, 801,1222, 1618,1227 # P7-1920: thr=0.25: 0.9968 BPR, 6.71 anchors past thr, n=15, img_size=1920, metric_all=0.273/0.732-mean/best, past_thr=0.463-mean: 29,34, 81,55, 47,115, 105,124, 207,107, 113,259, 247,238, 222,500, 563,227, 501,476, 376,939, 749,711, 1126,489, 801,1222, 1618,1227
anchors_p7_1920: anchors_p7_1920:
- [ 29,34, 81,55, 47,115 ] # P3/8 - [29,34, 81,55, 47,115] # P3/8
- [ 105,124, 207,107, 113,259 ] # P4/16 - [105,124, 207,107, 113,259] # P4/16
- [ 247,238, 222,500, 563,227 ] # P5/32 - [247,238, 222,500, 563,227] # P5/32
- [ 501,476, 376,939, 749,711 ] # P6/64 - [501,476, 376,939, 749,711] # P6/64
- [ 1126,489, 801,1222, 1618,1227 ] # P7/128 - [1126,489, 801,1222, 1618,1227] # P7/128
+3 -3
View File
@@ -1,9 +1,9 @@
# parameters # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
# Parameters
nc: 80 # number of classes nc: 80 # number of classes
depth_multiple: 1.0 # model depth multiple depth_multiple: 1.0 # model depth multiple
width_multiple: 1.0 # layer channel multiple width_multiple: 1.0 # layer channel multiple
# anchors
anchors: anchors:
- [10,13, 16,30, 33,23] # P3/8 - [10,13, 16,30, 33,23] # P3/8
- [30,61, 62,45, 59,119] # P4/16 - [30,61, 62,45, 59,119] # P4/16
+3 -3
View File
@@ -1,9 +1,9 @@
# parameters # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
# Parameters
nc: 80 # number of classes nc: 80 # number of classes
depth_multiple: 1.0 # model depth multiple depth_multiple: 1.0 # model depth multiple
width_multiple: 1.0 # layer channel multiple width_multiple: 1.0 # layer channel multiple
# anchors
anchors: anchors:
- [10,14, 23,27, 37,58] # P4/16 - [10,14, 23,27, 37,58] # P4/16
- [81,82, 135,169, 344,319] # P5/32 - [81,82, 135,169, 344,319] # P5/32
+4 -4
View File
@@ -1,9 +1,9 @@
# parameters # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
# Parameters
nc: 80 # number of classes nc: 80 # number of classes
depth_multiple: 1.0 # model depth multiple depth_multiple: 1.0 # model depth multiple
width_multiple: 1.0 # layer channel multiple width_multiple: 1.0 # layer channel multiple
# anchors
anchors: anchors:
- [10,13, 16,30, 33,23] # P3/8 - [10,13, 16,30, 33,23] # P3/8
- [30,61, 62,45, 59,119] # P4/16 - [30,61, 62,45, 59,119] # P4/16
@@ -28,7 +28,7 @@ backbone:
# YOLOv3 head # YOLOv3 head
head: head:
[[-1, 1, Bottleneck, [1024, False]], [[-1, 1, Bottleneck, [1024, False]],
[-1, 1, Conv, [512, [1, 1]]], [-1, 1, Conv, [512, 1, 1]],
[-1, 1, Conv, [1024, 3, 1]], [-1, 1, Conv, [1024, 3, 1]],
[-1, 1, Conv, [512, 1, 1]], [-1, 1, Conv, [512, 1, 1]],
[-1, 1, Conv, [1024, 3, 1]], # 15 (P5/32-large) [-1, 1, Conv, [1024, 3, 1]], # 15 (P5/32-large)
+48
View File
@@ -0,0 +1,48 @@
# YOLOv5 🚀 by Ultralytics, GPL-3.0 license
# Parameters
nc: 80 # number of classes
depth_multiple: 1.0 # model depth multiple
width_multiple: 1.0 # 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 BiFPN 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, 6], 1, Concat, [1]], # cat P4 <--- BiFPN change
[-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)
]
+14 -14
View File
@@ -1,42 +1,42 @@
# parameters # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
# Parameters
nc: 80 # number of classes nc: 80 # number of classes
depth_multiple: 1.0 # model depth multiple depth_multiple: 1.0 # model depth multiple
width_multiple: 1.0 # layer channel multiple width_multiple: 1.0 # layer channel multiple
# anchors
anchors: anchors:
- [10,13, 16,30, 33,23] # P3/8 - [10,13, 16,30, 33,23] # P3/8
- [30,61, 62,45, 59,119] # P4/16 - [30,61, 62,45, 59,119] # P4/16
- [116,90, 156,198, 373,326] # P5/32 - [116,90, 156,198, 373,326] # P5/32
# YOLOv5 backbone # YOLOv5 v6.0 backbone
backbone: backbone:
# [from, number, module, args] # [from, number, module, args]
[[-1, 1, Focus, [64, 3]], # 0-P1/2 [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
[-1, 1, Conv, [128, 3, 2]], # 1-P2/4 [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
[-1, 3, Bottleneck, [128]], [-1, 3, C3, [128]],
[-1, 1, Conv, [256, 3, 2]], # 3-P3/8 [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
[-1, 9, BottleneckCSP, [256]], [-1, 6, C3, [256]],
[-1, 1, Conv, [512, 3, 2]], # 5-P4/16 [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
[-1, 9, BottleneckCSP, [512]], [-1, 9, C3, [512]],
[-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
[-1, 1, SPP, [1024, [5, 9, 13]]], [-1, 3, C3, [1024]],
[-1, 6, BottleneckCSP, [1024]], # 9 [-1, 1, SPPF, [1024, 5]], # 9
] ]
# YOLOv5 FPN head # YOLOv5 v6.0 FPN head
head: head:
[[-1, 3, BottleneckCSP, [1024, False]], # 10 (P5/32-large) [[-1, 3, C3, [1024, False]], # 10 (P5/32-large)
[-1, 1, nn.Upsample, [None, 2, 'nearest']], [-1, 1, nn.Upsample, [None, 2, 'nearest']],
[[-1, 6], 1, Concat, [1]], # cat backbone P4 [[-1, 6], 1, Concat, [1]], # cat backbone P4
[-1, 1, Conv, [512, 1, 1]], [-1, 1, Conv, [512, 1, 1]],
[-1, 3, BottleneckCSP, [512, False]], # 14 (P4/16-medium) [-1, 3, C3, [512, False]], # 14 (P4/16-medium)
[-1, 1, nn.Upsample, [None, 2, 'nearest']], [-1, 1, nn.Upsample, [None, 2, 'nearest']],
[[-1, 4], 1, Concat, [1]], # cat backbone P3 [[-1, 4], 1, Concat, [1]], # cat backbone P3
[-1, 1, Conv, [256, 1, 1]], [-1, 1, Conv, [256, 1, 1]],
[-1, 3, BottleneckCSP, [256, False]], # 18 (P3/8-small) [-1, 3, C3, [256, False]], # 18 (P3/8-small)
[[18, 14, 10], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) [[18, 14, 10], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
] ]
+38 -38
View File
@@ -1,54 +1,54 @@
# parameters # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
# Parameters
nc: 80 # number of classes nc: 80 # number of classes
depth_multiple: 1.0 # model depth multiple depth_multiple: 1.0 # model depth multiple
width_multiple: 1.0 # layer channel multiple width_multiple: 1.0 # layer channel multiple
anchors: 3 # AutoAnchor evolves 3 anchors per P output layer
# anchors # YOLOv5 v6.0 backbone
anchors: 3
# YOLOv5 backbone
backbone: backbone:
# [from, number, module, args] # [from, number, module, args]
[ [ -1, 1, Focus, [ 64, 3 ] ], # 0-P1/2 [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
[ -1, 1, Conv, [ 128, 3, 2 ] ], # 1-P2/4 [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
[ -1, 3, C3, [ 128 ] ], [-1, 3, C3, [128]],
[ -1, 1, Conv, [ 256, 3, 2 ] ], # 3-P3/8 [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
[ -1, 9, C3, [ 256 ] ], [-1, 6, C3, [256]],
[ -1, 1, Conv, [ 512, 3, 2 ] ], # 5-P4/16 [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
[ -1, 9, C3, [ 512 ] ], [-1, 9, C3, [512]],
[ -1, 1, Conv, [ 1024, 3, 2 ] ], # 7-P5/32 [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
[ -1, 1, SPP, [ 1024, [ 5, 9, 13 ] ] ], [-1, 3, C3, [1024]],
[ -1, 3, C3, [ 1024, False ] ], # 9 [-1, 1, SPPF, [1024, 5]], # 9
] ]
# YOLOv5 head # YOLOv5 v6.0 head with (P2, P3, P4, P5) outputs
head: head:
[ [ -1, 1, Conv, [ 512, 1, 1 ] ], [[-1, 1, Conv, [512, 1, 1]],
[ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], [-1, 1, nn.Upsample, [None, 2, 'nearest']],
[ [ -1, 6 ], 1, Concat, [ 1 ] ], # cat backbone P4 [[-1, 6], 1, Concat, [1]], # cat backbone P4
[ -1, 3, C3, [ 512, False ] ], # 13 [-1, 3, C3, [512, False]], # 13
[ -1, 1, Conv, [ 256, 1, 1 ] ], [-1, 1, Conv, [256, 1, 1]],
[ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], [-1, 1, nn.Upsample, [None, 2, 'nearest']],
[ [ -1, 4 ], 1, Concat, [ 1 ] ], # cat backbone P3 [[-1, 4], 1, Concat, [1]], # cat backbone P3
[ -1, 3, C3, [ 256, False ] ], # 17 (P3/8-small) [-1, 3, C3, [256, False]], # 17 (P3/8-small)
[ -1, 1, Conv, [ 128, 1, 1 ] ], [-1, 1, Conv, [128, 1, 1]],
[ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], [-1, 1, nn.Upsample, [None, 2, 'nearest']],
[ [ -1, 2 ], 1, Concat, [ 1 ] ], # cat backbone P2 [[-1, 2], 1, Concat, [1]], # cat backbone P2
[ -1, 1, C3, [ 128, False ] ], # 21 (P2/4-xsmall) [-1, 1, C3, [128, False]], # 21 (P2/4-xsmall)
[ -1, 1, Conv, [ 128, 3, 2 ] ], [-1, 1, Conv, [128, 3, 2]],
[ [ -1, 18 ], 1, Concat, [ 1 ] ], # cat head P3 [[-1, 18], 1, Concat, [1]], # cat head P3
[ -1, 3, C3, [ 256, False ] ], # 24 (P3/8-small) [-1, 3, C3, [256, False]], # 24 (P3/8-small)
[ -1, 1, Conv, [ 256, 3, 2 ] ], [-1, 1, Conv, [256, 3, 2]],
[ [ -1, 14 ], 1, Concat, [ 1 ] ], # cat head P4 [[-1, 14], 1, Concat, [1]], # cat head P4
[ -1, 3, C3, [ 512, False ] ], # 27 (P4/16-medium) [-1, 3, C3, [512, False]], # 27 (P4/16-medium)
[ -1, 1, Conv, [ 512, 3, 2 ] ], [-1, 1, Conv, [512, 3, 2]],
[ [ -1, 10 ], 1, Concat, [ 1 ] ], # cat head P5 [[-1, 10], 1, Concat, [1]], # cat head P5
[ -1, 3, C3, [ 1024, False ] ], # 30 (P5/32-large) [-1, 3, C3, [1024, False]], # 30 (P5/32-large)
[ [ 24, 27, 30 ], 1, Detect, [ nc, anchors ] ], # Detect(P3, P4, P5) [[21, 24, 27, 30], 1, Detect, [nc, anchors]], # Detect(P2, P3, P4, P5)
] ]
+41
View File
@@ -0,0 +1,41 @@
# YOLOv5 🚀 by Ultralytics, GPL-3.0 license
# Parameters
nc: 80 # number of classes
depth_multiple: 0.33 # model depth multiple
width_multiple: 0.50 # layer channel multiple
anchors: 3 # AutoAnchor evolves 3 anchors per P output layer
# 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 with (P3, P4) outputs
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)
[ [ 17, 20 ], 1, Detect, [ nc, anchors ] ], # Detect(P3, P4)
]
+40 -40
View File
@@ -1,56 +1,56 @@
# parameters # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
# Parameters
nc: 80 # number of classes nc: 80 # number of classes
depth_multiple: 1.0 # model depth multiple depth_multiple: 1.0 # model depth multiple
width_multiple: 1.0 # layer channel multiple width_multiple: 1.0 # layer channel multiple
anchors: 3 # AutoAnchor evolves 3 anchors per P output layer
# anchors # YOLOv5 v6.0 backbone
anchors: 3
# YOLOv5 backbone
backbone: backbone:
# [from, number, module, args] # [from, number, module, args]
[ [ -1, 1, Focus, [ 64, 3 ] ], # 0-P1/2 [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
[ -1, 1, Conv, [ 128, 3, 2 ] ], # 1-P2/4 [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
[ -1, 3, C3, [ 128 ] ], [-1, 3, C3, [128]],
[ -1, 1, Conv, [ 256, 3, 2 ] ], # 3-P3/8 [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
[ -1, 9, C3, [ 256 ] ], [-1, 6, C3, [256]],
[ -1, 1, Conv, [ 512, 3, 2 ] ], # 5-P4/16 [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
[ -1, 9, C3, [ 512 ] ], [-1, 9, C3, [512]],
[ -1, 1, Conv, [ 768, 3, 2 ] ], # 7-P5/32 [-1, 1, Conv, [768, 3, 2]], # 7-P5/32
[ -1, 3, C3, [ 768 ] ], [-1, 3, C3, [768]],
[ -1, 1, Conv, [ 1024, 3, 2 ] ], # 9-P6/64 [-1, 1, Conv, [1024, 3, 2]], # 9-P6/64
[ -1, 1, SPP, [ 1024, [ 3, 5, 7 ] ] ], [-1, 3, C3, [1024]],
[ -1, 3, C3, [ 1024, False ] ], # 11 [-1, 1, SPPF, [1024, 5]], # 11
] ]
# YOLOv5 head # YOLOv5 v6.0 head with (P3, P4, P5, P6) outputs
head: head:
[ [ -1, 1, Conv, [ 768, 1, 1 ] ], [[-1, 1, Conv, [768, 1, 1]],
[ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], [-1, 1, nn.Upsample, [None, 2, 'nearest']],
[ [ -1, 8 ], 1, Concat, [ 1 ] ], # cat backbone P5 [[-1, 8], 1, Concat, [1]], # cat backbone P5
[ -1, 3, C3, [ 768, False ] ], # 15 [-1, 3, C3, [768, False]], # 15
[ -1, 1, Conv, [ 512, 1, 1 ] ], [-1, 1, Conv, [512, 1, 1]],
[ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], [-1, 1, nn.Upsample, [None, 2, 'nearest']],
[ [ -1, 6 ], 1, Concat, [ 1 ] ], # cat backbone P4 [[-1, 6], 1, Concat, [1]], # cat backbone P4
[ -1, 3, C3, [ 512, False ] ], # 19 [-1, 3, C3, [512, False]], # 19
[ -1, 1, Conv, [ 256, 1, 1 ] ], [-1, 1, Conv, [256, 1, 1]],
[ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], [-1, 1, nn.Upsample, [None, 2, 'nearest']],
[ [ -1, 4 ], 1, Concat, [ 1 ] ], # cat backbone P3 [[-1, 4], 1, Concat, [1]], # cat backbone P3
[ -1, 3, C3, [ 256, False ] ], # 23 (P3/8-small) [-1, 3, C3, [256, False]], # 23 (P3/8-small)
[ -1, 1, Conv, [ 256, 3, 2 ] ], [-1, 1, Conv, [256, 3, 2]],
[ [ -1, 20 ], 1, Concat, [ 1 ] ], # cat head P4 [[-1, 20], 1, Concat, [1]], # cat head P4
[ -1, 3, C3, [ 512, False ] ], # 26 (P4/16-medium) [-1, 3, C3, [512, False]], # 26 (P4/16-medium)
[ -1, 1, Conv, [ 512, 3, 2 ] ], [-1, 1, Conv, [512, 3, 2]],
[ [ -1, 16 ], 1, Concat, [ 1 ] ], # cat head P5 [[-1, 16], 1, Concat, [1]], # cat head P5
[ -1, 3, C3, [ 768, False ] ], # 29 (P5/32-large) [-1, 3, C3, [768, False]], # 29 (P5/32-large)
[ -1, 1, Conv, [ 768, 3, 2 ] ], [-1, 1, Conv, [768, 3, 2]],
[ [ -1, 12 ], 1, Concat, [ 1 ] ], # cat head P6 [[-1, 12], 1, Concat, [1]], # cat head P6
[ -1, 3, C3, [ 1024, False ] ], # 32 (P5/64-xlarge) [-1, 3, C3, [1024, False]], # 32 (P6/64-xlarge)
[ [ 23, 26, 29, 32 ], 1, Detect, [ nc, anchors ] ], # Detect(P3, P4, P5, P6) [[23, 26, 29, 32], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5, P6)
] ]
+49 -49
View File
@@ -1,67 +1,67 @@
# parameters # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
# Parameters
nc: 80 # number of classes nc: 80 # number of classes
depth_multiple: 1.0 # model depth multiple depth_multiple: 1.0 # model depth multiple
width_multiple: 1.0 # layer channel multiple width_multiple: 1.0 # layer channel multiple
anchors: 3 # AutoAnchor evolves 3 anchors per P output layer
# anchors # YOLOv5 v6.0 backbone
anchors: 3
# YOLOv5 backbone
backbone: backbone:
# [from, number, module, args] # [from, number, module, args]
[ [ -1, 1, Focus, [ 64, 3 ] ], # 0-P1/2 [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
[ -1, 1, Conv, [ 128, 3, 2 ] ], # 1-P2/4 [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
[ -1, 3, C3, [ 128 ] ], [-1, 3, C3, [128]],
[ -1, 1, Conv, [ 256, 3, 2 ] ], # 3-P3/8 [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
[ -1, 9, C3, [ 256 ] ], [-1, 6, C3, [256]],
[ -1, 1, Conv, [ 512, 3, 2 ] ], # 5-P4/16 [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
[ -1, 9, C3, [ 512 ] ], [-1, 9, C3, [512]],
[ -1, 1, Conv, [ 768, 3, 2 ] ], # 7-P5/32 [-1, 1, Conv, [768, 3, 2]], # 7-P5/32
[ -1, 3, C3, [ 768 ] ], [-1, 3, C3, [768]],
[ -1, 1, Conv, [ 1024, 3, 2 ] ], # 9-P6/64 [-1, 1, Conv, [1024, 3, 2]], # 9-P6/64
[ -1, 3, C3, [ 1024 ] ], [-1, 3, C3, [1024]],
[ -1, 1, Conv, [ 1280, 3, 2 ] ], # 11-P7/128 [-1, 1, Conv, [1280, 3, 2]], # 11-P7/128
[ -1, 1, SPP, [ 1280, [ 3, 5 ] ] ], [-1, 3, C3, [1280]],
[ -1, 3, C3, [ 1280, False ] ], # 13 [-1, 1, SPPF, [1280, 5]], # 13
] ]
# YOLOv5 head # YOLOv5 v6.0 head with (P3, P4, P5, P6, P7) outputs
head: head:
[ [ -1, 1, Conv, [ 1024, 1, 1 ] ], [[-1, 1, Conv, [1024, 1, 1]],
[ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], [-1, 1, nn.Upsample, [None, 2, 'nearest']],
[ [ -1, 10 ], 1, Concat, [ 1 ] ], # cat backbone P6 [[-1, 10], 1, Concat, [1]], # cat backbone P6
[ -1, 3, C3, [ 1024, False ] ], # 17 [-1, 3, C3, [1024, False]], # 17
[ -1, 1, Conv, [ 768, 1, 1 ] ], [-1, 1, Conv, [768, 1, 1]],
[ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], [-1, 1, nn.Upsample, [None, 2, 'nearest']],
[ [ -1, 8 ], 1, Concat, [ 1 ] ], # cat backbone P5 [[-1, 8], 1, Concat, [1]], # cat backbone P5
[ -1, 3, C3, [ 768, False ] ], # 21 [-1, 3, C3, [768, False]], # 21
[ -1, 1, Conv, [ 512, 1, 1 ] ], [-1, 1, Conv, [512, 1, 1]],
[ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], [-1, 1, nn.Upsample, [None, 2, 'nearest']],
[ [ -1, 6 ], 1, Concat, [ 1 ] ], # cat backbone P4 [[-1, 6], 1, Concat, [1]], # cat backbone P4
[ -1, 3, C3, [ 512, False ] ], # 25 [-1, 3, C3, [512, False]], # 25
[ -1, 1, Conv, [ 256, 1, 1 ] ], [-1, 1, Conv, [256, 1, 1]],
[ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], [-1, 1, nn.Upsample, [None, 2, 'nearest']],
[ [ -1, 4 ], 1, Concat, [ 1 ] ], # cat backbone P3 [[-1, 4], 1, Concat, [1]], # cat backbone P3
[ -1, 3, C3, [ 256, False ] ], # 29 (P3/8-small) [-1, 3, C3, [256, False]], # 29 (P3/8-small)
[ -1, 1, Conv, [ 256, 3, 2 ] ], [-1, 1, Conv, [256, 3, 2]],
[ [ -1, 26 ], 1, Concat, [ 1 ] ], # cat head P4 [[-1, 26], 1, Concat, [1]], # cat head P4
[ -1, 3, C3, [ 512, False ] ], # 32 (P4/16-medium) [-1, 3, C3, [512, False]], # 32 (P4/16-medium)
[ -1, 1, Conv, [ 512, 3, 2 ] ], [-1, 1, Conv, [512, 3, 2]],
[ [ -1, 22 ], 1, Concat, [ 1 ] ], # cat head P5 [[-1, 22], 1, Concat, [1]], # cat head P5
[ -1, 3, C3, [ 768, False ] ], # 35 (P5/32-large) [-1, 3, C3, [768, False]], # 35 (P5/32-large)
[ -1, 1, Conv, [ 768, 3, 2 ] ], [-1, 1, Conv, [768, 3, 2]],
[ [ -1, 18 ], 1, Concat, [ 1 ] ], # cat head P6 [[-1, 18], 1, Concat, [1]], # cat head P6
[ -1, 3, C3, [ 1024, False ] ], # 38 (P6/64-xlarge) [-1, 3, C3, [1024, False]], # 38 (P6/64-xlarge)
[ -1, 1, Conv, [ 1024, 3, 2 ] ], [-1, 1, Conv, [1024, 3, 2]],
[ [ -1, 14 ], 1, Concat, [ 1 ] ], # cat head P7 [[-1, 14], 1, Concat, [1]], # cat head P7
[ -1, 3, C3, [ 1280, False ] ], # 41 (P7/128-xxlarge) [-1, 3, C3, [1280, False]], # 41 (P7/128-xxlarge)
[ [ 29, 32, 35, 38, 41 ], 1, Detect, [ nc, anchors ] ], # Detect(P3, P4, P5, P6, P7) [[29, 32, 35, 38, 41], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5, P6, P7)
] ]
+15 -15
View File
@@ -1,48 +1,48 @@
# parameters # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
# Parameters
nc: 80 # number of classes nc: 80 # number of classes
depth_multiple: 1.0 # model depth multiple depth_multiple: 1.0 # model depth multiple
width_multiple: 1.0 # layer channel multiple width_multiple: 1.0 # layer channel multiple
# anchors
anchors: anchors:
- [10,13, 16,30, 33,23] # P3/8 - [10,13, 16,30, 33,23] # P3/8
- [30,61, 62,45, 59,119] # P4/16 - [30,61, 62,45, 59,119] # P4/16
- [116,90, 156,198, 373,326] # P5/32 - [116,90, 156,198, 373,326] # P5/32
# YOLOv5 backbone # YOLOv5 v6.0 backbone
backbone: backbone:
# [from, number, module, args] # [from, number, module, args]
[[-1, 1, Focus, [64, 3]], # 0-P1/2 [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
[-1, 1, Conv, [128, 3, 2]], # 1-P2/4 [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
[-1, 3, BottleneckCSP, [128]], [-1, 3, C3, [128]],
[-1, 1, Conv, [256, 3, 2]], # 3-P3/8 [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
[-1, 9, BottleneckCSP, [256]], [-1, 6, C3, [256]],
[-1, 1, Conv, [512, 3, 2]], # 5-P4/16 [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
[-1, 9, BottleneckCSP, [512]], [-1, 9, C3, [512]],
[-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
[-1, 1, SPP, [1024, [5, 9, 13]]], [-1, 3, C3, [1024]],
[-1, 3, BottleneckCSP, [1024, False]], # 9 [-1, 1, SPPF, [1024, 5]], # 9
] ]
# YOLOv5 PANet head # YOLOv5 v6.0 PANet head
head: head:
[[-1, 1, Conv, [512, 1, 1]], [[-1, 1, Conv, [512, 1, 1]],
[-1, 1, nn.Upsample, [None, 2, 'nearest']], [-1, 1, nn.Upsample, [None, 2, 'nearest']],
[[-1, 6], 1, Concat, [1]], # cat backbone P4 [[-1, 6], 1, Concat, [1]], # cat backbone P4
[-1, 3, BottleneckCSP, [512, False]], # 13 [-1, 3, C3, [512, False]], # 13
[-1, 1, Conv, [256, 1, 1]], [-1, 1, Conv, [256, 1, 1]],
[-1, 1, nn.Upsample, [None, 2, 'nearest']], [-1, 1, nn.Upsample, [None, 2, 'nearest']],
[[-1, 4], 1, Concat, [1]], # cat backbone P3 [[-1, 4], 1, Concat, [1]], # cat backbone P3
[-1, 3, BottleneckCSP, [256, False]], # 17 (P3/8-small) [-1, 3, C3, [256, False]], # 17 (P3/8-small)
[-1, 1, Conv, [256, 3, 2]], [-1, 1, Conv, [256, 3, 2]],
[[-1, 14], 1, Concat, [1]], # cat head P4 [[-1, 14], 1, Concat, [1]], # cat head P4
[-1, 3, BottleneckCSP, [512, False]], # 20 (P4/16-medium) [-1, 3, C3, [512, False]], # 20 (P4/16-medium)
[-1, 1, Conv, [512, 3, 2]], [-1, 1, Conv, [512, 3, 2]],
[[-1, 10], 1, Concat, [1]], # cat head P5 [[-1, 10], 1, Concat, [1]], # cat head P5
[-1, 3, BottleneckCSP, [1024, False]], # 23 (P5/32-large) [-1, 3, C3, [1024, False]], # 23 (P5/32-large)
[[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
] ]
+43 -43
View File
@@ -1,60 +1,60 @@
# parameters # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
# Parameters
nc: 80 # number of classes nc: 80 # number of classes
depth_multiple: 1.0 # model depth multiple depth_multiple: 1.0 # model depth multiple
width_multiple: 1.0 # layer channel multiple width_multiple: 1.0 # layer channel multiple
# anchors
anchors: anchors:
- [ 19,27, 44,40, 38,94 ] # P3/8 - [19,27, 44,40, 38,94] # P3/8
- [ 96,68, 86,152, 180,137 ] # P4/16 - [96,68, 86,152, 180,137] # P4/16
- [ 140,301, 303,264, 238,542 ] # P5/32 - [140,301, 303,264, 238,542] # P5/32
- [ 436,615, 739,380, 925,792 ] # P6/64 - [436,615, 739,380, 925,792] # P6/64
# YOLOv5 backbone # YOLOv5 v6.0 backbone
backbone: backbone:
# [from, number, module, args] # [from, number, module, args]
[ [ -1, 1, Focus, [ 64, 3 ] ], # 0-P1/2 [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
[ -1, 1, Conv, [ 128, 3, 2 ] ], # 1-P2/4 [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
[ -1, 3, C3, [ 128 ] ], [-1, 3, C3, [128]],
[ -1, 1, Conv, [ 256, 3, 2 ] ], # 3-P3/8 [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
[ -1, 9, C3, [ 256 ] ], [-1, 6, C3, [256]],
[ -1, 1, Conv, [ 512, 3, 2 ] ], # 5-P4/16 [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
[ -1, 9, C3, [ 512 ] ], [-1, 9, C3, [512]],
[ -1, 1, Conv, [ 768, 3, 2 ] ], # 7-P5/32 [-1, 1, Conv, [768, 3, 2]], # 7-P5/32
[ -1, 3, C3, [ 768 ] ], [-1, 3, C3, [768]],
[ -1, 1, Conv, [ 1024, 3, 2 ] ], # 9-P6/64 [-1, 1, Conv, [1024, 3, 2]], # 9-P6/64
[ -1, 1, SPP, [ 1024, [ 3, 5, 7 ] ] ], [-1, 3, C3, [1024]],
[ -1, 3, C3, [ 1024, False ] ], # 11 [-1, 1, SPPF, [1024, 5]], # 11
] ]
# YOLOv5 head # YOLOv5 v6.0 head
head: head:
[ [ -1, 1, Conv, [ 768, 1, 1 ] ], [[-1, 1, Conv, [768, 1, 1]],
[ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], [-1, 1, nn.Upsample, [None, 2, 'nearest']],
[ [ -1, 8 ], 1, Concat, [ 1 ] ], # cat backbone P5 [[-1, 8], 1, Concat, [1]], # cat backbone P5
[ -1, 3, C3, [ 768, False ] ], # 15 [-1, 3, C3, [768, False]], # 15
[ -1, 1, Conv, [ 512, 1, 1 ] ], [-1, 1, Conv, [512, 1, 1]],
[ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], [-1, 1, nn.Upsample, [None, 2, 'nearest']],
[ [ -1, 6 ], 1, Concat, [ 1 ] ], # cat backbone P4 [[-1, 6], 1, Concat, [1]], # cat backbone P4
[ -1, 3, C3, [ 512, False ] ], # 19 [-1, 3, C3, [512, False]], # 19
[ -1, 1, Conv, [ 256, 1, 1 ] ], [-1, 1, Conv, [256, 1, 1]],
[ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], [-1, 1, nn.Upsample, [None, 2, 'nearest']],
[ [ -1, 4 ], 1, Concat, [ 1 ] ], # cat backbone P3 [[-1, 4], 1, Concat, [1]], # cat backbone P3
[ -1, 3, C3, [ 256, False ] ], # 23 (P3/8-small) [-1, 3, C3, [256, False]], # 23 (P3/8-small)
[ -1, 1, Conv, [ 256, 3, 2 ] ], [-1, 1, Conv, [256, 3, 2]],
[ [ -1, 20 ], 1, Concat, [ 1 ] ], # cat head P4 [[-1, 20], 1, Concat, [1]], # cat head P4
[ -1, 3, C3, [ 512, False ] ], # 26 (P4/16-medium) [-1, 3, C3, [512, False]], # 26 (P4/16-medium)
[ -1, 1, Conv, [ 512, 3, 2 ] ], [-1, 1, Conv, [512, 3, 2]],
[ [ -1, 16 ], 1, Concat, [ 1 ] ], # cat head P5 [[-1, 16], 1, Concat, [1]], # cat head P5
[ -1, 3, C3, [ 768, False ] ], # 29 (P5/32-large) [-1, 3, C3, [768, False]], # 29 (P5/32-large)
[ -1, 1, Conv, [ 768, 3, 2 ] ], [-1, 1, Conv, [768, 3, 2]],
[ [ -1, 12 ], 1, Concat, [ 1 ] ], # cat head P6 [[-1, 12], 1, Concat, [1]], # cat head P6
[ -1, 3, C3, [ 1024, False ] ], # 32 (P6/64-xlarge) [-1, 3, C3, [1024, False]], # 32 (P6/64-xlarge)
[ [ 23, 26, 29, 32 ], 1, Detect, [ nc, anchors ] ], # Detect(P3, P4, P5, P6) [[23, 26, 29, 32], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5, P6)
] ]
+43 -43
View File
@@ -1,60 +1,60 @@
# parameters # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
# Parameters
nc: 80 # number of classes nc: 80 # number of classes
depth_multiple: 0.67 # model depth multiple depth_multiple: 0.67 # model depth multiple
width_multiple: 0.75 # layer channel multiple width_multiple: 0.75 # layer channel multiple
# anchors
anchors: anchors:
- [ 19,27, 44,40, 38,94 ] # P3/8 - [19,27, 44,40, 38,94] # P3/8
- [ 96,68, 86,152, 180,137 ] # P4/16 - [96,68, 86,152, 180,137] # P4/16
- [ 140,301, 303,264, 238,542 ] # P5/32 - [140,301, 303,264, 238,542] # P5/32
- [ 436,615, 739,380, 925,792 ] # P6/64 - [436,615, 739,380, 925,792] # P6/64
# YOLOv5 backbone # YOLOv5 v6.0 backbone
backbone: backbone:
# [from, number, module, args] # [from, number, module, args]
[ [ -1, 1, Focus, [ 64, 3 ] ], # 0-P1/2 [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
[ -1, 1, Conv, [ 128, 3, 2 ] ], # 1-P2/4 [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
[ -1, 3, C3, [ 128 ] ], [-1, 3, C3, [128]],
[ -1, 1, Conv, [ 256, 3, 2 ] ], # 3-P3/8 [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
[ -1, 9, C3, [ 256 ] ], [-1, 6, C3, [256]],
[ -1, 1, Conv, [ 512, 3, 2 ] ], # 5-P4/16 [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
[ -1, 9, C3, [ 512 ] ], [-1, 9, C3, [512]],
[ -1, 1, Conv, [ 768, 3, 2 ] ], # 7-P5/32 [-1, 1, Conv, [768, 3, 2]], # 7-P5/32
[ -1, 3, C3, [ 768 ] ], [-1, 3, C3, [768]],
[ -1, 1, Conv, [ 1024, 3, 2 ] ], # 9-P6/64 [-1, 1, Conv, [1024, 3, 2]], # 9-P6/64
[ -1, 1, SPP, [ 1024, [ 3, 5, 7 ] ] ], [-1, 3, C3, [1024]],
[ -1, 3, C3, [ 1024, False ] ], # 11 [-1, 1, SPPF, [1024, 5]], # 11
] ]
# YOLOv5 head # YOLOv5 v6.0 head
head: head:
[ [ -1, 1, Conv, [ 768, 1, 1 ] ], [[-1, 1, Conv, [768, 1, 1]],
[ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], [-1, 1, nn.Upsample, [None, 2, 'nearest']],
[ [ -1, 8 ], 1, Concat, [ 1 ] ], # cat backbone P5 [[-1, 8], 1, Concat, [1]], # cat backbone P5
[ -1, 3, C3, [ 768, False ] ], # 15 [-1, 3, C3, [768, False]], # 15
[ -1, 1, Conv, [ 512, 1, 1 ] ], [-1, 1, Conv, [512, 1, 1]],
[ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], [-1, 1, nn.Upsample, [None, 2, 'nearest']],
[ [ -1, 6 ], 1, Concat, [ 1 ] ], # cat backbone P4 [[-1, 6], 1, Concat, [1]], # cat backbone P4
[ -1, 3, C3, [ 512, False ] ], # 19 [-1, 3, C3, [512, False]], # 19
[ -1, 1, Conv, [ 256, 1, 1 ] ], [-1, 1, Conv, [256, 1, 1]],
[ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], [-1, 1, nn.Upsample, [None, 2, 'nearest']],
[ [ -1, 4 ], 1, Concat, [ 1 ] ], # cat backbone P3 [[-1, 4], 1, Concat, [1]], # cat backbone P3
[ -1, 3, C3, [ 256, False ] ], # 23 (P3/8-small) [-1, 3, C3, [256, False]], # 23 (P3/8-small)
[ -1, 1, Conv, [ 256, 3, 2 ] ], [-1, 1, Conv, [256, 3, 2]],
[ [ -1, 20 ], 1, Concat, [ 1 ] ], # cat head P4 [[-1, 20], 1, Concat, [1]], # cat head P4
[ -1, 3, C3, [ 512, False ] ], # 26 (P4/16-medium) [-1, 3, C3, [512, False]], # 26 (P4/16-medium)
[ -1, 1, Conv, [ 512, 3, 2 ] ], [-1, 1, Conv, [512, 3, 2]],
[ [ -1, 16 ], 1, Concat, [ 1 ] ], # cat head P5 [[-1, 16], 1, Concat, [1]], # cat head P5
[ -1, 3, C3, [ 768, False ] ], # 29 (P5/32-large) [-1, 3, C3, [768, False]], # 29 (P5/32-large)
[ -1, 1, Conv, [ 768, 3, 2 ] ], [-1, 1, Conv, [768, 3, 2]],
[ [ -1, 12 ], 1, Concat, [ 1 ] ], # cat head P6 [[-1, 12], 1, Concat, [1]], # cat head P6
[ -1, 3, C3, [ 1024, False ] ], # 32 (P6/64-xlarge) [-1, 3, C3, [1024, False]], # 32 (P6/64-xlarge)
[ [ 23, 26, 29, 32 ], 1, Detect, [ nc, anchors ] ], # Detect(P3, P4, P5, P6) [[23, 26, 29, 32], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5, P6)
] ]
+60
View File
@@ -0,0 +1,60 @@
# YOLOv5 🚀 by Ultralytics, GPL-3.0 license
# Parameters
nc: 80 # number of classes
depth_multiple: 0.33 # model depth multiple
width_multiple: 0.25 # layer channel multiple
anchors:
- [19,27, 44,40, 38,94] # P3/8
- [96,68, 86,152, 180,137] # P4/16
- [140,301, 303,264, 238,542] # P5/32
- [436,615, 739,380, 925,792] # P6/64
# 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, [768, 3, 2]], # 7-P5/32
[-1, 3, C3, [768]],
[-1, 1, Conv, [1024, 3, 2]], # 9-P6/64
[-1, 3, C3, [1024]],
[-1, 1, SPPF, [1024, 5]], # 11
]
# YOLOv5 v6.0 head
head:
[[-1, 1, Conv, [768, 1, 1]],
[-1, 1, nn.Upsample, [None, 2, 'nearest']],
[[-1, 8], 1, Concat, [1]], # cat backbone P5
[-1, 3, C3, [768, False]], # 15
[-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]], # 19
[-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]], # 23 (P3/8-small)
[-1, 1, Conv, [256, 3, 2]],
[[-1, 20], 1, Concat, [1]], # cat head P4
[-1, 3, C3, [512, False]], # 26 (P4/16-medium)
[-1, 1, Conv, [512, 3, 2]],
[[-1, 16], 1, Concat, [1]], # cat head P5
[-1, 3, C3, [768, False]], # 29 (P5/32-large)
[-1, 1, Conv, [768, 3, 2]],
[[-1, 12], 1, Concat, [1]], # cat head P6
[-1, 3, C3, [1024, False]], # 32 (P6/64-xlarge)
[[23, 26, 29, 32], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5, P6)
]
+48
View File
@@ -0,0 +1,48 @@
# YOLOv5 🚀 by Ultralytics, GPL-3.0 license
# Parameters
nc: 80 # 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, GhostConv, [128, 3, 2]], # 1-P2/4
[-1, 3, C3Ghost, [128]],
[-1, 1, GhostConv, [256, 3, 2]], # 3-P3/8
[-1, 6, C3Ghost, [256]],
[-1, 1, GhostConv, [512, 3, 2]], # 5-P4/16
[-1, 9, C3Ghost, [512]],
[-1, 1, GhostConv, [1024, 3, 2]], # 7-P5/32
[-1, 3, C3Ghost, [1024]],
[-1, 1, SPPF, [1024, 5]], # 9
]
# YOLOv5 v6.0 head
head:
[[-1, 1, GhostConv, [512, 1, 1]],
[-1, 1, nn.Upsample, [None, 2, 'nearest']],
[[-1, 6], 1, Concat, [1]], # cat backbone P4
[-1, 3, C3Ghost, [512, False]], # 13
[-1, 1, GhostConv, [256, 1, 1]],
[-1, 1, nn.Upsample, [None, 2, 'nearest']],
[[-1, 4], 1, Concat, [1]], # cat backbone P3
[-1, 3, C3Ghost, [256, False]], # 17 (P3/8-small)
[-1, 1, GhostConv, [256, 3, 2]],
[[-1, 14], 1, Concat, [1]], # cat head P4
[-1, 3, C3Ghost, [512, False]], # 20 (P4/16-medium)
[-1, 1, GhostConv, [512, 3, 2]],
[[-1, 10], 1, Concat, [1]], # cat head P5
[-1, 3, C3Ghost, [1024, False]], # 23 (P5/32-large)
[[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
]
+48
View File
@@ -0,0 +1,48 @@
# YOLOv5 🚀 by Ultralytics, GPL-3.0 license
# Parameters
nc: 80 # 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, C3TR, [1024]], # 9 <--- C3TR() Transformer module
[-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)
]
+43 -43
View File
@@ -1,60 +1,60 @@
# parameters # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
# Parameters
nc: 80 # number of classes nc: 80 # number of classes
depth_multiple: 0.33 # model depth multiple depth_multiple: 0.33 # model depth multiple
width_multiple: 0.50 # layer channel multiple width_multiple: 0.50 # layer channel multiple
# anchors
anchors: anchors:
- [ 19,27, 44,40, 38,94 ] # P3/8 - [19,27, 44,40, 38,94] # P3/8
- [ 96,68, 86,152, 180,137 ] # P4/16 - [96,68, 86,152, 180,137] # P4/16
- [ 140,301, 303,264, 238,542 ] # P5/32 - [140,301, 303,264, 238,542] # P5/32
- [ 436,615, 739,380, 925,792 ] # P6/64 - [436,615, 739,380, 925,792] # P6/64
# YOLOv5 backbone # YOLOv5 v6.0 backbone
backbone: backbone:
# [from, number, module, args] # [from, number, module, args]
[ [ -1, 1, Focus, [ 64, 3 ] ], # 0-P1/2 [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
[ -1, 1, Conv, [ 128, 3, 2 ] ], # 1-P2/4 [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
[ -1, 3, C3, [ 128 ] ], [-1, 3, C3, [128]],
[ -1, 1, Conv, [ 256, 3, 2 ] ], # 3-P3/8 [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
[ -1, 9, C3, [ 256 ] ], [-1, 6, C3, [256]],
[ -1, 1, Conv, [ 512, 3, 2 ] ], # 5-P4/16 [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
[ -1, 9, C3, [ 512 ] ], [-1, 9, C3, [512]],
[ -1, 1, Conv, [ 768, 3, 2 ] ], # 7-P5/32 [-1, 1, Conv, [768, 3, 2]], # 7-P5/32
[ -1, 3, C3, [ 768 ] ], [-1, 3, C3, [768]],
[ -1, 1, Conv, [ 1024, 3, 2 ] ], # 9-P6/64 [-1, 1, Conv, [1024, 3, 2]], # 9-P6/64
[ -1, 1, SPP, [ 1024, [ 3, 5, 7 ] ] ], [-1, 3, C3, [1024]],
[ -1, 3, C3, [ 1024, False ] ], # 11 [-1, 1, SPPF, [1024, 5]], # 11
] ]
# YOLOv5 head # YOLOv5 v6.0 head
head: head:
[ [ -1, 1, Conv, [ 768, 1, 1 ] ], [[-1, 1, Conv, [768, 1, 1]],
[ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], [-1, 1, nn.Upsample, [None, 2, 'nearest']],
[ [ -1, 8 ], 1, Concat, [ 1 ] ], # cat backbone P5 [[-1, 8], 1, Concat, [1]], # cat backbone P5
[ -1, 3, C3, [ 768, False ] ], # 15 [-1, 3, C3, [768, False]], # 15
[ -1, 1, Conv, [ 512, 1, 1 ] ], [-1, 1, Conv, [512, 1, 1]],
[ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], [-1, 1, nn.Upsample, [None, 2, 'nearest']],
[ [ -1, 6 ], 1, Concat, [ 1 ] ], # cat backbone P4 [[-1, 6], 1, Concat, [1]], # cat backbone P4
[ -1, 3, C3, [ 512, False ] ], # 19 [-1, 3, C3, [512, False]], # 19
[ -1, 1, Conv, [ 256, 1, 1 ] ], [-1, 1, Conv, [256, 1, 1]],
[ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], [-1, 1, nn.Upsample, [None, 2, 'nearest']],
[ [ -1, 4 ], 1, Concat, [ 1 ] ], # cat backbone P3 [[-1, 4], 1, Concat, [1]], # cat backbone P3
[ -1, 3, C3, [ 256, False ] ], # 23 (P3/8-small) [-1, 3, C3, [256, False]], # 23 (P3/8-small)
[ -1, 1, Conv, [ 256, 3, 2 ] ], [-1, 1, Conv, [256, 3, 2]],
[ [ -1, 20 ], 1, Concat, [ 1 ] ], # cat head P4 [[-1, 20], 1, Concat, [1]], # cat head P4
[ -1, 3, C3, [ 512, False ] ], # 26 (P4/16-medium) [-1, 3, C3, [512, False]], # 26 (P4/16-medium)
[ -1, 1, Conv, [ 512, 3, 2 ] ], [-1, 1, Conv, [512, 3, 2]],
[ [ -1, 16 ], 1, Concat, [ 1 ] ], # cat head P5 [[-1, 16], 1, Concat, [1]], # cat head P5
[ -1, 3, C3, [ 768, False ] ], # 29 (P5/32-large) [-1, 3, C3, [768, False]], # 29 (P5/32-large)
[ -1, 1, Conv, [ 768, 3, 2 ] ], [-1, 1, Conv, [768, 3, 2]],
[ [ -1, 12 ], 1, Concat, [ 1 ] ], # cat head P6 [[-1, 12], 1, Concat, [1]], # cat head P6
[ -1, 3, C3, [ 1024, False ] ], # 32 (P6/64-xlarge) [-1, 3, C3, [1024, False]], # 32 (P6/64-xlarge)
[ [ 23, 26, 29, 32 ], 1, Detect, [ nc, anchors ] ], # Detect(P3, P4, P5, P6) [[23, 26, 29, 32], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5, P6)
] ]
+43 -43
View File
@@ -1,60 +1,60 @@
# parameters # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
# Parameters
nc: 80 # number of classes nc: 80 # number of classes
depth_multiple: 1.33 # model depth multiple depth_multiple: 1.33 # model depth multiple
width_multiple: 1.25 # layer channel multiple width_multiple: 1.25 # layer channel multiple
# anchors
anchors: anchors:
- [ 19,27, 44,40, 38,94 ] # P3/8 - [19,27, 44,40, 38,94] # P3/8
- [ 96,68, 86,152, 180,137 ] # P4/16 - [96,68, 86,152, 180,137] # P4/16
- [ 140,301, 303,264, 238,542 ] # P5/32 - [140,301, 303,264, 238,542] # P5/32
- [ 436,615, 739,380, 925,792 ] # P6/64 - [436,615, 739,380, 925,792] # P6/64
# YOLOv5 backbone # YOLOv5 v6.0 backbone
backbone: backbone:
# [from, number, module, args] # [from, number, module, args]
[ [ -1, 1, Focus, [ 64, 3 ] ], # 0-P1/2 [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
[ -1, 1, Conv, [ 128, 3, 2 ] ], # 1-P2/4 [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
[ -1, 3, C3, [ 128 ] ], [-1, 3, C3, [128]],
[ -1, 1, Conv, [ 256, 3, 2 ] ], # 3-P3/8 [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
[ -1, 9, C3, [ 256 ] ], [-1, 6, C3, [256]],
[ -1, 1, Conv, [ 512, 3, 2 ] ], # 5-P4/16 [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
[ -1, 9, C3, [ 512 ] ], [-1, 9, C3, [512]],
[ -1, 1, Conv, [ 768, 3, 2 ] ], # 7-P5/32 [-1, 1, Conv, [768, 3, 2]], # 7-P5/32
[ -1, 3, C3, [ 768 ] ], [-1, 3, C3, [768]],
[ -1, 1, Conv, [ 1024, 3, 2 ] ], # 9-P6/64 [-1, 1, Conv, [1024, 3, 2]], # 9-P6/64
[ -1, 1, SPP, [ 1024, [ 3, 5, 7 ] ] ], [-1, 3, C3, [1024]],
[ -1, 3, C3, [ 1024, False ] ], # 11 [-1, 1, SPPF, [1024, 5]], # 11
] ]
# YOLOv5 head # YOLOv5 v6.0 head
head: head:
[ [ -1, 1, Conv, [ 768, 1, 1 ] ], [[-1, 1, Conv, [768, 1, 1]],
[ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], [-1, 1, nn.Upsample, [None, 2, 'nearest']],
[ [ -1, 8 ], 1, Concat, [ 1 ] ], # cat backbone P5 [[-1, 8], 1, Concat, [1]], # cat backbone P5
[ -1, 3, C3, [ 768, False ] ], # 15 [-1, 3, C3, [768, False]], # 15
[ -1, 1, Conv, [ 512, 1, 1 ] ], [-1, 1, Conv, [512, 1, 1]],
[ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], [-1, 1, nn.Upsample, [None, 2, 'nearest']],
[ [ -1, 6 ], 1, Concat, [ 1 ] ], # cat backbone P4 [[-1, 6], 1, Concat, [1]], # cat backbone P4
[ -1, 3, C3, [ 512, False ] ], # 19 [-1, 3, C3, [512, False]], # 19
[ -1, 1, Conv, [ 256, 1, 1 ] ], [-1, 1, Conv, [256, 1, 1]],
[ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], [-1, 1, nn.Upsample, [None, 2, 'nearest']],
[ [ -1, 4 ], 1, Concat, [ 1 ] ], # cat backbone P3 [[-1, 4], 1, Concat, [1]], # cat backbone P3
[ -1, 3, C3, [ 256, False ] ], # 23 (P3/8-small) [-1, 3, C3, [256, False]], # 23 (P3/8-small)
[ -1, 1, Conv, [ 256, 3, 2 ] ], [-1, 1, Conv, [256, 3, 2]],
[ [ -1, 20 ], 1, Concat, [ 1 ] ], # cat head P4 [[-1, 20], 1, Concat, [1]], # cat head P4
[ -1, 3, C3, [ 512, False ] ], # 26 (P4/16-medium) [-1, 3, C3, [512, False]], # 26 (P4/16-medium)
[ -1, 1, Conv, [ 512, 3, 2 ] ], [-1, 1, Conv, [512, 3, 2]],
[ [ -1, 16 ], 1, Concat, [ 1 ] ], # cat head P5 [[-1, 16], 1, Concat, [1]], # cat head P5
[ -1, 3, C3, [ 768, False ] ], # 29 (P5/32-large) [-1, 3, C3, [768, False]], # 29 (P5/32-large)
[ -1, 1, Conv, [ 768, 3, 2 ] ], [-1, 1, Conv, [768, 3, 2]],
[ [ -1, 12 ], 1, Concat, [ 1 ] ], # cat head P6 [[-1, 12], 1, Concat, [1]], # cat head P6
[ -1, 3, C3, [ 1024, False ] ], # 32 (P6/64-xlarge) [-1, 3, C3, [1024, False]], # 32 (P6/64-xlarge)
[ [ 23, 26, 29, 32 ], 1, Detect, [ nc, anchors ] ], # Detect(P3, P4, P5, P6) [[23, 26, 29, 32], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5, P6)
] ]
+574
View File
@@ -0,0 +1,574 @@
# YOLOv5 🚀 by Ultralytics, GPL-3.0 license
"""
TensorFlow, Keras and TFLite versions of YOLOv5
Authored by https://github.com/zldrobit in PR https://github.com/ultralytics/yolov5/pull/1127
Usage:
$ python models/tf.py --weights yolov5s.pt
Export:
$ python path/to/export.py --weights yolov5s.pt --include saved_model pb tflite tfjs
"""
import argparse
import sys
from copy import deepcopy
from pathlib import Path
FILE = Path(__file__).resolve()
ROOT = FILE.parents[1] # YOLOv5 root directory
if str(ROOT) not in sys.path:
sys.path.append(str(ROOT)) # add ROOT to PATH
# ROOT = ROOT.relative_to(Path.cwd()) # relative
import numpy as np
import tensorflow as tf
import torch
import torch.nn as nn
from tensorflow import keras
from models.common import (C3, SPP, SPPF, Bottleneck, BottleneckCSP, C3x, Concat, Conv, CrossConv, DWConv,
DWConvTranspose2d, Focus, autopad)
from models.experimental import MixConv2d, attempt_load
from models.yolo import Detect
from utils.activations import SiLU
from utils.general import LOGGER, make_divisible, print_args
class TFBN(keras.layers.Layer):
# TensorFlow BatchNormalization wrapper
def __init__(self, w=None):
super().__init__()
self.bn = keras.layers.BatchNormalization(
beta_initializer=keras.initializers.Constant(w.bias.numpy()),
gamma_initializer=keras.initializers.Constant(w.weight.numpy()),
moving_mean_initializer=keras.initializers.Constant(w.running_mean.numpy()),
moving_variance_initializer=keras.initializers.Constant(w.running_var.numpy()),
epsilon=w.eps)
def call(self, inputs):
return self.bn(inputs)
class TFPad(keras.layers.Layer):
# Pad inputs in spatial dimensions 1 and 2
def __init__(self, pad):
super().__init__()
if isinstance(pad, int):
self.pad = tf.constant([[0, 0], [pad, pad], [pad, pad], [0, 0]])
else: # tuple/list
self.pad = tf.constant([[0, 0], [pad[0], pad[0]], [pad[1], pad[1]], [0, 0]])
def call(self, inputs):
return tf.pad(inputs, self.pad, mode='constant', constant_values=0)
class TFConv(keras.layers.Layer):
# Standard convolution
def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True, w=None):
# ch_in, ch_out, weights, kernel, stride, padding, groups
super().__init__()
assert g == 1, "TF v2.2 Conv2D does not support 'groups' argument"
# TensorFlow convolution padding is inconsistent with PyTorch (e.g. k=3 s=2 'SAME' padding)
# see https://stackoverflow.com/questions/52975843/comparing-conv2d-with-padding-between-tensorflow-and-pytorch
conv = keras.layers.Conv2D(
filters=c2,
kernel_size=k,
strides=s,
padding='SAME' if s == 1 else 'VALID',
use_bias=not hasattr(w, 'bn'),
kernel_initializer=keras.initializers.Constant(w.conv.weight.permute(2, 3, 1, 0).numpy()),
bias_initializer='zeros' if hasattr(w, 'bn') else keras.initializers.Constant(w.conv.bias.numpy()))
self.conv = conv if s == 1 else keras.Sequential([TFPad(autopad(k, p)), conv])
self.bn = TFBN(w.bn) if hasattr(w, 'bn') else tf.identity
self.act = activations(w.act) if act else tf.identity
def call(self, inputs):
return self.act(self.bn(self.conv(inputs)))
class TFDWConv(keras.layers.Layer):
# Depthwise convolution
def __init__(self, c1, c2, k=1, s=1, p=None, act=True, w=None):
# ch_in, ch_out, weights, kernel, stride, padding, groups
super().__init__()
assert c2 % c1 == 0, f'TFDWConv() output={c2} must be a multiple of input={c1} channels'
conv = keras.layers.DepthwiseConv2D(
kernel_size=k,
depth_multiplier=c2 // c1,
strides=s,
padding='SAME' if s == 1 else 'VALID',
use_bias=not hasattr(w, 'bn'),
depthwise_initializer=keras.initializers.Constant(w.conv.weight.permute(2, 3, 1, 0).numpy()),
bias_initializer='zeros' if hasattr(w, 'bn') else keras.initializers.Constant(w.conv.bias.numpy()))
self.conv = conv if s == 1 else keras.Sequential([TFPad(autopad(k, p)), conv])
self.bn = TFBN(w.bn) if hasattr(w, 'bn') else tf.identity
self.act = activations(w.act) if act else tf.identity
def call(self, inputs):
return self.act(self.bn(self.conv(inputs)))
class TFDWConvTranspose2d(keras.layers.Layer):
# Depthwise ConvTranspose2d
def __init__(self, c1, c2, k=1, s=1, p1=0, p2=0, w=None):
# ch_in, ch_out, weights, kernel, stride, padding, groups
super().__init__()
assert c1 == c2, f'TFDWConv() output={c2} must be equal to input={c1} channels'
assert k == 4 and p1 == 1, 'TFDWConv() only valid for k=4 and p1=1'
weight, bias = w.weight.permute(2, 3, 1, 0).numpy(), w.bias.numpy()
self.c1 = c1
self.conv = [
keras.layers.Conv2DTranspose(filters=1,
kernel_size=k,
strides=s,
padding='VALID',
output_padding=p2,
use_bias=True,
kernel_initializer=keras.initializers.Constant(weight[..., i:i + 1]),
bias_initializer=keras.initializers.Constant(bias[i])) for i in range(c1)]
def call(self, inputs):
return tf.concat([m(x) for m, x in zip(self.conv, tf.split(inputs, self.c1, 3))], 3)[:, 1:-1, 1:-1]
class TFFocus(keras.layers.Layer):
# Focus wh information into c-space
def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True, w=None):
# ch_in, ch_out, kernel, stride, padding, groups
super().__init__()
self.conv = TFConv(c1 * 4, c2, k, s, p, g, act, w.conv)
def call(self, inputs): # x(b,w,h,c) -> y(b,w/2,h/2,4c)
# inputs = inputs / 255 # normalize 0-255 to 0-1
inputs = [inputs[:, ::2, ::2, :], inputs[:, 1::2, ::2, :], inputs[:, ::2, 1::2, :], inputs[:, 1::2, 1::2, :]]
return self.conv(tf.concat(inputs, 3))
class TFBottleneck(keras.layers.Layer):
# Standard bottleneck
def __init__(self, c1, c2, shortcut=True, g=1, e=0.5, w=None): # ch_in, ch_out, shortcut, groups, expansion
super().__init__()
c_ = int(c2 * e) # hidden channels
self.cv1 = TFConv(c1, c_, 1, 1, w=w.cv1)
self.cv2 = TFConv(c_, c2, 3, 1, g=g, w=w.cv2)
self.add = shortcut and c1 == c2
def call(self, inputs):
return inputs + self.cv2(self.cv1(inputs)) if self.add else self.cv2(self.cv1(inputs))
class TFCrossConv(keras.layers.Layer):
# Cross Convolution
def __init__(self, c1, c2, k=3, s=1, g=1, e=1.0, shortcut=False, w=None):
super().__init__()
c_ = int(c2 * e) # hidden channels
self.cv1 = TFConv(c1, c_, (1, k), (1, s), w=w.cv1)
self.cv2 = TFConv(c_, c2, (k, 1), (s, 1), g=g, w=w.cv2)
self.add = shortcut and c1 == c2
def call(self, inputs):
return inputs + self.cv2(self.cv1(inputs)) if self.add else self.cv2(self.cv1(inputs))
class TFConv2d(keras.layers.Layer):
# Substitution for PyTorch nn.Conv2D
def __init__(self, c1, c2, k, s=1, g=1, bias=True, w=None):
super().__init__()
assert g == 1, "TF v2.2 Conv2D does not support 'groups' argument"
self.conv = keras.layers.Conv2D(filters=c2,
kernel_size=k,
strides=s,
padding='VALID',
use_bias=bias,
kernel_initializer=keras.initializers.Constant(
w.weight.permute(2, 3, 1, 0).numpy()),
bias_initializer=keras.initializers.Constant(w.bias.numpy()) if bias else None)
def call(self, inputs):
return self.conv(inputs)
class TFBottleneckCSP(keras.layers.Layer):
# CSP Bottleneck https://github.com/WongKinYiu/CrossStagePartialNetworks
def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5, w=None):
# ch_in, ch_out, number, shortcut, groups, expansion
super().__init__()
c_ = int(c2 * e) # hidden channels
self.cv1 = TFConv(c1, c_, 1, 1, w=w.cv1)
self.cv2 = TFConv2d(c1, c_, 1, 1, bias=False, w=w.cv2)
self.cv3 = TFConv2d(c_, c_, 1, 1, bias=False, w=w.cv3)
self.cv4 = TFConv(2 * c_, c2, 1, 1, w=w.cv4)
self.bn = TFBN(w.bn)
self.act = lambda x: keras.activations.swish(x)
self.m = keras.Sequential([TFBottleneck(c_, c_, shortcut, g, e=1.0, w=w.m[j]) for j in range(n)])
def call(self, inputs):
y1 = self.cv3(self.m(self.cv1(inputs)))
y2 = self.cv2(inputs)
return self.cv4(self.act(self.bn(tf.concat((y1, y2), axis=3))))
class TFC3(keras.layers.Layer):
# CSP Bottleneck with 3 convolutions
def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5, w=None):
# ch_in, ch_out, number, shortcut, groups, expansion
super().__init__()
c_ = int(c2 * e) # hidden channels
self.cv1 = TFConv(c1, c_, 1, 1, w=w.cv1)
self.cv2 = TFConv(c1, c_, 1, 1, w=w.cv2)
self.cv3 = TFConv(2 * c_, c2, 1, 1, w=w.cv3)
self.m = keras.Sequential([TFBottleneck(c_, c_, shortcut, g, e=1.0, w=w.m[j]) for j in range(n)])
def call(self, inputs):
return self.cv3(tf.concat((self.m(self.cv1(inputs)), self.cv2(inputs)), axis=3))
class TFC3x(keras.layers.Layer):
# 3 module with cross-convolutions
def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5, w=None):
# ch_in, ch_out, number, shortcut, groups, expansion
super().__init__()
c_ = int(c2 * e) # hidden channels
self.cv1 = TFConv(c1, c_, 1, 1, w=w.cv1)
self.cv2 = TFConv(c1, c_, 1, 1, w=w.cv2)
self.cv3 = TFConv(2 * c_, c2, 1, 1, w=w.cv3)
self.m = keras.Sequential([
TFCrossConv(c_, c_, k=3, s=1, g=g, e=1.0, shortcut=shortcut, w=w.m[j]) for j in range(n)])
def call(self, inputs):
return self.cv3(tf.concat((self.m(self.cv1(inputs)), self.cv2(inputs)), axis=3))
class TFSPP(keras.layers.Layer):
# Spatial pyramid pooling layer used in YOLOv3-SPP
def __init__(self, c1, c2, k=(5, 9, 13), w=None):
super().__init__()
c_ = c1 // 2 # hidden channels
self.cv1 = TFConv(c1, c_, 1, 1, w=w.cv1)
self.cv2 = TFConv(c_ * (len(k) + 1), c2, 1, 1, w=w.cv2)
self.m = [keras.layers.MaxPool2D(pool_size=x, strides=1, padding='SAME') for x in k]
def call(self, inputs):
x = self.cv1(inputs)
return self.cv2(tf.concat([x] + [m(x) for m in self.m], 3))
class TFSPPF(keras.layers.Layer):
# Spatial pyramid pooling-Fast layer
def __init__(self, c1, c2, k=5, w=None):
super().__init__()
c_ = c1 // 2 # hidden channels
self.cv1 = TFConv(c1, c_, 1, 1, w=w.cv1)
self.cv2 = TFConv(c_ * 4, c2, 1, 1, w=w.cv2)
self.m = keras.layers.MaxPool2D(pool_size=k, strides=1, padding='SAME')
def call(self, inputs):
x = self.cv1(inputs)
y1 = self.m(x)
y2 = self.m(y1)
return self.cv2(tf.concat([x, y1, y2, self.m(y2)], 3))
class TFDetect(keras.layers.Layer):
# TF YOLOv5 Detect layer
def __init__(self, nc=80, anchors=(), ch=(), imgsz=(640, 640), w=None): # detection layer
super().__init__()
self.stride = tf.convert_to_tensor(w.stride.numpy(), dtype=tf.float32)
self.nc = nc # number of classes
self.no = nc + 5 # number of outputs per anchor
self.nl = len(anchors) # number of detection layers
self.na = len(anchors[0]) // 2 # number of anchors
self.grid = [tf.zeros(1)] * self.nl # init grid
self.anchors = tf.convert_to_tensor(w.anchors.numpy(), dtype=tf.float32)
self.anchor_grid = tf.reshape(self.anchors * tf.reshape(self.stride, [self.nl, 1, 1]), [self.nl, 1, -1, 1, 2])
self.m = [TFConv2d(x, self.no * self.na, 1, w=w.m[i]) for i, x in enumerate(ch)]
self.training = False # set to False after building model
self.imgsz = imgsz
for i in range(self.nl):
ny, nx = self.imgsz[0] // self.stride[i], self.imgsz[1] // self.stride[i]
self.grid[i] = self._make_grid(nx, ny)
def call(self, inputs):
z = [] # inference output
x = []
for i in range(self.nl):
x.append(self.m[i](inputs[i]))
# x(bs,20,20,255) to x(bs,3,20,20,85)
ny, nx = self.imgsz[0] // self.stride[i], self.imgsz[1] // self.stride[i]
x[i] = tf.reshape(x[i], [-1, ny * nx, self.na, self.no])
if not self.training: # inference
y = tf.sigmoid(x[i])
grid = tf.transpose(self.grid[i], [0, 2, 1, 3]) - 0.5
anchor_grid = tf.transpose(self.anchor_grid[i], [0, 2, 1, 3]) * 4
xy = (y[..., 0:2] * 2 + grid) * self.stride[i] # xy
wh = y[..., 2:4] ** 2 * anchor_grid
# Normalize xywh to 0-1 to reduce calibration error
xy /= tf.constant([[self.imgsz[1], self.imgsz[0]]], dtype=tf.float32)
wh /= tf.constant([[self.imgsz[1], self.imgsz[0]]], dtype=tf.float32)
y = tf.concat([xy, wh, y[..., 4:]], -1)
z.append(tf.reshape(y, [-1, self.na * ny * nx, self.no]))
return tf.transpose(x, [0, 2, 1, 3]) if self.training else (tf.concat(z, 1), x)
@staticmethod
def _make_grid(nx=20, ny=20):
# yv, xv = torch.meshgrid([torch.arange(ny), torch.arange(nx)])
# return torch.stack((xv, yv), 2).view((1, 1, ny, nx, 2)).float()
xv, yv = tf.meshgrid(tf.range(nx), tf.range(ny))
return tf.cast(tf.reshape(tf.stack([xv, yv], 2), [1, 1, ny * nx, 2]), dtype=tf.float32)
class TFUpsample(keras.layers.Layer):
# TF version of torch.nn.Upsample()
def __init__(self, size, scale_factor, mode, w=None): # warning: all arguments needed including 'w'
super().__init__()
assert scale_factor == 2, "scale_factor must be 2"
self.upsample = lambda x: tf.image.resize(x, (x.shape[1] * 2, x.shape[2] * 2), method=mode)
# self.upsample = keras.layers.UpSampling2D(size=scale_factor, interpolation=mode)
# with default arguments: align_corners=False, half_pixel_centers=False
# self.upsample = lambda x: tf.raw_ops.ResizeNearestNeighbor(images=x,
# size=(x.shape[1] * 2, x.shape[2] * 2))
def call(self, inputs):
return self.upsample(inputs)
class TFConcat(keras.layers.Layer):
# TF version of torch.concat()
def __init__(self, dimension=1, w=None):
super().__init__()
assert dimension == 1, "convert only NCHW to NHWC concat"
self.d = 3
def call(self, inputs):
return tf.concat(inputs, self.d)
def parse_model(d, ch, model, imgsz): # model_dict, input_channels(3)
LOGGER.info(f"\n{'':>3}{'from':>18}{'n':>3}{'params':>10} {'module':<40}{'arguments':<30}")
anchors, nc, gd, gw = d['anchors'], d['nc'], d['depth_multiple'], d['width_multiple']
na = (len(anchors[0]) // 2) if isinstance(anchors, list) else anchors # number of anchors
no = na * (nc + 5) # number of outputs = anchors * (classes + 5)
layers, save, c2 = [], [], ch[-1] # layers, savelist, ch out
for i, (f, n, m, args) in enumerate(d['backbone'] + d['head']): # from, number, module, args
m_str = m
m = eval(m) if isinstance(m, str) else m # eval strings
for j, a in enumerate(args):
try:
args[j] = eval(a) if isinstance(a, str) else a # eval strings
except NameError:
pass
n = max(round(n * gd), 1) if n > 1 else n # depth gain
if m in [
nn.Conv2d, Conv, DWConv, DWConvTranspose2d, Bottleneck, SPP, SPPF, MixConv2d, Focus, CrossConv,
BottleneckCSP, C3, C3x]:
c1, c2 = ch[f], args[0]
c2 = make_divisible(c2 * gw, 8) if c2 != no else c2
args = [c1, c2, *args[1:]]
if m in [BottleneckCSP, C3, C3x]:
args.insert(2, n)
n = 1
elif m is nn.BatchNorm2d:
args = [ch[f]]
elif m is Concat:
c2 = sum(ch[-1 if x == -1 else x + 1] for x in f)
elif m is Detect:
args.append([ch[x + 1] for x in f])
if isinstance(args[1], int): # number of anchors
args[1] = [list(range(args[1] * 2))] * len(f)
args.append(imgsz)
else:
c2 = ch[f]
tf_m = eval('TF' + m_str.replace('nn.', ''))
m_ = keras.Sequential([tf_m(*args, w=model.model[i][j]) for j in range(n)]) if n > 1 \
else tf_m(*args, w=model.model[i]) # module
torch_m_ = nn.Sequential(*(m(*args) for _ in range(n))) if n > 1 else m(*args) # module
t = str(m)[8:-2].replace('__main__.', '') # module type
np = sum(x.numel() for x in torch_m_.parameters()) # number params
m_.i, m_.f, m_.type, m_.np = i, f, t, np # attach index, 'from' index, type, number params
LOGGER.info(f'{i:>3}{str(f):>18}{str(n):>3}{np:>10} {t:<40}{str(args):<30}') # print
save.extend(x % i for x in ([f] if isinstance(f, int) else f) if x != -1) # append to savelist
layers.append(m_)
ch.append(c2)
return keras.Sequential(layers), sorted(save)
class TFModel:
# TF YOLOv5 model
def __init__(self, cfg='yolov5s.yaml', ch=3, nc=None, model=None, imgsz=(640, 640)): # model, channels, classes
super().__init__()
if isinstance(cfg, dict):
self.yaml = cfg # model dict
else: # is *.yaml
import yaml # for torch hub
self.yaml_file = Path(cfg).name
with open(cfg) as f:
self.yaml = yaml.load(f, Loader=yaml.FullLoader) # model dict
# Define model
if nc and nc != self.yaml['nc']:
LOGGER.info(f"Overriding {cfg} nc={self.yaml['nc']} with nc={nc}")
self.yaml['nc'] = nc # override yaml value
self.model, self.savelist = parse_model(deepcopy(self.yaml), ch=[ch], model=model, imgsz=imgsz)
def predict(self,
inputs,
tf_nms=False,
agnostic_nms=False,
topk_per_class=100,
topk_all=100,
iou_thres=0.45,
conf_thres=0.25):
y = [] # outputs
x = inputs
for m in self.model.layers:
if m.f != -1: # if not from previous layer
x = y[m.f] if isinstance(m.f, int) else [x if j == -1 else y[j] for j in m.f] # from earlier layers
x = m(x) # run
y.append(x if m.i in self.savelist else None) # save output
# Add TensorFlow NMS
if tf_nms:
boxes = self._xywh2xyxy(x[0][..., :4])
probs = x[0][:, :, 4:5]
classes = x[0][:, :, 5:]
scores = probs * classes
if agnostic_nms:
nms = AgnosticNMS()((boxes, classes, scores), topk_all, iou_thres, conf_thres)
else:
boxes = tf.expand_dims(boxes, 2)
nms = tf.image.combined_non_max_suppression(boxes,
scores,
topk_per_class,
topk_all,
iou_thres,
conf_thres,
clip_boxes=False)
return nms, x[1]
return x[0] # output only first tensor [1,6300,85] = [xywh, conf, class0, class1, ...]
# x = x[0][0] # [x(1,6300,85), ...] to x(6300,85)
# xywh = x[..., :4] # x(6300,4) boxes
# conf = x[..., 4:5] # x(6300,1) confidences
# cls = tf.reshape(tf.cast(tf.argmax(x[..., 5:], axis=1), tf.float32), (-1, 1)) # x(6300,1) classes
# return tf.concat([conf, cls, xywh], 1)
@staticmethod
def _xywh2xyxy(xywh):
# Convert nx4 boxes from [x, y, w, h] to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right
x, y, w, h = tf.split(xywh, num_or_size_splits=4, axis=-1)
return tf.concat([x - w / 2, y - h / 2, x + w / 2, y + h / 2], axis=-1)
class AgnosticNMS(keras.layers.Layer):
# TF Agnostic NMS
def call(self, input, topk_all, iou_thres, conf_thres):
# wrap map_fn to avoid TypeSpec related error https://stackoverflow.com/a/65809989/3036450
return tf.map_fn(lambda x: self._nms(x, topk_all, iou_thres, conf_thres),
input,
fn_output_signature=(tf.float32, tf.float32, tf.float32, tf.int32),
name='agnostic_nms')
@staticmethod
def _nms(x, topk_all=100, iou_thres=0.45, conf_thres=0.25): # agnostic NMS
boxes, classes, scores = x
class_inds = tf.cast(tf.argmax(classes, axis=-1), tf.float32)
scores_inp = tf.reduce_max(scores, -1)
selected_inds = tf.image.non_max_suppression(boxes,
scores_inp,
max_output_size=topk_all,
iou_threshold=iou_thres,
score_threshold=conf_thres)
selected_boxes = tf.gather(boxes, selected_inds)
padded_boxes = tf.pad(selected_boxes,
paddings=[[0, topk_all - tf.shape(selected_boxes)[0]], [0, 0]],
mode="CONSTANT",
constant_values=0.0)
selected_scores = tf.gather(scores_inp, selected_inds)
padded_scores = tf.pad(selected_scores,
paddings=[[0, topk_all - tf.shape(selected_boxes)[0]]],
mode="CONSTANT",
constant_values=-1.0)
selected_classes = tf.gather(class_inds, selected_inds)
padded_classes = tf.pad(selected_classes,
paddings=[[0, topk_all - tf.shape(selected_boxes)[0]]],
mode="CONSTANT",
constant_values=-1.0)
valid_detections = tf.shape(selected_inds)[0]
return padded_boxes, padded_scores, padded_classes, valid_detections
def activations(act=nn.SiLU):
# Returns TF activation from input PyTorch activation
if isinstance(act, nn.LeakyReLU):
return lambda x: keras.activations.relu(x, alpha=0.1)
elif isinstance(act, nn.Hardswish):
return lambda x: x * tf.nn.relu6(x + 3) * 0.166666667
elif isinstance(act, (nn.SiLU, SiLU)):
return lambda x: keras.activations.swish(x)
else:
raise Exception(f'no matching TensorFlow activation found for PyTorch activation {act}')
def representative_dataset_gen(dataset, ncalib=100):
# Representative dataset generator for use with converter.representative_dataset, returns a generator of np arrays
for n, (path, img, im0s, vid_cap, string) in enumerate(dataset):
im = np.transpose(img, [1, 2, 0])
im = np.expand_dims(im, axis=0).astype(np.float32)
im /= 255
yield [im]
if n >= ncalib:
break
def run(
weights=ROOT / 'yolov5s.pt', # weights path
imgsz=(640, 640), # inference size h,w
batch_size=1, # batch size
dynamic=False, # dynamic batch size
):
# PyTorch model
im = torch.zeros((batch_size, 3, *imgsz)) # BCHW image
model = attempt_load(weights, device=torch.device('cpu'), inplace=True, fuse=False)
_ = model(im) # inference
model.info()
# TensorFlow model
im = tf.zeros((batch_size, *imgsz, 3)) # BHWC image
tf_model = TFModel(cfg=model.yaml, model=model, nc=model.nc, imgsz=imgsz)
_ = tf_model.predict(im) # inference
# Keras model
im = keras.Input(shape=(*imgsz, 3), batch_size=None if dynamic else batch_size)
keras_model = keras.Model(inputs=im, outputs=tf_model.predict(im))
keras_model.summary()
LOGGER.info('PyTorch, TensorFlow and Keras models successfully verified.\nUse export.py for TF model export.')
def parse_opt():
parser = argparse.ArgumentParser()
parser.add_argument('--weights', type=str, default=ROOT / 'yolov5s.pt', help='weights path')
parser.add_argument('--imgsz', '--img', '--img-size', nargs='+', type=int, default=[640], help='inference size h,w')
parser.add_argument('--batch-size', type=int, default=1, help='batch size')
parser.add_argument('--dynamic', action='store_true', help='dynamic batch size')
opt = parser.parse_args()
opt.imgsz *= 2 if len(opt.imgsz) == 1 else 1 # expand
print_args(vars(opt))
return opt
def main(opt):
run(**vars(opt))
if __name__ == "__main__":
opt = parse_opt()
main(opt)
+179 -116
View File
@@ -1,203 +1,256 @@
# YOLOv5 🚀 by Ultralytics, GPL-3.0 license
"""
YOLO-specific modules
Usage:
$ python path/to/models/yolo.py --cfg yolov5s.yaml
"""
import argparse import argparse
import logging import os
import platform
import sys import sys
from copy import deepcopy from copy import deepcopy
from pathlib import Path
sys.path.append('./') # to run '$ python *.py' files in subdirectories FILE = Path(__file__).resolve()
logger = logging.getLogger(__name__) ROOT = FILE.parents[1] # YOLOv5 root directory
if str(ROOT) not in sys.path:
sys.path.append(str(ROOT)) # add ROOT to PATH
if platform.system() != 'Windows':
ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative
from Y5.models.common import * from models.common import *
from Y5.models.experimental import * from models.experimental import *
from Y5.utils.autoanchor import check_anchor_order from utils.autoanchor import check_anchor_order
from Y5.utils.general import make_divisible, check_file, set_logging from utils.general import LOGGER, check_version, check_yaml, make_divisible, print_args
from Y5.utils.torch_utils import time_synchronized, fuse_conv_and_bn, model_info, scale_img, initialize_weights, \ from utils.plots import feature_visualization
select_device, copy_attr from utils.torch_utils import (fuse_conv_and_bn, initialize_weights, model_info, profile, scale_img, select_device,
time_sync)
try: try:
import thop # for FLOPS computation import thop # for FLOPs computation
except ImportError: except ImportError:
thop = None thop = None
class Detect(nn.Module): class Detect(nn.Module):
stride = None # strides computed during build stride = None # strides computed during build
export = False # onnx export onnx_dynamic = False # ONNX export parameter
export = False # export mode
def __init__(self, nc=80, anchors=(), ch=()): # detection layer def __init__(self, nc=80, anchors=(), ch=(), inplace=True): # detection layer
super(Detect, self).__init__() super().__init__()
self.nc = nc # number of classes self.nc = nc # number of classes
self.no = nc + 5 # number of outputs per anchor self.no = nc + 5 # number of outputs per anchor
self.nl = len(anchors) # number of detection layers self.nl = len(anchors) # number of detection layers
self.na = len(anchors[0]) // 2 # number of anchors self.na = len(anchors[0]) // 2 # number of anchors
self.grid = [torch.zeros(1)] * self.nl # init grid self.grid = [torch.zeros(1)] * self.nl # init grid
a = torch.tensor(anchors).float().view(self.nl, -1, 2) self.anchor_grid = [torch.zeros(1)] * self.nl # init anchor grid
self.register_buffer('anchors', a) # shape(nl,na,2) self.register_buffer('anchors', torch.tensor(anchors).float().view(self.nl, -1, 2)) # shape(nl,na,2)
self.register_buffer('anchor_grid', a.clone().view(self.nl, 1, -1, 1, 1, 2)) # shape(nl,1,na,1,1,2)
self.m = nn.ModuleList(nn.Conv2d(x, self.no * self.na, 1) for x in ch) # output conv self.m = nn.ModuleList(nn.Conv2d(x, self.no * self.na, 1) for x in ch) # output conv
self.inplace = inplace # use in-place ops (e.g. slice assignment)
def forward(self, x): def forward(self, x):
# x = x.copy() # for profiling
z = [] # inference output z = [] # inference output
self.training |= self.export
for i in range(self.nl): for i in range(self.nl):
x[i] = self.m[i](x[i]) # conv x[i] = self.m[i](x[i]) # conv
bs, _, ny, nx = x[i].shape # x(bs,255,20,20) to x(bs,3,20,20,85) bs, _, ny, nx = x[i].shape # x(bs,255,20,20) to x(bs,3,20,20,85)
x[i] = x[i].view(bs, self.na, self.no, ny, nx).permute(0, 1, 3, 4, 2).contiguous() x[i] = x[i].view(bs, self.na, self.no, ny, nx).permute(0, 1, 3, 4, 2).contiguous()
if not self.training: # inference if not self.training: # inference
if self.grid[i].shape[2:4] != x[i].shape[2:4]: if self.onnx_dynamic or self.grid[i].shape[2:4] != x[i].shape[2:4]:
self.grid[i] = self._make_grid(nx, ny).to(x[i].device) self.grid[i], self.anchor_grid[i] = self._make_grid(nx, ny, i)
y = x[i].sigmoid() y = x[i].sigmoid()
y[..., 0:2] = (y[..., 0:2] * 2. - 0.5 + self.grid[i]) * self.stride[i] # xy if self.inplace:
y[..., 2:4] = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i] # wh y[..., 0:2] = (y[..., 0:2] * 2 + self.grid[i]) * self.stride[i] # xy
y[..., 2:4] = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i] # wh
else: # for YOLOv5 on AWS Inferentia https://github.com/ultralytics/yolov5/pull/2953
xy, wh, conf = y.split((2, 2, self.nc + 1), 4) # y.tensor_split((2, 4, 5), 4) # torch 1.8.0
xy = (xy * 2 + self.grid[i]) * self.stride[i] # xy
wh = (wh * 2) ** 2 * self.anchor_grid[i] # wh
y = torch.cat((xy, wh, conf), 4)
z.append(y.view(bs, -1, self.no)) z.append(y.view(bs, -1, self.no))
return x if self.training else (torch.cat(z, 1), x) return x if self.training else (torch.cat(z, 1),) if self.export else (torch.cat(z, 1), x)
@staticmethod def _make_grid(self, nx=20, ny=20, i=0):
def _make_grid(nx=20, ny=20): d = self.anchors[i].device
yv, xv = torch.meshgrid([torch.arange(ny), torch.arange(nx)]) t = self.anchors[i].dtype
return torch.stack((xv, yv), 2).view((1, 1, ny, nx, 2)).float() shape = 1, self.na, ny, nx, 2 # grid shape
y, x = torch.arange(ny, device=d, dtype=t), torch.arange(nx, device=d, dtype=t)
if check_version(torch.__version__, '1.10.0'): # torch>=1.10.0 meshgrid workaround for torch>=0.7 compatibility
yv, xv = torch.meshgrid(y, x, indexing='ij')
else:
yv, xv = torch.meshgrid(y, x)
grid = torch.stack((xv, yv), 2).expand(shape) - 0.5 # add grid offset, i.e. y = 2.0 * x - 0.5
anchor_grid = (self.anchors[i] * self.stride[i]).view((1, self.na, 1, 1, 2)).expand(shape)
return grid, anchor_grid
class Model(nn.Module): class Model(nn.Module):
# YOLOv5 model
def __init__(self, cfg='yolov5s.yaml', ch=3, nc=None, anchors=None): # model, input channels, number of classes def __init__(self, cfg='yolov5s.yaml', ch=3, nc=None, anchors=None): # model, input channels, number of classes
super(Model, self).__init__() super().__init__()
if isinstance(cfg, dict): if isinstance(cfg, dict):
self.yaml = cfg # model dict self.yaml = cfg # model dict
else: # is *.yaml else: # is *.yaml
import yaml # for torch hub import yaml # for torch hub
self.yaml_file = Path(cfg).name self.yaml_file = Path(cfg).name
with open(cfg) as f: with open(cfg, encoding='ascii', errors='ignore') as f:
self.yaml = yaml.load(f, Loader=yaml.SafeLoader) # model dict self.yaml = yaml.safe_load(f) # model dict
# Define model # Define model
ch = self.yaml['ch'] = self.yaml.get('ch', ch) # input channels ch = self.yaml['ch'] = self.yaml.get('ch', ch) # input channels
if nc and nc != self.yaml['nc']: if nc and nc != self.yaml['nc']:
logger.info(f"Overriding model.yaml nc={self.yaml['nc']} with nc={nc}") LOGGER.info(f"Overriding model.yaml nc={self.yaml['nc']} with nc={nc}")
self.yaml['nc'] = nc # override yaml value self.yaml['nc'] = nc # override yaml value
if anchors: if anchors:
logger.info(f'Overriding model.yaml anchors with anchors={anchors}') LOGGER.info(f'Overriding model.yaml anchors with anchors={anchors}')
self.yaml['anchors'] = round(anchors) # override yaml value self.yaml['anchors'] = round(anchors) # override yaml value
self.model, self.save = parse_model(deepcopy(self.yaml), ch=[ch]) # model, savelist self.model, self.save = parse_model(deepcopy(self.yaml), ch=[ch]) # model, savelist
self.names = [str(i) for i in range(self.yaml['nc'])] # default names self.names = [str(i) for i in range(self.yaml['nc'])] # default names
# print([x.shape for x in self.forward(torch.zeros(1, ch, 64, 64))]) self.inplace = self.yaml.get('inplace', True)
# Build strides, anchors # Build strides, anchors
m = self.model[-1] # Detect() m = self.model[-1] # Detect()
if isinstance(m, Detect): if isinstance(m, Detect):
s = 256 # 2x min stride s = 256 # 2x min stride
m.inplace = self.inplace
m.stride = torch.tensor([s / x.shape[-2] for x in self.forward(torch.zeros(1, ch, s, s))]) # forward m.stride = torch.tensor([s / x.shape[-2] for x in self.forward(torch.zeros(1, ch, s, s))]) # forward
check_anchor_order(m) # must be in pixel-space (not grid-space)
m.anchors /= m.stride.view(-1, 1, 1) m.anchors /= m.stride.view(-1, 1, 1)
check_anchor_order(m)
self.stride = m.stride self.stride = m.stride
self._initialize_biases() # only run once self._initialize_biases() # only run once
# print('Strides: %s' % m.stride.tolist())
# Init weights, biases # Init weights, biases
initialize_weights(self) initialize_weights(self)
self.info() self.info()
logger.info('') LOGGER.info('')
def forward(self, x, augment=False, profile=False): def forward(self, x, augment=False, profile=False, visualize=False):
if augment: if augment:
img_size = x.shape[-2:] # height, width return self._forward_augment(x) # augmented inference, None
s = [1, 0.83, 0.67] # scales return self._forward_once(x, profile, visualize) # single-scale inference, train
f = [None, 3, None] # flips (2-ud, 3-lr)
y = [] # outputs
for si, fi in zip(s, f):
xi = scale_img(x.flip(fi) if fi else x, si, gs=int(self.stride.max()))
yi = self.forward_once(xi)[0] # forward
# cv2.imwrite(f'img_{si}.jpg', 255 * xi[0].cpu().numpy().transpose((1, 2, 0))[:, :, ::-1]) # save
yi[..., :4] /= si # de-scale
if fi == 2:
yi[..., 1] = img_size[0] - yi[..., 1] # de-flip ud
elif fi == 3:
yi[..., 0] = img_size[1] - yi[..., 0] # de-flip lr
y.append(yi)
return torch.cat(y, 1), None # augmented inference, train
else:
return self.forward_once(x, profile) # single-scale inference, train
def forward_once(self, x, profile=False): def _forward_augment(self, x):
img_size = x.shape[-2:] # height, width
s = [1, 0.83, 0.67] # scales
f = [None, 3, None] # flips (2-ud, 3-lr)
y = [] # outputs
for si, fi in zip(s, f):
xi = scale_img(x.flip(fi) if fi else x, si, gs=int(self.stride.max()))
yi = self._forward_once(xi)[0] # forward
# cv2.imwrite(f'img_{si}.jpg', 255 * xi[0].cpu().numpy().transpose((1, 2, 0))[:, :, ::-1]) # save
yi = self._descale_pred(yi, fi, si, img_size)
y.append(yi)
y = self._clip_augmented(y) # clip augmented tails
return torch.cat(y, 1), None # augmented inference, train
def _forward_once(self, x, profile=False, visualize=False):
y, dt = [], [] # outputs y, dt = [], [] # outputs
for m in self.model: for m in self.model:
if m.f != -1: # if not from previous layer if m.f != -1: # if not from previous layer
x = y[m.f] if isinstance(m.f, int) else [x if j == -1 else y[j] for j in m.f] # from earlier layers x = y[m.f] if isinstance(m.f, int) else [x if j == -1 else y[j] for j in m.f] # from earlier layers
if profile: if profile:
o = thop.profile(m, inputs=(x,), verbose=False)[0] / 1E9 * 2 if thop else 0 # FLOPS self._profile_one_layer(m, x, dt)
t = time_synchronized()
for _ in range(10):
_ = m(x)
dt.append((time_synchronized() - t) * 100)
print('%10.1f%10.0f%10.1fms %-40s' % (o, m.np, dt[-1], m.type))
x = m(x) # run x = m(x) # run
y.append(x if m.i in self.save else None) # save output y.append(x if m.i in self.save else None) # save output
if visualize:
if profile: feature_visualization(x, m.type, m.i, save_dir=visualize)
print('%.1fms total' % sum(dt))
return x return x
def _descale_pred(self, p, flips, scale, img_size):
# de-scale predictions following augmented inference (inverse operation)
if self.inplace:
p[..., :4] /= scale # de-scale
if flips == 2:
p[..., 1] = img_size[0] - p[..., 1] # de-flip ud
elif flips == 3:
p[..., 0] = img_size[1] - p[..., 0] # de-flip lr
else:
x, y, wh = p[..., 0:1] / scale, p[..., 1:2] / scale, p[..., 2:4] / scale # de-scale
if flips == 2:
y = img_size[0] - y # de-flip ud
elif flips == 3:
x = img_size[1] - x # de-flip lr
p = torch.cat((x, y, wh, p[..., 4:]), -1)
return p
def _clip_augmented(self, y):
# Clip YOLOv5 augmented inference tails
nl = self.model[-1].nl # number of detection layers (P3-P5)
g = sum(4 ** x for x in range(nl)) # grid points
e = 1 # exclude layer count
i = (y[0].shape[1] // g) * sum(4 ** x for x in range(e)) # indices
y[0] = y[0][:, :-i] # large
i = (y[-1].shape[1] // g) * sum(4 ** (nl - 1 - x) for x in range(e)) # indices
y[-1] = y[-1][:, i:] # small
return y
def _profile_one_layer(self, m, x, dt):
c = isinstance(m, Detect) # is final layer, copy input as inplace fix
o = thop.profile(m, inputs=(x.copy() if c else x,), verbose=False)[0] / 1E9 * 2 if thop else 0 # FLOPs
t = time_sync()
for _ in range(10):
m(x.copy() if c else x)
dt.append((time_sync() - t) * 100)
if m == self.model[0]:
LOGGER.info(f"{'time (ms)':>10s} {'GFLOPs':>10s} {'params':>10s} module")
LOGGER.info(f'{dt[-1]:10.2f} {o:10.2f} {m.np:10.0f} {m.type}')
if c:
LOGGER.info(f"{sum(dt):10.2f} {'-':>10s} {'-':>10s} Total")
def _initialize_biases(self, cf=None): # initialize biases into Detect(), cf is class frequency def _initialize_biases(self, cf=None): # initialize biases into Detect(), cf is class frequency
# https://arxiv.org/abs/1708.02002 section 3.3 # https://arxiv.org/abs/1708.02002 section 3.3
# cf = torch.bincount(torch.tensor(np.concatenate(dataset.labels, 0)[:, 0]).long(), minlength=nc) + 1. # cf = torch.bincount(torch.tensor(np.concatenate(dataset.labels, 0)[:, 0]).long(), minlength=nc) + 1.
m = self.model[-1] # Detect() module m = self.model[-1] # Detect() module
for mi, s in zip(m.m, m.stride): # from for mi, s in zip(m.m, m.stride): # from
b = mi.bias.view(m.na, -1) # conv.bias(255) to (3,85) b = mi.bias.view(m.na, -1).detach() # conv.bias(255) to (3,85)
b.data[:, 4] += math.log(8 / (640 / s) ** 2) # obj (8 objects per 640 image) b[:, 4] += math.log(8 / (640 / s) ** 2) # obj (8 objects per 640 image)
b.data[:, 5:] += math.log(0.6 / (m.nc - 0.99)) if cf is None else torch.log(cf / cf.sum()) # cls b[:, 5:] += math.log(0.6 / (m.nc - 0.999999)) if cf is None else torch.log(cf / cf.sum()) # cls
mi.bias = torch.nn.Parameter(b.view(-1), requires_grad=True) mi.bias = torch.nn.Parameter(b.view(-1), requires_grad=True)
def _print_biases(self): def _print_biases(self):
m = self.model[-1] # Detect() module m = self.model[-1] # Detect() module
for mi in m.m: # from for mi in m.m: # from
b = mi.bias.detach().view(m.na, -1).T # conv.bias(255) to (3,85) b = mi.bias.detach().view(m.na, -1).T # conv.bias(255) to (3,85)
print(('%6g Conv2d.bias:' + '%10.3g' * 6) % (mi.weight.shape[1], *b[:5].mean(1).tolist(), b[5:].mean())) LOGGER.info(
('%6g Conv2d.bias:' + '%10.3g' * 6) % (mi.weight.shape[1], *b[:5].mean(1).tolist(), b[5:].mean()))
# def _print_weights(self): # def _print_weights(self):
# for m in self.model.modules(): # for m in self.model.modules():
# if type(m) is Bottleneck: # if type(m) is Bottleneck:
# print('%10.3g' % (m.w.detach().sigmoid() * 2)) # shortcut weights # LOGGER.info('%10.3g' % (m.w.detach().sigmoid() * 2)) # shortcut weights
def fuse(self): # fuse model Conv2d() + BatchNorm2d() layers def fuse(self): # fuse model Conv2d() + BatchNorm2d() layers
#print('Fusing layers... ') LOGGER.info('Fusing layers... ')
for m in self.model.modules(): for m in self.model.modules():
if type(m) is Conv and hasattr(m, 'bn'): if isinstance(m, (Conv, DWConv)) and hasattr(m, 'bn'):
m.conv = fuse_conv_and_bn(m.conv, m.bn) # update conv m.conv = fuse_conv_and_bn(m.conv, m.bn) # update conv
delattr(m, 'bn') # remove batchnorm delattr(m, 'bn') # remove batchnorm
m.forward = m.fuseforward # update forward m.forward = m.forward_fuse # update forward
self.info() self.info()
return self return self
def nms(self, mode=True): # add or remove NMS module
present = type(self.model[-1]) is NMS # last layer is NMS
if mode and not present:
print('Adding NMS... ')
m = NMS() # module
m.f = -1 # from
m.i = self.model[-1].i + 1 # index
self.model.add_module(name='%s' % m.i, module=m) # add
self.eval()
elif not mode and present:
print('Removing NMS... ')
self.model = self.model[:-1] # remove
return self
def autoshape(self): # add autoShape module
print('Adding autoShape... ')
m = autoShape(self) # wrap model
copy_attr(m, self, include=('yaml', 'nc', 'hyp', 'names', 'stride'), exclude=()) # copy attributes
return m
def info(self, verbose=False, img_size=640): # print model information def info(self, verbose=False, img_size=640): # print model information
model_info(self, verbose, img_size) model_info(self, verbose, img_size)
def _apply(self, fn):
# Apply to(), cpu(), cuda(), half() to model tensors that are not parameters or registered buffers
self = super()._apply(fn)
m = self.model[-1] # Detect()
if isinstance(m, Detect):
m.stride = fn(m.stride)
m.grid = list(map(fn, m.grid))
if isinstance(m.anchor_grid, list):
m.anchor_grid = list(map(fn, m.anchor_grid))
return self
def parse_model(d, ch): # model_dict, input_channels(3) def parse_model(d, ch): # model_dict, input_channels(3)
logger.info('\n%3s%18s%3s%10s %-40s%-30s' % ('', 'from', 'n', 'params', 'module', 'arguments')) LOGGER.info(f"\n{'':>3}{'from':>18}{'n':>3}{'params':>10} {'module':<40}{'arguments':<30}")
anchors, nc, gd, gw = d['anchors'], d['nc'], d['depth_multiple'], d['width_multiple'] anchors, nc, gd, gw = d['anchors'], d['nc'], d['depth_multiple'], d['width_multiple']
na = (len(anchors[0]) // 2) if isinstance(anchors, list) else anchors # number of anchors na = (len(anchors[0]) // 2) if isinstance(anchors, list) else anchors # number of anchors
no = na * (nc + 5) # number of outputs = anchors * (classes + 5) no = na * (nc + 5) # number of outputs = anchors * (classes + 5)
@@ -208,24 +261,24 @@ def parse_model(d, ch): # model_dict, input_channels(3)
for j, a in enumerate(args): for j, a in enumerate(args):
try: try:
args[j] = eval(a) if isinstance(a, str) else a # eval strings args[j] = eval(a) if isinstance(a, str) else a # eval strings
except: except NameError:
pass pass
n = max(round(n * gd), 1) if n > 1 else n # depth gain n = n_ = max(round(n * gd), 1) if n > 1 else n # depth gain
if m in [Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, DWConv, MixConv2d, Focus, CrossConv, BottleneckCSP, if m in (Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, MixConv2d, Focus, CrossConv,
C3]: BottleneckCSP, C3, C3TR, C3SPP, C3Ghost, nn.ConvTranspose2d, DWConvTranspose2d, C3x):
c1, c2 = ch[f], args[0] c1, c2 = ch[f], args[0]
if c2 != no: # if not output if c2 != no: # if not output
c2 = make_divisible(c2 * gw, 8) c2 = make_divisible(c2 * gw, 8)
args = [c1, c2, *args[1:]] args = [c1, c2, *args[1:]]
if m in [BottleneckCSP, C3]: if m in [BottleneckCSP, C3, C3TR, C3Ghost, C3x]:
args.insert(2, n) # number of repeats args.insert(2, n) # number of repeats
n = 1 n = 1
elif m is nn.BatchNorm2d: elif m is nn.BatchNorm2d:
args = [ch[f]] args = [ch[f]]
elif m is Concat: elif m is Concat:
c2 = sum([ch[x] for x in f]) c2 = sum(ch[x] for x in f)
elif m is Detect: elif m is Detect:
args.append([ch[x] for x in f]) args.append([ch[x] for x in f])
if isinstance(args[1], int): # number of anchors if isinstance(args[1], int): # number of anchors
@@ -237,11 +290,11 @@ def parse_model(d, ch): # model_dict, input_channels(3)
else: else:
c2 = ch[f] c2 = ch[f]
m_ = nn.Sequential(*[m(*args) for _ in range(n)]) if n > 1 else m(*args) # module m_ = nn.Sequential(*(m(*args) for _ in range(n))) if n > 1 else m(*args) # module
t = str(m)[8:-2].replace('__main__.', '') # module type t = str(m)[8:-2].replace('__main__.', '') # module type
np = sum([x.numel() for x in m_.parameters()]) # number params np = sum(x.numel() for x in m_.parameters()) # number params
m_.i, m_.f, m_.type, m_.np = i, f, t, np # attach index, 'from' index, type, number params m_.i, m_.f, m_.type, m_.np = i, f, t, np # attach index, 'from' index, type, number params
logger.info('%3s%18s%3s%10.0f %-40s%-30s' % (i, f, n, np, t, args)) # print LOGGER.info(f'{i:>3}{str(f):>18}{n_:>3}{np:10.0f} {t:<40}{str(args):<30}') # print
save.extend(x % i for x in ([f] if isinstance(f, int) else f) if x != -1) # append to savelist save.extend(x % i for x in ([f] if isinstance(f, int) else f) if x != -1) # append to savelist
layers.append(m_) layers.append(m_)
if i == 0: if i == 0:
@@ -253,23 +306,33 @@ def parse_model(d, ch): # model_dict, input_channels(3)
if __name__ == '__main__': if __name__ == '__main__':
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('--cfg', type=str, default='yolov5s.yaml', help='model.yaml') parser.add_argument('--cfg', type=str, default='yolov5s.yaml', help='model.yaml')
parser.add_argument('--batch-size', type=int, default=1, help='total batch size for all GPUs')
parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
parser.add_argument('--profile', action='store_true', help='profile model speed')
parser.add_argument('--line-profile', action='store_true', help='profile model speed layer by layer')
parser.add_argument('--test', action='store_true', help='test all yolo*.yaml')
opt = parser.parse_args() opt = parser.parse_args()
opt.cfg = check_file(opt.cfg) # check file opt.cfg = check_yaml(opt.cfg) # check YAML
set_logging() print_args(vars(opt))
device = select_device(opt.device) device = select_device(opt.device)
# Create model # Create model
im = torch.rand(opt.batch_size, 3, 640, 640).to(device)
model = Model(opt.cfg).to(device) model = Model(opt.cfg).to(device)
model.train()
# Profile # Options
# img = torch.rand(8 if torch.cuda.is_available() else 1, 3, 640, 640).to(device) if opt.line_profile: # profile layer by layer
# y = model(img, profile=True) _ = model(im, profile=True)
# Tensorboard elif opt.profile: # profile forward-backward
# from torch.utils.tensorboard import SummaryWriter results = profile(input=im, ops=[model], n=3)
# tb_writer = SummaryWriter()
# print("Run 'tensorboard --logdir=models/runs' to view tensorboard at http://localhost:6006/") elif opt.test: # test all models
# tb_writer.add_graph(model.model, img) # add model to tensorboard for cfg in Path(ROOT / 'models').rglob('yolo*.yaml'):
# tb_writer.add_image('test', img[0], dataformats='CWH') # add model to tensorboard try:
_ = Model(cfg)
except Exception as e:
print(f'Error in {cfg}: {e}')
else: # report fused model summary
model.fuse()
+9 -9
View File
@@ -1,30 +1,30 @@
# parameters # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
# Parameters
nc: 80 # number of classes nc: 80 # number of classes
depth_multiple: 1.0 # model depth multiple depth_multiple: 1.0 # model depth multiple
width_multiple: 1.0 # layer channel multiple width_multiple: 1.0 # layer channel multiple
# anchors
anchors: anchors:
- [10,13, 16,30, 33,23] # P3/8 - [10,13, 16,30, 33,23] # P3/8
- [30,61, 62,45, 59,119] # P4/16 - [30,61, 62,45, 59,119] # P4/16
- [116,90, 156,198, 373,326] # P5/32 - [116,90, 156,198, 373,326] # P5/32
# YOLOv5 backbone # YOLOv5 v6.0 backbone
backbone: backbone:
# [from, number, module, args] # [from, number, module, args]
[[-1, 1, Focus, [64, 3]], # 0-P1/2 [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
[-1, 1, Conv, [128, 3, 2]], # 1-P2/4 [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
[-1, 3, C3, [128]], [-1, 3, C3, [128]],
[-1, 1, Conv, [256, 3, 2]], # 3-P3/8 [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
[-1, 9, C3, [256]], [-1, 6, C3, [256]],
[-1, 1, Conv, [512, 3, 2]], # 5-P4/16 [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
[-1, 9, C3, [512]], [-1, 9, C3, [512]],
[-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
[-1, 1, SPP, [1024, [5, 9, 13]]], [-1, 3, C3, [1024]],
[-1, 3, C3, [1024, False]], # 9 [-1, 1, SPPF, [1024, 5]], # 9
] ]
# YOLOv5 head # YOLOv5 v6.0 head
head: head:
[[-1, 1, Conv, [512, 1, 1]], [[-1, 1, Conv, [512, 1, 1]],
[-1, 1, nn.Upsample, [None, 2, 'nearest']], [-1, 1, nn.Upsample, [None, 2, 'nearest']],
+9 -9
View File
@@ -1,30 +1,30 @@
# parameters # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
# Parameters
nc: 80 # number of classes nc: 80 # number of classes
depth_multiple: 0.67 # model depth multiple depth_multiple: 0.67 # model depth multiple
width_multiple: 0.75 # layer channel multiple width_multiple: 0.75 # layer channel multiple
# anchors
anchors: anchors:
- [10,13, 16,30, 33,23] # P3/8 - [10,13, 16,30, 33,23] # P3/8
- [30,61, 62,45, 59,119] # P4/16 - [30,61, 62,45, 59,119] # P4/16
- [116,90, 156,198, 373,326] # P5/32 - [116,90, 156,198, 373,326] # P5/32
# YOLOv5 backbone # YOLOv5 v6.0 backbone
backbone: backbone:
# [from, number, module, args] # [from, number, module, args]
[[-1, 1, Focus, [64, 3]], # 0-P1/2 [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
[-1, 1, Conv, [128, 3, 2]], # 1-P2/4 [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
[-1, 3, C3, [128]], [-1, 3, C3, [128]],
[-1, 1, Conv, [256, 3, 2]], # 3-P3/8 [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
[-1, 9, C3, [256]], [-1, 6, C3, [256]],
[-1, 1, Conv, [512, 3, 2]], # 5-P4/16 [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
[-1, 9, C3, [512]], [-1, 9, C3, [512]],
[-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
[-1, 1, SPP, [1024, [5, 9, 13]]], [-1, 3, C3, [1024]],
[-1, 3, C3, [1024, False]], # 9 [-1, 1, SPPF, [1024, 5]], # 9
] ]
# YOLOv5 head # YOLOv5 v6.0 head
head: head:
[[-1, 1, Conv, [512, 1, 1]], [[-1, 1, Conv, [512, 1, 1]],
[-1, 1, nn.Upsample, [None, 2, 'nearest']], [-1, 1, nn.Upsample, [None, 2, 'nearest']],
+48
View File
@@ -0,0 +1,48 @@
# YOLOv5 🚀 by Ultralytics, GPL-3.0 license
# Parameters
nc: 80 # number of classes
depth_multiple: 0.33 # model depth multiple
width_multiple: 0.25 # 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)
]
+9 -9
View File
@@ -1,30 +1,30 @@
# parameters # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
# Parameters
nc: 80 # number of classes nc: 80 # number of classes
depth_multiple: 0.33 # model depth multiple depth_multiple: 0.33 # model depth multiple
width_multiple: 0.50 # layer channel multiple width_multiple: 0.50 # layer channel multiple
# anchors
anchors: anchors:
- [10,13, 16,30, 33,23] # P3/8 - [10,13, 16,30, 33,23] # P3/8
- [30,61, 62,45, 59,119] # P4/16 - [30,61, 62,45, 59,119] # P4/16
- [116,90, 156,198, 373,326] # P5/32 - [116,90, 156,198, 373,326] # P5/32
# YOLOv5 backbone # YOLOv5 v6.0 backbone
backbone: backbone:
# [from, number, module, args] # [from, number, module, args]
[[-1, 1, Focus, [64, 3]], # 0-P1/2 [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
[-1, 1, Conv, [128, 3, 2]], # 1-P2/4 [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
[-1, 3, C3, [128]], [-1, 3, C3, [128]],
[-1, 1, Conv, [256, 3, 2]], # 3-P3/8 [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
[-1, 9, C3, [256]], [-1, 6, C3, [256]],
[-1, 1, Conv, [512, 3, 2]], # 5-P4/16 [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
[-1, 9, C3, [512]], [-1, 9, C3, [512]],
[-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
[-1, 1, SPP, [1024, [5, 9, 13]]], [-1, 3, C3, [1024]],
[-1, 3, C3, [1024, False]], # 9 [-1, 1, SPPF, [1024, 5]], # 9
] ]
# YOLOv5 head # YOLOv5 v6.0 head
head: head:
[[-1, 1, Conv, [512, 1, 1]], [[-1, 1, Conv, [512, 1, 1]],
[-1, 1, nn.Upsample, [None, 2, 'nearest']], [-1, 1, nn.Upsample, [None, 2, 'nearest']],
+9 -9
View File
@@ -1,30 +1,30 @@
# parameters # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
# Parameters
nc: 80 # number of classes nc: 80 # number of classes
depth_multiple: 1.33 # model depth multiple depth_multiple: 1.33 # model depth multiple
width_multiple: 1.25 # layer channel multiple width_multiple: 1.25 # layer channel multiple
# anchors
anchors: anchors:
- [10,13, 16,30, 33,23] # P3/8 - [10,13, 16,30, 33,23] # P3/8
- [30,61, 62,45, 59,119] # P4/16 - [30,61, 62,45, 59,119] # P4/16
- [116,90, 156,198, 373,326] # P5/32 - [116,90, 156,198, 373,326] # P5/32
# YOLOv5 backbone # YOLOv5 v6.0 backbone
backbone: backbone:
# [from, number, module, args] # [from, number, module, args]
[[-1, 1, Focus, [64, 3]], # 0-P1/2 [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
[-1, 1, Conv, [128, 3, 2]], # 1-P2/4 [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
[-1, 3, C3, [128]], [-1, 3, C3, [128]],
[-1, 1, Conv, [256, 3, 2]], # 3-P3/8 [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
[-1, 9, C3, [256]], [-1, 6, C3, [256]],
[-1, 1, Conv, [512, 3, 2]], # 5-P4/16 [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
[-1, 9, C3, [512]], [-1, 9, C3, [512]],
[-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
[-1, 1, SPP, [1024, [5, 9, 13]]], [-1, 3, C3, [1024]],
[-1, 3, C3, [1024, False]], # 9 [-1, 1, SPPF, [1024, 5]], # 9
] ]
# YOLOv5 head # YOLOv5 v6.0 head
head: head:
[[-1, 1, Conv, [512, 1, 1]], [[-1, 1, Conv, [512, 1, 1]],
[-1, 1, nn.Upsample, [None, 2, 'nearest']], [-1, 1, nn.Upsample, [None, 2, 'nearest']],
+36
View File
@@ -0,0 +1,36 @@
# YOLOv5 🚀 by Ultralytics, GPL-3.0 license
"""
utils/initialization
"""
def notebook_init(verbose=True):
# Check system software and hardware
print('Checking setup...')
import os
import shutil
from utils.general import check_requirements, emojis, is_colab
from utils.torch_utils import select_device # imports
check_requirements(('psutil', 'IPython'))
import psutil
from IPython import display # to display images and clear console output
if is_colab():
shutil.rmtree('/content/sample_data', ignore_errors=True) # remove colab /sample_data directory
# System info
if verbose:
gb = 1 << 30 # bytes to GiB (1024 ** 3)
ram = psutil.virtual_memory().total
total, used, free = shutil.disk_usage("/")
display.clear_output()
s = f'({os.cpu_count()} CPUs, {ram / gb:.1f} GB RAM, {(total - free) / gb:.1f}/{total / gb:.1f} GB disk)'
else:
s = ''
select_device(newline=False)
print(emojis(f'Setup complete ✅ {s}'))
return display
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loaded 100 of 514 files, more files were not shown because too many files have changed in this diff. Show more