|
Download README.md from Dehsahk-AI/Pcos-Detect: direct link, hf CLI and curl.
- Browser
- Download file 8.48 kB
-
https://huggingface.co/Dehsahk-AI/Pcos-Detect/resolve/main/README.md
- Command line
-
hf download hf://Dehsahk-AI/Pcos-Detect/README.md
-
curl -L -o README.md https://huggingface.co/Dehsahk-AI/Pcos-Detect/resolve/main/README.md
8.48 kB
| license: mit | |
| tags: | |
| - medical-imaging | |
| - pcos-detection | |
| - explainable-ai | |
| - grad-cam | |
| - ultrasound | |
| - image Classification | |
| - pcos | |
| language: en | |
| metrics: | |
| - accuracy | |
| library_name: tensorflow | |
| # PCOS Detection with Explainable AI | |
| A deep learning model for **Polycystic Ovary Syndrome (PCOS)** detection from ultrasound images with **Grad-CAM** visualization for clinical interpretability. | |
| ## Model Overview | |
| - **Architecture**: Dual-path CNN with multi-head attention | |
| - **Input**: 224Γ224 RGB ultrasound images | |
| - **Output**: Binary classification (PCOS-positive / Healthy) | |
| - **Accuracy**: ~95%+ on test set | |
| - **XAI**: Grad-CAM heatmaps for interpretability | |
| ## π Quick Start | |
| ```bash | |
| pip install tensorflow opencv-python matplotlib numpy requests huggingface-hub | |
| ``` | |
| ### Complete Working Example | |
| ```python | |
| # ============================================================ | |
| # π PCOS Prediction + Grad-CAM (HF VERSION) | |
| # ============================================================ | |
| import numpy as np | |
| import cv2 | |
| import tensorflow as tf | |
| import matplotlib.pyplot as plt | |
| from tensorflow.keras import Model, Input | |
| from tensorflow.keras.layers import ( | |
| Conv2D, MaxPooling2D, Flatten, Dense, | |
| Lambda, Reshape, Concatenate, | |
| MultiHeadAttention, GlobalAveragePooling1D | |
| ) | |
| import requests | |
| from huggingface_hub import hf_hub_download | |
| # ============================================================ | |
| # Config | |
| # ============================================================ | |
| IMG_SIZE = (224, 224) | |
| HF_MODEL_REPO = "Dehsahk-AI/Pcos-Detect" | |
| MODEL_FILENAME = "best_pcos_model.h5" | |
| IMAGE_URL = "https://example.com/ultrasound.jpg" # Your image URL | |
| CLASS_NAMES = ["infected", "noninfected"] | |
| # ============================================================ | |
| # Download model from HF | |
| # ============================================================ | |
| MODEL_PATH = hf_hub_download(repo_id=HF_MODEL_REPO, filename=MODEL_FILENAME) | |
| print(f" Model downloaded to: {MODEL_PATH}") | |
| # ============================================================ | |
| # Custom Lambda Functions | |
| # ============================================================ | |
| def split_image(image): | |
| upper = image[:, :IMG_SIZE[0]//2, :, :] | |
| lower = image[:, IMG_SIZE[0]//2:, :, :] | |
| return upper, lower | |
| def flip_lower(lower_half): | |
| return tf.image.flip_left_right(lower_half) | |
| # ============================================================ | |
| # Rebuild Model Architecture | |
| # ============================================================ | |
| input_layer = Input(shape=(224,224,3)) | |
| upper_half, lower_half = Lambda(split_image)(input_layer) | |
| lower_half = Lambda(flip_lower)(lower_half) | |
| # Upper CNN | |
| u = Conv2D(32, 3, activation="relu", padding="same")(upper_half) | |
| u = MaxPooling2D(2)(u) | |
| u = Conv2D(64, 3, activation="relu", padding="same")(u) | |
| u = MaxPooling2D(2)(u) | |
| u = Conv2D(128, 3, activation="relu", padding="same", name="upper_last_conv")(u) | |
| u = MaxPooling2D(2)(u) | |
| u = Flatten()(u) | |
| # Lower CNN | |
| l = Conv2D(32, 3, activation="relu", padding="same")(lower_half) | |
| l = MaxPooling2D(2)(l) | |
| l = Conv2D(64, 3, activation="relu", padding="same")(l) | |
| l = MaxPooling2D(2)(l) | |
| l = Conv2D(128, 3, activation="relu", padding="same", name="lower_last_conv")(l) | |
| l = MaxPooling2D(2)(l) | |
| l = Flatten()(l) | |
| u_dense = Dense(512, activation="relu")(u) | |
| l_dense = Dense(512, activation="relu")(l) | |
| u_r = Reshape((1,512))(u_dense) | |
| l_r = Reshape((1,512))(l_dense) | |
| concat = Concatenate(axis=1)([u_r, l_r]) | |
| att = MultiHeadAttention(num_heads=4, key_dim=64)(concat, concat) | |
| att = GlobalAveragePooling1D()(att) | |
| fc = Dense(256, activation="relu")(att) | |
| fc = Dense(128, activation="relu")(fc) | |
| # Logits for Grad-CAM | |
| logits = Dense(2, name="logits")(fc) | |
| output = tf.keras.layers.Activation('softmax', name='softmax')(logits) | |
| model = Model(input_layer, output) | |
| model.load_weights(MODEL_PATH) | |
| print(" Weights loaded successfully") | |
| # ============================================================ | |
| # Load & Preprocess Image | |
| # ============================================================ | |
| response = requests.get(IMAGE_URL) | |
| img_array_raw = np.asarray(bytearray(response.content), dtype=np.uint8) | |
| img = cv2.imdecode(img_array_raw, cv2.IMREAD_COLOR) | |
| img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) | |
| img = cv2.resize(img, IMG_SIZE) | |
| img = img.astype(np.float32) / 255.0 | |
| img_array = np.expand_dims(img, axis=0) | |
| # ============================================================ | |
| # Prediction | |
| # ============================================================ | |
| pred = model.predict(img_array, verbose=0)[0] | |
| pred_class = np.argmax(pred) | |
| confidence = pred[pred_class] | |
| print(f"\n Prediction: {CLASS_NAMES[pred_class]}") | |
| print(f" Confidence: {confidence:.2%}") | |
| # ============================================================ | |
| # Grad-CAM | |
| # ============================================================ | |
| def gradcam(img_array, model, layer_name, pred_index): | |
| logits_layer = model.get_layer('logits') | |
| grad_model = Model( | |
| model.input, | |
| [model.get_layer(layer_name).output, logits_layer.output] | |
| ) | |
| with tf.GradientTape() as tape: | |
| conv_out, logits = grad_model(img_array) | |
| loss = logits[:, pred_index] | |
| grads = tape.gradient(loss, conv_out) | |
| pooled = tf.reduce_mean(grads, axis=(0,1,2)) | |
| conv_out = conv_out[0] | |
| heatmap = conv_out @ pooled[..., tf.newaxis] | |
| heatmap = tf.squeeze(heatmap) | |
| heatmap = tf.maximum(heatmap, 0) | |
| if tf.reduce_max(heatmap) > 0: | |
| heatmap /= tf.reduce_max(heatmap) | |
| return heatmap.numpy() | |
| upper = gradcam(img_array, model, "upper_last_conv", pred_class) | |
| lower = gradcam(img_array, model, "lower_last_conv", pred_class) | |
| h = IMG_SIZE[0] // 2 | |
| upper = cv2.resize(upper, (IMG_SIZE[1], h)) | |
| lower = cv2.resize(lower, (IMG_SIZE[1], h)) | |
| lower = cv2.flip(lower, 1) | |
| heatmap = np.vstack([upper, lower]) | |
| heatmap_color = cv2.applyColorMap(np.uint8(255*heatmap), cv2.COLORMAP_JET) | |
| heatmap_color = cv2.cvtColor(heatmap_color, cv2.COLOR_BGR2RGB) / 255.0 | |
| overlay = 0.5 * heatmap_color + 0.5 * img | |
| # ============================================================ | |
| # Visualization | |
| # ============================================================ | |
| plt.figure(figsize=(15,5)) | |
| plt.subplot(1,3,1) | |
| plt.imshow(img) | |
| plt.title("Original") | |
| plt.axis("off") | |
| plt.subplot(1,3,2) | |
| plt.imshow(heatmap, cmap="jet") | |
| plt.title("Grad-CAM") | |
| plt.axis("off") | |
| plt.subplot(1,3,3) | |
| plt.imshow(overlay) | |
| plt.title(f"{CLASS_NAMES[pred_class]} ({confidence:.2%})") | |
| plt.axis("off") | |
| plt.tight_layout() | |
| plt.show() | |
| ``` | |
| ### Load from Local File | |
| ```python | |
| # Replace URL loading with: | |
| img = cv2.imread('path/to/ultrasound.jpg') | |
| img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) | |
| img = cv2.resize(img, IMG_SIZE) | |
| img = img.astype(np.float32) / 255.0 | |
| img_array = np.expand_dims(img, axis=0) | |
| ``` | |
| ## Understanding Grad-CAM Output | |
| - **Red/Hot regions**: High importance for prediction (follicles, cysts) | |
| - **Blue/Cool regions**: Low influence on decision | |
| - **Dual visualization**: Separate heatmaps for upper and lower ovarian regions | |
| ## Model Architecture | |
| ``` | |
| Input (224Γ224Γ3) | |
| βββ Split horizontally (upper/lower) | |
| βββ Upper Path: Conv32 β Conv64 β Conv128 β Dense512 | |
| βββ Lower Path: Conv32 β Conv64 β Conv128 β Dense512 | |
| βββ Multi-Head Attention (4 heads, dim=64) | |
| βββ Classification: Dense256 β Dense128 β Dense2 | |
| ``` | |
| **Key Features:** | |
| - Dual-path CNN for separate ovarian region analysis | |
| - Lower region flipped for symmetry normalization | |
| - Multi-head attention for feature fusion | |
| - Logits-based Grad-CAM (fixes saturated softmax gradients) | |
| ## Dataset | |
| - **Total**: 11,784 ultrasound images | |
| - **PCOS-positive**: 6,784 images (57.5%) | |
| - **Healthy**: 5,000 images (42.5%) | |
| - **Source**: 3 clinics (2018-2022), expert-annotated | |
| - **Dataset**: [PCOS XAI Ultrasound](https://www.kaggle.com/datasets/ibadeus/pcos-xai-ultrasound-dataset) | |
| ## Important Notes | |
| **Clinical Use:** | |
| - Research purposes only - NOT FDA approved | |
| - Not a diagnostic tool - requires professional validation | |
| - Must be validated on local datasets before clinical deployment | |
| **Technical:** | |
| - Fixed 224Γ224 input size required | |
| - RGB images only | |
| - Model performance may vary across different ultrasound machines | |
| ## Citation | |
| ```bibtex | |
| @misc{pcos_xai_2024, | |
| title={PCOS Detection with Explainable AI}, | |
| author={Dehsahk-AI}, | |
| year={2025}, | |
| url={https://huggingface.co/Dehsahk-AI/Pcos-Detect} | |
| } | |
| ``` | |
| ## License | |
| MIT License - See LICENSE file for details. | |
| --- | |
| **Model Version**: 1.0 | **Last Updated**: December 2025 | |
| license: MIT | |
| --- |