Update documentation

This commit is contained in:
Tobias Eidelpes 2023-12-28 16:12:31 +01:00
parent a6ed18303e
commit 2a29b414b1
12 changed files with 8674 additions and 3668 deletions

File diff suppressed because it is too large Load Diff

View File

@ -34,6 +34,14 @@
"np.random.seed(42)" "np.random.seed(42)"
] ]
}, },
{
"cell_type": "markdown",
"id": "4d29e56f-ee81-4f43-96ff-99bb22c52f6a",
"metadata": {},
"source": [
"# Download Metrics from WandB"
]
},
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 2, "execution_count": 2,
@ -70,6 +78,16 @@
"runs_df.to_csv(\"hyp-metrics.csv\")" "runs_df.to_csv(\"hyp-metrics.csv\")"
] ]
}, },
{
"cell_type": "markdown",
"id": "821aeb7d-784b-4e38-b4f8-c49245ee25ce",
"metadata": {},
"source": [
"# Transform Metrics\n",
"\n",
"The column `summary` contains most of the metrics we are interested in (`test/precision`,…) but all of the metrics are in a dictionary in this column."
]
},
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 3, "execution_count": 3,
@ -970,7 +988,7 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython3", "pygments_lexer": "ipython3",
"version": "3.7.15" "version": "3.10.13"
} }
}, },
"nbformat": 4, "nbformat": 4,

View File

