基于YOLO目标检测及OpenCV实现的游戏代玩人工智能体(Auto Gaming Agent) [3] (更新)
大型生存類游戲自動代玩人工智能[3] -- 目標識別(新)
- 一、目標檢測算法更新
- 二、YOLOv5模型訓練
- 1. 數據準備
- 2. 訓練模型
- 三、Pytorch推理預測YOLOv5
- 1. 引入庫
- 2. 加載模型
- 2. 讀圖預測
- 3. 可視化
- 四、實時識別
自從上次斷更以后已經過去3年,是之前幾篇不斷收到的點贊、評論、私信支持著博主(既然明日之后這個游戲現在還活著)索性就繼續更新下去吧 [doge][doge][doge]
一、目標檢測算法更新
人工智能領域的算法更新迭代速度非常之快,上一篇中使用的目標檢測模型yolov3已然過時,目前yolo算法已經更新至第5代,在準確度、速度、穩定性、易用性上已經遠遠超越之前。本篇就與時俱進,使用最新的yolov5s6模型來重構我們的目標檢測任務。雖然說是重構,但實際代碼量和操作步驟減少了非常多。
yolov5繼承了各代yolo的傳統,出廠即提供多種不同大小的模型,這次v5版本更是直接一口氣發布了4個模型(s, m, l, x),而截至目前已經更新到10個模型之多(n, s, m, l, x, n6, s6, m6, l6, x6),簡直選擇困難癥犯了。這里不需要糾結,越大的模型肯定越準確同時幀率相對越低,所以直接選一個最低幀率需求下自己硬件能滿足的模型就好,訓練和部署的步驟都是一樣的跟模型選擇無關,對博主來說yolov5s6就是最適合的模型。
| YOLOv5n | 640 | 28.0 | 45.7 | 45 | 6.3 | 0.6 | 1.9 | 4.5 |
| YOLOv5s | 640 | 37.4 | 56.8 | 98 | 6.4 | 0.9 | 7.2 | 16.5 |
| YOLOv5m | 640 | 45.4 | 64.1 | 224 | 8.2 | 1.7 | 21.2 | 49.0 |
| YOLOv5l | 640 | 49.0 | 67.3 | 430 | 10.1 | 2.7 | 46.5 | 109.1 |
| YOLOv5x | 640 | 50.7 | 68.9 | 766 | 12.1 | 4.8 | 86.7 | 205.7 |
| YOLOv5n6 | 1280 | 36.0 | 54.4 | 153 | 8.1 | 2.1 | 3.2 | 4.6 |
| YOLOv5s6 | 1280 | 44.8 | 63.7 | 385 | 8.2 | 3.6 | 12.6 | 16.8 |
| YOLOv5m6 | 1280 | 51.3 | 69.3 | 887 | 11.1 | 6.8 | 35.7 | 50.0 |
| YOLOv5l6 | 1280 | 53.7 | 71.3 | 1784 | 15.8 | 10.5 | 76.8 | 111.4 |
| YOLOv5x6 | 1280 | 55.0 | 72.7 | 3136 | 26.2 | 19.4 | 140.7 | 209.8 |
二、YOLOv5模型訓練
1. 數據準備
訓練數據主要指圖像和標記,YOLO各個版本的算法都采用統一的標記格式,即標準化過后的中心點標記,這里yolov5跟v3需要的訓練數據是完全一樣的。如果已經有了之前訓練v3的數據即可零轉換馬上訓練v5的模型,如果還沒有數據那么數據標注的步驟也是和原來一樣的,這里不再贅述(詳見上一篇中的“創建自定義數據集”章節)。
2. 訓練模型
首先下載yolov5的源碼然后安裝必要的運行庫,官方是使用了近幾年大火的pytorch取代了原本的darknet,如果有英偉達顯卡就可以安裝pytorch的cuda版本,沒有就安裝cpu版本。博主用的30系顯卡必須安裝cuda11.0以上的pytorch版本才能正常使用gpu加速。
git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txt安裝好以后先準備一下 .yaml 格式的訓練配置文件,主要設置數據集的路徑 path、訓練數據路徑 train、驗證數據路徑 val、和可選的測試數據路徑 test,以及我們目標總共分類的數目 nc 還有類名 names,其中 train, val, test 都是相對 path 的路徑。我們把這個配置文件命名為 bot.yaml 然后放到主目錄下的 data/ 文件夾,配置文件內容如下
# Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..] path: datasets/qrsl # dataset root dir train: images # train images (relative to 'path') val: images # val images (relative to 'path') test: # test images (optional)# Classes nc: 11 # number of classes names: ['tree', 'stone', 'herb', 'wolf', 'zombie', 'dear', 'bear', 'helicopter', 'berry', 'mushroom', 'cole'] # class names接下來我們把標記好的數據集放到上面配置文件指定的位置 datasets/qrsl,圖片位于 datasets/qrsl/images,標記位于 datasets/qrsl/labels,最終目錄結構如下
一切準備就緒后在命令行中輸入一行代碼即可開始訓練
使用 --img 來設定模型輸入的圖像尺寸,--batch 設定訓練的批量大小,--epochs 設定最大的訓練次數,--data 設定訓練配置文件,--weights 設定預訓練模型。
這里輸入尺寸可以根據實際應用場景的目標大小來設置,一般越大的輸入尺寸能檢測到的小目標就越精確但是耗時會成指數增加。越大的圖像尺寸訓練時消耗的cpu和gpu內存也會更多,如果訓練集很大的話非常容易導致內存不足而無法運行,這時候就需要調節批量大小來使數據順利的載入訓練。博主在訓練的時候就遇到了cpu內存不足的情況,所以設置 --batch 1 每次只輸入一張圖片才可以開始訓練。當然越大的批數量可以使訓練收斂的更快而且模型的健壯性會更好,所以還是根據自己硬件來選擇一個最大的批量大小。
顯示如下的進度條就說明訓練已經開始了,每個epoch分別進行一次訓練和一次驗證,系統會自動保存一個最近的和一個最佳的checkpoint到 runs/train/exp*/weights 路徑,中途停止以后下次訓練參數設置比如 --weight runs/trian/exp*/weights/last.pt 就會從上次的checkpoint繼續,完成到最后一個epoch以后就自動生成優化過的模型,模型參數會變少(主要裁掉了batchnorm等推理時無用的層)但也無法繼續訓練。
可以從打印的信息看到比較豐富的訓練指標數據,一些比較重要的指標:
- box – 標記框的loss
- obj – 單目標的loss
- cls – 分類的loss
- P – 精確率
- R – 召回率
- mAP@.5 – 置信度50%以上的平均精度
- mAP@.5:.95 – 置信度50%~95%的平均精度
精確率反應的是識別出的框的正確率,召回率反應的是有多少正確的框被識別出來,像我們這個任務可以允許一些目標沒被識別出來,但是被識別出來的目標一定要準確,所以也就是精確率對我們來說更重要。mAP反應了所有類別的綜合精度,要是不想看其他的數據光看這個準沒錯。
訓練指標達到如下的程度基本就是一個比較合格的模型了
這里因為我的數據量偏少只有700多張圖,就沒有劃分訓練和驗證集,驗證集也是訓練過的,所以看起來的數據都很虛高,這存在過擬合的風險,不過對我們的任務影響不大,畢竟訓練截取的場景就是我們實際應用的場景。一般比較健壯的模型最好需要每個類1000張,每個類10000個標記,然后劃分10%左右的數據進行驗證,訓練數據包含5%左右的無標記圖像用來減少False Positive,但是對于我們這個任務不太有必要。
所有訓練都完成后在對應的runs/train/exp*/weights 路徑找到 best.pt 文件作為我們最終拿去預測的最佳模型。
三、Pytorch推理預測YOLOv5
1. 引入庫
直接用pytorch的hub包進行預測是非常簡單的,只需要opencv,pytorch和numpy三個常見的庫
import cv2 import torch import numpy as np2. 加載模型
直接使用 torch.hub 包來加載yolov5源碼和我們自己訓練的模型,device='0'用來指定運行在gpu上,如果沒有gpu就不用這個參數。
yolov5 = torch.hub.load('ultralytics/yolov5', 'custom', path='best.pt', device='0')2. 讀圖預測
用opencv來讀取一張沒有訓練過的圖片,然后輸入到我們的模型中進行推理,最后輸出結果轉成numpy格式的標記框數組,代碼非常少。
img = cv2.imread('scrsht/1652240462.png') img = img.copy()[:,:,::-1] # BGR to RGB results = yolov5(img,size=1280) bboxes = np.array(results.xyxy[0].cpu())3. 可視化
使用opencv畫出所有識別出的框
def drawBBox(image,bboxes):for bbox in bboxes:x0,y0,x1,y1 = int(bbox[0]),int(bbox[1]),int(bbox[2]),int(bbox[3])cv2.rectangle(image, (x0, y0), (x1, y1), (255,0,0), 2)return imageimg = drawBBox(img.copy(),bboxes) cv2.imshow("", img) cv2.waitKey()四、實時識別
以上只是測試單張圖片,在上面代碼的基礎上結合高速截屏庫 mss 和多線程庫 threading 可以實現實時識別游戲窗口。使用 win32gui 庫來定位窗口在桌面的具體位置坐標。
import mss import cv2 import os import threading import time import torch import numpy as np from win32gui import FindWindow, GetWindowRectyolov5 = torch.hub.load('ultralytics/yolov5', 'custom', path='best.pt', device='0') yolov5.conf = 0.6 yolov5.iou = 0.4COLORS = [(0, 0, 255), (255, 0, 0), (0, 255, 0), (255, 255, 0), (0, 255, 255),(255, 0, 255), (192, 192, 192), (128, 128, 128), (128, 0, 0),(128, 128, 0), (0, 128, 0), (128, 0, 128), (0, 128, 128), (0, 0, 128)]LABELS = ['tree','stone','herb','wolf','zombie','dear','bear','helicopter','berry','mushroom','cole']img_src = np.zeros((1280,720,3),np.uint8)def getScreenshot():id = FindWindow(None, "明日之后 - MuMu模擬器")x0,y0,x1,y1 = GetWindowRect(id)mtop,mbot = 30,50monitor = {"left": x0, "top": y0, "width": x1-x0, "height": y1-y0}img_src = np.array(mss.mss().grab(monitor))img_src = img_src[:,:,:3]img_src = img_src[mtop:-mbot]return img_src, [x0,y0,x1,y1,mtop,mbot]def getMonitor():global img_srcwhile True:# last_time = time.time()img_src, _ = getScreenshot()#print("fps: {}".format(1 / (time.time() - last_time+0.000000001)))def yolov5Detect():cv2.namedWindow("",cv2.WINDOW_NORMAL)cv2.resizeWindow("",960,540)cv2.moveWindow("",1560,0)global img_srcwhile True:img = img_src.copy()bboxes = getDetection(img)img = drawBBox(img,bboxes)cv2.imshow("", img)if cv2.waitKey(1) & 0xFF == ord("q"):cv2.destroyAllWindows()breakdef getLargestBox(bboxes,type):largest = -1bbox_largest = np.array([])for bbox in bboxes:if LABELS[int(bbox[5])] in type:x0,y0,x1,y1 = int(bbox[0]),int(bbox[1]),int(bbox[2]),int(bbox[3])area = (x1-x0)*(y1-y0)if area > largest:largest = areabbox_largest = bboxreturn bbox_largestdef drawBBox(image, bboxes):for bbox in bboxes:conf = bbox[4]classID = int(bbox[5])if conf > yolov5.conf and classID==0:x0,y0,x1,y1 = int(bbox[0]),int(bbox[1]),int(bbox[2]),int(bbox[3])color = [int(c) for c in COLORS[classID]]cv2.rectangle(image, (x0, y0), (x1, y1), color, 3)text = "{}: {:.2f}".format(LABELS[classID], conf)cv2.putText(image, text, (max(0,x0), max(0,y0-5)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)return imagedef getDetection(img):bboxes = np.array(yolov5(img[:,:,::-1],size=1280).xyxy[0].cpu())return bboxesif __name__ == '__main__':t1 = threading.Thread(target=getMonitor,args=())t1.start()t2 = threading.Thread(target=yolov5Detect,args=())t2.start()最終的運行效果在這個視頻展示
https://www.bilibili.com/video/BV15B4y197Vo/
因為相比三年前的渣配置,這次鳥槍換大炮,在1280x720的原生分辨率下也能達到40~50fps了,整體準確率和穩定性上升了一個檔次。
總結
以上是生活随笔為你收集整理的基于YOLO目标检测及OpenCV实现的游戏代玩人工智能体(Auto Gaming Agent) [3] (更新)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mc服务器 领地插件配置文件,《我的世界
- 下一篇: 深入springboot怎么启动tomc