File size: 6,239 Bytes
665a66c
8a9a28b
 
 
 
 
 
665a66c
155423f
7fdb879
2c202de
8a9a28b
665a66c
8a9a28b
155423f
7fdb879
2c202de
 
7fdb879
665a66c
2c202de
 
 
665a66c
2c202de
 
 
 
 
 
 
 
 
 
 
 
155423f
 
 
2c202de
 
 
 
 
7fdb879
155423f
2c202de
665a66c
2c202de
665a66c
 
2c202de
 
 
 
8a9a28b
2c202de
8a9a28b
 
2c202de
 
 
 
 
155423f
8a9a28b
 
 
2c202de
8a9a28b
 
155423f
8a9a28b
 
 
2c202de
 
8a9a28b
 
 
2c202de
 
155423f
2c202de
8a9a28b
 
155423f
8a9a28b
2c202de
 
 
 
 
 
 
 
665a66c
2c202de
 
 
 
8a9a28b
155423f
8a9a28b
 
665a66c
8a9a28b
 
2c202de
 
 
 
 
 
 
 
665a66c
2c202de
 
 
 
 
 
 
8a9a28b
 
 
 
2c202de
8a9a28b
2c202de
665a66c
 
8a9a28b
 
 
 
 
2c202de
8a9a28b
 
 
2c202de
8a9a28b
 
2c202de
665a66c
 
 
2c202de
7fdb879
2c202de
7fdb879
 
2c202de
7fdb879
 
2c202de
7fdb879
665a66c
2c202de
7fdb879
 
 
2c202de
 
 
 
 
 
7fdb879
2c202de
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
import streamlit as st 
import tensorflow as tf
import numpy as np
import os
import pandas as pd
import altair as alt
from PIL import Image
from tensorflow.keras.preprocessing.image import ImageDataGenerator
import zipfile
import io
import shutil

# 🎨 App Title
st.title("🐢🐱 Cat vs Dog Classifier")

# πŸ“– About the App
st.write(
    """
    ## About This App
    This is a machine learning application that classifies images into two categories:
    **Cats 🐱** and **Dogs 🐢**. The model is trained using a deep learning architecture
    called Convolutional Neural Networks (CNNs) and is able to distinguish between images 
    of cats and dogs with high accuracy.
    ### Features:
    - **Dataset Overview**: View the number of images in the dataset, categorized by "Cats" and "Dogs".
    - **Model Evaluation**: Check the model's performance on the validation set, including accuracy and loss.
    - **Image Classification**: Upload an image, and the model will predict whether it's a cat or a dog, along with the confidence level.
    - **Download Test Folder**: Download a ZIP file containing the test images.
    The app is powered by **Streamlit** for an interactive user interface and **TensorFlow** for image classification.
    """
)

# βœ… Detect Environment & Set Dataset Path
BASE_DIR = "dataset"  # In Hugging Face Spaces, the dataset folder should be at the root of the Space
ZIP_PATH = "dataset.zip"  # If dataset is uploaded as a ZIP (make sure it's in the same directory as app.py)

TRAIN_DIR = os.path.join(BASE_DIR, "train")
TEST_DIR = os.path.join(BASE_DIR, "test")

# βœ… Extract Dataset if Needed (Hugging Face)
if ZIP_PATH and os.path.exists(ZIP_PATH):
    if not os.path.exists(BASE_DIR):  # Avoid re-extracting
        with zipfile.ZipFile(ZIP_PATH, "r") as zip_ref:
            zip_ref.extractall(BASE_DIR)  # Extract into dataset folder
    st.success("βœ… Dataset extracted!")

# πŸ“Œ Check if dataset exists
if not os.path.exists(TRAIN_DIR):
    st.error(f"❌ Dataset folder 'train' not found at {TRAIN_DIR}. Please upload the dataset.")
    st.stop()

# πŸ“Œ Verify Cats & Dogs Folders
cat_dir = os.path.join(TRAIN_DIR, "cats")
dog_dir = os.path.join(TRAIN_DIR, "dogs")

if not os.path.exists(cat_dir) or not os.path.exists(dog_dir):
    st.error("❌ Missing 'cats' or 'dogs' folders inside 'train'. Please check your dataset.")
    st.stop()

