{ "cells": [ { "cell_type": "markdown", "id": "419e9476", "metadata": {}, "source": [ "# 下載課程所需檔案 (YOLOv7, Dataset)" ] }, { "cell_type": "code", "execution_count": null, "id": "89a8e830", "metadata": {}, "outputs": [], "source": [ "!wget https://github.com/TA-aiacademy/course_3.0/releases/download/CVCNN_Data/dog_cat_for_YOLO.zip\n", "!unzip dog_cat_for_YOLO.zip\n", "!wget https://github.com/TA-aiacademy/course_3.0/releases/download/CVCNN_Data/yolov7.zip\n", "!unzip yolov7.zip" ] }, { "cell_type": "markdown", "id": "0b363a9b", "metadata": {}, "source": [ "# YOLOv7 實作\n" ] }, { "cell_type": "markdown", "id": "0dce3ccb", "metadata": {}, "source": [ "## [貓狗公開資料集](https://public.roboflow.com/object-detection/oxford-pets/2/images/fc82071578629d4d44696cb666898d45)\n", "![](https://i.imgur.com/VnNscKi.png)\n", "這個貓狗公開資料集提供了 3680 張影像,為了訓練快一點,這邊只取了 250 張影像來訓練,檔案放在 datasets/pet.zip 中" ] }, { "cell_type": "markdown", "id": "e68b2961", "metadata": {}, "source": [ "## 1. 準備資料集\n", " 改變標籤格式,從Pascal_voc->Yolo\n", " \n", "![](https://i.imgur.com/eNWUWGQ.png)" ] }, { "cell_type": "code", "execution_count": null, "id": "ba0d8e54", "metadata": {}, "outputs": [], "source": [ "import os\n", "import glob\n", "import random\n", "import shutil\n", "import xml.etree.ElementTree as ET\n", "\n", "#讀取資料夾的圖片名稱\n", "def getImagesInDir(dir_path):\n", " img_formats = ['bmp', 'jpg', 'jpeg', 'png', 'tif', 'tiff', 'dng']\n", " image_list = []\n", " for img_format in img_formats:\n", " for filename in glob.glob(dir_path + f'/*.{img_format}'):\n", " image_list.append(filename)\n", "\n", " return image_list\n", "\n", "# 座標轉換\n", "def convert(size, box):\n", " dw = 1./(size[0])\n", " dh = 1./(size[1])\n", " x = (box[0] + box[1])/2.0 - 1\n", " y = (box[2] + box[3])/2.0 - 1\n", " w = box[1] - box[0]\n", " h = box[3] - box[2]\n", " x = x*dw\n", " w = w*dw\n", " y = y*dh\n", " h = h*dh\n", " return (x, y, w, h)\n", "\n", "# 讀取 annotation 檔案內容並轉換\n", "def convert_annotation(img_path, ann_dir,\n", " output_image_path, output_label_path):\n", " basename = os.path.basename(img_path)\n", " basename_no_ext = os.path.splitext(basename)[0]\n", "\n", " # copy image\n", " shutil.copy(img_path, os.path.join(output_image_path, basename))\n", "\n", " in_file = open(ann_dir + '/' + basename_no_ext + '.xml')\n", " out_file = open(output_label_path + basename_no_ext + '.txt', 'w')\n", " tree = ET.parse(in_file)\n", " root = tree.getroot()\n", " size = root.find('size')\n", " w = int(size.find('width').text)\n", " h = int(size.find('height').text)\n", "\n", " for obj in root.iter('object'):\n", " difficult = obj.find('difficult').text\n", " cls = obj.find('name').text\n", " if cls not in classes or int(difficult) == 1:\n", " continue\n", " cls_id = classes.index(cls)\n", " xmlbox = obj.find('bndbox')\n", " b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text),\n", " float(xmlbox.find('ymin').text), float(xmlbox.find('ymax').text))\n", " bb = convert((w, h), b)\n", " out_file.write(str(cls_id) + \" \" + \" \".join(\n", " [str(a) for a in bb]) + '\\n')" ] }, { "cell_type": "code", "execution_count": null, "id": "acebedea", "metadata": {}, "outputs": [], "source": [ "\n", "name = 'pet' # 資料集名稱\n", "classes = ['cat', 'dog'] # 修改自己的類別\n", "train_test_split_rate = 0.2\n", "\n", "img_dir = 'datasets/JPEGImages/' # 照片存放路徑\n", "ann_dir = 'datasets/Annotations/' # 標籤存放路徑\n", "image_paths = getImagesInDir(img_dir)\n", "random.seed(2022)\n", "random.shuffle(image_paths)\n", "\n", "train_image_path = f'datasets/{name}/train/images/'\n", "train_label_path = f'datasets/{name}/train/labels/'\n", "valid_image_path = f'datasets/{name}/valid/images/'\n", "valid_label_path = f'datasets/{name}/valid/labels/'\n", "\n", "if not os.path.exists(train_image_path):\n", " os.makedirs(train_image_path)\n", "if not os.path.exists(train_label_path):\n", " os.makedirs(train_label_path)\n", "if not os.path.exists(valid_image_path):\n", " os.makedirs(valid_image_path)\n", "if not os.path.exists(valid_label_path):\n", " os.makedirs(valid_label_path)\n", "\n", "train_test_split = len(image_paths)*train_test_split_rate\n", "\n", "for i, img_path in enumerate(image_paths):\n", " if i >= train_test_split:\n", " # train\n", " convert_annotation(img_path, ann_dir,\n", " train_image_path, train_label_path)\n", " else:\n", " # valid\n", " convert_annotation(img_path, ann_dir,\n", " valid_image_path, valid_label_path)" ] }, { "cell_type": "markdown", "id": "8cd2d1f3", "metadata": {}, "source": [ "## 2. 更改設定檔案\n", "- 修改 cfg/training/yolov7.yaml\n", "- 修改 data/coco.yaml 製作一個自己資料集的 yaml" ] }, { "cell_type": "markdown", "id": "3beea9c9", "metadata": {}, "source": [ "將yolov7.yaml 設定檔複製一份\n", " \n", "!cp 要複製的檔案 新檔案名稱" ] }, { "cell_type": "code", "execution_count": null, "id": "1da4d0ea", "metadata": {}, "outputs": [], "source": [ "!cp cfg/training/yolov7.yaml cfg/training/yolov7-pet.yaml" ] }, { "cell_type": "markdown", "id": "eecaf7e9", "metadata": {}, "source": [ "將class的地方改成自己的class數量\n", "\n", "!sed -n -e (顯示) 第幾行 檔案名稱" ] }, { "cell_type": "code", "execution_count": null, "id": "4d0c055f", "metadata": {}, "outputs": [], "source": [ "!sed -n -e 2p cfg/training/yolov7-pet.yaml" ] }, { "cell_type": "markdown", "id": "22a4fc1a", "metadata": {}, "source": [ "\n", "\n", "!sed -i (修改) 第幾行/欲修改的字/目標字/ 檔案名稱" ] }, { "cell_type": "code", "execution_count": null, "id": "034cd458", "metadata": {}, "outputs": [], "source": [ "!sed -i '2s/80/2/' cfg/training/yolov7-pet.yaml" ] }, { "cell_type": "code", "execution_count": null, "id": "dadf99a6", "metadata": {}, "outputs": [], "source": [ "!sed -n -e 2p cfg/training/yolov7-pet.yaml" ] }, { "cell_type": "markdown", "id": "939075e6", "metadata": {}, "source": [ "![](https://i.imgur.com/ZmNHP9h.png)" ] }, { "cell_type": "markdown", "id": "2e1a0f59", "metadata": {}, "source": [ "參考data/coco.yaml 製作一個自己資料集的yaml" ] }, { "cell_type": "code", "execution_count": null, "id": "61c7bdde", "metadata": {}, "outputs": [], "source": [ "text = \\\n", " \"\"\"\n", " train: ./datasets/pet/train # 訓練資料夾位置\n", " val: ./datasets/pet/valid # 驗證資料夾位置\n", "\n", " # number of classes\n", " nc: 2 # <-需修改乘自己的類別數量\n", "\n", " # class names\n", " names: [ 'cat','dog' ]\n", " \"\"\"" ] }, { "cell_type": "code", "execution_count": null, "id": "532bbd90", "metadata": {}, "outputs": [], "source": [ "with open(f'data/{name}.yaml', 'w') as file:\n", " file.write(text)" ] }, { "cell_type": "markdown", "id": "1d23554f", "metadata": {}, "source": [ "![](https://i.imgur.com/DKR925y.png)" ] }, { "cell_type": "markdown", "id": "d8782513", "metadata": {}, "source": [ "下載預訓練權重檔案\n", "https://github.com/WongKinYiu/yolov7" ] }, { "cell_type": "markdown", "id": "8f97dea5", "metadata": {}, "source": [ "![](https://i.imgur.com/5jsscuE.png)放置於weights/資料夾底下" ] }, { "cell_type": "markdown", "id": "4854c4d3", "metadata": {}, "source": [ "執行訓練,訓練參數介紹:\n", "- --weights : 預先訓練的權重路徑(weights/yolov7_training.pt)\n", "- --cfg:模型設定檔案路徑(cfg/training/yolov7-pet.yaml)\n", "- --data:資料集設定檔案路徑(data/pet.yaml)\n", "- --device:GPU設定\n", "- --batch-size:一次訓練照片張數\n", "- --epoch: 訓練圈數\n", "\n", "其他可調控參數可置train.py中察看" ] }, { "cell_type": "code", "execution_count": null, "id": "bcb164a1", "metadata": {}, "outputs": [], "source": [ "!python train.py --weights weights/yolov7_training.pt --cfg cfg/training/yolov7-pet.yaml --data data/pet.yaml --device 0 --batch-size 16 --epoch 50\n" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.12" } }, "nbformat": 4, "nbformat_minor": 5 }