mirror of
https://github.com/azaion/ai-training.git
synced 2026-04-22 06:46:35 +00:00
fix augmentation - correct bboxes to be within borders+margin
Add classes = 80 as default number in yaml file
This commit is contained in:
@@ -36,13 +36,12 @@ Linux
|
||||
```
|
||||
|
||||
**3. Fix possible problems**
|
||||
* Windows:
|
||||
* cv2.error: OpenCV(4.10.0) ...\window.cpp:1301: error: (-2:Unspecified error)
|
||||
```
|
||||
pip uninstall opencv-python
|
||||
pip install opencv-python
|
||||
```
|
||||
* fbgemm.dll error
|
||||
* fbgemm.dll error (Windows specific)
|
||||
```
|
||||
copypaste libomp140.x86_64.dll to C:\Windows\System32
|
||||
```
|
||||
|
||||
+11
-11
@@ -1,62 +1,62 @@
|
||||
[
|
||||
{
|
||||
"Id": 0,
|
||||
"Name": "Броньована техніка",
|
||||
"Name": "Armored-Vehicle",
|
||||
"Color": "#80FF0000",
|
||||
"ColorBrush": "#80FF0000"
|
||||
},
|
||||
{
|
||||
"Id": 1,
|
||||
"Name": "Вантажівка",
|
||||
"Name": "Truck",
|
||||
"Color": "#8000FF00",
|
||||
"ColorBrush": "#8000FF00"
|
||||
},
|
||||
{
|
||||
"Id": 2,
|
||||
"Name": "Машина легкова",
|
||||
"Name": "Vehicle",
|
||||
"Color": "#800000FF",
|
||||
"ColorBrush": "#800000FF"
|
||||
},
|
||||
{
|
||||
"Id": 3,
|
||||
"Name": "Артилерія",
|
||||
"Name": "Artillery",
|
||||
"Color": "#80FFFF00",
|
||||
"ColorBrush": "#80FFFF00"
|
||||
},
|
||||
{
|
||||
"Id": 4,
|
||||
"Name": "Тінь від техніки",
|
||||
"Name": "Shadow",
|
||||
"Color": "#80FF00FF",
|
||||
"ColorBrush": "#80FF00FF"
|
||||
},
|
||||
{
|
||||
"Id": 5,
|
||||
"Name": "Окопи",
|
||||
"Name": "Trenches",
|
||||
"Color": "#8000FFFF",
|
||||
"ColorBrush": "#8000FFFF"
|
||||
},
|
||||
{
|
||||
"Id": 6,
|
||||
"Name": "Військовий",
|
||||
"Name": "Military-men",
|
||||
"Color": "#80000000",
|
||||
"ColorBrush": "#80000000"
|
||||
},
|
||||
{
|
||||
"Id": 7,
|
||||
"Name": "Накати",
|
||||
"Name": "Tyre-tracks",
|
||||
"Color": "#80800000",
|
||||
"ColorBrush": "#80800000"
|
||||
},
|
||||
{
|
||||
"Id": 8,
|
||||
"Name": "Танк з додатковим захистом",
|
||||
"Name": "Additional-armored-tank",
|
||||
"Color": "#80008000",
|
||||
"ColorBrush": "#80008000"
|
||||
},
|
||||
{
|
||||
"Id": 9,
|
||||
"Name": "Дим",
|
||||
"Name": "Smoke",
|
||||
"Color": "#80000080",
|
||||
"ColorBrush": "#80000080"
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
@@ -4,8 +4,6 @@ import xml.etree.cElementTree as et
|
||||
from pathlib import Path
|
||||
import cv2
|
||||
|
||||
labels_dir = 'labels'
|
||||
images_dir = 'images'
|
||||
|
||||
tag_size = 'size'
|
||||
tag_object = 'object'
|
||||
@@ -17,9 +15,11 @@ default_class = 1
|
||||
image_extensions = ['jpg', 'png', 'jpeg']
|
||||
|
||||
|
||||
def convert(folder, read_annotations, ann_format):
|
||||
os.makedirs(images_dir, exist_ok=True)
|
||||
os.makedirs(labels_dir, exist_ok=True)
|
||||
def convert(folder, dest_folder, read_annotations, ann_format):
|
||||
dest_images_dir = os.path.join(dest_folder, 'images')
|
||||
dest_labels_dir = os.path.join(dest_folder, 'labels')
|
||||
os.makedirs(dest_images_dir, exist_ok=True)
|
||||
os.makedirs(dest_labels_dir, exist_ok=True)
|
||||
|
||||
for f in os.listdir(folder):
|
||||
if not f[-3:] in image_extensions:
|
||||
@@ -39,8 +39,8 @@ def convert(folder, read_annotations, ann_format):
|
||||
except Exception as e:
|
||||
print(f'Error conversion for {f}. Error: {e}')
|
||||
|
||||
shutil.copy(os.path.join(folder, f), os.path.join(images_dir, f))
|
||||
with open(os.path.join(labels_dir, f'{Path(label).stem}.txt'), 'w') as new_label_file:
|
||||
shutil.copy(os.path.join(folder, f), os.path.join(dest_images_dir, f))
|
||||
with open(os.path.join(dest_labels_dir, f'{Path(label).stem}.txt'), 'w') as new_label_file:
|
||||
new_label_file.writelines(lines)
|
||||
new_label_file.close()
|
||||
print(f'Image {f} has been processed successfully')
|
||||
@@ -115,5 +115,5 @@ def rename_images(folder):
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
convert('datasets/others/UAVHeightImages', read_bbox_oriented, 'txt')
|
||||
convert('datasets/others/UAVimages', read_pascal_voc, 'xml')
|
||||
convert('/azaion/datasets/others/cars_height', '/azaion/datasets/converted', read_bbox_oriented, 'txt')
|
||||
convert('/azaion/datasets/others/cars', '/azaion/datasets/converted', read_pascal_voc, 'xml')
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
# prerequisites
|
||||
sudo apt install python3.12-venv python-is-python3
|
||||
if [ ! -f azaion.pt ]; then
|
||||
echo "----ERROR!----"
|
||||
echo "Script requires azaion.pt file model in this folder!!!"
|
||||
echo "----ERROR!----"
|
||||
exit
|
||||
fi
|
||||
|
||||
# convert PT to ONNX
|
||||
git clone https://github.com/airockchip/ultralytics_yolov8
|
||||
cd ultralytics_yolov8
|
||||
python -m venv env
|
||||
source env/bin/activate
|
||||
pip install .
|
||||
|
||||
cp ../azaion.pt .
|
||||
sed -i -E "s/(model:).*$/\1 azaion.pt/" ultralytics/cfg/default.yaml
|
||||
export PYTHONPATH=./
|
||||
python ./ultralytics/engine/exporter.py
|
||||
cp azaion.onnx ../
|
||||
cd ..
|
||||
|
||||
exit
|
||||
|
||||
# convert ONNX to RKNN
|
||||
wget -c https://mirrors.bfsu.edu.cn/anaconda/miniconda/Miniconda3-latest-Linux-x86_64.sh
|
||||
chmod +x Miniconda3-latest-Linux-x86_64.sh
|
||||
bash Miniconda3-latest-Linux-x86_64.sh
|
||||
source ~/miniconda3/bin/activate
|
||||
conda create -n toolkit2 python=3.11
|
||||
conda activate toolkit2
|
||||
git clone https://github.com/rockchip-linux/rknn-toolkit2.git
|
||||
cd rknn-toolkit2/rknn-toolkit2/packages
|
||||
pip install -r requirements_cp311-1.6.0.txt
|
||||
pip install rknn_toolkit2-1.6.0+81f21f4d-cp311-cp311-linux_x86_64.whl
|
||||
cd ~/opi5-rknn
|
||||
git clone https://github.com/airockchip/rknn_model_zoo.git
|
||||
cd rknn_model_zoo/examples/yolov8/python
|
||||
python convert.py ~/azaion/models/azaion-2024-08-13.onnx rk3588 i8
|
||||
cp ../model/yolov8.rknn ~/azaion/models/azaion-2024-08-13.rknn # Output file form convert script is hard-coded...
|
||||
+32
-5
@@ -11,10 +11,35 @@ from constants import (data_images_dir, data_labels_dir, processed_images_dir, p
|
||||
from dto.imageLabel import ImageLabel
|
||||
|
||||
|
||||
def correct_bboxes(labels):
|
||||
margin = 0.0005
|
||||
min_size = 0.01
|
||||
res = []
|
||||
for bboxes in labels:
|
||||
x = bboxes[0]
|
||||
y = bboxes[1]
|
||||
half_width = 0.5*bboxes[2]
|
||||
half_height = 0.5*bboxes[3]
|
||||
|
||||
# calc how much bboxes are outside borders ( +small margin ).
|
||||
# value should be negative. If it's positive, then put 0, as no correction
|
||||
w_diff = min( (1 - margin) - (x + half_width), (x - half_width) - margin, 0 )
|
||||
w = bboxes[2] + 2*w_diff
|
||||
if w < min_size:
|
||||
continue
|
||||
h_diff = min( (1 - margin) - (y + half_height), ((y - half_height) - margin), 0)
|
||||
h = bboxes[3] + 2 * h_diff
|
||||
if h < min_size:
|
||||
continue
|
||||
res.append([x, y, w, h, bboxes[4]])
|
||||
return res
|
||||
pass
|
||||
|
||||
|
||||
def image_processing(img_ann: ImageLabel) -> [ImageLabel]:
|
||||
transforms = [
|
||||
A.Compose([A.HorizontalFlip(always_apply=True)],
|
||||
bbox_params=A.BboxParams(format='yolo')),
|
||||
bbox_params=A.BboxParams(format='yolo', )),
|
||||
A.Compose([A.RandomBrightnessContrast(always_apply=True)],
|
||||
bbox_params=A.BboxParams(format='yolo')),
|
||||
A.Compose([A.SafeRotate(limit=90, always_apply=True)],
|
||||
@@ -33,9 +58,12 @@ def image_processing(img_ann: ImageLabel) -> [ImageLabel]:
|
||||
]
|
||||
|
||||
results = []
|
||||
labels = correct_bboxes(img_ann.labels)
|
||||
if len(labels) == 0 and len(img_ann.labels) != 0:
|
||||
print('no labels but was!!!')
|
||||
for i, transform in enumerate(transforms):
|
||||
try:
|
||||
res = transform(image=img_ann.image, bboxes=img_ann.labels)
|
||||
res = transform(image=img_ann.image, bboxes=labels)
|
||||
path = Path(img_ann.image_path)
|
||||
name = f'{path.stem}_{i + 1}'
|
||||
img = ImageLabel(
|
||||
@@ -51,9 +79,6 @@ def image_processing(img_ann: ImageLabel) -> [ImageLabel]:
|
||||
|
||||
|
||||
def write_result(img_ann: ImageLabel):
|
||||
os.makedirs(os.path.dirname(img_ann.image_path), exist_ok=True)
|
||||
os.makedirs(os.path.dirname(img_ann.labels_path), exist_ok=True)
|
||||
|
||||
cv2.imencode('.jpg', img_ann.image)[1].tofile(img_ann.image_path)
|
||||
print(f'{img_ann.image_path} written')
|
||||
|
||||
@@ -92,6 +117,8 @@ def process_image(img_ann):
|
||||
|
||||
|
||||
def main():
|
||||
os.makedirs(processed_images_dir, exist_ok=True)
|
||||
os.makedirs(processed_labels_dir, exist_ok=True)
|
||||
while True:
|
||||
processed_images = set(f.name for f in os.scandir(processed_images_dir))
|
||||
images = []
|
||||
|
||||
+27
-7
@@ -3,18 +3,38 @@ apt update
|
||||
apt upgrade
|
||||
apt install -y ssh
|
||||
|
||||
addgroup sftp
|
||||
adduser azaionsftp
|
||||
usermod -G sftp azaionsftp
|
||||
usermod -a -G sftp zxsanny
|
||||
|
||||
mkdir /azaion-media/sftphome
|
||||
chown -R azaionsftp:azaionsftp /azaion-media/sftphome/
|
||||
chmod -R 755 /azaion-media/sftphome/
|
||||
chown root:root /home/azaionsftp
|
||||
|
||||
cd /home/azaionsftp
|
||||
mkdir datasets
|
||||
chown -R azaionsftp:azaionsftp datasets
|
||||
mount -o bind /azaion/datasets datasets
|
||||
|
||||
chown -R zxsanny:sftp /azaion/data
|
||||
mkdir data
|
||||
chown -R azaionsftp:azaionsftp data
|
||||
mount -o bind /azaion/data data
|
||||
|
||||
chown -R zxsanny:sftp /azaion/data-processed
|
||||
mkdir data-processed
|
||||
chown -R azaionsftp:azaionsftp data-processed
|
||||
mount -o bind /azaion/data-processed data-processed
|
||||
|
||||
|
||||
chmod -R 755 /home/azaionsftp/
|
||||
|
||||
cat <<EOT >> /etc/ssh/sshd_config
|
||||
Match Group azaionsftp
|
||||
Match Group sftp
|
||||
ChrootDirectory %h
|
||||
PasswordAuthentication yes
|
||||
AllowTcpForwarding no
|
||||
X11Forwarding no
|
||||
ForceCommand internal-sftp
|
||||
AllowTcpForwarding no
|
||||
PasswordAuthentication yes
|
||||
EOT
|
||||
service ssh restart
|
||||
service ssh restart
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@ train_set = 70
|
||||
valid_set = 20
|
||||
test_set = 10
|
||||
|
||||
DEFAULT_CLASS_NUM = 80
|
||||
|
||||
|
||||
def form_dataset(from_date: datetime):
|
||||
makedirs(today_dataset, exist_ok=True)
|
||||
@@ -89,7 +91,10 @@ def create_yaml():
|
||||
lines = ['names:']
|
||||
for c in annotation_classes:
|
||||
lines.append(f'- {annotation_classes[c].name}')
|
||||
lines.append(f'nc: {len(annotation_classes)}')
|
||||
classes_count = len(annotation_classes)
|
||||
for c in range(DEFAULT_CLASS_NUM - classes_count):
|
||||
lines.append(f'- Class-{c + classes_count + 1}')
|
||||
lines.append(f'nc: {DEFAULT_CLASS_NUM}')
|
||||
|
||||
lines.append(f'test: test/images')
|
||||
lines.append(f'train: train/images')
|
||||
@@ -132,17 +137,19 @@ def get_latest_model():
|
||||
|
||||
if __name__ == '__main__':
|
||||
latest_date, latest_model = get_latest_model()
|
||||
# create_yaml()
|
||||
# form_dataset(latest_date)
|
||||
|
||||
|
||||
model_name = latest_model if latest_model is not None and path.isfile(latest_model) else 'yolov8m.yaml'
|
||||
print(f'Initial model: {model_name}')
|
||||
model = YOLO(model_name)
|
||||
|
||||
# cur_folder = path.join(datasets_dir, f'{prefix}2024-06-18')
|
||||
cur_folder = path.join(datasets_dir, f'{prefix}2024-09-19')
|
||||
|
||||
cur_folder = today_dataset
|
||||
# cur_folder = today_dataset
|
||||
yaml = abspath(path.join(cur_folder, 'data.yaml'))
|
||||
results = model.train(data=yaml, epochs=100, batch=60, imgsz=640)
|
||||
results = model.train(data=yaml, epochs=100, batch=58, imgsz=640)
|
||||
|
||||
shutil.copytree(results.save_dir, path.join(models_dir, today_folder))
|
||||
shutil.rmtree('runs')
|
||||
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
# Ultralytics YOLO 🚀, AGPL-3.0 license
|
||||
# YOLOv8 object detection model with P3-P5 outputs. For Usage examples see https://docs.ultralytics.com/tasks/detect
|
||||
|
||||
# Parameters
|
||||
nc: 80 # number of classes
|
||||
scales: # model compound scaling constants, i.e. 'model=yolov8n.yaml' will call yolov8.yaml with scale 'n'
|
||||
# [depth, width, max_channels]
|
||||
n: [0.33, 0.25, 1024] # YOLOv8n summary: 225 layers, 3157200 parameters, 3157184 gradients, 8.9 GFLOPs
|
||||
s: [0.33, 0.50, 1024] # YOLOv8s summary: 225 layers, 11166560 parameters, 11166544 gradients, 28.8 GFLOPs
|
||||
m: [0.67, 0.75, 768] # YOLOv8m summary: 295 layers, 25902640 parameters, 25902624 gradients, 79.3 GFLOPs
|
||||
l: [1.00, 1.00, 512] # YOLOv8l summary: 365 layers, 43691520 parameters, 43691504 gradients, 165.7 GFLOPs
|
||||
x: [1.00, 1.25, 512] # YOLOv8x summary: 365 layers, 68229648 parameters, 68229632 gradients, 258.5 GFLOPs
|
||||
|
||||
# YOLOv8.0n backbone
|
||||
backbone:
|
||||
# [from, repeats, module, args]
|
||||
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
|
||||
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
|
||||
- [-1, 3, C2f, [128, True]]
|
||||
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
|
||||
- [-1, 6, C2f, [256, True]]
|
||||
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
|
||||
- [-1, 6, C2f, [512, True]]
|
||||
- [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
|
||||
- [-1, 3, C2f, [1024, True]]
|
||||
- [-1, 1, SPPF, [1024, 5]] # 9
|
||||
|
||||
# YOLOv8.0n head
|
||||
head:
|
||||
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
|
||||
- [[-1, 6], 1, Concat, [1]] # cat backbone P4
|
||||
- [-1, 3, C2f, [512]] # 12
|
||||
|
||||
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
|
||||
- [[-1, 4], 1, Concat, [1]] # cat backbone P3
|
||||
- [-1, 3, C2f, [256]] # 15 (P3/8-small)
|
||||
|
||||
- [-1, 1, Conv, [256, 3, 2]]
|
||||
- [[-1, 12], 1, Concat, [1]] # cat head P4
|
||||
- [-1, 3, C2f, [512]] # 18 (P4/16-medium)
|
||||
|
||||
- [-1, 1, Conv, [512, 3, 2]]
|
||||
- [[-1, 9], 1, Concat, [1]] # cat head P5
|
||||
- [-1, 3, C2f, [1024]] # 21 (P5/32-large)
|
||||
|
||||
- [[15, 18, 21], 1, Detect, [nc]] # Detect(P3, P4, P5)
|
||||
@@ -1,40 +0,0 @@
|
||||
# Ultralytics YOLO 🚀, GPL-3.0 license
|
||||
|
||||
# Parameters
|
||||
nc: 50 # number of classes
|
||||
depth_multiple: 0.67 # scales module repeats
|
||||
width_multiple: 0.75 # scales convolution channels
|
||||
|
||||
# YOLOv8.0m backbone
|
||||
backbone:
|
||||
# [from, repeats, module, args]
|
||||
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
|
||||
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
|
||||
- [-1, 3, C2f, [128, True]]
|
||||
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
|
||||
- [-1, 6, C2f, [256, True]]
|
||||
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
|
||||
- [-1, 6, C2f, [512, True]]
|
||||
- [-1, 1, Conv, [768, 3, 2]] # 7-P5/32
|
||||
- [-1, 3, C2f, [768, True]]
|
||||
- [-1, 1, SPPF, [768, 5]] # 9
|
||||
|
||||
# YOLOv8.0m head
|
||||
head:
|
||||
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
|
||||
- [[-1, 6], 1, Concat, [1]] # cat backbone P4
|
||||
- [-1, 3, C2f, [512]] # 13
|
||||
|
||||
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
|
||||
- [[-1, 4], 1, Concat, [1]] # cat backbone P3
|
||||
- [-1, 3, C2f, [256]] # 17 (P3/8-small)
|
||||
|
||||
- [-1, 1, Conv, [256, 3, 2]]
|
||||
- [[-1, 12], 1, Concat, [1]] # cat head P4
|
||||
- [-1, 3, C2f, [512]] # 20 (P4/16-medium)
|
||||
|
||||
- [-1, 1, Conv, [512, 3, 2]]
|
||||
- [[-1, 9], 1, Concat, [1]] # cat head P5
|
||||
- [-1, 3, C2f, [768]] # 23 (P5/32-large)
|
||||
|
||||
- [[15, 18, 21], 1, Detect, [nc]] # Detect(P3, P4, P5)
|
||||
Reference in New Issue
Block a user