@ -1,5 +1,15 @@
{ {
"cells": [ "cells": [
{
"cell_type": "markdown",
"id": "5eca6897-e43c-4358-9281-ab6b1ece871a",
"metadata": {},
"source": [
"# Local Hyperparameter Optimization\n",
"\n",
"This notebook is similar to the `classifier_hyp` notebook, but it runs the hyperparameter optimization locally instead of on Google Colab. The definitive version is the Google Colab one because we run many more iterations and parameter combinations there due to GPU availability."
]
},
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 1, "execution_count": 1,
@ -4636,7 +4646,7 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython3", "pygments_lexer": "ipython3",
"version": "3.7.15" "version": "3.10.13"
} }
}, },
"nbformat": 4, "nbformat": 4,

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,8 @@
# Detector Directory
This directory is mainly composed of code from the following github
repository: [YOLOv7](https://github.com/WongKinYiu/yolov7).
It has some changes, however, mostly relating to the number of
iterations to run for hyperparameter optimization, which was somehow
fixed to `300` by the original authors.

View File

@ -63,7 +63,6 @@ def detect_yolo_only(img_path: str, yolo_path: str):
:param str yolo_path: path to yolo weights :param str yolo_path: path to yolo weights
:returns: tuple of recent image and dict of bounding boxes and :returns: tuple of recent image and dict of bounding boxes and
their predictions their predictions
""" """
img = cv2.imread(img_path) img = cv2.imread(img_path)
@ -112,13 +111,6 @@ def classify(resnet_path, img):
session.run_with_iobinding(io_binding) session.run_with_iobinding(io_binding)
out = torch.tensor(io_binding.copy_outputs_to_cpu()[0]) out = torch.tensor(io_binding.copy_outputs_to_cpu()[0])
# Do inference
# session = onnxruntime.InferenceSession(resnet_path)
# outname = [i.name for i in session.get_outputs()]
# inname = [i.name for i in session.get_inputs()]
# inp = {inname[0]: batch.numpy()}
# out = torch.tensor(np.array(session.run(outname, inp)))[0]
# Apply softmax to get percentage confidence of classes # Apply softmax to get percentage confidence of classes
out = torch.nn.functional.softmax(out, dim=1)[0] * 100 out = torch.nn.functional.softmax(out, dim=1)[0] * 100
return out return out
@ -201,12 +193,9 @@ def get_boxes(yolo_path, image):
session.run_with_iobinding(io_binding) session.run_with_iobinding(io_binding)
outs = torch.tensor(io_binding.copy_outputs_to_cpu()[0]) outs = torch.tensor(io_binding.copy_outputs_to_cpu()[0])
# out = torch.tensor(np.array(session.run(outname, inp)))[0]
# print(out.shape)
# Apply NMS to results # Apply NMS to results
preds_nms = apply_nms([outs])[0] preds_nms = apply_nms([outs])[0]
#preds_nms = outs
# Convert boxes from resized img to original img # Convert boxes from resized img to original img
xyxy_boxes = preds_nms[:, [1, 2, 3, 4]] # xmin, ymin, xmax, ymax xyxy_boxes = preds_nms[:, [1, 2, 3, 4]] # xmin, ymin, xmax, ymax

View File

@ -1,64 +1,5 @@
{ {
"cells": [ "cells": [
{
"cell_type": "markdown",
"id": "945c9b80",
"metadata": {},
"source": [
"# Table of contents\n",
"1. [Introduction](#introduction)\n",
"2. [Aggregate Model Evaluation](#modelevaluation)\n",
" 1. [Loading the dataset](#modeload)\n",
" 2. [Perform detections](#modeldetect)\n",
" 3. [Evaluate detections](#modeldetectionseval)\n",
" 4. [Calculate results and plot them](#modelshowresults)\n",
" 5. [View dataset in fiftyone](#modelfiftyonesession)"
]
},
{
"cell_type": "markdown",
"id": "01339680",
"metadata": {},
"source": [
"## Introduction <a name=\"introduction\"></a>\n",
"\n",
"This notebook loads the test dataset in YOLOv5 format from disk and evaluates the model's performance."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "ff25695e",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/home/zenon/.local/share/miniconda3/lib/python3.7/site-packages/requests/__init__.py:104: RequestsDependencyWarning: urllib3 (1.26.13) or chardet (5.1.0)/charset_normalizer (2.0.4) doesn't match a supported version!\n",
" RequestsDependencyWarning)\n"
]
}
],
"source": [
"import fiftyone as fo\n",
"from PIL import Image\n",
"from detection import detect\n",
"from detection import detect_yolo_only"
]
},
{
"cell_type": "markdown",
"id": "86a5e832",
"metadata": {},
"source": [
"## Aggregate Model Evaluation <a name=\"modelevaluation\"></a>\n",
"\n",
"First, load the dataset from the directory containing the images and the labels in YOLOv5 format.\n",
"\n",
"### Loading the dataset <a name=\"modeload\"></a>"
]
},
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
@ -237,76 +178,6 @@
"The code for the LaTeX table of the classification report can be printed by first converting the results to a pandas DataFrame and then calling the `to_latex()` method of the DataFrame. This code can then be inserted into the LaTeX document." "The code for the LaTeX table of the classification report can be printed by first converting the results to a pandas DataFrame and then calling the `to_latex()` method of the DataFrame. This code can then be inserted into the LaTeX document."
] ]
}, },
{
"cell_type": "code",
"execution_count": 20,
"id": "f7ad63b0",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\\begin{tabular}{lrrrr}\n",
"\\toprule\n",
"{} & precision & recall & f1-score & support \\\\\n",
"\\midrule\n",
"Healthy & 0.679 & 0.525 & 0.592 & 766.0 \\\\\n",
"Stressed & 0.646 & 0.447 & 0.529 & 494.0 \\\\\n",
"micro avg & 0.667 & 0.494 & 0.568 & 1260.0 \\\\\n",
"macro avg & 0.663 & 0.486 & 0.560 & 1260.0 \\\\\n",
"weighted avg & 0.666 & 0.494 & 0.567 & 1260.0 \\\\\n",
"\\bottomrule\n",
"\\end{tabular}\n",
"\n",
"0.3374377395168513\n"
]
}
],
"source": [
"results_df = pd.DataFrame(results.report()).transpose().round(3)\n",
"\n",
"# Export DataFrame to LaTeX tabular environment\n",
"print(results_df.to_latex())\n",
"# YOLO second hyp with Resnet optimized and relabeled dataset\n",
"print(results.mAP())"
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "d73cca50",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\\begin{tabular}{lrrrr}\n",
"\\toprule\n",
"{} & precision & recall & f1-score & support \\\\\n",
"\\midrule\n",
"Healthy & 0.653 & 0.604 & 0.628 & 766.0 \\\\\n",
"Stressed & 0.566 & 0.492 & 0.527 & 494.0 \\\\\n",
"micro avg & 0.620 & 0.560 & 0.589 & 1260.0 \\\\\n",
"macro avg & 0.610 & 0.548 & 0.577 & 1260.0 \\\\\n",
"weighted avg & 0.619 & 0.560 & 0.588 & 1260.0 \\\\\n",
"\\bottomrule\n",
"\\end{tabular}\n",
"\n",
"0.36171308664990176\n"
]
}
],
"source": [
"results_df = pd.DataFrame(results.report()).transpose().round(3)\n",
"\n",
"# Export DataFrame to LaTeX tabular environment\n",
"print(results_df.to_latex())\n",
"# YOLO original with Resnet optimized and relabeled dataset\n",
"print(results.mAP())"
]
},
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 14, "execution_count": 14,
@ -338,7 +209,7 @@
"\n", "\n",
"# Export DataFrame to LaTeX tabular environment\n", "# Export DataFrame to LaTeX tabular environment\n",
"print(results_df.to_latex())\n", "print(results_df.to_latex())\n",
"# YOLO optimized with Resnet optimized and relabeled dataset\n", "# YOLO original with Resnet original and relabeled dataset\n",
"print(results.mAP())" "print(results.mAP())"
] ]
}, },
@ -373,154 +244,10 @@
"\n", "\n",
"# Export DataFrame to LaTeX tabular environment\n", "# Export DataFrame to LaTeX tabular environment\n",
"print(results_df.to_latex())\n", "print(results_df.to_latex())\n",
"# YOLO original with Resnet original and relabeled dataset\n", "# YOLO optimized with Resnet optimized and relabeled dataset\n",
"print(results.mAP())" "print(results.mAP())"
] ]
}, },
{
"cell_type": "code",
"execution_count": 10,
"id": "b14d2b25",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\\begin{tabular}{lrrrr}\n",
"\\toprule\n",
"{} & precision & recall & f1-score & support \\\\\n",
"\\midrule\n",
"Healthy & 0.841 & 0.759 & 0.798 & 663.0 \\\\\n",
"Stressed & 0.726 & 0.810 & 0.766 & 484.0 \\\\\n",
"micro avg & 0.786 & 0.780 & 0.783 & 1147.0 \\\\\n",
"macro avg & 0.784 & 0.784 & 0.782 & 1147.0 \\\\\n",
"weighted avg & 0.793 & 0.780 & 0.784 & 1147.0 \\\\\n",
"\\bottomrule\n",
"\\end{tabular}\n",
"\n"
]
}
],
"source": [
"results_df = pd.DataFrame(results.report()).transpose().round(3)\n",
"\n",
"# Export DataFrame to LaTeX tabular environment\n",
"print(results_df.to_latex())\n",
"# YOLO original with Resnet original and new dataset"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "900e9014",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\\begin{tabular}{lrrrr}\n",
"\\toprule\n",
"{} & precision & recall & f1-score & support \\\\\n",
"\\midrule\n",
"Healthy & 0.674 & 0.721 & 0.696 & 662.0 \\\\\n",
"Stressed & 0.616 & 0.543 & 0.577 & 488.0 \\\\\n",
"micro avg & 0.652 & 0.645 & 0.649 & 1150.0 \\\\\n",
"macro avg & 0.645 & 0.632 & 0.637 & 1150.0 \\\\\n",
"weighted avg & 0.649 & 0.645 & 0.646 & 1150.0 \\\\\n",
"\\bottomrule\n",
"\\end{tabular}\n",
"\n",
"0.49320073714096757\n"
]
}
],
"source": [
"results_df = pd.DataFrame(results.report()).transpose().round(3)\n",
"\n",
"# Export DataFrame to LaTeX tabular environment\n",
"print(results_df.to_latex())\n",
"print(results.mAP())\n",
"# YOLO original and Resnet final with old dataset"
]
},
{
"cell_type": "code",
"execution_count": 51,
"id": "24df35b4",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" precision recall f1-score support\n",
"\n",
" Healthy 0.82 0.74 0.78 662\n",
" Stressed 0.71 0.78 0.74 488\n",
"\n",
" micro avg 0.77 0.76 0.76 1150\n",
" macro avg 0.77 0.76 0.76 1150\n",
"weighted avg 0.77 0.76 0.77 1150\n",
"\n",
"0.6225848121901868\n"
]
}
],
"source": [
"# Print a classification report for all classes\n",
"results.print_report()\n",
"\n",
"print(results.mAP())\n",
"# YOLO original and Resnet original with old dataset"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "a6bb272a",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" precision recall f1-score support\n",
"\n",
" Healthy 0.66 0.64 0.65 662\n",
" Stressed 0.68 0.54 0.60 488\n",
"\n",
" micro avg 0.67 0.60 0.63 1150\n",
" macro avg 0.67 0.59 0.63 1150\n",
"weighted avg 0.67 0.60 0.63 1150\n",
"\n",
"0.44258882390400406\n",
"\\begin{tabular}{lrrrr}\n",
"\\toprule\n",
"{} & precision & recall & f1-score & support \\\\\n",
"\\midrule\n",
"Healthy & 0.664 & 0.640 & 0.652 & 662.0 \\\\\n",
"Stressed & 0.680 & 0.539 & 0.601 & 488.0 \\\\\n",
"micro avg & 0.670 & 0.597 & 0.631 & 1150.0 \\\\\n",
"macro avg & 0.672 & 0.590 & 0.626 & 1150.0 \\\\\n",
"weighted avg & 0.670 & 0.597 & 0.630 & 1150.0 \\\\\n",
"\\bottomrule\n",
"\\end{tabular}\n",
"\n"
]
}
],
"source": [
"# Print a classification report for all classes\n",
"results.print_report()\n",
"results_df = pd.DataFrame(results.report()).transpose().round(3)\n",
"\n",
"print(results.mAP())\n",
"print(results_df.to_latex())\n",
"# YOLO final and Resnet final with old dataset"
]
},
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 35, "execution_count": 35,
@ -676,7 +403,7 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython3", "pygments_lexer": "ipython3",
"version": "3.7.15" "version": "3.10.13"
} }
}, },
"nbformat": 4, "nbformat": 4,

