实时训练Real-Time Training 教程
在上一篇文章(https://blog.csdn.net/walchina2017/article/details/130334374)中,我介紹了什么是實時學習,并且開源了一個我做出來的作品。
接下來,我會手把手教你如何把它做出來。
首先,你得先下載Pycharm(https://www.jetbrains.com/pycharm/download/)和Python(有鏡像),并知道如何在Pycharm中新建一個Project。
然后,新建一個Project,選擇Virualvenv,然后點擊創建:
等Pycharm創建完虛擬環境(Virtualvenv)后,會出現這個界面。
?接下來,點擊畫紅圈的地方來打開Terminal。
接著,在Terminal中輸入:pip install ultralytics -i https://pypi.douban.com/simple --trusted-host pypi.douban.com,然后點擊回車鍵來安裝所需要的Python庫:
接著,在你的文件瀏覽器中找到你的項目的文件夾,并打開它。根據下圖所顯示的列表新建這些文件夾:
注:在dataset一下的所有文件夾都必須是和上圖列表一樣的,否則無法訓練模型。
?接著,把在train · main · 何榮基 / Real Time Learning Yolov8 · GitCode中的yolov8n-face.pt 和 costum_data.yaml 下載到train文件夾內,文件列表應該是這樣的:
接下來,進入右邊的編輯器里,刪掉所有的代碼,我們要開始編寫我們自己的代碼了:
?1. 導入所需要的庫:
import cv2 from threading import Thread import numpy as np from ultralytics import YOLO? cv2: opencv-python的簡稱,可以幫助我們打開攝像頭,并獲取實時圖像。
? threading(Python自帶): 可以讓多個代碼同時運行
? numpy:可以進行復雜的矩陣乘法,還可以把tensor類型轉換成numpy。
? ultralytics:Yolo的官方PythonAPI,可以在代碼中實現訓練,而不需要CLI。
? 2. 做一個簡單的用cv2打開攝像頭的程序:
import cv2 from threading import Thread import numpy as np from ultralytics import YOLOcap = cv2.VideoCapture(0)while True:ret, frame = cap.read()cv2.imshow('returned', frame)if cv2.waitKey(1) & 0xFF == ord('q'):breakcap.release()cv2.destroyAllWindows()? cap = cv2.VideoCapture(0):將cap設為攝像頭
? ret, frame = cap.read():讀取攝像頭的畫面
? cv2.imshow('returned', frame):顯示攝像頭看到的東西,并將打開的窗口的名字設為return.
? if cv2.waitKey(1) & 0xFF == ord('q'):檢測q鍵是否按下, 如果是的話,就強制推出while循環。
? cap.release():關閉攝像頭
? cv2.destroyAllWindows():把所有窗口都關閉。
我們來試一試效果:
接下來,我們就得實現檢測到人臉,并且畫出來位置:
1.?
import cv2 from threading import Thread import numpy as np from ultralytics import YOLOmodel = YOLO('train/train_yolov8n-face.pt')cap = cv2.VideoCapture(0)while True:ret, frame = cap.read()results = model.predict(frame)annotated = results[0].plot()cv2.imshow('returned', annotated)if cv2.waitKey(1) & 0xFF == ord('q'):breakcap.release()cv2.destroyAllWindows()?model = YOLOY('train/train_yolov8n-face.pt'):把要運算的模型設為YOLO模型,位置在相對路徑?train/yolov8n-face.pt(注意:應為yolov8n-face.pt是從gitee上下載下來的,名字會改成train_yolov8n-face.pt)
?results = model.predict(frame):檢測人臉
?results[0].plot():把人臉的位置畫出來。
?cv2.imshow('returned', annotated):把畫出來的位置顯示出來(注意,第二個參數已經換成了annotated,而不是frame)
讓我們倆看一看效果:
然后,我們需要把‘問題’和‘回答’記錄下來:
import cv2 from threading import Thread import numpy as np from ultralytics import YOLOmodel = YOLO('train/train_yolov8n-face.pt')cap = cv2.VideoCapture(0)while True:ret, frame = cap.read()results = model.predict(frame)boxes = result[0].boxesif bool(boxes.numpy()):if face_count < 300:face_count += 1else:face_count = 0# 獲取人臉位置信息# 保存人臉圖像和位置信息到文件if face_count >= 0 and face_count < 100:# 記錄到驗證集filepath = f'train/dataset/images/val/{face_count}.png'labelspath = f'train/dataset/labels/val/{face_count}.txt'else:# 記錄到訓練集filepath = f'train/dataset/images/train/{face_count}.png'labelspath = f'train/dataset/labels/train/{face_count}.txt'# 保存人臉圖像cv2.imwrite(filepath, frame)# 保存位置信息到文件with open(labelspath, 'w') as file:for bboxes in boxes:for xywh in bboxes.xywh:xywh = xywh * np.array([1/frame.shape[1], 1/frame.shape[0], 1/frame.shape[1], 1/frame.shape[0]])file.write(f'0 {xywh[0]} {xywh[1]} {xywh[2]} {xywh[3]}\n')file.close()annotated = results[0].plot()cv2.imshow('returned', annotated)if cv2.waitKey(1) & 0xFF == ord('q'):breakcap.release()cv2.destroyAllWindows()?夸嚓一下多了這么多行代碼,是不是有點蒙?沒事,我會慢慢幫你講解。
?第一部分:
boxes = result[0].boxes if bool(boxes.numpy()):if face_count < 300:face_count += 1else:face_count = 0if bool(boxes.numpy()) 使用后來檢測有咩有檢測到人臉,這樣就可以預防沒有人臉的照片被錄入訓練文件夾。
這個是用來數有多少數據被收集了,如果超過300,就會歸零。
第二部分:
# 保存人臉圖像和位置信息到文件if face_count >= 0 and face_count < 100:# 記錄到驗證集filepath = f'train/dataset/images/val/{face_count}.png'labelspath = f'train/dataset/labels/val/{face_count}.txt'else:# 記錄到訓練集filepath = f'train/dataset/images/train/{face_count}.png'labelspath = f'train/dataset/labels/train/{face_count}.txt'首先,我們需要知道Yolov8在被訓練的時候是需要train數據集和val數據集的,所以,我們決定把1/3的數據給val數據集,然后把剩下的2/3給train數據集。
第三部分:
# 保存人臉圖像cv2.imwrite(filepath, frame)# 保存位置信息到文件with open(labelspath, 'w') as file:for bboxes in boxes:for xywh in bboxes.xywh:xywh = xywh * np.array([1/frame.shape[1], 1/frame.shape[0], 1/frame.shape[1], 1/frame.shape[0]])file.write(f'0 {xywh[0]} {xywh[1]} {xywh[2]} {xywh[3]}\n')file.close()我們會用cv2.imwrite把沒有標記的圖片記錄下來(我們記錄下來的的圖片是frame,也就是攝像頭實時讀取的數據)。
接著,就到了把標記的參數記錄下來。我們知道 yolo_label 的格式是這樣的:
0 x_center/width_of_image?y_center/img_heighy?width/img_width?height/img_height在上一部分里有一個變量叫boxes,它被設為result[0].boxes。在result[0].boxes中有很多格式選項,但是只有result[0].boxes.xywh符合我們的要求。x在xywh中的意思就是bbox的x軸中心點,y在xywh中的意思就是bbox的y軸中心點,w在xywh中的意思就是bbox的寬度,而h在xywh中的意思就是bbox的高度。
我們只需要把數據乘以 [1/frame.shape[1](frame的寬度), 1/frame.shape[0] (frame的高度),?1/frame.shape[1](frame的寬度), 1/frame.shape[0] (frame的高度)]就可以了。
但是,bboxes.xywh的輸出格式是tensor格式(tensor([x,xx,xxx,xxxx])),所以我們還要把它乘以一個numpy格式的列表才能同化tensor格式的列表。
最后就是把數據寫到指定的文件夾中的一個.txt格式中。
最后,我們要實現訓練模型。
先打開在train中的train_custom_data.yaml。
可以看到train和val數據集已經被設置好。
接下來就開始先訓練模塊了:
import cv2 from threading import Thread import numpy as np from ultralytics import YOLOdef train_it():global model, trainingdef do():global model, training# 訓練模型model.train(data='train/custom_data.yaml', epochs=epochs)# 將在訓練設為 False(不在訓練)training = FalseThread(target=do).start()model = YOLO('train/train_yolov8n-face.pt')training = Falsecap = cv2.VideoCapture(0)while True:ret, frame = cap.read()results = model.predict(frame)boxes = result[0].boxesif not training:if bool(boxes.numpy):# 檢測是否需要繼續記錄人臉if face_count < 300:face_count += 1else:# 開始訓練新模型train_it()# 將在訓練設為 True(在訓練)training = True# 重置人臉錄取次數face_count = 0# 獲取人臉位置信息# 保存人臉圖像和位置信息到文件if face_count >= 0 and face_count < 100:# 記錄到驗證集filepath = f'train/dataset/images/val/{face_count}.png'labelspath = f'train/dataset/labels/val/{face_count}.txt'else:# 記錄到訓練集filepath = f'train/dataset/images/train/{face_count}.png'labelspath = f'train/dataset/labels/train/{face_count}.txt'# 保存人臉圖像cv2.imwrite(filepath, frame)# 保存位置信息到文件with open(labelspath, 'w') as file:for bboxes in boxes:for xywh in bboxes.xywh:xywh = xywh * np.array([1/frame.shape[1], 1/frame.shape[0], 1/frame.shape[1], 1/frame.shape[0]])file.write(f'0 {xywh[0]} {xywh[1]} {xywh[2]} {xywh[3]}\n')file.close()annotated = results[0].plot()cv2.imshow('returned', annotated)if cv2.waitKey(1) & 0xFF == ord('q'):breakcap.release()cv2.destroyAllWindows()天哪!
還是老樣子,我們拆分一下新增的程序:
第一部分:
def train_it():global model, trainingdef do():global model, training# 訓練模型model.train(data='train/train_custom_data.yaml', epochs=epochs)# 將在訓練設為 False(不在訓練)training = FalseThread(target=do).start()training = False我們新加了一個函數,來訓練新的模型,所以要global model。
我們新加training是應為我們不想要AI在學習的時候數據會改變,所以在學習的時候就會停止錄取數據。
為了實現這個,我們在需要在負責記錄的模塊前面加一個if語句,這樣的話,只有training是False(沒有在訓練)的時候才會記錄數據。
第二部分:
if not training:if bool(boxes.numpy()):# 檢測是否需要繼續記錄人臉if face_count < 300:face_count += 1else:# 開始訓練新模型train_it()# 將在訓練設為 True(在訓練)training = True# 重置人臉錄取次數face_count = 0現在我們可以看到else下面加了一些代碼,這些是用來啟動訓練程序的。
train_it():這個是啟動訓練模型的。我們把train_it函數設為thread,這可以讓訓練和檢測同時進行。
當啟動完成后,training就會被設為True(在訓練),這樣就可防止AI在訓練的時候還在記錄數據,導致數據變化。
每次訓練的結果都能在runs/detect/trainx/weights中找到(x是第幾個被訓練的模型)。比如說,我想要第七次被訓練的模型,就得進入這個文件路徑:runs/detect/train9/weights/best.pt。
?最后,讓我們測試一下(這里的epochs是2,有可能比較慢,所以我就快進一下):
看到視頻里的進度條了嗎?這個進度條就是訓練完成了多少。雖然只是2個epochs,但是還是用了10分鐘(沒有加速的原始視頻),如果電腦的配置高一點會更快。
但這不是重點,重點是訓練和檢測可以同步執行,并且新的模型和舊的模型可以無縫銜接!
OK!這個教程到這里就結束啦!最后,整理一下代碼:
# 導入需要的庫 import cv2 from threading import Thread import numpy as np from ultralytics import YOLO# 初始化變量 def init_variables():# 導入人臉檢測模型model = YOLO("train/train_yolov8n-face.pt")# 初始化同步運行訓練模塊#train_new_yolo = Thread(target=train_it)# 初始化人臉錄取數變量face_count = 0# 初始化是否在訓練中變量training = False# 初始化 epochsepochs = 5# 初始化攝像頭cap = cv2.VideoCapture(0)MAX_FACE_COUNT = 600VALIDATION_SPLIT_COUNT = 200return model, face_count, training, epochs, cap, MAX_FACE_COUNT, VALIDATION_SPLIT_COUNT# 記錄人臉函數 def record_faces(frame, result):global face_count, training, model# 訓練函數def train_it():global model, trainingdef do():global model, training# 訓練模型model.train(data='train/train_custom_data.yaml', epochs=epochs)# 將在訓練設為 False(不在訓練)training = FalseThread(target=do).start()# 檢測是否在訓練if not training:boxes = result[0].boxesif bool(boxes.numpy()):#檢測是否需要繼續記錄人臉if face_count < MAX_FACE_COUNT:face_count += 1else:# 開始訓練新模型train_it()# 將在訓練設為 True(在訓練)training = True# 重置人臉錄取次數face_count = 0# 獲取人臉位置信息boxes = result[0].boxes# 保存人臉圖像和位置信息到文件if face_count >= 0 and face_count < VALIDATION_SPLIT_COUNT:# 記錄到驗證集filepath = f'train/dataset/images/val/{face_count}.png'labelspath = f'train/dataset/labels/val/{face_count}.txt'else:# 記錄到訓練集filepath = f'train/dataset/images/train/{face_count}.png'labelspath = f'train/dataset/labels/train/{face_count}.txt'# 保存人臉圖像cv2.imwrite(filepath, frame)# 保存位置信息到文件with open(labelspath, 'w') as file:for bboxes in boxes:for xywh in bboxes.xywh:xywh = xywh * np.array([1 / frame.shape[1], 1 / frame.shape[0], 1 / frame.shape[1], 1 / frame.shape[0]])file.write(f'0 {xywh[0]} {xywh[1]} {xywh[2]} {xywh[3]}\n')file.close() model,face_count, training, epochs, cap, MAX_FACE_COUNT, VALIDATION_SPLIT_COUNT = init_variables()while True:# 讀取實時圖像ret, frame = cap.read()# 獲取檢測的結果results = model.predict(frame, show=False)# 記錄人臉record_faces(frame, results)# 在圖像上繪制檢測結果annotated = results[0].plot()# 顯示畫出來的效果cv2.imshow('returned', annotated)# 檢測是否要退出if cv2.waitKey(1) & 0xFF == ord('q'):break# 釋放攝像頭并關閉窗口 cap.release() cv2.destroyAllWindows()最后,來看一下我搞出來的結果:
原始模型:
實時訓練3次,epochs=5,?MAX_FACE_COUNT=600,VALIDATION_SPLIT_COUNT=200:
可以看到無論是P,還是R,還是mAP50,或是mAP50-95都有顯著的提升,mAP50-95更是從71%提到了95%。
總結
以上是生活随笔為你收集整理的实时训练Real-Time Training 教程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android攻城狮ScrollView
- 下一篇: 常用windows XP 系统命令