# Finetune YOLO v7 on i7-1370PE iGPU with 64GB system SDRAM
### Ref : https://learnopencv.com/fine-tuning-yolov7-on-custom-dataset/
### Setup Intel PyTorch Extension on 1370PE : https://hackmd.io/@chungyeh/BkkPR5Hxp
YOLO v7 Tiny

YOLO

Below are steps,
Get custom data,
```
wget https://learnopencv.s3.us-west-2.amazonaws.com/pothole_dataset.zip
unzip -q pothole_dataset.zip
```
Clone YOLOv7 repository from github and then patch for XPU,
```
git clone https://github.com/WongKinYiu/yolov7.git
cd yolov7
pip install -r requirements.txt
patch -p1 < yolov7_xpu.patch
```
Here is the yolov7_xpu.patch.
```
diff --git a/train.py b/train.py
index 86c7e48..d60a0f8 100644
--- a/train.py
+++ b/train.py
@@ -286,7 +286,9 @@ def train(hyp, opt, device, tb_writer=None):
model.nc = nc # attach number of classes to model
model.hyp = hyp # attach hyperparameters to model
model.gr = 1.0 # iou loss ratio (obj_loss = 1.0 or iou)
- model.class_weights = labels_to_class_weights(dataset.labels, nc).to(device) * nc # attach class weights
+# model.class_weights = labels_to_class_weights(dataset.labels, nc).to(device) * nc # attach class weights
+ model.class_weights = labels_to_class_weights(dataset.labels, nc) * nc # a ttach class weights
+ model.class_weights = model.class_weights.to(device)
model.names = names
# Start training
diff --git a/utils/autoanchor.py b/utils/autoanchor.py
index f491032..744722c 100644
--- a/utils/autoanchor.py
+++ b/utils/autoanchor.py
@@ -49,7 +49,9 @@ def check_anchors(dataset, model, thr=4.0, imgsz=640):
print(f'{prefix}ERROR: {e}')
new_bpr = metric(anchors)[0]
if new_bpr > bpr: # replace anchors
- anchors = torch.tensor(anchors, device=m.anchors.device).type_as(m.anchors)
+ #anchors = torch.tensor(anchors, device=m.anchors.device).type_as(m.anchors)
+ anchors = torch.tensor(anchors).type_as(m.anchors)
+ anchors = anchors.to(m.anchors.device)
m.anchor_grid[:] = anchors.clone().view_as(m.anchor_grid) # for inference
check_anchor_order(m)
m.anchors[:] = anchors.clone().view_as(m.anchors) / m.stride.to(m.anchors.device).view(-1, 1, 1) # loss
diff --git a/utils/torch_utils.py b/utils/torch_utils.py
index 1e631b5..27dad00 100644
--- a/utils/torch_utils.py
+++ b/utils/torch_utils.py
@@ -17,6 +17,8 @@ import torch.nn as nn
import torch.nn.functional as F
import torchvision
+import intel_extension_for_pytorch as ipex
+
try:
import thop # for FLOPS computation
except ImportError:
@@ -64,13 +66,18 @@ def select_device(device='', batch_size=None):
# device = 'cpu' or '0' or '0,1,2,3'
s = f'YOLOR 🚀 {git_describe() or date_modified()} torch {torch.__version__} ' # string
cpu = device.lower() == 'cpu'
+ xpu = device.lower() == 'xpu'
if cpu:
os.environ['CUDA_VISIBLE_DEVICES'] = '-1' # force torch.cuda.is_available() = False
+ elif xpu: # non-cpu device requested
+ os.environ['CUDA_VISIBLE_DEVICES'] = '-1' # force torch.cuda.is_availa ble() = False
+ assert torch.xpu.is_available(), f'XPU unavailable, invalid device {dev ice} requested' # check availability
elif device: # non-cpu device requested
os.environ['CUDA_VISIBLE_DEVICES'] = device # set environment variable
assert torch.cuda.is_available(), f'CUDA unavailable, invalid device {device} requested' # check availability
- cuda = not cpu and torch.cuda.is_available()
+ #cuda = not cpu and torch.cuda.is_available()
+ cuda = not cpu and not xpu and torch.cuda.is_available()
if cuda:
n = torch.cuda.device_count()
if n > 1 and batch_size: # check that batch_size is compatible with device_count
@@ -79,11 +86,18 @@ def select_device(device='', batch_size=None):
for i, d in enumerate(device.split(',') if device else range(n)):
p = torch.cuda.get_device_properties(i)
s += f"{'' if i == 0 else space}CUDA:{d} ({p.name}, {p.total_memory / 1024 ** 2}MB)\n" # bytes to MB
+ elif xpu:
+ s += 'XPU\n'
else:
s += 'CPU\n'
logger.info(s.encode().decode('ascii', 'ignore') if platform.system() == 'Windows' else s) # emoji-safe
- return torch.device('cuda:0' if cuda else 'cpu')
+ if cuda:
+ return torch.device('cuda:0')
+ elif xpu:
+ return torch.device('xpu')
+ else:
+ return torch.device('cpu')
def time_synchronized():
@@ -371,4 +385,4 @@ class TracedModel(nn.Module):
def forward(self, x, augment=False, profile=False):
out = self.model(x)
out = self.detect_layer(out)
- return out
\ No newline at end of file
+ return out
```
Download yolov7 and yolov7-tiny models,
```
wget https://github.com/WongKinYiu/yolov7/releases/download/v0.1/yolov7-tiny.pt
wget https://github.com/WongKinYiu/yolov7/releases/download/v0.1/yolov7_training.pt
```
Add custom data and model configuration files for training,
```
vim data/pothole.yaml
```
## Begin content of data/pothole.yaml ##
```
train: ../pothole_dataset/images/train
val: ../pothole_dataset/images/valid
test: ../pothole_dataset/images/test
# Classes
nc: 1 # number of classes
names: ['pothole'] # class names
```
## End of content of data/pothole.yaml ##
YOLOv7 Tiny training configuration,
```
cp cfg/training/yolov7-tiny.yaml cfg/training/yolov7_pothole-tiny.yaml
## modify "nc: 80" to "nc: 1" in cfg/training/yolov7_pothole-tiny.yaml ##
```
YOLOv7 training configuration,
```
cp cfg/training/yolov7.yaml cfg/training/yolov7_pothole.yaml
## modify "nc: 80" to "nc: 1" in cfg/training/yolov7_pothole.yaml ##
```
Train command,
### YOLO V7 Tiny
```
python train.py --epochs 10 --workers 4 --device xpu --batch-size 32 --data data/pothole.yaml --img 640 640 --cfg cfg/training/yolov7_pothole-tiny.yaml --weights 'yolov7-tiny.pt' --name yolov7_tiny_pothole_fixed_res --hyp data/hyp.scratch.tiny.yaml
```
### YOLO V7
```
python train.py --epochs 10 --workers 4 --device xpu --batch-size 16 --data data/pothole.yaml --img 640 640 --cfg cfg/training/yolov7_pothole.yaml --weights 'yolov7_training.pt' --name yolov7_pothole_fixed_res --hyp data/hyp.scratch.custom.yaml
```