View File

@ -569,7 +569,7 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython3", "pygments_lexer": "ipython3",
"version": "3.7.15" "version": "3.10.13"
} }
}, },
"nbformat": 4, "nbformat": 4,

View File

@ -21,6 +21,8 @@ string video_pipeline(int capture_width, int capture_height, int framerate,
"appsink"; "appsink";
} }
// Calls nvarguscamerasrc to take a 1s video at maximum resolution,
// flips the video and then captures one image and writes it to disk.
int main() { int main() {
int capture_width = 3264; int capture_width = 3264;
int capture_height = 2464; int capture_height = 2464;

View File

@ -25,6 +25,16 @@ pred = manager.dict()
def get_pred(): def get_pred():
"""Calls the detection and classification models on current.jpg
and stores the predictions in the global variable `pred` in the
following format:
{
'image': base64 encoded image,
'0': [state, timestamp, time since state < 3],
'1': [state, timestamp, time since state < 3],
}
"""
tmp = deepcopy(pred) tmp = deepcopy(pred)
take_image() take_image()
logging.debug('Starting image classification') logging.debug('Starting image classification')
@ -41,15 +51,6 @@ def get_pred():
'Finished drawing bounding boxes. Saving to current_bbox.jpg ...') 'Finished drawing bounding boxes. Saving to current_bbox.jpg ...')
cv2.imwrite('current_bbox.jpg', bbox_img) cv2.imwrite('current_bbox.jpg', bbox_img)
# Clear superfluous bboxes if less detected
# if len(preds) < len(pred):
# logging.debug(
# 'Current round contains less bboxes than previous round: old: %s\nnew: %s',
# json.dumps(preds.copy()), json.dumps(pred.copy()))
# for key in pred:
# if key not in preds:
# pred.pop(key)
pred.clear() pred.clear()
for idx, row in preds.iterrows(): for idx, row in preds.iterrows():
new = [] new = []