# πŸ“Œ Constants
IMG_SIZE = (150, 150)
BATCH_SIZE = 32
MODEL_PATH = "cats_dogs_model.h5"  # Ensure the model is uploaded to Hugging Face Space

# 🎯 Load Model
if os.path.exists(MODEL_PATH):
    model = tf.keras.models.load_model(MODEL_PATH)
else:
    st.error("⚠ No trained model found. Please upload 'cats_dogs_model.h5' to your Hugging Face repository.")
    st.stop()

# πŸ“· Image Preprocessing
def preprocess_image(image):
    image = image.convert('RGB').resize(IMG_SIZE)
    img_array = np.array(image, dtype=np.float32) / 255.0
    img_array = np.expand_dims(img_array, axis=0)
    return img_array

# 🐢🐱 Classify Image
def classify_image(image):
    processed_img = preprocess_image(image)
    prediction = model.predict(processed_img)[0][0]
    label = "Dog 🐢" if prediction > 0.5 else "Cat 🐱"
    confidence = prediction if label == "Dog 🐢" else 1 - prediction
    return label, confidence

# πŸ“Š Model Evaluation
def evaluate_model():
    datagen = ImageDataGenerator(rescale=1.0 / 255, validation_split=0.2)
    
    test_data = datagen.flow_from_directory(
        TRAIN_DIR,
        target_size=IMG_SIZE,
        batch_size=BATCH_SIZE,
        class_mode='binary',
        subset='validation'
    )

    loss, accuracy = model.evaluate(test_data, verbose=0)

    return accuracy, loss

# πŸŽ› Streamlit Tabs
tab1, tab2, tab3 = st.tabs(["πŸ“ Dataset Preview", "πŸ“Š Model Performance", "🐢🐱 Image Classification"])

# πŸ“ Tab 1: Dataset Preview
with tab1:
    st.write("### Dataset Overview")

    dataset_info = {
        "Total Images": len(os.listdir(cat_dir)) + len(os.listdir(dog_dir)),
        "Cat Images": len(os.listdir(cat_dir)),
        "Dog Images": len(os.listdir(dog_dir))
    }
    
    df_info = pd.DataFrame(list(dataset_info.items()), columns=["Category", "Count"])
    st.dataframe(df_info)

    # Visualization
    st.write("### Image Distribution")
    chart = alt.Chart(df_info).mark_bar().encode(
        x="Category", y="Count", color="Category"
    )
    st.altair_chart(chart, use_container_width=True)

# πŸ“Š Tab 2: Model Performance
with tab2:
    st.write("### Model Evaluation")
    
    accuracy, loss = evaluate_model()
    
    st.write(f"βœ… **Validation Accuracy:** {accuracy*100:.2f}%")
    st.write(f"βœ… **Validation Loss:** {loss:.4f}")

# 🐢🐱 Tab 3: Image Classification
with tab3:
    st.write("### Upload an Image for Classification")
    uploaded_file = st.file_uploader("Choose an image...", type=["jpg", "png", "jpeg"])

    if uploaded_file:
        image = Image.open(uploaded_file)
        st.image(image, caption="Uploaded Image", use_container_width=True)

        with st.spinner("Classifying..."):
            label, confidence = classify_image(image)

        st.subheader("Prediction:")
        st.write(f"This is a **{label}** with **{confidence*100:.2f}%** confidence.")

    # **New Feature: Download the 'test' folder as a ZIP**
    def zip_folder(folder_path):
        # Create an in-memory zip file
        zip_buffer = io.BytesIO()
        with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zip_file:
            for root, dirs, files in os.walk(folder_path):
                for file in files:
                    zip_file.write(os.path.join(root, file), os.path.relpath(os.path.join(root, file), folder_path))
        zip_buffer.seek(0)  # Go to the beginning of the file
        return zip_buffer

    # Button to download 'test' folder
    if os.path.exists(TEST_DIR):
        st.write("### Download Test Folder")
        zip_buffer = zip_folder(TEST_DIR)
        st.download_button(
            label="Download Test Folder as ZIP",
            data=zip_buffer,
            file_name="test_folder.zip",
            mime="application/zip"
        )
    else:
        st.warning(f"❌ Test folder not found at {TEST_DIR}")