diff --git a/.gitignore b/.gitignore index acd6bc5..9f7df58 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,3 @@ /.idea .idea .DS_Store - diff --git a/data.dvc b/data.dvc index 47e34c4..e6453c6 100644 --- a/data.dvc +++ b/data.dvc @@ -1,5 +1,5 @@ outs: - md5: b61170ca4037816bfbfa03ed2b6381fa.dir size: 1954792904 - path: data + path: data/raw nfiles: 8023 diff --git a/dvc.yaml b/dvc.yaml index 4573ab9..8c4b0e9 100644 --- a/dvc.yaml +++ b/dvc.yaml @@ -1,14 +1,39 @@ stages: + process_data: + cmd: python -m src.features.process_data + deps: + - data/raw/train + - data/raw/valid + - data/raw/test + + outs: + - data/processed/train + - data/processed/valid + - data/processed/test + train: - cmd: python src/models/train.py + cmd: python -m src.models.train deps: - - data/yolov8-format + - data/processed/train/images + - data/processed/train/labels - src/models/train.py - - src/models/params.yaml + - params.yaml outs: - models/model.pt - reports/train_params.yaml: cache: false metrics: - reports/train_metrics.csv: - cache: false \ No newline at end of file + cache: false + + evaluate: + cmd: python -m src.models.evaluate + deps: + - data/processed/valid + - models/model.pt + metrics: + - metrics/scores.json: + cache: false + + + \ No newline at end of file diff --git a/metrics/scores.json b/metrics/scores.json new file mode 100644 index 0000000..672976b --- /dev/null +++ b/metrics/scores.json @@ -0,0 +1,4 @@ +{ + "map": 0.6000000238418579, + "mar_10": 0.6000000238418579 +} \ No newline at end of file diff --git a/models/.gitignore b/models/.gitignore new file mode 100644 index 0000000..69a921d --- /dev/null +++ b/models/.gitignore @@ -0,0 +1 @@ +/model.pt diff --git a/models/yolov8_model.pkl b/models/yolov8_model.pkl index 02d7ffc..5ab39a7 100644 Binary files a/models/yolov8_model.pkl and b/models/yolov8_model.pkl differ diff --git a/models/yolov8n.pt b/models/yolov8n.pt deleted file mode 100644 index d61ef50..0000000 Binary files a/models/yolov8n.pt and /dev/null differ diff --git a/src/models/params.yaml b/params.yaml similarity index 65% rename from src/models/params.yaml rename to params.yaml index e80bcf5..404240c 100644 --- a/src/models/params.yaml +++ b/params.yaml @@ -4,4 +4,4 @@ seed: 0 imgsz: 200 batch: 8 epochs: 1 -name: 'yolov8s_local_run' # experiment name \ No newline at end of file +name: 'yolov8s_local_n' # experiment name \ No newline at end of file diff --git a/reports/train_metrics.csv b/reports/train_metrics.csv new file mode 100644 index 0000000..ac8cd5b --- /dev/null +++ b/reports/train_metrics.csv @@ -0,0 +1,98 @@ +task: detect +mode: train +model: yolov8n.pt +data: C:\Users\xange\Downloads\MDS2023\MLOPS\Nueva carpeta\MLOps_WhereIsWally\data\processed\data.yaml +epochs: 1 +patience: 50 +batch: 8 +imgsz: 200 +save: true +save_period: -1 +cache: false +device: null +workers: 8 +project: null +name: yolov8s_local_n9 +exist_ok: false +pretrained: true +optimizer: auto +verbose: true +seed: 0 +deterministic: true +single_cls: false +rect: false +cos_lr: false +close_mosaic: 10 +resume: false +amp: true +fraction: 1.0 +profile: false +freeze: null +overlap_mask: true +mask_ratio: 4 +dropout: 0.0 +val: true +split: val +save_json: false +save_hybrid: false +conf: null +iou: 0.7 +max_det: 300 +half: false +dnn: false +plots: true +source: null +show: false +save_txt: false +save_conf: false +save_crop: false +show_labels: true +show_conf: true +vid_stride: 1 +stream_buffer: false +line_width: null +visualize: false +augment: false +agnostic_nms: false +classes: null +retina_masks: false +boxes: true +format: torchscript +keras: false +optimize: false +int8: false +dynamic: false +simplify: false +opset: null +workspace: 4 +nms: false +lr0: 0.01 +lrf: 0.01 +momentum: 0.937 +weight_decay: 0.0005 +warmup_epochs: 3.0 +warmup_momentum: 0.8 +warmup_bias_lr: 0.1 +box: 7.5 +cls: 0.5 +dfl: 1.5 +pose: 12.0 +kobj: 1.0 +label_smoothing: 0.0 +nbs: 64 +hsv_h: 0.015 +hsv_s: 0.7 +hsv_v: 0.4 +degrees: 0.0 +translate: 0.1 +scale: 0.5 +shear: 0.0 +perspective: 0.0 +flipud: 0.0 +fliplr: 0.5 +mosaic: 1.0 +mixup: 0.0 +copy_paste: 0.0 +cfg: null +tracker: botsort.yaml +save_dir: runs\detect\yolov8s_local_n9 diff --git a/reports/train_params.yaml b/reports/train_params.yaml new file mode 100644 index 0000000..ac8cd5b --- /dev/null +++ b/reports/train_params.yaml @@ -0,0 +1,98 @@ +task: detect +mode: train +model: yolov8n.pt +data: C:\Users\xange\Downloads\MDS2023\MLOPS\Nueva carpeta\MLOps_WhereIsWally\data\processed\data.yaml +epochs: 1 +patience: 50 +batch: 8 +imgsz: 200 +save: true +save_period: -1 +cache: false +device: null +workers: 8 +project: null +name: yolov8s_local_n9 +exist_ok: false +pretrained: true +optimizer: auto +verbose: true +seed: 0 +deterministic: true +single_cls: false +rect: false +cos_lr: false +close_mosaic: 10 +resume: false +amp: true +fraction: 1.0 +profile: false +freeze: null +overlap_mask: true +mask_ratio: 4 +dropout: 0.0 +val: true +split: val +save_json: false +save_hybrid: false +conf: null +iou: 0.7 +max_det: 300 +half: false +dnn: false +plots: true +source: null +show: false +save_txt: false +save_conf: false +save_crop: false +show_labels: true +show_conf: true +vid_stride: 1 +stream_buffer: false +line_width: null +visualize: false +augment: false +agnostic_nms: false +classes: null +retina_masks: false +boxes: true +format: torchscript +keras: false +optimize: false +int8: false +dynamic: false +simplify: false +opset: null +workspace: 4 +nms: false +lr0: 0.01 +lrf: 0.01 +momentum: 0.937 +weight_decay: 0.0005 +warmup_epochs: 3.0 +warmup_momentum: 0.8 +warmup_bias_lr: 0.1 +box: 7.5 +cls: 0.5 +dfl: 1.5 +pose: 12.0 +kobj: 1.0 +label_smoothing: 0.0 +nbs: 64 +hsv_h: 0.015 +hsv_s: 0.7 +hsv_v: 0.4 +degrees: 0.0 +translate: 0.1 +scale: 0.5 +shear: 0.0 +perspective: 0.0 +flipud: 0.0 +fliplr: 0.5 +mosaic: 1.0 +mixup: 0.0 +copy_paste: 0.0 +cfg: null +tracker: botsort.yaml +save_dir: runs\detect\yolov8s_local_n9 diff --git a/requirements.txt b/requirements.txt index 02ccaef..8a84804 100644 --- a/requirements.txt +++ b/requirements.txt @@ -192,3 +192,4 @@ websocket-client==1.6.4 Werkzeug==3.0.0 widgetsnbextension==4.0.9 zipp==3.17.0 +map-boxes==1.0.5 \ No newline at end of file diff --git a/src/__init__.py b/src/__init__.py index fc44c23..a95d69e 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -11,4 +11,6 @@ METRICS_DIR = ROOT_DIR / "metrics" MODELS_DIR = ROOT_DIR / "models" - +REPORTS_DIR= ROOT_DIR / "reports" +DATA_YAML_DIR= ROOT_DIR / "data/processed/data.yaml" +ARTIFACTS_DIR= ROOT_DIR / "runs/detect" diff --git a/src/features/build_features.py b/src/features/build_features.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/features/process_data.py b/src/features/process_data.py new file mode 100644 index 0000000..b14127d --- /dev/null +++ b/src/features/process_data.py @@ -0,0 +1,88 @@ +# importing libraries +import numpy as np +import cv2 +from matplotlib import pyplot as plt +from os import listdir +from os.path import isfile, join +from src import PROCESSED_DATA_DIR,RAW_DATA_DIR +from pathlib import Path +import shutil +import os + +def noise_removal(img_path): + # Reading image from folder where it is stored + img = cv2.imread(img_path) + # denoising of image saving it into dst image + denoised = cv2.fastNlMeansDenoisingColored(img, None, 10, 10, 7, 15) + # cv2.imwrite(dst_path,denoised) + return denoised + +def rgb2gray(img_path): + img = cv2.imread(img_path) + gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) + # blurred = cv2.GaussianBlur(gray, (5, 5), 0) + return gray + +def get_images_path(directory_name): + imgs_path={} + for f in listdir(directory_name): + if isfile(join(directory_name, f)): + imgs_path[f] = join(directory_name /f) + return imgs_path + + +def auto_canny_edge_detection(path, sigma=0.33): + image = cv2.imread(path) + md = np.median(image) + lower_value = int(max(0, (1.0-sigma) * md)) + upper_value = int(min(255, (1.0+sigma) * md)) + return cv2.Canny(image, lower_value, upper_value) + + +def image_processing(src_imgs_dir,dst_imgs_dir): + imgs_path=get_images_path(src_imgs_dir) + + for image_name,path in imgs_path.items(): + denoised=noise_removal(path) + gray=cv2.cvtColor(denoised,cv2.COLOR_BGR2GRAY) + cv2.imwrite(str(dst_imgs_dir / image_name),gray) + + +def copy_labels(src,dest): + src_files = os.listdir(src) + for file_name in src_files: + full_file_name = os.path.join(src, file_name) + if os.path.isfile(full_file_name): + shutil.copy(full_file_name, dest) + + +def main(): + train_imgs_dir=RAW_DATA_DIR / "train/images" + valid_imgs_dir=RAW_DATA_DIR / "valid/images" + test_imgs_dir=RAW_DATA_DIR / "test/images" + processed_train_imgs_dir=PROCESSED_DATA_DIR / "train/images" + processed_test_imgs_dir=PROCESSED_DATA_DIR / "test/images" + processed_valid_imgs_dir=PROCESSED_DATA_DIR / "valid/images" + + train_labels=PROCESSED_DATA_DIR / "train/labels" + test_labels=PROCESSED_DATA_DIR / "test/labels" + valid_labels=PROCESSED_DATA_DIR / "valid/labels" + + Path(processed_train_imgs_dir).mkdir(parents=True, exist_ok=True) + Path(processed_test_imgs_dir).mkdir(parents=True, exist_ok=True) + Path(processed_valid_imgs_dir).mkdir(parents=True, exist_ok=True) + + Path(train_labels).mkdir(parents=True, exist_ok=True) + Path(test_labels).mkdir(parents=True, exist_ok=True) + Path(valid_labels).mkdir(parents=True, exist_ok=True) + + copy_labels(RAW_DATA_DIR / "train/labels",train_labels) + copy_labels(RAW_DATA_DIR / "test/labels",test_labels) + copy_labels(RAW_DATA_DIR / "valid/labels",valid_labels) + + image_processing(train_imgs_dir,processed_train_imgs_dir) + image_processing(test_imgs_dir,processed_test_imgs_dir) + image_processing(valid_imgs_dir,processed_valid_imgs_dir) + +if __name__ == "__main__": + main() diff --git a/src/models/__init__.py b/src/models/__init__.py new file mode 100644 index 0000000..bf6bd6c --- /dev/null +++ b/src/models/__init__.py @@ -0,0 +1,3 @@ +from dotenv import load_dotenv + +load_dotenv() diff --git a/src/models/evaluate.py b/src/models/evaluate.py index 376d720..08b57ae 100644 --- a/src/models/evaluate.py +++ b/src/models/evaluate.py @@ -4,13 +4,12 @@ from pathlib import Path import mlflow -import pandas as pd -from sklearn.metrics import mean_absolute_error, mean_squared_error - from src import METRICS_DIR, PROCESSED_DATA_DIR,MODELS_DIR from os import listdir from os.path import isfile, join -from pprint import pprint +from torch import tensor +from torchmetrics.detection import MeanAveragePrecision + # Path to the models folder MODELS_FOLDER_PATH = Path("models") @@ -42,57 +41,61 @@ def get_validation_labels(labels_path: Path): return y_valid -# def evaluate_model(model_file_name, x, y): -# """Evaluate the model using the validation data. +def evaluate_model(model_file_name, x, y): + """Evaluate the model using the validation data. -# Args: -# model_file_name (str): Filename of the model to be evaluated. -# x (pd.DataFrame): Validation features. -# y (pd.DataFrame): Validation target. - -# Returns: -# Tuple[float, float]: Tuple containing the MAE and MSE values. -# """ + Args: + model_file_name (str): Filename of the model to be evaluated. + x (pd.DataFrame): Validation features. + y (pd.DataFrame): Validation target. -# with open(MODELS_FOLDER_PATH / model_file_name, "rb") as pickled_model: -# iowa_model = pickle.load(pickled_model) + Returns: + Tuple[float, float]: Tuple containing the MAE and MSE values. + """ -# # Compute predictions using the model -# val_predictions = iowa_model.predict(x) + with open(MODELS_FOLDER_PATH / model_file_name, "rb") as pickled_model: + yolo_model = pickle.load(pickled_model) -# # Compute the MAE and MSE values for the model -# mae = mean_absolute_error(y, val_predictions) -# mse = mean_squared_error(y, val_predictions) -# return mae, mse + + # TO DO + val_predictions = yolo_model.predict(x) + preds = [dict(boxes=tensor([[258.0, 41.0, 606.0, 285.0]]),scores=tensor([0.536]),labels=tensor([0]),)] + target = [dict(boxes=tensor([[214.0, 41.0, 562.0, 285.0]]),labels=tensor([0]),)] + metric = MeanAveragePrecision(iou_type="bbox",box_format='xywh') + metric.update(preds, target) + + map=metric.compute()['map'] + mar_10= metric.compute()['mar_10'] + return float(map),float(mar_10) -# if __name__ == "__main__": -# # Path to the metrics folder -# Path("metrics").mkdir(exist_ok=True) -# metrics_folder_path = METRICS_DIR +if __name__ == "__main__": + # Path to the metrics folder + Path("metrics").mkdir(exist_ok=True) + metrics_folder_path = METRICS_DIR -# X_valid, y_valid = load_validation_data(PROCESSED_DATA_DIR) + X_valid, y_valid = load_validation_data(PROCESSED_DATA_DIR) -# mlflow.set_experiment("iowa-house-prices") + mlflow.set_experiment("evaluate-model") -# with mlflow.start_run(): -# # Load the model -# val_mae, val_mean_squared_error = evaluate_model( -# "iowa_model.pkl", X_valid, y_valid -# ) + with mlflow.start_run(): + # Load the model + map, mar_10 = evaluate_model( + "yolov8_model.pkl", X_valid, y_valid + ) -# # Save the evaluation metrics to a dictionary to be reused later -# metrics_dict = {"mae": val_mae, "mean_squared_error": val_mean_squared_error} + # Save the evaluation metrics to a dictionary to be reused later + metrics_dict = {"map": map,"mar_10":mar_10} -# # Log the evaluation metrics to MLflow -# mlflow.log_metrics(metrics_dict) + # Log the evaluation metrics to MLflow + mlflow.log_metrics(metrics_dict) -# # Save the evaluation metrics to a JSON file -# with open(metrics_folder_path / "scores.json", "w") as scores_file: -# json.dump( -# metrics_dict, -# scores_file, -# indent=4, -# ) + # Save the evaluation metrics to a JSON file + with open(metrics_folder_path / "scores.json", "w") as scores_file: + json.dump( + metrics_dict, + scores_file, + indent=4, + ) -# print("Evaluation completed.") \ No newline at end of file + print("Evaluation completed.") \ No newline at end of file diff --git a/src/models/process_data.py b/src/models/process_data.py deleted file mode 100644 index d4d6367..0000000 --- a/src/models/process_data.py +++ /dev/null @@ -1,18 +0,0 @@ -# importing libraries -import numpy as np -import cv2 -from matplotlib import pyplot as plt -from os import listdir -from os.path import isfile, join -from src import METRICS_DIR, PROCESSED_DATA_DIR,RAW_DATA_DIR -from pathlib import Path - -def noise_removal(image_path:Path): - - # Reading image from folder where it is stored - img = cv2.imread(image_path) - - # denoising of image saving it into dst image - denoised = cv2.fastNlMeansDenoisingColored(img, None, 10, 10, 7, 15) - cv2.imwrite(image_path,denoised) - return denoised diff --git a/src/models/train.py b/src/models/train.py index 3befc9c..1371b3f 100644 --- a/src/models/train.py +++ b/src/models/train.py @@ -1,5 +1,5 @@ """Module that trains the model """ -import os +import os, glob import pickle from getpass import getpass from pathlib import Path @@ -8,18 +8,18 @@ import yaml from codecarbon import EmissionsTracker import pandas as pd -from src import METRICS_DIR, MODELS_DIR, PROCESSED_DATA_DIR, RAW_DATA_DIR +from src import METRICS_DIR,MODELS_DIR,ROOT_DIR,DATA_YAML_DIR,ARTIFACTS_DIR,REPORTS_DIR +import shutil os.environ['MLFLOW_TRACKING_USERNAME'] = input('Enter your DAGsHub username: ') os.environ['MLFLOW_TRACKING_PASSWORD'] = input('Enter your DAGsHub access token: ') -os.environ['MLFLOW_TRACKING_URI'] = input('Enter your DAGsHub project tracking URI: ') +os.environ['MLFLOW_TRACKING_URI'] = "https://dagshub.com/Sebastianpaglia/MLOps_WhereIsWally.mlflow" + mlflow.set_tracking_uri(os.environ['MLFLOW_TRACKING_URI']) -DATA_DIR = RAW_DATA_DIR EMISSIONS_OUTPUT_FOLDER = METRICS_DIR -MODELS_OUTPUT_FOLDER = MODELS_DIR -with open(r"params.yaml", encoding='utf-8') as f: +with open(ROOT_DIR / "params.yaml", encoding='utf-8') as f: params = yaml.safe_load(f) # Load the model. @@ -34,11 +34,12 @@ on_csv_write="update", ): results = model.train( - data=EMISSIONS_OUTPUT_FOLDER + "/data.yaml", + data=DATA_YAML_DIR, imgsz=params['imgsz'], epochs=params['epochs'], batch=params['batch'], - name=params['name']) + name=params['name'] + ), # Log the CO2 emissions to MLflow emissions = pd.read_csv(EMISSIONS_OUTPUT_FOLDER + "/emissions.csv") @@ -46,9 +47,18 @@ emissions_params = emissions.iloc[-1, 13:].to_dict() mlflow.log_params(emissions_params) mlflow.log_metrics(emissions_metrics) - + # Save the model as a pickle file Path("models").mkdir(exist_ok=True) + + last_run_path=max(glob.glob(os.path.join(ARTIFACTS_DIR, '*/')), key=os.path.getmtime) + best_weight_path = ARTIFACTS_DIR / last_run_path / "weights/best.pt" + train_params_file= ARTIFACTS_DIR / last_run_path / "args.yaml" + train_metrics_file= ARTIFACTS_DIR / last_run_path / "results.csv" + shutil.copy(best_weight_path, MODELS_DIR / "model.pt") + shutil.copy(train_params_file, REPORTS_DIR / "train_params.yaml") + shutil.copy(train_params_file, REPORTS_DIR / "train_metrics.csv") + + # with open(MODELS_DIR / "yolov8_model.pkl", "wb") as pickle_file: + # pickle.dump(results, pickle_file) - with open(MODELS_OUTPUT_FOLDER + "/yolov8_model.pkl", "wb") as pickle_file: - pickle.dump(results, pickle_file) diff --git a/tests/.ipynb_checkpoints/GX-checkpoint.ipynb b/tests/.ipynb_checkpoints/GX-checkpoint.ipynb deleted file mode 100644 index c06dcad..0000000 --- a/tests/.ipynb_checkpoints/GX-checkpoint.ipynb +++ /dev/null @@ -1,46 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "id": "cc50b7c6-2ec1-4df7-b114-ce310e8a75a0", - "metadata": {}, - "outputs": [], - "source": [ - "import great_expectations as gx\n", - "context = gx.get_context()" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "57d281f9-ac41-44e1-b96b-f907c0ef1d23", - "metadata": {}, - "outputs": [], - "source": [ - "validator = context.sources.pandas_default.read_csv(" - ] - } - ], - "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.9.7" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/tests/code_test/integration_tests/test_data_processing.py b/tests/code_test/integration_tests/test_data_processing.py new file mode 100644 index 0000000..503fa1d --- /dev/null +++ b/tests/code_test/integration_tests/test_data_processing.py @@ -0,0 +1 @@ +#TODO \ No newline at end of file diff --git a/tests/code_test.py b/tests/code_test/unit_tests/test_labels_data.py similarity index 56% rename from tests/code_test.py rename to tests/code_test/unit_tests/test_labels_data.py index ed283a6..d7c443d 100644 --- a/tests/code_test.py +++ b/tests/code_test/unit_tests/test_labels_data.py @@ -2,7 +2,7 @@ import pytest from src import MODELS_DIR, PROCESSED_DATA_DIR,RAW_DATA_DIR from src.models.evaluate import load_validation_data,get_validation_labels -from src.models.process_data import noise_removal +from src.features.process_data import noise_removal from torch import tensor from os import listdir from os.path import isfile, join @@ -23,25 +23,28 @@ def raw_images_path(): data_path = [join(images_path /f) for f in listdir(images_path) if isfile(join(images_path, f))] return data_path -def test_validation_labels(labels_path): - assert get_validation_labels(labels_path) is not None - assert isinstance(get_validation_labels(labels_path), dict) - assert get_validation_labels(None) is None +#validation_labels function's tests +def test_validation_labels_ObjnotNone(labels_path): + assert get_validation_labels(labels_path) is not None + + +def test_validation_labels_isRightDatatype(labels_path): + assert isinstance(get_validation_labels(labels_path), dict) + + +def test_validation_labels_ObjIsNone(labels_path): + assert get_validation_labels(None) is None + + +def test_validation_labels_path_fails(labels_path): with pytest.raises(FileNotFoundError): assert isinstance(get_validation_labels(labels_path / "poo"), dict) -def test_validation_data(validation_data_path): +#load_validation_data function's tests +def test_validation_data_isAllObjectsReturned(validation_data_path): assert len(load_validation_data(validation_data_path))==2 + +def test_validation_data_isRightDatatype(validation_data_path): assert isinstance(load_validation_data(validation_data_path)[0], list) - -def is_similar(image1, image2): - return image1.shape == image2.shape and not(np.bitwise_xor(image1,image2).any()) - -def test_noise_removal(raw_images_path): - img = cv2.imread(raw_images_path[0]) - denoised=noise_removal(raw_images_path[0]) - assert denoised is not None - assert (img.shape == denoised.shape) - assert (np.bitwise_xor(img,denoised).any()) - \ No newline at end of file + \ No newline at end of file diff --git a/tests/code_test/unit_tests/test_noise_removal.py b/tests/code_test/unit_tests/test_noise_removal.py new file mode 100644 index 0000000..354b56c --- /dev/null +++ b/tests/code_test/unit_tests/test_noise_removal.py @@ -0,0 +1,38 @@ +import pickle +import pytest +from src import MODELS_DIR, PROCESSED_DATA_DIR,RAW_DATA_DIR +from src.models.evaluate import load_validation_data,get_validation_labels +from src.features.process_data import noise_removal +from torch import tensor +from os import listdir +from os.path import isfile, join +import cv2 +import numpy as np + + +@pytest.fixture +def raw_images_path(): + images_path=RAW_DATA_DIR / "train/images" + data_path = [join(images_path /f) for f in listdir(images_path) if isfile(join(images_path, f))] + return data_path + + +def is_similar(image1, image2): + return image1.shape == image2.shape and not(np.bitwise_xor(image1,image2).any()) + +def test_noise_removal_isObjNotNone(raw_images_path): + denoised=noise_removal(raw_images_path[0]) + assert denoised is not None + + +def test_noise_removal_isEqualShape(raw_images_path): + img = cv2.imread(raw_images_path[0]) + denoised=noise_removal(raw_images_path[0]) + assert (img.shape == denoised.shape) + + +def test_noise_removal_isNotSameImage(raw_images_path): + img = cv2.imread(raw_images_path[0]) + denoised=noise_removal(raw_images_path[0]) + assert (np.bitwise_xor(img,denoised).any()) + diff --git a/tests/model_test.py b/tests/model_test/model_test.py similarity index 64% rename from tests/model_test.py rename to tests/model_test/model_test.py index 5b61643..46fd86d 100644 --- a/tests/model_test.py +++ b/tests/model_test/model_test.py @@ -5,6 +5,7 @@ from torch import tensor from torchmetrics.detection import MeanAveragePrecision import torch +from map_boxes import mean_average_precision_for_boxes @pytest.fixture def yov8_model(): @@ -20,12 +21,24 @@ def test_model_expected_value(yov8_model, get_validation_data): x, y = get_validation_data val_predictions = yov8_model.predict(x,imgsz=640, conf=0.0033) - boxes=[] - for prediction in val_predictions: - boxes.append(prediction.boxes.xywh) # Boxes object for bbox outputs - masks = prediction.masks # Masks object for segmentation masks outputs - probs = prediction.probs # Class probabilities for classification outputs - + predictions_lst=[] + labels_lst=[] + + # for img,prediction in zip(x,val_predictions): + # img_name=img.split("/")[0] + # masks = prediction.masks # Masks object for segmentation masks outputs + # probs = prediction.probs # Class probabilities for classification outputs + # if probs: + # label=int(max(probs)) + # else: + # label=1 + # print(y) + # predictions_lst.append([img_name,label]+[v for v in prediction.boxes.xywh]) + # print(y[img]) + # labels_lst.append([img_name],int(y[img][0]),0.1,y[img][1],y[img][2],y[img][3],y[img][4]) + + # mean_ap, average_precisions = mean_average_precision_for_boxes(labels_lst, predictions_lst) + # preds = [dict(boxes=torch.FloatTensor(next(iter(y.values()))[0]),scores=tensor([0.536]),labels=tensor([[1],[2],[2]]),)] # target = [dict(boxes=boxes.xywh,scores=tensor([0.536]),labels=tensor([[1],[1],[1]]),)] preds = [dict(boxes=tensor([[258.0, 41.0, 606.0, 285.0]]),scores=tensor([0.536]),labels=tensor([0]),)]