View File

@ -1,4 +1,12 @@
def convert_to_yolo(bbox, width, height): def convert_to_yolo(bbox, width, height):
"""Transform bounding boxes in xmin, ymin, xmax, ymax format to
YOLO format.
:param bbox: bounding box in xmin, ymin, xmax, ymax format
:param width: width of the image
:param height: height of the image
:returns List[int]: bounding box in YOLO format
"""
modified = bbox.copy() modified = bbox.copy()
modified['xmin%'] = round(bbox['xmin'] / width * 100, 2) modified['xmin%'] = round(bbox['xmin'] / width * 100, 2)
modified['ymin%'] = round(bbox['ymin'] / height * 100, 2) modified['ymin%'] = round(bbox['ymin'] / height * 100, 2)

View File

@ -2,6 +2,14 @@ import cv2
def draw_boxes(image, bboxes): def draw_boxes(image, bboxes):
"""Draw bounding boxes in xmin, ymin, xmax, ymax format onto
image.
:param image: opencv2 image object in BGR
:param List bboxes: bounding boxes in xmin, ymin, xmax, ymax
format
:returns: img with bounding boxes drawn
"""
img = image.copy() img = image.copy()
for idx, bbox in enumerate(bboxes): for idx, bbox in enumerate(bboxes):
xmin, ymin, xmax, ymax = bbox xmin, ymin, xmax, ymax = bbox