This article mainly describes the specific steps of using yolov3 to train the model in the Windows10 environment
This article mainly includes the following contents:
- 1. Program download and preparation
- 2. Environment Construction
- 3. Data set production
- Fourth, yolov3 model training
-
- (1) Modify the data configuration file
- (2) Modify the model configuration file
- (3) Train.py main function modification
- (4) Problems that may be encountered in model training
-
- 1. Encountered the error subprocess.CalledProcessError: Command 'git tag' returned non-zero exit status 1.
- 2. Encountered the error UnicodeDecodeError:: 'utf-8' codec can't decode byte 0xc8 in position 0: invalid contin
- 3. Encountered the error BrokenPipeError: [Errno 32] Broken pipe
- 4. Encountered the error OMP: Error #15: Initializing libiomp5md.dll, but found libiomp5md.dll already initialized.
- 5. Test results
Software preparation: anaconda3, pycharm
1. Program download and preparation
(1) yolov3 download
The github address of yolov3: yolov3
1. You can click here to select the version you want to download (this article takes 9.5.0 as an example)
2. Click download on the left to download the compressed package
3. The downloaded and decompressed folder is as shown in the figure Shown:
Open the project directory in pycharm as shown below:
(2) Training set folder creation
1. Under the yolov3-9.5.0 project folder, create a new folder named VOCdevkit 2.
Under the VOCdevkit folder, create three new folders named images , labels , and VOC2007
3. In the images and labels files Create two new folders named train and val under the folder
4. Create three folders named Annotations , JPEGImages , and YOLOLabels under the VOC2007 folder , as shown in the
figure below:
Annotations: xml tag folder
JPEGImages: image file Folder
YOLOLabels: txt label folder (yolov training requires label files in txt format)
(3) Pre-training weight download
Loading pre-trained weights for network training can reduce network training time and improve accuracy. The larger the pre-training weight, the higher the training accuracy, but the slower the detection speed.
1. Pre-training weight download address: yolov5 weight
This article chooses to download yolov3-tiny.pt
(different pre-training weights correspond to different network layers, we need to use the corresponding yaml files according to the pre-training weights, namely A file named yolov3-tiny.yaml needs to be used in subsequent training)
2. Save the downloaded weight file in the weights folder
2. Environment Construction
(1) pytorch installation
For the specific steps to install pytorch through anaconda in the windows10 system, you can read this blog:
anaconda installs pytorch (anaconda3, Windows10)
(2) Apply pytorch to the project
In the previous step, we installed pytorch through anaconda and imported it into pycharm. Let's apply the compiler in the environment named pyotch to the project file.
1. Click File → Settings
2. Select Project Interpreter , select the pytorch environment just imported into pycharm , click Apply , and finally click Confirm
. In this way, we have successfully applied the compiler named pytorch environment to the yolov3-9.5.0 project
(3) Dependency package installation in requirements
1. Next, install the dependency packages required by the project, first open the terminal
2. Copy the command line in the requirements.txt file:
pip install -r requirements.txt
Paste it in the terminal and press Enter to run the command line, and the dependencies in the requirements will be installed.
(4) Problems that may be encountered in the construction of the environment
1.遇到错误 ERROR: Could not build wheels for pycocotools which use PEP 517 and cannot be installed directly
Refer to the problems that may be encountered in the environment construction in this blog :
target detection - target detection project based on Yolov5 (study notes)
(if there are other errors, it will be updated later)
3. Data set production
Use labelimg to make our own data set, the installation and basic operation of labelimg can read this blog:
Data set production - use labelimg to make a data set
The file format required for yolov network training is in txt format.
If you give the data set through labelimg When labeling, the output is in xml format, and the label file in xml format can be converted into a label file in txt format through code;
if the output is a label file in txt format, it can be used directly. At the same time, when training your own yolov3 detection model, the data set needs to be divided into training set and validation set, which can also be implemented through related codes.
This paper takes the identification of two labels "person" and "har" as an example, and the data set in this paper is based on the data set of identifying people wearing helmets as an example
This article uses labelimg to mark the label file in xml format as an example:
(The labeling process is omitted)
1. First, store the image dataset in the JPEGImages folder; store the xml label file in the Annotations folder; that is:
JPEGImages stores The image file
Annotations stores tags in xml format
as shown in the figure:
2. Create a new python file in the project, copy and paste the following code and run it to divide the data set into training set and validation set
(note that the label types in the following code classes = ["hat", "person" ] Modify it to its own label, the training set in the following code accounts for 80% of TRAIN_RATIO = 80 )
import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join
import random
from shutil import copyfile
classes = ["hat", "person"] #标签种类
#classes=["ball"]
TRAIN_RATIO = 80 #训练集占比
def clear_hidden_files(path):
dir_list = os.listdir(path)
for i in dir_list:
abspath = os.path.join(os.path.abspath(path), i)
if os.path.isfile(abspath):
if i.startswith("._"):
os.remove(abspath)
else:
clear_hidden_files(abspath)
def convert(size, box):
dw = 1./size[0]
dh = 1./size[1]
x = (box[0] + box[1])/2.0
y = (box[2] + box[3])/2.0
w = box[1] - box[0]
h = box[3] - box[2]
x = x*dw
w = w*dw
y = y*dh
h = h*dh
return (x,y,w,h)
def convert_annotation(image_id):
in_file = open('VOCdevkit/VOC2007/Annotations/%s.xml' %image_id)
out_file = open('VOCdevkit/VOC2007/YOLOLabels/%s.txt' %image_id, 'w')
tree=ET.parse(in_file)
root = tree.getroot()
size = root.find('size')
w = int(size.find('width').text)
h = int(size.find('height').text)
for obj in root.iter('object'):
difficult = obj.find('difficult').text
cls = obj.find('name').text
if cls not in classes or int(difficult) == 1:
continue
cls_id = classes.index(cls)
xmlbox = obj.find('bndbox')
b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text), float(xmlbox.find('ymax').text))
bb = convert((w,h), b)
out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')
in_file.close()
out_file.close()
wd = os.getcwd()
wd = os.getcwd()
data_base_dir = os.path.join(wd, "VOCdevkit/")
if not os.path.isdir(data_base_dir):
os.mkdir(data_base_dir)
work_sapce_dir = os.path.join(data_base_dir, "VOC2007/")
if not os.path.isdir(work_sapce_dir):
os.mkdir(work_sapce_dir)
annotation_dir = os.path.join(work_sapce_dir, "Annotations/")
if not os.path.isdir(annotation_dir):
os.mkdir(annotation_dir)
clear_hidden_files(annotation_dir)
image_dir = os.path.join(work_sapce_dir, "JPEGImages/")
if not os.path.isdir(image_dir):
os.mkdir(image_dir)
clear_hidden_files(image_dir)
yolo_labels_dir = os.path.join(work_sapce_dir, "YOLOLabels/")
if not os.path.isdir(yolo_labels_dir):
os.mkdir(yolo_labels_dir)
clear_hidden_files(yolo_labels_dir)
yolov5_images_dir = os.path.join(data_base_dir, "images/")
if not os.path.isdir(yolov5_images_dir):
os.mkdir(yolov5_images_dir)
clear_hidden_files(yolov5_images_dir)
yolov5_labels_dir = os.path.join(data_base_dir, "labels/")
if not os.path.isdir(yolov5_labels_dir):
os.mkdir(yolov5_labels_dir)
clear_hidden_files(yolov5_labels_dir)
yolov5_images_train_dir = os.path.join(yolov5_images_dir, "train/")
if not os.path.isdir(yolov5_images_train_dir):
os.mkdir(yolov5_images_train_dir)
clear_hidden_files(yolov5_images_train_dir)
yolov5_images_test_dir = os.path.join(yolov5_images_dir, "val/")
if not os.path.isdir(yolov5_images_test_dir):
os.mkdir(yolov5_images_test_dir)
clear_hidden_files(yolov5_images_test_dir)
yolov5_labels_train_dir = os.path.join(yolov5_labels_dir, "train/")
if not os.path.isdir(yolov5_labels_train_dir):
os.mkdir(yolov5_labels_train_dir)
clear_hidden_files(yolov5_labels_train_dir)
yolov5_labels_test_dir = os.path.join(yolov5_labels_dir, "val/")
if not os.path.isdir(yolov5_labels_test_dir):
os.mkdir(yolov5_labels_test_dir)
clear_hidden_files(yolov5_labels_test_dir)
train_file = open(os.path.join(wd, "yolov5_train.txt"), 'w')
test_file = open(os.path.join(wd, "yolov5_val.txt"), 'w')
train_file.close()
test_file.close()
train_file = open(os.path.join(wd, "yolov5_train.txt"), 'a')
test_file = open(os.path.join(wd, "yolov5_val.txt"), 'a')
list_imgs = os.listdir(image_dir) # list image files
prob = random.randint(1, 100)
print("Probability: %d" % prob)
for i in range(0,len(list_imgs)):
path = os.path.join(image_dir,list_imgs[i])
if os.path.isfile(path):
image_path = image_dir + list_imgs[i]
voc_path = list_imgs[i]
(nameWithoutExtention, extention) = os.path.splitext(os.path.basename(image_path))
(voc_nameWithoutExtention, voc_extention) = os.path.splitext(os.path.basename(voc_path))
annotation_name = nameWithoutExtention + '.xml'
annotation_path = os.path.join(annotation_dir, annotation_name)
label_name = nameWithoutExtention + '.txt'
label_path = os.path.join(yolo_labels_dir, label_name)
prob = random.randint(1, 100)
print("Probability: %d" % prob)
if(prob < TRAIN_RATIO): # train dataset
if os.path.exists(annotation_path):
train_file.write(image_path + '\n')
convert_annotation(nameWithoutExtention) # convert label
copyfile(image_path, yolov5_images_train_dir + voc_path)
copyfile(label_path, yolov5_labels_train_dir + label_name)
else: # test dataset
if os.path.exists(annotation_path):
test_file.write(image_path + '\n')
convert_annotation(nameWithoutExtention) # convert label
copyfile(image_path, yolov5_images_test_dir + voc_path)
copyfile(label_path, yolov5_labels_test_dir + label_name)
train_file.close()
test_file.close()
Run this code, the process is shown in the following figure: (Note that the name of the dataset folder must be the same as the training set folder creation part above, you can directly copy and paste to run)
Then you can see the divided image dataset and label dataset in the images and labels folders respectively.
Fourth, yolov3 model training
(1) Modify the data configuration file
1. Find the voc.yaml file in the data directory, copy the file, and rename the copied file to facilitate subsequent operations. In this article, it is changed to hat.yaml
2. Click the hat.yaml file and modify the following parts:
Comment out the statement: download: bash data/scripts/get_voc.sh
Modify the train and val addresses to the data set address in your computer
Modify the number of classes value to the number of types of data set labels (the labels in this article are two types)
Modify the class names Types of labels for your own data set (hat and person in this article)
(2) Modify the model configuration file
The weight file selected to download earlier is yolov3-tiny.pt, we need to use the corresponding model to configure the yaml file
1. Find the yolov3-tiny.yaml file in the models directory, make a copy of the file, and rename the copied file to facilitate subsequent operations. This article is modified to yolov3-tiny_hat.yaml
2. Open yolov3-tiny_hat.yaml file, change the number of classes to the type of dataset label (the dataset identified in this article is two types)
(3) Train.py main function modification
Mainly modify the following five functions:
-weights: the path address of the initialized weight file
-cfg: the path address of the model yaml file
-data: the path address of the data yaml file
-epochs: the number of trainings -batch
-size: the file for one round of training Number
1. Open train.py and make the following modifications:
Modify the address of the weight file in "--weights" to the address of the file yolov3-tiny.pt
Modify the address of the model yaml file in "--cfg" to the address of the file yolov3-tiny_hat.yaml Address
Modify the address of the data yaml file in "–data" to the address of the file hat.yaml
parser.add_argument('--weights', type=str, default='weights/yolov3-tiny.pt', help='initial weights path')
parser.add_argument('--cfg', type=str, default='models/yolov3-tiny_hat.yaml', help='model.yaml path')
parser.add_argument('--data', type=str, default='data/hat.yaml', help='data.yaml path')
As shown in the figure below:
The values of "--epochs" and "--batch-size" can be set according to the GPU situation
2. Run train.py to start training the model
After loading the train and val datasets, you can see that the model starts training~
(4) Problems that may be encountered in model training
1. Encountered the error subprocess.CalledProcessError: Command 'git tag' returned non-zero exit status 1.
As shown in the figure below:
Solution:
Open the subprocess.py file, in line 410, change the check value to False and
click OK
2. Encountered the error UnicodeDecodeError:: 'utf-8' codec can't decode byte 0xc8 in position 0: invalid contin
As shown in the figure below:
Solution:
Open torch_utils.py and change the encoding method to decode('gb2312') on line 58
3. Encountered the error BrokenPipeError: [Errno 32] Broken pipe
As shown in the figure below:
Solution:
On line 488, change the value of '--workers' to 0
4. Encountered the error OMP: Error #15: Initializing libiomp5md.dll, but found libiomp5md.dll already initialized.
As shown in the figure below:
Solution:
In the envs folder of the anaconda installation directory, find the pytorch environment, enter the bin folder of the library, and delete the libiomp5md.dll file
5. Test results
After the training, two weight files will be generated in the runs/train/exp/weights directory, one is the weight file with the best training effect, and the other is the weight file for the last round of training
(the next best.pt weight file is example)
(1) Picture test steps
1. Copy and paste the best.pt weight file in the weights folder of the main directory (for the convenience of subsequent operations)
2. Put the picture you want to test in the data folder of the main directory, as shown in the figure:
3. Open defect .py, change the following parts: Change
"--weight" to the address of the best.pt weight file (in the weights folder) Change "--source" to the address
of the image to be tested (in the data folder)
parser.add_argument('--weights', nargs='+', type=str, default='weights/best.pt', help='model.pt path(s)')
parser.add_argument('--source', type=str, default='data/1.jpg', help='source') # file/folder, 0 for webcam
As shown in the figure:
4. Run defect.py to get the result;
5. If the video is recognized, change "--source" to the video address to be tested (note the .mp4 suffix).
If the camera is recognized, Just set the value of "-source" to 0, that is:
parser.add_argument('--source', type=str, default='0', help='source') # file/folder, 0 for webcam