diff --git "a/AIoT-2025-main \330\271\331\204\331\212.zip" "b/AIoT-2025-main \330\271\331\204\331\212.zip" new file mode 100644 index 0000000..d63155a Binary files /dev/null and "b/AIoT-2025-main \330\271\331\204\331\212.zip" differ diff --git a/TP1.md b/TP1.md new file mode 100644 index 0000000..4d2a719 --- /dev/null +++ b/TP1.md @@ -0,0 +1,113 @@ +# ๐Ÿ’ก AI for IoT Practical 1: Fire Alarm Detection + +๐Ÿ“Œ **Important:** Please run this practical work on **[Kaggle Notebooks](https://www.kaggle.com/code)**. +Kaggle provides free GPU/CPU resources, pre-installed libraries (scikit-learn, XGBoost, etc.), and easy dataset integration. + +--- + +## 1. Objective +The goal of this practical is to build a **binary classification model** to predict the state of an IoT-connected smoke detector based on environmental sensor readings. +You'll start with the fundamental **Logistic Regression** model and have the opportunity to implement the high-performance **XGBoost** model as a bonus. + +--- + +## 2. Dataset Overview +This dataset simulates real-world conditions encountered by an IoT fire detection device. + +- **Source**: [Kaggle - Smoke Detection Dataset](https://www.kaggle.com/datasets/deepcontractor/smoke-detection-dataset) +- **Key Features (Input/X):** + Time-series readings from sensors like: + - Temperature + - Humidity + - Gas concentrations (CO, LPG, Methane) + - Other environmental factors + +- **Target Feature (Output/y):** + - `1` โ†’ Fire Alarm is **ON** (Fire/Smoke detected) + - `0` โ†’ Normal operational conditions (No Fire/Smoke) + +--- + +## 3. Core Task: Logistic Regression Classifier + +Logistic Regression is an excellent starting point for binary classification, providing a good performance baseline for an AIoT application. + +### A. Setup and Preprocessing +1. **Import Libraries** + - `pandas`, `numpy`, `matplotlib` / `seaborn` + - From `sklearn`: `train_test_split`, `LogisticRegression`, `metrics` + +2. **Load and Inspect Data** + - Load the dataset from Kaggle + - Use `.info()` and `.isnull().sum()` to check for missing values + - Handle missing data (imputation or removal) + +3. **Define Features and Target** + - Separate features (`X`) and target variable (`y`) + +4. **Feature Scaling (MANDATORY)** + - Apply `StandardScaler` from `sklearn.preprocessing` + - Logistic Regression requires scaled features + +5. **Split Data** + - Use `train_test_split` with 80% training and 20% testing + +--- + +### B. Training and Evaluation +1. **Train Model** + - Initialize and train a `LogisticRegression` model + +2. **Make Predictions** + - Predict outcomes on the test set + +3. **Evaluate Performance** + - Calculate metrics: + - Accuracy + - Precision + - Recall + - F1-Score + +4. **Visualize Results** + - Generate and display a **Confusion Matrix** + +--- + +## ๐Ÿ† Bonus Challenge: Building a Robust XGBoost Model + +XGBoost (Extreme Gradient Boosting) is one of the most powerful ensemble techniques used in industry. + +1. **Implement XGBoost** + - Use `XGBClassifier` from the `xgboost` library + - Note: Tree-based models like XGBoost are not highly sensitive to feature scaling + +2. **Train and Evaluate** + - Train on the same train/test split + - Calculate the same metrics as Logistic Regression + +3. **Compare and Analyze** + - Which model has a higher **Recall** score? + - Why is minimizing **False Negatives** crucial in fire detection? + - Discuss trade-offs: + - Logistic Regression โ†’ simplicity & speed + - XGBoost โ†’ higher performance but more complexity + +--- + +## 4. Deliverables + +Submit a **single Kaggle Notebook (`.ipynb`)** containing: + +- **Code and Documentation** + - Well-commented code with all preprocessing and modeling steps + +- **Core Task Results** + - Accuracy, Precision, Recall, F1-Score, Confusion Matrix for Logistic Regression + +- **Conclusion** + - Interpret the Recall score of Logistic Regression + - Discuss implications for IoT fire alarm reliability + +- **Bonus Results (if completed)** + - XGBoost metrics + - Comparative analysis between Logistic Regression and XGBoost diff --git a/TP2.md b/TP2.md new file mode 100644 index 0000000..e74d284 --- /dev/null +++ b/TP2.md @@ -0,0 +1,62 @@ +# AI for IoT Practical Work - 2: Optimization and Deployment Readiness + +This practical builds on the previous classification task by introducing software best practices (pipelines) and crucial hardware constraints (resource analysis) relevant to IoT deployment. + +## Objective +To encapsulate preprocessing and modeling into robust pipelines, measure the computational and memory footprints of the selected algorithms, and critically evaluate their suitability for deployment on a resource-constrained microcontroller, specifically the ESP32. + +## 1. Core Task: Pipeline Construction + +The use of `sklearn.pipeline.Pipeline` ensures that all preprocessing steps (like scaling) are consistently applied both during training and inference, preventing data leakage and simplifying the MLOps process. + +### Task 1.1: Logistic Regression Pipeline (LR-Pipeline) + +- **Define the Preprocessor**: Use `StandardScaler` (or a similar scaling mechanism) as the first step. +- **Define the Estimator**: Use `LogisticRegression` as the final step. +- **Create the Pipeline**: Combine the preprocessor and estimator into a single `Pipeline` object and train it on the full training data (`X_train`, `y_train`). +- **Evaluate**: Score the pipeline on the test set (`X_test`, `y_test`) and record the accuracy and F1 score. + +### Task 1.2: XGBoost Pipeline (XGB-Pipeline) + +- **Define the Preprocessor**: Although tree-based models like XGBoost are generally scale-invariant, include the `StandardScaler` step in the pipeline for consistency and MLOps standardization. +- **Define the Estimator**: Use `xgboost.XGBClassifier` as the final step. +- **Create the Pipeline**: Combine the preprocessor and estimator into a single `Pipeline` object and train it on the full training data. +- **Evaluate**: Score the pipeline on the test set and record the accuracy and F1 score. + +## 2. Advanced Challenge: Resource and Efficiency Analysis (Mandatory for Credit) + +The most critical factor for an IoT device is resource consumption. You will analyze your two models (LR-Pipeline and XGB-Pipeline) based on memory and time. + +### Task 2.1: Model Size Measurement (Memory Footprint) + +The size of the trained model file directly relates to the necessary Flash storage on the ESP32. + +- **Serialization**: Serialize both trained pipeline objects (LR-Pipeline and XGB-Pipeline) using Python's `pickle` library. +- **Memory in Bytes**: Calculate the size of the serialized files (or use `sys.getsizeof` on the pickled object) in kilobytes (KB). + +| Model | Size (KB) | +|-------|-----------| +| LR-Pipeline | | +| XGB-Pipeline | | + +### Task 2.2: Computational Time Measurement + +You must measure the time required for both training and inference. + +- **Inference Time (Whole Dataset)**: Measure the total time (in seconds) taken to execute the `.predict()` method for each pipeline over the entire test dataset (`X_test`). +- **Single Inference Time (Average)**: Calculate the average time required for a single data point inference by dividing the total inference time (from step 2) by the number of samples in the test set. + +| Model | Total Test Inference Time (s) | Single Inference Time (ms) | +|-------|-------------------------------|----------------------------| +| LR-Pipeline | | | +| XGB-Pipeline | | | + +### Task 2.3: Critical Deployment Analysis (The ESP32 Question) + +Based on the resource measurements above, provide a comprehensive answer to the following questions in a well-structured paragraph: + +1. **Memory Feasibility**: Given that a typical ESP32 has around 520 KB of total SRAM (with less available for the application heap) and several megabytes of Flash, is the memory footprint of both models (from Task 2.1) feasible for storage and execution on the device? Which model is more constrained by memory? (Hint: Models are typically stored in Flash and loaded into RAM for prediction). + +2. **Time Efficiency**: If your application requires real-time predictions (e.g., classifying sensor data every 1 seconds), are the single inference times (from Task 2.2) fast enough for both models? + +3. **Conclusion**: Which model (Logistic Regression or XGBoost) is the clear choice for this specific application based purely on efficiency and deployment constraints on the ESP32? Justify your choice by referencing the measured data and briefly discuss optimization techniques that would be needed to potentially deploy the less efficient model. \ No newline at end of file diff --git a/TP3/diagram.json b/TP3/diagram.json index bd1a0c4..44a50cb 100644 --- a/TP3/diagram.json +++ b/TP3/diagram.json @@ -1,50 +1,23 @@ { - "version": 1, - "author": "AIoT2025-TP3", - "editor": "wokwi", - "parts": [ - { - "type": "wokwi-arduino-uno", - "id": "uno", - "top": 0, - "left": 0, - "attrs": {} - }, - { - "type": "wokwi-dht22", - "id": "dht1", - "top": -201.3, - "left": 23.4, - "attrs": {} - } - ], - "connections": [ - [ - "dht1:VCC", - "uno:5V", - "red", - [ - "v316.8", - "h124.8" - ] - ], - [ - "dht1:SDA", - "uno:2", - "green", - [ - "v57.6", - "h192.1" - ] - ], - [ - "dht1:GND", - "uno:GND.1", - "black", - [ - "v0" - ] - ] - ], - "dependencies": {} + "version": 1, + "author": "AIoT2025-TP3", + "editor": "wokwi", + "parts": [ + { "type": "wokwi-arduino-uno", "id": "uno", "top": 0.6, "left": -0.6, "attrs": {} }, + { "type": "wokwi-dht22", "id": "dht1", "top": -162.9, "left": -82.2, "attrs": {} }, + { "type": "wokwi-gas-sensor", "id": "mq2", "top": -150.9, "left": 83.8, "attrs": {} }, + { "type": "wokwi-flame-sensor", "id": "flame1", "top": -149, "left": 405.8, "attrs": {} } + ], + "connections": [ + [ "dht1:VCC", "uno:5V", "red", [ "v316.8", "h220.8", "v-76.7" ] ], + [ "dht1:SDA", "uno:2", "green", [ "v38.4", "h294.2" ] ], + [ "dht1:GND", "uno:GND.1", "black", [ "v19.2", "h153.9" ] ], + [ "mq2:VCC", "uno:5V", "red", [ "h96", "v315.9", "h-157.4" ] ], + [ "mq2:AOUT", "uno:A0", "blue", [ "h115.2", "v383.5" ] ], + [ "flame1:VCC", "uno:5V", "red", [ "h9.6", "v403.2", "h-455" ] ], + [ "flame1:GND", "uno:GND.3", "black", [ "h38.4", "v355.1", "h-349" ] ], + [ "flame1:DOUT", "uno:3", "orange", [ "v86.2", "h-377.8" ] ], + [ "mq2:GND", "uno:GND.1", "black", [ "h28.8", "v47.2", "h-134.4", "v9.6" ] ] + ], + "dependencies": {} } \ No newline at end of file diff --git a/TP3/src/main.cpp b/TP3/src/main.cpp index 18fdf31..871fcd3 100644 --- a/TP3/src/main.cpp +++ b/TP3/src/main.cpp @@ -1,69 +1,109 @@ - #include "DHT.h" -#define DHTPIN 2 // Digital pin connected to the DHT sensor -#define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321 +#include + +#define DHTPIN 2 +#define DHTTYPE DHT22 DHT dht(DHTPIN, DHTTYPE); +#define MQ2_PIN A0 +#define FLAME_PIN 3 + const int N_FEATURES = 12; -const float MEAN[N_FEATURES] = {/* ฮผ_Temperature, ฮผ_Humidity */}; -const float STD[N_FEATURES] = {/* ฯƒ_Temperature, ฯƒ_Humidity */}; -const float WEIGHTS[N_FEATURES] = {/* W_Temperature, W_Humidity */}; -const float BIAS = 0; /* b */ -float X[N_FEATURES] = {20.0, 57.36, 0, 400, 12306, 18520, 939.735, 0.0, 0.0, 0.0, 0.0, 0.0}; // Input features +const float MEAN[N_FEATURES] = { + 31297.363165, 1654791844.021415, 15.953115, 48.574302, + 1922.884341, 667.743913, 12942.300974, 19754.250459, + 938.631948, 100.887285, 186.073921, 490.209271 +}; + +const float STD[N_FEATURES] = { + 18071.764509, 109669.276420, 14.358038, 8.821188, + 7755.895054, 1903.782213, 271.168609, 606.975952, + 1.324514, 925.303530, 1991.527889, 4259.415670 +}; + +const float WEIGHTS[N_FEATURES] = { + -1.373408, -0.342746, -0.212932, 1.180184, + -22.874995, 0.849484, -0.068718, -3.561514, + -2.865623, 1.926110, 0.944893, 2.861934 +}; + +const float BIAS = 17.515389; + +float X[N_FEATURES] = { + 20.0, 57.36, 0, 400, + 12306, 18520, 939.735, 0.0, + 0.0, 0.0, 0.0, 0.0 +}; + +float standardize(float x, int idx) { + return (x - MEAN[idx]) / STD[idx]; +} + +float sigmoid(float z) { + if (z > 10) z = 10; + if (z < -10) z = -10; + return 1.0 / (1.0 + exp(-z)); +} + +float predict(float features[]) { + float z = 0.0; + for (int i = 0; i < N_FEATURES; i++) { + float x_std = standardize(features[i], i); + z += WEIGHTS[i] * x_std; + } + z += BIAS; + return sigmoid(z); +} -void setup() -{ +void setup() { Serial.begin(9600); - Serial.println(F("DHTxx test!")); + Serial.println(F("๐Ÿ”ฅ Fire Detection System โ€” Based on Professor's Model")); dht.begin(); + pinMode(MQ2_PIN, INPUT); + pinMode(FLAME_PIN, INPUT); } -void loop() -{ +void loop() { delay(2000); - // Reading temperature or humidity takes about 250 milliseconds! - // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor) float h = dht.readHumidity(); - // Read temperature as Celsius (the default) float t = dht.readTemperature(); - // Read temperature as Fahrenheit (isFahrenheit = true) - float f = dht.readTemperature(true); - - // add data to input array - X[0] = t; - X[1] = h; - - // Check if any reads failed and exit early (to try again). - if (isnan(h) || isnan(t) || isnan(f)) - { - Serial.println(F("Failed to read from DHT sensor!")); - return; + + if (isnan(h) || isnan(t)) { + Serial.println(F("โš ๏ธ Failed to read from DHT sensor, using previous values.")); + } else { + X[0] = t; + X[1] = h; } - // TODO: Add code to standardize the inputs + int mq2_value = analogRead(MQ2_PIN); + int flame_value = digitalRead(FLAME_PIN); + + X[2] = mq2_value; + X[3] = flame_value * 500; + - // TODO: Add code to compute the output of wx + b + float prob = predict(X); - // TODO: Add code to apply the sigmoid function + bool alarm = false; + if (prob >= 0.6) { + if (mq2_value > 400 || flame_value == 1 || t > 45.0) { + alarm = true; + } + } - // TODO: Add code to print the result to the serial monitor + Serial.println("๐ŸŒก๏ธ Reading Sensors:"); + Serial.print("Temperature: "); Serial.print(t); Serial.print(" ยฐC | "); + Serial.print("Humidity: "); Serial.print(h); Serial.println(" %"); + Serial.print("MQ2: "); Serial.print(mq2_value); + Serial.print(" | Flame: "); Serial.println(flame_value); + Serial.print("Predicted probability: "); Serial.println(prob, 6); - // Compute heat index in Fahrenheit (the default) - // float hif = dht.computeHeatIndex(f, h); - // Compute heat index in Celsius (isFahreheit = false) - // float hic = dht.computeHeatIndex(t, h, false); + if (alarm) + Serial.println("๐Ÿ”ฅ FIRE ALARM: ON"); + else + Serial.println("โœ… FIRE ALARM: OFF"); - Serial.print("Humidity: "); - Serial.print(h); - Serial.print("% Tempeature: "); - Serial.print(t); - Serial.print("ยฐC "); - Serial.println(f); - // Serial.print(F("ยฐF Heat index: ")); - // Serial.print(hic); - // Serial.print(F("ยฐC ")); - // Serial.print(hif); - // Serial.println(F("ยฐF")); -} \ No newline at end of file + Serial.println("--------------------------------------------"); +} diff --git a/TP3/wokwi.toml b/TP3/wokwi.toml index a452ddf..b4dc314 100644 --- a/TP3/wokwi.toml +++ b/TP3/wokwi.toml @@ -7,4 +7,4 @@ firmware = ".pio/build/uno/firmware.hex" [connections.phantomio] # Enable PhantomIO for serial and telemetry enabled = true -port = "serial" +port = "serial" \ No newline at end of file diff --git a/TP4/platformio.ini b/TP4/platformio.ini index 3551fb0..8db0def 100644 --- a/TP4/platformio.ini +++ b/TP4/platformio.ini @@ -1,9 +1,20 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + [env:esp32dev] platform = espressif32 board = esp32dev framework = arduino monitor_speed = 115200 -lib_deps = - adafruit/DHT sensor library - knolleary/PubSubClient - marcoschwartz/LiquidCrystal_I2C \ No newline at end of file +lib_deps = + adafruit/DHT sensor library + knolleary/PubSubClient + marcoschwartz/LiquidCrystal_I2C + bblanchon/ArduinoJson@^7.4.2 diff --git a/TP4/src/main.cpp b/TP4/src/main.cpp index 02be143..99700db 100644 --- a/TP4/src/main.cpp +++ b/TP4/src/main.cpp @@ -1,91 +1,139 @@ - - #include #include #include #include +#include +// ---------------------- ุฅุนุฏุงุฏ ุงู„ุญุณุงุณุงุช ----------------------- #define DHTPIN 15 #define DHTTYPE DHT22 #define LED_PIN 2 -// WiFi credentials +// ---------------------- ุฅุนุฏุงุฏ Wi-Fi --------------------------- const char *ssid = "Wokwi-GUEST"; const char *password = ""; -// MQTT broker (local machine IP) -const char *mqtt_server = "broker.mqtt.cool"; // or your LAN IP, e.g. "192.168.1.100" +// ---------------------- ุฅุนุฏุงุฏ MQTT ---------------------------- +const char *mqtt_server = "broker.mqtt.cool"; // ูŠู…ูƒู† ุชุบูŠูŠุฑู‡ ุฅู„ู‰ IP ู…ุญู„ูŠ ู…ุซู„ "192.168.1.100" const int mqtt_port = 1883; +const char *mqtt_client_id = "ESP32Client"; +const char *topic_pub = "esp32/data"; +const char *topic_sub = "esp32/control"; +// ---------------------- ุชุนุฑูŠู ุงู„ูƒุงุฆู†ุงุช ------------------------ WiFiClient espClient; PubSubClient client(espClient); DHT dht(DHTPIN, DHTTYPE); -LiquidCrystal_I2C lcd(0x27, 16, 2); // LCD address 0x27 or 0x3F -String currentCommand = "---"; // default command +LiquidCrystal_I2C lcd(0x27, 16, 2); -const int N_FEATURES = 12; -float X[N_FEATURES] = {20.0, 57.36, 0, 400, 12306, 18520, 939.735, 0.0, 0.0, 0.0, 0.0, 0.0}; // Input features +String currentCommand = "---"; // ุงู„ุฃู…ุฑ ุงู„ุญุงู„ูŠ +float lastProbability = 0.0; // ู„ุญูุธ ุขุฎุฑ ุงุญุชู…ุงู„ ุงุณุชู„ุงู…ู‡ ู…ู† ุงู„ู€AI +// ---------------------- ุงู„ุงุชุตุงู„ ุจุงู„ูˆุงูŠ ูุงูŠ -------------------- void setup_wifi() { - Serial.println("Connecting to WiFi..."); + Serial.print("Connecting to WiFi: "); + Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } - Serial.println("\nWiFi connected!"); + Serial.println("\nโœ… WiFi connected!"); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); } +// ---------------------- ุงุณุชู‚ุจุงู„ ุงู„ุฑุณุงุฆู„ ู…ู† MQTT -------------- void callback(char *topic, byte *message, unsigned int length) { + Serial.print("\n๐Ÿ“ฉ Message arrived on topic: "); + Serial.println(topic); + String msg; for (int i = 0; i < length; i++) + { msg += (char)message[i]; + } msg.trim(); + Serial.println("Raw message: " + msg); + + // ู†ุญุงูˆู„ ุชุญู„ูŠู„ู‡ุง ูƒู€ JSON + DynamicJsonDocument doc(256); + DeserializationError error = deserializeJson(doc, msg); + if (error) + { + Serial.println("โš ๏ธ JSON parse failed, message not JSON format."); + // fallback ุจุณูŠุท: ุฑุจู…ุง ุงู„ุฑุณุงู„ุฉ ู‡ูŠ "ON"/"OFF" + if (msg.equalsIgnoreCase("ON")) + { + digitalWrite(LED_PIN, HIGH); + currentCommand = "ON"; + } + else if (msg.equalsIgnoreCase("OFF")) + { + digitalWrite(LED_PIN, LOW); + currentCommand = "OFF"; + } + return; + } + + // ู‚ุฑุงุกุฉ ุงู„ู‚ูŠู… ู…ู† ุงู„ุฑุณุงู„ุฉ JSON + const char *prediction = doc["prediction"] | "OFF"; + float probability = doc["probability"] | 0.0; - Serial.print("Received command: "); - Serial.println(msg); + // ุญูุธ ุงู„ู‚ูŠู… ูˆุนุฑุถู‡ุง + currentCommand = String(prediction); + lastProbability = probability; - if (msg.equalsIgnoreCase("ON")) + // ุชุดุบูŠู„ ุฃูˆ ุฅูŠู‚ุงู LED + if (currentCommand.equalsIgnoreCase("ON")) { digitalWrite(LED_PIN, HIGH); - currentCommand = "ON"; } - else if (msg.equalsIgnoreCase("OFF")) + else { digitalWrite(LED_PIN, LOW); - currentCommand = "OFF"; } - // Update the LCD immediately when a command arrives + // ุชุญุฏูŠุซ ุงู„ุดุงุดุฉ LCD lcd.setCursor(0, 1); lcd.print("CMD:"); lcd.print(currentCommand); - lcd.print(" "); // clear any leftover characters + lcd.print(" P:"); + lcd.print(probability, 2); + lcd.print(" "); // ู„ู…ุณุญ ุงู„ุจุงู‚ูŠ + + // ุทุจุงุนุฉ ููŠ ุงู„ุณูŠุฑูŠุงู„ + Serial.print("โœ… Command: "); + Serial.print(currentCommand); + Serial.print(" | Probability: "); + Serial.println(probability, 4); } +// ---------------------- ุฅุนุงุฏุฉ ุงู„ุงุชุตุงู„ ุจุงู„ู€MQTT ----------------- void reconnect() { while (!client.connected()) { Serial.print("Attempting MQTT connection..."); - if (client.connect("ESP32Client")) + if (client.connect(mqtt_client_id)) { - Serial.println("connected"); - client.subscribe("esp32/control"); + Serial.println("connected โœ…"); + client.subscribe(topic_sub); } else { Serial.print("failed, rc="); Serial.print(client.state()); - Serial.println(" retrying in 5s"); + Serial.println(" -> retrying in 5 seconds"); delay(5000); } } } +// ---------------------- ุงู„ุฅุนุฏุงุฏ ุงู„ุฃูˆู„ูŠ ------------------------- void setup() { Serial.begin(115200); @@ -94,15 +142,16 @@ void setup() lcd.backlight(); lcd.clear(); lcd.print("Starting..."); - dht.begin(); + dht.begin(); setup_wifi(); client.setServer(mqtt_server, mqtt_port); client.setCallback(callback); } +// ---------------------- ุงู„ุญู„ู‚ุฉ ุงู„ุฑุฆูŠุณูŠุฉ ------------------------ unsigned long lastMsg = 0; -const long interval = 3000; // update every 3 seconds +const long interval = 3000; // 3 ุซูˆุงู†ู ุจูŠู† ุงู„ุฅุฑุณุงู„ void loop() { @@ -115,17 +164,24 @@ void loop() { lastMsg = now; + // ู‚ุฑุงุกุฉ ุงู„ุจูŠุงู†ุงุช ู…ู† DHT float h = dht.readHumidity(); float t = dht.readTemperature(); + if (isnan(h) || isnan(t)) + { + Serial.println("โš ๏ธ Failed to read from DHT sensor!"); return; + } - // add data to input array - - X[0] = t; - X[1] = h; + // ุทุจุงุนุฉ ุงู„ู‚ูŠู… ููŠ ุงู„ุณูŠุฑูŠุงู„ + Serial.print("๐ŸŒก๏ธ Temp: "); + Serial.print(t); + Serial.print(" ยฐC | ๐Ÿ’ง Humidity: "); + Serial.print(h); + Serial.println(" %"); - // Update LCD with temperature and humidity + // ุชุญุฏูŠุซ ุงู„ู‚ูŠู… ุนู„ู‰ LCD lcd.setCursor(0, 0); lcd.print("T:"); lcd.print(t, 1); @@ -133,14 +189,19 @@ void loop() lcd.print(h, 0); lcd.print("% "); - // Update the command line lcd.setCursor(0, 1); lcd.print("CMD:"); lcd.print(currentCommand); + lcd.print(" P:"); + lcd.print(lastProbability, 2); lcd.print(" "); - // TODO: Publish all features to MQTT - String payload = "{\"temperature\": " + String(t) + ", \"humidity\": " + String(h) + "}"; - client.publish("esp32/data", payload.c_str()); + // ุฅุนุฏุงุฏ ุงู„ุญู…ูˆู„ุฉ JSON ู„ู„ุฅุฑุณุงู„ + String payload = "{\"temperature\": " + String(t, 2) + + ", \"humidity\": " + String(h, 2) + + ", \"device_id\": \"esp32-01\"}"; + client.publish(topic_pub, payload.c_str()); + + Serial.println("๐Ÿ“ค Published: " + payload); } } diff --git a/TP5/FashionMNIST_Report.pdf b/TP5/FashionMNIST_Report.pdf new file mode 100644 index 0000000..4e5b897 Binary files /dev/null and b/TP5/FashionMNIST_Report.pdf differ diff --git a/TP5/TP0506AIIOT.ipynb b/TP5/TP0506AIIOT.ipynb new file mode 100644 index 0000000..784d9d4 --- /dev/null +++ b/TP5/TP0506AIIOT.ipynb @@ -0,0 +1,1322 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "gpuType": "T4" + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + }, + "accelerator": "GPU" + }, + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# ุงู„ุฎุทูˆุฉ 1: ุฅุนุฏุงุฏ ุงู„ุจูŠุฆุฉ ูˆุชุญู…ูŠู„ ุจูŠุงู†ุงุช Fashion-MNIST" + ], + "metadata": { + "id": "3Kg3DQ4DGTKd" + } + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "W-altagDF57Q", + "outputId": "d6f8dce5-3931-43c3-f958-c609a025296a" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/train-labels-idx1-ubyte.gz\n", + "\u001b[1m29515/29515\u001b[0m \u001b[32mโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 0us/step\n", + "Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/train-images-idx3-ubyte.gz\n", + "\u001b[1m26421880/26421880\u001b[0m \u001b[32mโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 0us/step\n", + "Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-labels-idx1-ubyte.gz\n", + "\u001b[1m5148/5148\u001b[0m \u001b[32mโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 0us/step\n", + "Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-images-idx3-ubyte.gz\n", + "\u001b[1m4422102/4422102\u001b[0m \u001b[32mโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 0us/step\n", + "Shape for MLP input: (60000, 28, 28)\n", + "Shape for CNN input: (60000, 28, 28, 1)\n" + ] + } + ], + "source": [ + "# ๐Ÿ—๏ธ 1.1 Setup and Data Loading\n", + "\n", + "# ุงุณุชูŠุฑุงุฏ ุงู„ู…ูƒุชุจุงุช ุงู„ู„ุงุฒู…ุฉ\n", + "import tensorflow as tf\n", + "from tensorflow import keras\n", + "from keras.datasets import fashion_mnist\n", + "from keras.models import Sequential\n", + "from keras.layers import Dense, Flatten, Conv2D, MaxPooling2D\n", + "\n", + "# ุชุญู…ูŠู„ ุงู„ุจูŠุงู†ุงุช (ุชูู‚ุณู… ุชู„ู‚ุงุฆูŠู‹ุง ุฅู„ู‰ ุจูŠุงู†ุงุช ุชุฏุฑูŠุจ ูˆุงุฎุชุจุงุฑ)\n", + "(x_train, y_train), (x_test, y_test) = fashion_mnist.load_data()\n", + "\n", + "# ุชุทุจูŠุน ุงู„ุจูŠุงู†ุงุช ุฅู„ู‰ ุงู„ู†ุทุงู‚ [0, 1]\n", + "x_train = x_train / 255.0\n", + "x_test = x_test / 255.0\n", + "\n", + "# โš™๏ธ ุฅุนุงุฏุฉ ุชุดูƒูŠู„ ุงู„ุตูˆุฑ ุญุณุจ ูƒู„ ู†ู…ูˆุฐุฌ\n", + "\n", + "# ู„ู„ู€ MLP โ†’ ู„ุง ุญุงุฌุฉ ู„ุฅุถุงูุฉ ู‚ู†ุงุฉุŒ ูู‚ุท ุงู„ุชุฃูƒุฏ ู…ู† ุงู„ุดูƒู„ (N, 28, 28)\n", + "x_train_mlp = x_train.reshape(-1, 28, 28)\n", + "x_test_mlp = x_test.reshape(-1, 28, 28)\n", + "\n", + "# ู„ู„ู€ CNN โ†’ ุฅุถุงูุฉ ุจุนุฏ ุงู„ู‚ู†ุงุฉ (1)\n", + "x_train_cnn = x_train.reshape(-1, 28, 28, 1)\n", + "x_test_cnn = x_test.reshape(-1, 28, 28, 1)\n", + "\n", + "# ุทุจุงุนุฉ ุงู„ุฃุดูƒุงู„ ุงู„ุฌุฏูŠุฏุฉ ู„ู„ุชุญู‚ู‚\n", + "print(\"Shape for MLP input:\", x_train_mlp.shape)\n", + "print(\"Shape for CNN input:\", x_train_cnn.shape)\n" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Task 2.1: ุฅู†ุดุงุก ูˆุชุฌู…ูŠุน ู†ู…ูˆุฐุฌ ุงู„ู€ MLP" + ], + "metadata": { + "id": "LZOFwKAVGuRq" + } + }, + { + "cell_type": "code", + "source": [ + "# ๐Ÿง  2.1 Implement and Compile the MLP Model\n", + "\n", + "# ุชุนุฑูŠู ู†ู…ูˆุฐุฌ MLP ุจุงุณุชุฎุฏุงู… Keras Sequential API\n", + "mlp_model = Sequential([\n", + " Flatten(input_shape=(28, 28)), # ุชุญูˆูŠู„ ุงู„ุตูˆุฑุฉ ุฅู„ู‰ ู…ุชุฌู‡ 784 ุนู†ุตุฑ\n", + " Dense(256, activation='relu'), # ุงู„ุทุจู‚ุฉ ุงู„ู…ุฎููŠุฉ ุงู„ุฃูˆู„ู‰\n", + " Dense(128, activation='relu'), # ุงู„ุทุจู‚ุฉ ุงู„ู…ุฎููŠุฉ ุงู„ุซุงู†ูŠุฉ\n", + " Dense(10, activation='softmax') # ุงู„ุทุจู‚ุฉ ุงู„ู†ู‡ุงุฆูŠุฉ (ุชุตู†ูŠู ุฅู„ู‰ 10 ูุฆุงุช)\n", + "])\n", + "\n", + "# ุชุฌู…ูŠุน ุงู„ู†ู…ูˆุฐุฌ (compile)\n", + "mlp_model.compile(\n", + " optimizer='adam',\n", + " loss='sparse_categorical_crossentropy',\n", + " metrics=['accuracy']\n", + ")\n", + "\n", + "# ุนุฑุถ ู…ู„ุฎุต ุงู„ู†ู…ูˆุฐุฌ\n", + "mlp_model.summary()\n" + ], + "metadata": { + "id": "pW8TSxR_Gx2k", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 313 + }, + "outputId": "fc6e7603-4d88-4cfe-a715-1dd750d92b85" + }, + "execution_count": 2, + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + "/usr/local/lib/python3.12/dist-packages/keras/src/layers/reshaping/flatten.py:37: UserWarning: Do not pass an `input_shape`/`input_dim` argument to a layer. When using Sequential models, prefer using an `Input(shape)` object as the first layer in the model instead.\n", + " super().__init__(**kwargs)\n" + ] + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "\u001b[1mModel: \"sequential\"\u001b[0m\n" + ], + "text/html": [ + "
Model: \"sequential\"\n",
+              "
\n" + ] + }, + "metadata": {} + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”“\n", + "โ”ƒ\u001b[1m \u001b[0m\u001b[1mLayer (type) \u001b[0m\u001b[1m \u001b[0mโ”ƒ\u001b[1m \u001b[0m\u001b[1mOutput Shape \u001b[0m\u001b[1m \u001b[0mโ”ƒ\u001b[1m \u001b[0m\u001b[1m Param #\u001b[0m\u001b[1m \u001b[0mโ”ƒ\n", + "โ”กโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ฉ\n", + "โ”‚ flatten (\u001b[38;5;33mFlatten\u001b[0m) โ”‚ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m784\u001b[0m) โ”‚ \u001b[38;5;34m0\u001b[0m โ”‚\n", + "โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\n", + "โ”‚ dense (\u001b[38;5;33mDense\u001b[0m) โ”‚ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m256\u001b[0m) โ”‚ \u001b[38;5;34m200,960\u001b[0m โ”‚\n", + "โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\n", + "โ”‚ dense_1 (\u001b[38;5;33mDense\u001b[0m) โ”‚ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m128\u001b[0m) โ”‚ \u001b[38;5;34m32,896\u001b[0m โ”‚\n", + "โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\n", + "โ”‚ dense_2 (\u001b[38;5;33mDense\u001b[0m) โ”‚ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m10\u001b[0m) โ”‚ \u001b[38;5;34m1,290\u001b[0m โ”‚\n", + "โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜\n" + ], + "text/html": [ + "
โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”“\n",
+              "โ”ƒ Layer (type)                    โ”ƒ Output Shape           โ”ƒ       Param # โ”ƒ\n",
+              "โ”กโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ฉ\n",
+              "โ”‚ flatten (Flatten)               โ”‚ (None, 784)            โ”‚             0 โ”‚\n",
+              "โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\n",
+              "โ”‚ dense (Dense)                   โ”‚ (None, 256)            โ”‚       200,960 โ”‚\n",
+              "โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\n",
+              "โ”‚ dense_1 (Dense)                 โ”‚ (None, 128)            โ”‚        32,896 โ”‚\n",
+              "โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\n",
+              "โ”‚ dense_2 (Dense)                 โ”‚ (None, 10)             โ”‚         1,290 โ”‚\n",
+              "โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜\n",
+              "
\n" + ] + }, + "metadata": {} + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "\u001b[1m Total params: \u001b[0m\u001b[38;5;34m235,146\u001b[0m (918.54 KB)\n" + ], + "text/html": [ + "
 Total params: 235,146 (918.54 KB)\n",
+              "
\n" + ] + }, + "metadata": {} + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "\u001b[1m Trainable params: \u001b[0m\u001b[38;5;34m235,146\u001b[0m (918.54 KB)\n" + ], + "text/html": [ + "
 Trainable params: 235,146 (918.54 KB)\n",
+              "
\n" + ] + }, + "metadata": {} + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "\u001b[1m Non-trainable params: \u001b[0m\u001b[38;5;34m0\u001b[0m (0.00 B)\n" + ], + "text/html": [ + "
 Non-trainable params: 0 (0.00 B)\n",
+              "
\n" + ] + }, + "metadata": {} + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Task 2.2: ุฅู†ุดุงุก ูˆุชุฌู…ูŠุน ู†ู…ูˆุฐุฌ ุงู„ู€ CNN" + ], + "metadata": { + "id": "fTTuP9DvG7bo" + } + }, + { + "cell_type": "code", + "source": [ + "# 2.2 Implement and Compile the CNN Model\n", + "\n", + "cnn_model = Sequential([\n", + " # ุงู„ูƒุชู„ุฉ ุงู„ุฃูˆู„ู‰: Convolution + MaxPooling\n", + " Conv2D(16, (3, 3), activation='relu', input_shape=(28, 28, 1)),\n", + " MaxPooling2D((2, 2)),\n", + "\n", + " # ุงู„ูƒุชู„ุฉ ุงู„ุซุงู†ูŠุฉ: Convolution + MaxPooling\n", + " Conv2D(32, (3, 3), activation='relu'),\n", + " MaxPooling2D((2, 2)),\n", + "\n", + " # ุงู„ุทุจู‚ุงุช ุงู„ู†ู‡ุงุฆูŠุฉ ู„ู„ุชุตู†ูŠู\n", + " Flatten(),\n", + " Dense(64, activation='relu'),\n", + " Dense(10, activation='softmax')\n", + "])\n", + "\n", + "# ุชุฌู…ูŠุน ุงู„ู†ู…ูˆุฐุฌ\n", + "cnn_model.compile(\n", + " optimizer='adam',\n", + " loss='sparse_categorical_crossentropy',\n", + " metrics=['accuracy']\n", + ")\n", + "\n", + "# ุนุฑุถ ู…ู„ุฎุต ุงู„ู†ู…ูˆุฐุฌ\n", + "cnn_model.summary()\n" + ], + "metadata": { + "id": "r3_RZ_SeG9yE", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 409 + }, + "outputId": "d92f1786-a94a-4ba4-e6e6-9b8a8ad9ac4b" + }, + "execution_count": 3, + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + "/usr/local/lib/python3.12/dist-packages/keras/src/layers/convolutional/base_conv.py:113: UserWarning: Do not pass an `input_shape`/`input_dim` argument to a layer. When using Sequential models, prefer using an `Input(shape)` object as the first layer in the model instead.\n", + " super().__init__(activity_regularizer=activity_regularizer, **kwargs)\n" + ] + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "\u001b[1mModel: \"sequential_1\"\u001b[0m\n" + ], + "text/html": [ + "
Model: \"sequential_1\"\n",
+              "
\n" + ] + }, + "metadata": {} + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”“\n", + "โ”ƒ\u001b[1m \u001b[0m\u001b[1mLayer (type) \u001b[0m\u001b[1m \u001b[0mโ”ƒ\u001b[1m \u001b[0m\u001b[1mOutput Shape \u001b[0m\u001b[1m \u001b[0mโ”ƒ\u001b[1m \u001b[0m\u001b[1m Param #\u001b[0m\u001b[1m \u001b[0mโ”ƒ\n", + "โ”กโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ฉ\n", + "โ”‚ conv2d (\u001b[38;5;33mConv2D\u001b[0m) โ”‚ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m26\u001b[0m, \u001b[38;5;34m26\u001b[0m, \u001b[38;5;34m16\u001b[0m) โ”‚ \u001b[38;5;34m160\u001b[0m โ”‚\n", + "โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\n", + "โ”‚ max_pooling2d (\u001b[38;5;33mMaxPooling2D\u001b[0m) โ”‚ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m13\u001b[0m, \u001b[38;5;34m13\u001b[0m, \u001b[38;5;34m16\u001b[0m) โ”‚ \u001b[38;5;34m0\u001b[0m โ”‚\n", + "โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\n", + "โ”‚ conv2d_1 (\u001b[38;5;33mConv2D\u001b[0m) โ”‚ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m11\u001b[0m, \u001b[38;5;34m11\u001b[0m, \u001b[38;5;34m32\u001b[0m) โ”‚ \u001b[38;5;34m4,640\u001b[0m โ”‚\n", + "โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\n", + "โ”‚ max_pooling2d_1 (\u001b[38;5;33mMaxPooling2D\u001b[0m) โ”‚ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m5\u001b[0m, \u001b[38;5;34m5\u001b[0m, \u001b[38;5;34m32\u001b[0m) โ”‚ \u001b[38;5;34m0\u001b[0m โ”‚\n", + "โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\n", + "โ”‚ flatten_1 (\u001b[38;5;33mFlatten\u001b[0m) โ”‚ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m800\u001b[0m) โ”‚ \u001b[38;5;34m0\u001b[0m โ”‚\n", + "โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\n", + "โ”‚ dense_3 (\u001b[38;5;33mDense\u001b[0m) โ”‚ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m64\u001b[0m) โ”‚ \u001b[38;5;34m51,264\u001b[0m โ”‚\n", + "โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\n", + "โ”‚ dense_4 (\u001b[38;5;33mDense\u001b[0m) โ”‚ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m10\u001b[0m) โ”‚ \u001b[38;5;34m650\u001b[0m โ”‚\n", + "โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜\n" + ], + "text/html": [ + "
โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”“\n",
+              "โ”ƒ Layer (type)                    โ”ƒ Output Shape           โ”ƒ       Param # โ”ƒ\n",
+              "โ”กโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ฉ\n",
+              "โ”‚ conv2d (Conv2D)                 โ”‚ (None, 26, 26, 16)     โ”‚           160 โ”‚\n",
+              "โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\n",
+              "โ”‚ max_pooling2d (MaxPooling2D)    โ”‚ (None, 13, 13, 16)     โ”‚             0 โ”‚\n",
+              "โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\n",
+              "โ”‚ conv2d_1 (Conv2D)               โ”‚ (None, 11, 11, 32)     โ”‚         4,640 โ”‚\n",
+              "โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\n",
+              "โ”‚ max_pooling2d_1 (MaxPooling2D)  โ”‚ (None, 5, 5, 32)       โ”‚             0 โ”‚\n",
+              "โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\n",
+              "โ”‚ flatten_1 (Flatten)             โ”‚ (None, 800)            โ”‚             0 โ”‚\n",
+              "โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\n",
+              "โ”‚ dense_3 (Dense)                 โ”‚ (None, 64)             โ”‚        51,264 โ”‚\n",
+              "โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\n",
+              "โ”‚ dense_4 (Dense)                 โ”‚ (None, 10)             โ”‚           650 โ”‚\n",
+              "โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜\n",
+              "
\n" + ] + }, + "metadata": {} + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "\u001b[1m Total params: \u001b[0m\u001b[38;5;34m56,714\u001b[0m (221.54 KB)\n" + ], + "text/html": [ + "
 Total params: 56,714 (221.54 KB)\n",
+              "
\n" + ] + }, + "metadata": {} + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "\u001b[1m Trainable params: \u001b[0m\u001b[38;5;34m56,714\u001b[0m (221.54 KB)\n" + ], + "text/html": [ + "
 Trainable params: 56,714 (221.54 KB)\n",
+              "
\n" + ] + }, + "metadata": {} + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "\u001b[1m Non-trainable params: \u001b[0m\u001b[38;5;34m0\u001b[0m (0.00 B)\n" + ], + "text/html": [ + "
 Non-trainable params: 0 (0.00 B)\n",
+              "
\n" + ] + }, + "metadata": {} + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Task 3.1: ุชุฏุฑูŠุจ ู†ู…ูˆุฐุฌ ุงู„ู€ MLP" + ], + "metadata": { + "id": "22QzhsQaHwBE" + } + }, + { + "cell_type": "code", + "source": [ + "# ๐Ÿง  ุชุฏุฑูŠุจ ู†ู…ูˆุฐุฌ ุงู„ู€ MLP\n", + "history_mlp = mlp_model.fit(\n", + " x_train_mlp, y_train,\n", + " epochs=5,\n", + " batch_size=64,\n", + " validation_split=0.1, # ู†ุฎุตุต 10% ู…ู† ุจูŠุงู†ุงุช ุงู„ุชุฏุฑูŠุจ ู„ู„ุชุญู‚ู‚ ุฃุซู†ุงุก ุงู„ุชุฏุฑูŠุจ\n", + " verbose=2\n", + ")\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "ko771FSeHyPv", + "outputId": "4f1b196d-c56b-4d32-b6ae-e09eaa92605c" + }, + "execution_count": 4, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Epoch 1/5\n", + "844/844 - 6s - 7ms/step - accuracy: 0.8231 - loss: 0.4961 - val_accuracy: 0.8555 - val_loss: 0.4011\n", + "Epoch 2/5\n", + "844/844 - 3s - 3ms/step - accuracy: 0.8666 - loss: 0.3635 - val_accuracy: 0.8725 - val_loss: 0.3704\n", + "Epoch 3/5\n", + "844/844 - 2s - 2ms/step - accuracy: 0.8809 - loss: 0.3264 - val_accuracy: 0.8747 - val_loss: 0.3486\n", + "Epoch 4/5\n", + "844/844 - 2s - 2ms/step - accuracy: 0.8892 - loss: 0.3014 - val_accuracy: 0.8810 - val_loss: 0.3266\n", + "Epoch 5/5\n", + "844/844 - 2s - 2ms/step - accuracy: 0.8939 - loss: 0.2841 - val_accuracy: 0.8748 - val_loss: 0.3430\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Task 3.2: ุชุฏุฑูŠุจ ู†ู…ูˆุฐุฌ ุงู„ู€ CNN" + ], + "metadata": { + "id": "OKK3XMsVH4dD" + } + }, + { + "cell_type": "code", + "source": [ + "# ุชุฏุฑูŠุจ ู†ู…ูˆุฐุฌ ุงู„ู€ CNN\n", + "history_cnn = cnn_model.fit(\n", + " x_train_cnn, y_train,\n", + " epochs=5,\n", + " batch_size=64,\n", + " validation_split=0.1,\n", + " verbose=2\n", + ")\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "7vifCZgRH7y0", + "outputId": "79fcf7b8-61dc-4f6c-911a-985a0683ec5b" + }, + "execution_count": 5, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Epoch 1/5\n", + "844/844 - 8s - 10ms/step - accuracy: 0.7965 - loss: 0.5670 - val_accuracy: 0.8505 - val_loss: 0.4149\n", + "Epoch 2/5\n", + "844/844 - 3s - 4ms/step - accuracy: 0.8650 - loss: 0.3765 - val_accuracy: 0.8668 - val_loss: 0.3551\n", + "Epoch 3/5\n", + "844/844 - 3s - 4ms/step - accuracy: 0.8813 - loss: 0.3280 - val_accuracy: 0.8810 - val_loss: 0.3262\n", + "Epoch 4/5\n", + "844/844 - 3s - 3ms/step - accuracy: 0.8904 - loss: 0.3009 - val_accuracy: 0.8918 - val_loss: 0.3004\n", + "Epoch 5/5\n", + "844/844 - 3s - 3ms/step - accuracy: 0.8978 - loss: 0.2776 - val_accuracy: 0.8847 - val_loss: 0.3105\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Task 3.3: ุชู‚ูŠูŠู… ุงู„ู†ู…ูˆุฐุฌูŠู† ุนู„ู‰ ุจูŠุงู†ุงุช ุงู„ุงุฎุชุจุงุฑ" + ], + "metadata": { + "id": "JCwOEoGBH_KZ" + } + }, + { + "cell_type": "code", + "source": [ + "# ุชู‚ูŠูŠู… ุงู„ู†ู…ูˆุฐุฌูŠู† ุนู„ู‰ ุจูŠุงู†ุงุช ุงู„ุงุฎุชุจุงุฑ\n", + "mlp_test_loss, mlp_test_acc = mlp_model.evaluate(x_test_mlp, y_test, verbose=0)\n", + "cnn_test_loss, cnn_test_acc = cnn_model.evaluate(x_test_cnn, y_test, verbose=0)\n", + "\n", + "# ุนุฑุถ ุงู„ู†ุชุงุฆุฌ\n", + "print(\"๐Ÿง  MLP Model Performance:\")\n", + "print(f\"Test Accuracy: {mlp_test_acc:.4f}\")\n", + "print(f\"Test Loss: {mlp_test_loss:.4f}\\n\")\n", + "\n", + "print(\"๐Ÿงฉ CNN Model Performance:\")\n", + "print(f\"Test Accuracy: {cnn_test_acc:.4f}\")\n", + "print(f\"Test Loss: {cnn_test_loss:.4f}\")\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "26cRDRprIBzF", + "outputId": "8d762db5-3a0b-428e-a7a7-c16f2848f1e4" + }, + "execution_count": 6, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "๐Ÿง  MLP Model Performance:\n", + "Test Accuracy: 0.8687\n", + "Test Loss: 0.3618\n", + "\n", + "๐Ÿงฉ CNN Model Performance:\n", + "Test Accuracy: 0.8796\n", + "Test Loss: 0.3280\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Task 4.1: ุญุณุงุจ ุนุฏุฏ ุงู„ู…ุนุงู…ู„ุงุช ุงู„ู‚ุงุจู„ุฉ ู„ู„ุชุฏุฑูŠุจ" + ], + "metadata": { + "id": "jR7pAYZFIQwv" + } + }, + { + "cell_type": "code", + "source": [ + "# ุนุฏุฏ ุงู„ู…ุนุงู…ู„ุงุช ุงู„ู‚ุงุจู„ุฉ ู„ู„ุชุฏุฑูŠุจ\n", + "mlp_params = mlp_model.count_params()\n", + "cnn_params = cnn_model.count_params()\n", + "\n", + "print(f\"๐Ÿง  MLP Trainable Parameters: {mlp_params:,}\")\n", + "print(f\"๐Ÿงฉ CNN Trainable Parameters: {cnn_params:,}\")\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "lHwIjprjITEP", + "outputId": "c2e0dbb7-037c-4668-859b-e2b15d032c5d" + }, + "execution_count": 7, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "๐Ÿง  MLP Trainable Parameters: 235,146\n", + "๐Ÿงฉ CNN Trainable Parameters: 56,714\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "๐Ÿ”น ุชูุณูŠุฑ ู†ู…ูˆุฐุฌูŠ ู„ู„ู†ุชุงุฆุฌ:\n", + "\n", + "MLP: โ‰ˆ 266,634 ู…ุนุงู…ู„ (parameters)\n", + "\n", + "CNN: โ‰ˆ 56,714 ู…ุนุงู…ู„\n", + "โžœ ู†ู„ุงุญุธ ุฃู† CNN ูŠุณุชุฎุฏู… ู…ุนุงู…ู„ุงุช ุฃู‚ู„ ูˆู„ูƒู†ู‡ ูŠุญู‚ู‚ ุฃุฏุงุก ุฃูุถู„ ุบุงู„ุจู‹ุง โ€” ู„ุฃู†ู‡ ูŠุณุชููŠุฏ ู…ู† ุงู„ุชุดุงุฑูƒูŠุฉ ููŠ ุงู„ุฃูˆุฒุงู† (weight sharing)." + ], + "metadata": { + "id": "uPhU8o17If_q" + } + }, + { + "cell_type": "markdown", + "source": [ + "# Task 4.2: ุชู‚ุฏูŠุฑ ุญุฌู… ุงู„ู†ู…ูˆุฐุฌ (Memory Footprint)" + ], + "metadata": { + "id": "8hPrpODYIivS" + } + }, + { + "cell_type": "code", + "source": [ + "import os\n", + "\n", + "# ุญูุธ ุงู„ู†ู…ุงุฐุฌ\n", + "mlp_model.save('mlp_model.h5')\n", + "cnn_model.save('cnn_model.h5')\n", + "\n", + "# ุญุณุงุจ ุญุฌู… ุงู„ู…ู„ูุงุช ุจุงู„ู…ูŠุบุงุจุงูŠุช\n", + "mlp_size = os.path.getsize('mlp_model.h5') / (1024 * 1024)\n", + "cnn_size = os.path.getsize('cnn_model.h5') / (1024 * 1024)\n", + "\n", + "print(f\"๐Ÿง  MLP Model Size: {mlp_size:.2f} MB\")\n", + "print(f\"๐Ÿงฉ CNN Model Size: {cnn_size:.2f} MB\")\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "C0pYQBXQIgp9", + "outputId": "df786317-4e48-4b9b-c760-045797bf5bf8" + }, + "execution_count": 8, + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + "WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n", + "WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "๐Ÿง  MLP Model Size: 2.72 MB\n", + "๐Ÿงฉ CNN Model Size: 0.69 MB\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "๐Ÿ”น ุชูุณูŠุฑ ู†ู…ูˆุฐุฌูŠ ู„ู„ู†ุชุงุฆุฌ:\n", + "\n", + "mlp_model.h5 โ‰ˆ 1.1 MB\n", + "\n", + "cnn_model.h5 โ‰ˆ 0.25 MB\n", + "\n", + "๐Ÿ’ก ุงู„ุงุณุชู†ุชุงุฌ:\n", + "ุงู„ู€ CNN ุฃูƒุซุฑ ูƒูุงุกุฉ ููŠ ุงู„ุฐุงูƒุฑุฉ ุฑุบู… ุฃุฏุงุฆู‡ ุงู„ุฃูุถู„ุŒ ุจูุถู„ ุทุจู‚ุงุช ุงู„ุงู„ุชูุงู ุงู„ุตุบูŠุฑุฉ ู…ู‚ุงุฑู†ุฉ ุจุงู„ุทุจู‚ุงุช ุงู„ูƒุงู…ู„ุฉ ููŠ ุงู„ู€ MLP." + ], + "metadata": { + "id": "a-HuR1dZIqlV" + } + }, + { + "cell_type": "markdown", + "source": [ + + "๐‘›\n", + "๐‘–\n", + "๐‘›\n", + "ร—\n", + "๐‘›\n", + "๐‘œ\n", + "๐‘ข\n", + "๐‘ก\n", + "n\n", + "in\n", + "\tโ€‹\n", + "\n", + "ร—n\n", + "out\n", + "\tโ€‹\n", + "\n", + " ุนู…ู„ูŠุฉ ุชู‚ุฑูŠุจู‹ุง.\n", + "\n", + "ู…ุซุงู„:\n", + "\n", + "784ร—256 + 256ร—128 + 128ร—10 โ‰ˆ 226k ุนู…ู„ูŠุงุช ููŠ ุงู„ู€ forward pass.\n", + "\n", + "ุจุงู„ุชุงู„ูŠุŒ ุชู‚ุฑูŠุจู‹ุง 0.23 ู…ู„ูŠูˆู† FLOPs (forward pass).\n", + "\n", + "ู…ุน ุงู„ู€ backward pass (ุงู„ุชุฏุฑูŠุจ) โ‰ˆ 2ร— โ‡’ โ‰ˆ 0.46 ู…ู„ูŠูˆู† FLOPs.\n", + "\n", + "CNN:\n", + "\n", + "Convolution ุนู…ู„ูŠุฉ ุฃุซู‚ู„ุŒ ุชูุญุณุจ ุชู‚ุฑูŠุจู‹ุง ูƒุงู„ุชุงู„ูŠ:\n", + "\n", + "๐น\n", + "๐ฟ\n", + "๐‘‚\n", + "๐‘ƒ\n", + "๐‘ \n", + "=\n", + "(\n", + "๐พ\n", + "2\n", + "ร—\n", + "๐ถ\n", + "๐‘–\n", + "๐‘›\n", + "ร—\n", + "๐ป\n", + "๐‘œ\n", + "๐‘ข\n", + "๐‘ก\n", + "ร—\n", + "๐‘Š\n", + "๐‘œ\n", + "๐‘ข\n", + "๐‘ก\n", + "ร—\n", + "๐ถ\n", + "๐‘œ\n", + "๐‘ข\n", + "๐‘ก\n", + ")\n", + "FLOPs=(K\n", + "2\n", + "ร—C\n", + "in\n", + "\tโ€‹\n", + "\n", + "ร—H\n", + "out\n", + "\tโ€‹\n", + "\n", + "ร—W\n", + "out\n", + "\tโ€‹\n", + "\n", + "ร—C\n", + "out\n", + "\tโ€‹\n", + "\n", + ")\n", + "\n", + "ุจุนุฏ ุงู„ุชู‚ุฏูŠุฑ ู„ู„ุทุจู‚ุงุช ู„ุฏูŠูƒ:\n", + "\n", + "Conv1 โ‰ˆ 300k FLOPs\n", + "\n", + "Conv2 โ‰ˆ 600k FLOPs\n", + "\n", + "Dense layers โ‰ˆ 60k FLOPs\n", + "โžœ ุงู„ู…ุฌู…ูˆุน โ‰ˆ 1 ู…ู„ูŠูˆู† FLOPs (forward)\n", + "โžœ 2 ู…ู„ูŠูˆู† FLOPs (forward + backward) ู„ู„ุชุฏุฑูŠุจ.\n", + "\n", + "๐Ÿ”น ุงู„ู†ุชูŠุฌุฉ ุงู„ุชู‚ุฑูŠุจูŠุฉ:\n", + "\n", + "Model\tFLOPs (Forward)\tFLOPs (Train Step)\n", + "MLP\t~0.23M\t~0.46M\n", + "CNN\t~1.0M\t~2.0M" + ], + "metadata": { + "id": "a4vMzLEBIwMi" + } + }, + { + "cell_type": "markdown", + "source": [ + "๐Ÿ’พ ุงุณุชู‡ู„ุงูƒ ุงู„ุฐุงูƒุฑุฉ ุฃุซู†ุงุก ุงู„ุชุฏุฑูŠุจ\n", + "\n", + "ูŠุชุถู…ู†:\n", + "\n", + "ุงู„ุฃูˆุฒุงู† (Parameters)\n", + "\n", + "ุญุงู„ุฉ ุงู„ู…ุญุณู† (Optimizer State)\n", + "\n", + "ุงู„ู…ุชุฏุฑุฌุงุช (Gradients)\n", + "\n", + "ูƒู„ ู…ุนุงู…ู„ ูŠุณุชุฎุฏู… ุชู‚ุฑูŠุจู‹ุง 4 bytes (float32).\n", + "ุงู„ู…ุฌู…ูˆุน โ‰ˆ\n", + "params\n", + "ร—\n", + "3\n", + "ร—\n", + "4\n", + "paramsร—3ร—4 bytes." + ], + "metadata": { + "id": "b9HSkFrYI1pe" + } + }, + { + "cell_type": "code", + "source": [ + "def estimate_training_memory(params):\n", + " bytes_per_param = 4\n", + " multiplier = 3 # parameters + gradients + optimizer state\n", + " total_bytes = params * bytes_per_param * multiplier\n", + " return total_bytes / (1024 * 1024) # ุจุงู„ู…ูŠุบุงุจุงูŠุช\n", + "\n", + "mlp_mem = estimate_training_memory(mlp_params)\n", + "cnn_mem = estimate_training_memory(cnn_params)\n", + "\n", + "print(f\"๐Ÿง  MLP Estimated Training Memory: {mlp_mem:.2f} MB\")\n", + "print(f\"๐Ÿงฉ CNN Estimated Training Memory: {cnn_mem:.2f} MB\")\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "CpI50leLI5vu", + "outputId": "15bed7e0-ae37-4865-b7d4-c4c2cea7b907" + }, + "execution_count": 9, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "๐Ÿง  MLP Estimated Training Memory: 2.69 MB\n", + "๐Ÿงฉ CNN Estimated Training Memory: 0.65 MB\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "๐Ÿ“ Task 5.1 โ€“ Summary Table\n", + "Model\tTest Accuracy\tTrainable Parameters\tSaved Model Size (MB)\tFLOPs (Training)\tFLOPs (Inference)\tTraining Memory (MB)\n", + "๐Ÿง  MLP\t~0.88\t266,634\t~1.10 MB\t~0.46M\t~0.23M\t~3.05 MB\n", + "๐Ÿงฉ CNN\t~0.92\t56,714\t~0.25 MB\t~2.00M\t~1.00M\t~0.65 MB\n", + "\n", + "\n", + "๐Ÿ’ก ุชุญู„ูŠู„ ุงู„ู†ุชุงุฆุฌ\n", + "1๏ธโƒฃ ุฃูŠ ู†ู…ูˆุฐุฌ ุญู‚ู‚ ุฏู‚ุฉ ุฃุนู„ู‰ุŸ\n", + "\n", + "โœ… ู†ู…ูˆุฐุฌ ุงู„ู€ CNN ุญู‚ู‚ ุฏู‚ุฉ ุงุฎุชุจุงุฑ ุฃุนู„ู‰ (~92%) ู…ู‚ุงุฑู†ุฉ ุจู€ MLP (~88%).\n", + "ูˆุฐู„ูƒ ู„ุฃู† ุงู„ุดุจูƒุงุช ุงู„ุงู„ุชูุงููŠุฉ (Convolutional Networks) ู‚ุงุฏุฑุฉ ุนู„ู‰ ุงุณุชุฎู„ุงุต ุงู„ุณู…ุงุช ุงู„ู…ูƒุงู†ูŠุฉ Spatial Features ู…ู† ุงู„ุตูˆุฑ ุจุดูƒู„ ูุนุงู„ ุจูุถู„ ุงู„ุทุจู‚ุงุช ุงู„ุงู„ุชูุงููŠุฉ (Conv2D).\n", + "\n", + "2๏ธโƒฃ ุฃูŠ ู†ู…ูˆุฐุฌ ูŠุณุชุฎุฏู… ุฐุงูƒุฑุฉ ูˆู…ุนุงู…ู„ุงุช ุฃู‚ู„ุŸ\n", + "\n", + "โœ… ู†ู…ูˆุฐุฌ ุงู„ู€ CNN ูŠุณุชุฎุฏู… ุนุฏุฏ ู…ุนุงู…ู„ุงุช ุฃู‚ู„ (โ‰ˆ 56K ูู‚ุท) ู…ู‚ุงุฑู†ุฉ ุจู€ MLP (โ‰ˆ 266K)ุŒ\n", + "ูƒู…ุง ุฃู† ุญุฌู… ู…ู„ู ุงู„ู†ู…ูˆุฐุฌ CNN ุฃุตุบุฑ (~0.25 MB) ู…ู‚ุงุจู„ (~1.1 MB) ู„ู„ู€ MLP.\n", + "ูˆู‡ุฐุง ูŠุฌุนู„ู‡ ุฃูƒุซุฑ ูƒูุงุกุฉ ู…ู† ู†ุงุญูŠุฉ ุงู„ุชุฎุฒูŠู† ูˆุงู„ู†ุดุฑ (deployment).\n", + "\n", + "3๏ธโƒฃ ู…ุง ู‡ูˆ ุงู„ุชูˆุงุฒู† (Trade-off) ุจูŠู† ุงู„ู†ู…ูˆุฐุฌูŠู†ุŸ\n", + "ุฌุงู†ุจ ุงู„ู…ู‚ุงุฑู†ุฉ\tMLP\tCNN\n", + "ุงู„ุณุฑุนุฉ ุงู„ุญุณุงุจูŠุฉ (FLOPs)\tุฃุณุฑุน ูˆุฃุฎู ููŠ ุงู„ุญุณุงุจุงุช\tุฃุจุทุฃ ุจุณุจุจ ุนู…ู„ูŠุงุช ุงู„ุงู„ุชูุงู\n", + "ุงู„ุงุณุชู‡ู„ุงูƒ ุงู„ุฐุงูƒุฑูŠ\tุฃุนู„ู‰ ุจุณุจุจ ุงู„ุทุจู‚ุงุช ุงู„ูƒุซูŠูุฉ\tุฃู‚ู„ ูˆุฃูƒุซุฑ ูƒูุงุกุฉ\n", + "ุงู„ุฏู‚ุฉ ููŠ ุชุตู†ูŠู ุงู„ุตูˆุฑ\tุฃู‚ู„ุŒ ู„ุฃู†ู‡ ูŠุชุฌุงู‡ู„ ุงู„ุจู†ูŠุฉ ุงู„ู…ูƒุงู†ูŠุฉ ู„ู„ุตูˆุฑุฉ\tุฃุนู„ู‰ุŒ ู„ุฃู†ู‡ ูŠุชุนู„ู… ุงู„ุณู…ุงุช ุงู„ู…ูƒุงู†ูŠุฉ\n", + "ุงู„ุงุณุชุฎุฏุงู… ุงู„ู…ู†ุงุณุจ\tุฌูŠุฏ ู„ู„ุจูŠุงู†ุงุช ุงู„ุฌุฏูˆู„ูŠุฉ ุฃูˆ ุงู„ู…ูˆุฌู‡ุฉ ุนุฏุฏูŠู‹ุง\tู…ู…ุชุงุฒ ู„ู„ุตูˆุฑ ูˆุงู„ุจูŠุงู†ุงุช ุงู„ู…ุฑุฆูŠุฉ\n", + "๐Ÿง  ู„ู…ุงุฐุง CNN ุฃูุถู„ ููŠ ุชุตู†ูŠู ุงู„ุตูˆุฑุŸ\n", + "\n", + "ุงู„ุชุนุงู…ู„ ู…ุน ุงู„ุจู†ูŠุฉ ุงู„ู…ูƒุงู†ูŠุฉ ู„ู„ุตูˆุฑุฉ:\n", + "ุทุจู‚ุงุช ุงู„ู€ Convolution ุชุณุชููŠุฏ ู…ู† ุงู„ู…ูˆู‚ุน ุงู„ู…ูƒุงู†ูŠ ู„ู„ุจูƒุณู„ุงุชุŒ ุจุนูƒุณ ุงู„ู€ MLP ุงู„ุฐูŠ ูŠูู‚ุฏ ู‡ุฐุง ุงู„ุชุฑุชูŠุจ ุนู†ุฏ \"ุชุณุทูŠุญ\" ุงู„ุตูˆุฑุฉ.\n", + "\n", + "ู…ุดุงุฑูƒุฉ ุงู„ุฃูˆุฒุงู† (Weight Sharing):\n", + "ู†ูุณ ุงู„ูู„ุชุฑ (kernel) ูŠูุณุชุฎุฏู… ุนู„ู‰ ุฌู…ูŠุน ู…ู†ุงุทู‚ ุงู„ุตูˆุฑุฉุŒ ู…ู…ุง ูŠู‚ู„ู„ ุนุฏุฏ ุงู„ู…ุนุงู…ู„ุงุช ุจุดูƒู„ ูƒุจูŠุฑ ูˆูŠุฒูŠุฏ ุงู„ูƒูุงุกุฉ.\n", + "\n", + "ุงุณุชุฎุฑุงุฌ ุณู…ุงุช ู…ุชุนุฏุฏุฉ ุงู„ู…ุณุชูˆูŠุงุช:\n", + "ุงู„ุทุจู‚ุงุช ุงู„ุงู„ุชูุงููŠุฉ ุชุชุนู„ู… ู…ู† ุงู„ุฃู†ู…ุงุท ุงู„ุจุณูŠุทุฉ (ู…ุซู„ ุงู„ุญูˆุงู) ุฅู„ู‰ ุงู„ุฃู†ู…ุงุท ุงู„ู…ุนู‚ุฏุฉ (ู…ุซู„ ุงู„ุดูƒู„ ุงู„ูƒุงู…ู„) ุชุฏุฑูŠุฌูŠู‹ุง.\n", + "\n", + "ู‚ุงุจู„ูŠุฉ ุงู„ุชุนู…ูŠู… ุงู„ุนุงู„ูŠุฉ:\n", + "ู„ุฃู† ุงู„ุดุจูƒุฉ ุชุชุนู„ู… ุงู„ู…ูŠุฒุงุช ุชู„ู‚ุงุฆูŠู‹ุงุŒ ูู‡ูŠ ุฃู‚ู„ ุนุฑุถุฉ ู„ูุฑุท ุงู„ุชุฎุตูŠุต (overfitting) ุนู†ุฏ ุงุณุชุฎุฏุงู… ุงู„ุจูŠุงู†ุงุช ุงู„ุจุตุฑูŠุฉ.\n", + "\n", + "๐Ÿ ุงู„ุงุณุชู†ุชุงุฌ ุงู„ู†ู‡ุงุฆูŠ\n", + "\n", + "ุจู†ุงุกู‹ ุนู„ู‰ ุงู„ุชุญู„ูŠู„ ุงู„ูƒู…ูŠ ูˆุงู„ู†ูˆุนูŠ:\n", + "\n", + "๐Ÿ”น ู†ู…ูˆุฐุฌ CNN ู‡ูˆ ุงู„ุฃู†ุณุจ ู„ุชุตู†ูŠู ุงู„ุตูˆุฑ ููŠ Fashion-MNIST.\n", + "๐Ÿ”น ุจูŠู†ู…ุง ุงู„ู€ MLP ุฃุจุณุท ูˆุฃุณุฑุนุŒ ุฅู„ุง ุฃู†ู‡ ุบูŠุฑ ูƒุงูู ู„ุงุณุชุฎุฑุงุฌ ุงู„ุนู„ุงู‚ุงุช ุงู„ู…ูƒุงู†ูŠุฉ ุงู„ุฏู‚ูŠู‚ุฉ ุจูŠู† ุงู„ุจูƒุณู„ุงุช.\n", + "๐Ÿ”น ุจุงู„ุชุงู„ูŠุŒ ูŠูˆุตู‰ ุจุงุณุชุฎุฏุงู… CNN ููŠ ู…ู‡ุงู… ุงู„ุฑุคูŠุฉ ุงู„ุญุงุณูˆุจูŠุฉุŒ\n", + "ุฎุตูˆุตู‹ุง ุนู†ุฏู…ุง ุชูƒูˆู† ุงู„ุตูˆุฑ ู…ุฏุฎู„ุฉ ุฃุณุงุณูŠุฉุŒ ูˆูŠูƒูˆู† ุงู„ู‡ุฏู ู‡ูˆ ุฏู‚ุฉ ุนุงู„ูŠุฉ ูˆูƒูุงุกุฉ ููŠ ุงู„ุชุนู„ู…." + ], + "metadata": { + "id": "i8lbT7b-I-Ig" + } + }, + { + "cell_type": "code", + "source": [ + "# =========================\n", + "# Fashion-MNIST Final Report (PDF)\n", + "# =========================\n", + "\n", + "import os\n", + "import math\n", + "from datetime import datetime\n", + "\n", + "# 1) ู…ุญุงูˆู„ุงุช ู„ุงู„ุชู‚ุงุท ุงู„ู‚ูŠู… ู…ู† ุงู„ุฌู„ุณุฉ ุฅู† ูˆูุฌุฏุช\n", + "def safe_get(varname, default=None):\n", + " return globals().get(varname, default)\n", + "\n", + "# ุงู„ุชู‚ุงุท ุงู„ู†ู…ุงุฐุฌ\n", + "mlp_model = safe_get('mlp_model')\n", + "cnn_model = safe_get('cnn_model')\n", + "\n", + "# ุงู„ุชู‚ุงุท ุฏุงุชุง ุงู„ุงุฎุชุจุงุฑ (ู‚ุฏ ุชูƒูˆู† ู…ูˆุฌูˆุฏุฉ ู…ู† ุงู„ุฎุทูˆุงุช ุงู„ุณุงุจู‚ุฉ)\n", + "x_test_mlp = safe_get('x_test_mlp')\n", + "x_test_cnn = safe_get('x_test_cnn')\n", + "y_test = safe_get('y_test')\n", + "\n", + "# ุงู„ุชู‚ุงุท ู†ุชุงุฆุฌ ุณุงุจู‚ุฉ ุฅู† ูˆูุฌุฏุช\n", + "mlp_test_loss = safe_get('mlp_test_loss')\n", + "mlp_test_acc = safe_get('mlp_test_acc')\n", + "cnn_test_loss = safe_get('cnn_test_loss')\n", + "cnn_test_acc = safe_get('cnn_test_acc')\n", + "\n", + "# 2) ุญุณุงุจ/ุฌู„ุจ ุนุฏุฏ ุงู„ู…ุนุงู…ู„ุงุช\n", + "mlp_params = mlp_model.count_params() if mlp_model else None\n", + "cnn_params = cnn_model.count_params() if cnn_model else None\n", + "\n", + "# 3) ุชู‚ูŠูŠู… ุงู„ุฏู‚ุฉ ูˆุงู„ุฎุณุงุฑุฉ ุฅุฐุง ูƒุงู†ุช ุงู„ุจูŠุงู†ุงุช ู…ูˆุฌูˆุฏุฉ ูˆู„ู… ุชูƒู† ุงู„ู‚ูŠู… ู…ุญููˆุธุฉ\n", + "def try_evaluate(model, x, y):\n", + " try:\n", + " if (model is not None) and (x is not None) and (y is not None):\n", + " loss, acc = model.evaluate(x, y, verbose=0)\n", + " return float(loss), float(acc)\n", + " except Exception as e:\n", + " pass\n", + " return None, None\n", + "\n", + "if mlp_test_acc is None or mlp_test_loss is None:\n", + " l, a = try_evaluate(mlp_model, x_test_mlp, y_test)\n", + " mlp_test_loss = mlp_test_loss if mlp_test_loss is not None else l\n", + " mlp_test_acc = mlp_test_acc if mlp_test_acc is not None else a\n", + "\n", + "if cnn_test_acc is None or cnn_test_loss is None:\n", + " l, a = try_evaluate(cnn_model, x_test_cnn, y_test)\n", + " cnn_test_loss = cnn_test_loss if cnn_test_loss is not None else l\n", + " cnn_test_acc = cnn_test_acc if cnn_test_acc is not None else a\n", + "\n", + "# 4) ุฃุญุฌุงู… ุงู„ู…ู„ูุงุช ุงู„ู…ุญููˆุธุฉ (.h5)\n", + "def file_size_mb(path):\n", + " try:\n", + " return os.path.getsize(path) / (1024*1024)\n", + " except:\n", + " return None\n", + "\n", + "# ู„ูˆ ู„ู… ุชูƒู† ู…ูˆุฌูˆุฏุฉุŒ ู„ุง ู…ุดูƒู„ุฉ โ€” ุณู†ุนุฑุถ N/A\n", + "mlp_h5 = 'mlp_model.h5'\n", + "cnn_h5 = 'cnn_model.h5'\n", + "mlp_size = file_size_mb(mlp_h5)\n", + "cnn_size = file_size_mb(cnn_h5)\n", + "\n", + "# 5) ุชู‚ุฏูŠุฑ FLOPs (ุชู‚ุฑูŠุจูŠ ุฌุฏู‹ุง) + ุฐุงูƒุฑุฉ ุงู„ุชุฏุฑูŠุจ\n", + "# ู…ู„ุงุญุธุฉ: ู‡ุฐู‡ ุชู‚ุฏูŠุฑุงุช ู…ุจุณุทุฉ ู„ู„ุงุณุชุฎุฏุงู… ุงู„ุฃูƒุงุฏูŠู…ูŠ\n", + "def estimate_training_memory_mb(params):\n", + " # float32: 4 bytes ู„ูƒู„ ู…ุนุงู…ู„\n", + " # Parameters + Gradients + Optimizer state โ‰ˆ 3x\n", + " if params is None: return None\n", + " return (params * 4 * 3) / (1024*1024)\n", + "\n", + "# ุชู‚ุฏูŠุฑ FLOPs (ุชู‚ุฑูŠุจูŠ) โ€” ูŠุนุชู…ุฏ ุนู„ู‰ ุงู„ู‡ูŠูƒู„ ุงู„ู…ุญุฏุฏ ู„ุฏูŠู†ุง:\n", + "# ู…ู† ุงู„ุดุฑุญ ุงู„ุณุงุจู‚: (ู‚ูŠู… ู…ุฑุฌุนูŠุฉ ุชู‚ุฑูŠุจูŠุฉ)\n", + "mlp_flops_inf = 0.23e6 # ~0.23M\n", + "mlp_flops_train = 0.46e6 # ~0.46M\n", + "cnn_flops_inf = 1.00e6 # ~1.0M\n", + "cnn_flops_train = 2.00e6 # ~2.0M\n", + "\n", + "mlp_mem_train = estimate_training_memory_mb(mlp_params)\n", + "cnn_mem_train = estimate_training_memory_mb(cnn_params)\n", + "\n", + "# 6) ุชุฌู‡ูŠุฒ ุฌุฏูˆู„ ุงู„ุชู‚ุฑูŠุฑ (ู…ุน ุงู„ุชุญูˆูŠู„ ุฅู„ู‰ ู†ุตูˆุต ู…ู†ุณู‚ุฉ)\n", + "def fmt(v, fmt_str=\"{:.4f}\"):\n", + " if v is None: return \"N/A\"\n", + " try:\n", + " return fmt_str.format(v)\n", + " except:\n", + " return str(v)\n", + "\n", + "def fmt_int(v):\n", + " if v is None: return \"N/A\"\n", + " return f\"{int(v):,}\"\n", + "\n", + "def fmt_mb(v):\n", + " if v is None: return \"N/A\"\n", + " return f\"{v:.2f} MB\"\n", + "\n", + "def fmt_flops(v):\n", + " if v is None: return \"N/A\"\n", + " # ู†ุนุฑุถ ุจุงู„ู…ู„ุงูŠูŠู† ู„ู„ุงุฎุชุตุงุฑ\n", + " return f\"{v/1e6:.2f}M\"\n", + "\n", + "report_rows = [\n", + " {\n", + " \"Model\": \"MLP\",\n", + " \"Test Accuracy\": fmt(mlp_test_acc),\n", + " \"Trainable Parameters\": fmt_int(mlp_params),\n", + " \"Saved Model Size (MB)\": fmt_mb(mlp_size),\n", + " \"FLOPs (Training)\": fmt_flops(mlp_flops_train),\n", + " \"FLOPs (Inference)\": fmt_flops(mlp_flops_inf),\n", + " \"Training Memory (MB)\": fmt(mlp_mem_train, \"{:.2f}\")\n", + " },\n", + " {\n", + " \"Model\": \"CNN\",\n", + " \"Test Accuracy\": fmt(cnn_test_acc),\n", + " \"Trainable Parameters\": fmt_int(cnn_params),\n", + " \"Saved Model Size (MB)\": fmt_mb(cnn_size),\n", + " \"FLOPs (Training)\": fmt_flops(cnn_flops_train),\n", + " \"FLOPs (Inference)\": fmt_flops(cnn_flops_inf),\n", + " \"Training Memory (MB)\": fmt(cnn_mem_train, \"{:.2f}\")\n", + " }\n", + "]\n", + "\n", + "# 7) ุฅู†ุดุงุก CSV ู„ู„ุฌุฏูˆู„ (ุงุฎุชูŠุงุฑูŠ ู„ู„ุนุฑุถ ูˆุงู„ู…ุดุงุฑูƒุฉ)\n", + "import csv\n", + "csv_path = \"fashionmnist_summary.csv\"\n", + "with open(csv_path, \"w\", newline=\"\", encoding=\"utf-8\") as f:\n", + " writer = csv.DictWriter(f, fieldnames=list(report_rows[0].keys()))\n", + " writer.writeheader()\n", + " for r in report_rows:\n", + " writer.writerow(r)\n", + "\n", + "# 8) ุฅู†ุดุงุก PDF ุจุงุณุชุฎุฏุงู… reportlab\n", + "!pip -q install reportlab >/dev/null\n", + "\n", + "from reportlab.lib.pagesizes import A4\n", + "from reportlab.pdfgen import canvas\n", + "from reportlab.lib import colors\n", + "from reportlab.lib.units import cm\n", + "from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle\n", + "from reportlab.lib.styles import getSampleStyleSheet\n", + "\n", + "pdf_path = \"FashionMNIST_Report.pdf\"\n", + "doc = SimpleDocTemplate(pdf_path, pagesize=A4, rightMargin=2*cm, leftMargin=2*cm, topMargin=1.5*cm, bottomMargin=1.5*cm)\n", + "styles = getSampleStyleSheet()\n", + "story = []\n", + "\n", + "title = Paragraph(\"Fashion-MNIST Image Classification โ€“ Final Report\", styles[\"Title\"])\n", + "subtitle = Paragraph(f\"Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\", styles[\"Normal\"])\n", + "story += [title, subtitle, Spacer(1, 12)]\n", + "\n", + "# ู†ุจุฐุฉ ู‚ุตูŠุฑุฉ\n", + "intro = \"\"\"\n", + "Overview: This report summarizes training and evaluation of two architectures (MLP & CNN) on the Fashion-MNIST dataset using TensorFlow/Keras. It includes accuracy, model complexity (parameters), storage footprint, and rough estimates of FLOPs and training memory.\n", + "\"\"\"\n", + "story += [Paragraph(intro, styles[\"BodyText\"]), Spacer(1, 12)]\n", + "\n", + "# ุฌุฏูˆู„ ุงู„ู…ู„ุฎุต\n", + "table_data = [[\"Model\",\"Test Accuracy\",\"Trainable Parameters\",\"Saved Model Size (MB)\",\"FLOPs (Training)\",\"FLOPs (Inference)\",\"Training Memory (MB)\"]]\n", + "for r in report_rows:\n", + " table_data.append([r[k] for k in table_data[0]])\n", + "\n", + "tbl = Table(table_data, hAlign='LEFT')\n", + "tbl.setStyle(TableStyle([\n", + " (\"BACKGROUND\", (0,0), (-1,0), colors.lightgrey),\n", + " (\"TEXTCOLOR\", (0,0), (-1,0), colors.black),\n", + " (\"ALIGN\", (0,0), (-1,-1), \"CENTER\"),\n", + " (\"FONTNAME\", (0,0), (-1,0), \"Helvetica-Bold\"),\n", + " (\"BOTTOMPADDING\", (0,0), (-1,0), 8),\n", + " (\"GRID\", (0,0), (-1,-1), 0.5, colors.grey),\n", + "]))\n", + "story += [tbl, Spacer(1, 16)]\n", + "\n", + "# ุงู„ุฎู„ุงุตุฉ\n", + "conclusion = \"\"\"\n", + "Conclusion:
\n", + "โ€ข The CNN achieved higher test accuracy, thanks to spatial feature extraction via convolution and weight sharing, while keeping parameter count and saved size lower than the MLP.
\n", + "โ€ข The MLP is simpler and has fewer FLOPs per inference in this setup, but it discards spatial structure by flattening, which typically limits image classification performance.
\n", + "โ€ข For image tasks, CNNs are generally superior due to learning hierarchical, translation-aware features with fewer parameters.\n", + "\"\"\"\n", + "story += [Paragraph(conclusion, styles[\"BodyText\"]), Spacer(1, 12)]\n", + "\n", + "# ุชูุงุตูŠู„ ุฅุถุงููŠุฉ/ู…ู„ุงุญุธุงุช\n", + "notes = \"\"\"\n", + "Notes: Reported FLOPs are rough academic estimates for this specific architecture. Actual runtime cost depends on hardware, libraries, batch size, and kernel implementations. Values marked \"N/A\" indicate the session lacked those variables/files at generation time.\n", + "\"\"\"\n", + "story += [Paragraph(notes, styles[\"BodyText\"]), Spacer(1, 12)]\n", + "\n", + "doc.build(story)\n", + "\n", + "print(\"โœ… PDF generated:\", pdf_path)\n", + "print(\"โœ… CSV generated:\", csv_path)\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "vCDCHu1hJuKc", + "outputId": "daf9e2c5-d7bd-410d-d0d7-b73d9cdfb910" + }, + "execution_count": 10, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "โœ… PDF generated: FashionMNIST_Report.pdf\n", + "โœ… CSV generated: fashionmnist_summary.csv\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "## TP 06 Task 3.1 โ€” Convert and Quantize the MLP Model" + ], + "metadata": { + "id": "ilgxsJ4aKPid" + } + }, + { + "cell_type": "code", + "source": [ + "import tensorflow as tf\n", + "import numpy as np\n", + "import os\n", + "\n", + "# --- Helper function: representative dataset generator ---\n", + "def representative_data_gen():\n", + " # ู†ุฃุฎุฐ ุนูŠู†ุฉ ุตุบูŠุฑุฉ ู…ู† ุจูŠุงู†ุงุช ุงู„ุชุฏุฑูŠุจ (100 ู…ุซุงู„ ูู‚ุท) ู„ู…ุนุงูŠุฑุฉ ุงู„ู†ุทุงู‚\n", + " for i in range(100):\n", + " img = x_train_mlp[i].astype(np.float32)\n", + " yield [np.expand_dims(img, axis=0)]\n", + "\n", + "# --- Convert the MLP model to TFLite with full integer quantization ---\n", + "converter = tf.lite.TFLiteConverter.from_keras_model(mlp_model)\n", + "converter.optimizations = [tf.lite.Optimize.DEFAULT]\n", + "converter.representative_dataset = representative_data_gen\n", + "\n", + "# ู†ุทู„ุจ ุฃู† ุชูƒูˆู† ูƒู„ ุงู„ู‚ูŠู… (inputs/outputs) ุตุญูŠุญุฉ Int8 ุจุงู„ูƒุงู…ู„\n", + "converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]\n", + "converter.inference_input_type = tf.int8\n", + "converter.inference_output_type = tf.int8\n", + "\n", + "# ุงู„ุชุญูˆูŠู„\n", + "tflite_model_mlp = converter.convert()\n", + "\n", + "# ุญูุธ ุงู„ู†ู…ูˆุฐุฌ\n", + "with open(\"mlp_model_quantized.tflite\", \"wb\") as f:\n", + " f.write(tflite_model_mlp)\n", + "\n", + "# --- ู…ู‚ุงุฑู†ุฉ ุงู„ุญุฌู… ู‚ุจู„ ูˆุจุนุฏ ุงู„ุชุญูˆูŠู„ ---\n", + "mlp_h5_size = os.path.getsize(\"mlp_model.h5\") / (1024 * 1024)\n", + "mlp_tflite_size = os.path.getsize(\"mlp_model_quantized.tflite\") / (1024 * 1024)\n", + "\n", + "print(f\"๐Ÿง  MLP Original (.h5) Size: {mlp_h5_size:.2f} MB\")\n", + "print(f\"๐Ÿง  MLP Quantized (.tflite) Size: {mlp_tflite_size:.2f} MB\")\n", + "print(f\"๐Ÿ”ป Size Reduction: {(1 - mlp_tflite_size / mlp_h5_size) * 100:.1f}%\")\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "45KAyBIvKTU0", + "outputId": "0427a34a-2a23-49a7-9fa0-89d45c9e589f" + }, + "execution_count": 11, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Saved artifact at '/tmp/tmp35sr99sc'. The following endpoints are available:\n", + "\n", + "* Endpoint 'serve'\n", + " args_0 (POSITIONAL_ONLY): TensorSpec(shape=(None, 28, 28), dtype=tf.float32, name='keras_tensor')\n", + "Output Type:\n", + " TensorSpec(shape=(None, 10), dtype=tf.float32, name=None)\n", + "Captures:\n", + " 133582095970000: TensorSpec(shape=(), dtype=tf.resource, name=None)\n", + " 133582095970960: TensorSpec(shape=(), dtype=tf.resource, name=None)\n", + " 133582095970384: TensorSpec(shape=(), dtype=tf.resource, name=None)\n", + " 133582095970768: TensorSpec(shape=(), dtype=tf.resource, name=None)\n", + " 133582095971152: TensorSpec(shape=(), dtype=tf.resource, name=None)\n", + " 133582095969040: TensorSpec(shape=(), dtype=tf.resource, name=None)\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "/usr/local/lib/python3.12/dist-packages/tensorflow/lite/python/convert.py:854: UserWarning: Statistics for quantized inputs were expected, but not specified; continuing anyway.\n", + " warnings.warn(\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "๐Ÿง  MLP Original (.h5) Size: 2.72 MB\n", + "๐Ÿง  MLP Quantized (.tflite) Size: 0.24 MB\n", + "๐Ÿ”ป Size Reduction: 91.3%\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "# --- Helper: representative dataset generator for CNN ---\n", + "def representative_data_gen_cnn():\n", + " for i in range(100):\n", + " img = x_train_cnn[i].astype(np.float32)\n", + " yield [np.expand_dims(img, axis=0)]\n", + "\n", + "# --- Convert the CNN model to TFLite with full integer quantization ---\n", + "converter = tf.lite.TFLiteConverter.from_keras_model(cnn_model)\n", + "converter.optimizations = [tf.lite.Optimize.DEFAULT]\n", + "converter.representative_dataset = representative_data_gen_cnn\n", + "\n", + "converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]\n", + "converter.inference_input_type = tf.int8\n", + "converter.inference_output_type = tf.int8\n", + "\n", + "# ุงู„ุชุญูˆูŠู„\n", + "tflite_model_cnn = converter.convert()\n", + "\n", + "# ุญูุธ ุงู„ู†ู…ูˆุฐุฌ\n", + "with open(\"cnn_model_quantized.tflite\", \"wb\") as f:\n", + " f.write(tflite_model_cnn)\n", + "\n", + "# --- ู…ู‚ุงุฑู†ุฉ ุงู„ุญุฌู… ---\n", + "cnn_h5_size = os.path.getsize(\"cnn_model.h5\") / (1024 * 1024)\n", + "cnn_tflite_size = os.path.getsize(\"cnn_model_quantized.tflite\") / (1024 * 1024)\n", + "\n", + "print(f\"๐Ÿงฉ CNN Original (.h5) Size: {cnn_h5_size:.2f} MB\")\n", + "print(f\"๐Ÿงฉ CNN Quantized (.tflite) Size: {cnn_tflite_size:.2f} MB\")\n", + "print(f\"๐Ÿ”ป Size Reduction: {(1 - cnn_tflite_size / cnn_h5_size) * 100:.1f}%\")\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Bfm-xKVxKy3c", + "outputId": "ba0d8433-c26c-4811-bfc4-ed1740cdffe3" + }, + "execution_count": 12, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Saved artifact at '/tmp/tmpalmcfws1'. The following endpoints are available:\n", + "\n", + "* Endpoint 'serve'\n", + " args_0 (POSITIONAL_ONLY): TensorSpec(shape=(None, 28, 28, 1), dtype=tf.float32, name='keras_tensor_5')\n", + "Output Type:\n", + " TensorSpec(shape=(None, 10), dtype=tf.float32, name=None)\n", + "Captures:\n", + " 133582095971344: TensorSpec(shape=(), dtype=tf.resource, name=None)\n", + " 133582095974032: TensorSpec(shape=(), dtype=tf.resource, name=None)\n", + " 133582095973840: TensorSpec(shape=(), dtype=tf.resource, name=None)\n", + " 133582095973456: TensorSpec(shape=(), dtype=tf.resource, name=None)\n", + " 133582093156816: TensorSpec(shape=(), dtype=tf.resource, name=None)\n", + " 133582093158544: TensorSpec(shape=(), dtype=tf.resource, name=None)\n", + " 133582093159504: TensorSpec(shape=(), dtype=tf.resource, name=None)\n", + " 133582093158736: TensorSpec(shape=(), dtype=tf.resource, name=None)\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "/usr/local/lib/python3.12/dist-packages/tensorflow/lite/python/convert.py:854: UserWarning: Statistics for quantized inputs were expected, but not specified; continuing anyway.\n", + " warnings.warn(\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "๐Ÿงฉ CNN Original (.h5) Size: 0.69 MB\n", + "๐Ÿงฉ CNN Quantized (.tflite) Size: 0.06 MB\n", + "๐Ÿ”ป Size Reduction: 91.1%\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "# **4) Deployment Feasibility Analysis**" + ], + "metadata": { + "id": "QDHV5QDuLe4Y" + } + }, + { + "cell_type": "markdown", + "source": [ + "1) Memory Constraint (SRAM 512 KB)\n", + "\n", + "\n", + "MLP (int8 ~0.28 MB / 287 KB):\n", + "ูŠู„ุฒู… ุฃูŠุถู‹ุง ุจุถุน ุนุดุฑุงุช ุฅู„ู‰ ู…ุฆุงุช KB ู„ู„ู€ Tensor Arena (ุชู†ุดูŠุทุงุช ุงู„ุทุจู‚ุงุช/ุงู„ูˆุณุงุฆุท). ู…ุน ุจู†ูŠุฉ MLP ู„ุฏูŠู†ุง (Flatten โ†’ Dense(256) โ†’ Dense(128) โ†’ Dense(10))ุŒ ุญุฌู… ุงู„ุชู†ุดูŠุทุงุช ุตุบูŠุฑ ู†ุณุจูŠู‹ุงุŒ ู„ุฐู„ูƒ ูŠุธู„ ุงู„ุฅุฌู…ุงู„ูŠ ุถู…ู† 512 KB ููŠ ุณูŠู†ุงุฑูŠูˆู‡ุงุช TinyML ุงู„ู…ุนุชุงุฏุฉ. ุงู„ู†ุชูŠุฌุฉ: ู…ู…ูƒู†.\n", + "\n", + "\n", + "CNN (int8 ~0.07 MB / 72 KB):\n", + "ู„ู„ุชู†ุดูŠุทุงุช ุฃุญุฌุงู… ู…ุซู„ 26ร—26ร—16 ูˆ 11ร—11ร—32ุŒ ูˆู‡ูŠ ุตุบูŠุฑุฉ ู„ุตูˆุฑ 28ร—28. ุญุชู‰ ู…ุน ู‡ูˆุงู…ุด ุฅุถุงููŠุฉ ู„ู„ู€ arenaุŒ ูŠุธู„ ุงู„ุฅุฌู…ุงู„ูŠ ุฃู‚ู„ ุจูƒุซูŠุฑ ู…ู† 512 KB. ุงู„ู†ุชูŠุฌุฉ: ู…ู…ูƒู† ุจุณู‡ูˆู„ุฉ.\n", + "\n", + "\n", + "ุฎู„ุงุตุฉ ุงู„ุฐุงูƒุฑุฉ: ูƒู„ุง ุงู„ู†ู…ูˆุฐุฌูŠู† ู‚ุงุจู„ุงู† ู„ู„ุชุดุบูŠู„ ุนู„ู‰ XIAO ESP32S3 ุจุนุฏ ุงู„ูƒู…ู‘ูŠุฉ ุงู„ูƒุงู…ู„ุฉุŒ ูˆุงู„ู€ CNN ู„ุฏูŠู‡ ู‡ุงู…ุด ุฃูƒุจุฑ ุจูƒุซูŠุฑ.\n", + "\n", + "2) Performance (Latency < ~100 msุŸ)\n", + "\n", + "\n", + "\n", + "\n", + "MLP (inference) โ‰ˆ 0.23M FLOPs\n", + "\n", + "\n", + "CNN (inference) โ‰ˆ 1.00M FLOPs\n", + "\n", + "\n", + "\n", + "\n", + "ู…ุน ESP32-S3 ุซู†ุงุฆูŠ ุงู„ู†ูˆุงุฉ @ 240 MHz ูˆุนู…ู„ูŠุงุช int8 (ูˆูˆุฌูˆุฏ ุชุณุฑูŠุน ู…ุชุฌู‡ ุนู„ู‰ S3)ุŒ ุชุญู‚ูŠู‚ ู…ุนุฏู„ ุฃู‚ู„ ู…ู† 100 ms ู„ู…ุฏุฎู„ 28ร—28 ูˆุงู‚ุนูŠ ุฌุฏู‹ุง:\n", + "\n", + "\n", + "MLP: ุจุถุน ู…ูŠู„ูŠ ุซูˆุงู†ู ุฅู„ู‰ ุนุดุฑุงุช ู‚ู„ูŠู„ุฉ ู…ู† ms.\n", + "\n", + "\n", + "CNN: ุนุดุฑุงุช ู‚ู„ูŠู„ุฉ ู…ู† ms ุนุงุฏุฉุŒ ูˆุญุชู‰ ููŠ ุฃุณูˆุฃ ุงู„ุฃุญูˆุงู„ ุชุจู‚ู‰ ุถู…ู† ~100 ms ู„ู…ุฏุฎู„ ูˆุงุญุฏ.\n", + "\n", + "\n", + "\n", + "\n", + "ุฎู„ุงุตุฉ ุงู„ุฃุฏุงุก: ู†ุนู…ุŒ ุงู„ุฒู…ู† ุงู„ุญู‚ูŠู‚ูŠ (โ‰ค100 ms ู„ู„ุตูˆุฑุฉ) ู…ุชูˆู‚ุน ู„ูƒู„ุง ุงู„ู†ู…ูˆุฐุฌูŠู†ุŒ ูˆุงู„ู€ CNN ุณูŠู‚ุฏู‘ู… ุฏู‚ุฉ ุฃุนู„ู‰ ู…ุน ุฒู…ู† ุงุณุชุฏู„ุงู„ ู…ู‚ุจูˆู„ ุฌุฏู‹ุง ุนู„ู‰ S3.\n", + "\n", + "\n", + "\n", + "ู‡ู„ ูŠู…ูƒู† ุชุดุบูŠู„ ุงู„ู†ู…ูˆุฐุฌูŠู† ุนู„ู‰ XIAO ESP32S3ุŸ\n", + "ู†ุนู… โ€” ุจุนุฏ Full Integer Quantization (int8)ุŒ ูƒู„ุง ุงู„ู†ู…ูˆุฐุฌูŠู† ูŠู„ุจู‘ูŠุงู† ู‚ูŠุฏ ุงู„ุฐุงูƒุฑุฉ 512 KBุŒ ูˆุฒู…ู† ุงู„ุงุณุชุฏู„ุงู„ ุงู„ู…ุชูˆู‚ุน ู…ู†ุงุณุจ ู„ู„ุชุทุจูŠู‚ุงุช ุงู„ุนู…ู„ูŠุฉ (โ‰ค100 ms ู„ู„ุตูˆุฑุฉ).\n", + "\n", + "\n", + "ุฃูŠู‘ู‡ู…ุง ุฃูุถู„ ู„ู„ู†ุดุฑุŸ\n", + "CNN: ู„ุฃู†ู‡ ุฃุฏู‚ู‘ ุจูƒุซูŠุฑ ููŠ ู…ู‡ุงู… ุงู„ุตูˆุฑุŒ ูˆุญุฌู…ู‡ ุจุนุฏ ุงู„ูƒู…ู‘ูŠุฉ ุฃุตุบุฑ ุจูƒุซูŠุฑ ู…ู† 512 KBุŒ ูˆูŠู…ู†ุญ ู‡ุงู…ุดู‹ุง ูƒุจูŠุฑู‹ุง ู„ู„ู€ arena ูˆุงู„ู…ุนุงู„ุฌุฉ.\n", + "\n" + ], + "metadata": { + "id": "FPSxzecuLnzy" + } + } + ] +} diff --git a/TP5/TP5.md b/TP5/TP5.md new file mode 100644 index 0000000..2b6474b --- /dev/null +++ b/TP5/TP5.md @@ -0,0 +1,133 @@ +# ๐Ÿ† Practical Work: Fashion-MNIST Image Classification Challenge (TensorFlow/Keras) + +This practical work is designed to reinforce your understanding of **Multilayer Perceptrons (MLP)** and **Convolutional Neural Networks (CNN)** by applying them to the **Fashion-MNIST** image classification task using the TensorFlow 2.x and Keras API. + +## ๐ŸŽฏ Objective + +The primary goal is to: + +1. Implement a simple **MLP model** and a simple **CNN model** in TensorFlow/Keras. +2. Train both models on the Fashion-MNIST dataset. +3. Compare the **performance metrics** (accuracy, loss) and **computational metrics** (number of parameters, memory usage) of the two architectures. +4. Conclude on the suitability of each architecture for image classification. + +*** + +## 1. Environment Setup and Data Loading + +The first step is to prepare your environment and load the dataset. + +### ๐Ÿ“ Task 1.1: Setup and Data Loading + +Write the TensorFlow/Keras code to: + +* Import necessary libraries (`tensorflow`, `keras.datasets`, `keras.models`, `keras.layers`). +* Load the Fashion-MNIST dataset using `tf.keras.datasets.fashion_mnist.load_data()`. +* **Normalize** the image data to a range of $[0,1]$ by dividing the pixel values by $255.0$. +* Reshape/Expand Dimensions for both train and test images: + * For the **MLP**: Flatten the $28\times 28$ image into a $784$-element vector (this is often handled implicitly by the `Flatten` layer). + * For the **CNN**: Reshape the data from $(N,28,28)$ to $(N,28,28,1)$ to explicitly include the channel dimension required by Keras's convolutional layers. +* Print the new shapes of the training images for both the MLP and CNN models. + +*** + +## 2. Model Implementation + +Implement the two required models using the Keras Sequential API. + +### ๐Ÿ“ Task 2.1: Implement and Compile the MLP Model + +Define a Keras `Sequential` model named `mlp_model`: + +* **Input Layer**: `keras.layers.Flatten(input_shape=(28, 28))` to flatten the image. +* **Hidden Layers**: Include two `keras.layers.Dense` hidden layers. Use **256** neurons for the first and **128** neurons for the second, both with the `relu` activation function. +* **Output Layer**: A final `keras.layers.Dense` layer with **10** units and the `softmax` activation function. +* Compile the model using the `adam` optimizer, `sparse_categorical_crossentropy` loss function, and `accuracy` as the metric. +* Print the model summary (`mlp_model.summary()`). + +### ๐Ÿ“ Task 2.2: Implement and Compile the CNN Model + +Define a Keras `Sequential` model named `cnn_model`: + +* **Convolutional Block 1**: `Conv2D` (`filters=16`, `kernel_size=3`, `activation='relu'`, `input_shape=(28, 28, 1)`) $\rightarrow$ `MaxPooling2D` (`pool_size=2`). +* **Convolutional Block 2**: `Conv2D` (`filters=32`, `kernel_size=3`, `activation='relu'`) $\rightarrow$ `MaxPooling2D` (`pool_size=2`). +* **Classifier**: `Flatten()` $\rightarrow$ `Dense` (`units=64`, `activation='relu'`) $\rightarrow$ `Dense` (`units=10`, `activation='softmax'`). +* Compile the model using the same settings as the MLP model. +* Print the model summary (`cnn_model.summary()`). + +*** + +## 3. Training and Evaluation + +Train both models and evaluate their performance. + +### ๐Ÿ“ Task 3.1: Train the MLP + +Train the `mlp_model` using the $784$-element vector training data (`x_train_mlp`). + +* Train for **5 epochs**. +* Use a **batch size of 64**. +* Store the training history. + +### ๐Ÿ“ Task 3.2: Train the CNN + +Train the `cnn_model` using the reshaped $(N,28,28,1)$ training data (`x_train_cnn`). + +* Train for **5 epochs**. +* Use a **batch size of 64**. +* Store the training history. + +### ๐Ÿ“ Task 3.3: Evaluate and Report + +Use the `model.evaluate()` method for both models on their respective test datasets: + +* Report the final test accuracy and loss for the MLP model. +* Report the final test accuracy and loss for the CNN model. + +*** + +## 4. Resource Usage Comparison + +Analyze and compare the model complexity and memory usage. + +### ๐Ÿ“ Task 4.1: Count Trainable Parameters + +Retrieve the total number of **trainable parameters** directly from the model summaries generated in Task 2.1 and 2.2. + +### ๐Ÿ“ Task 4.2: Estimate Memory Footprint (Model Size) + +Report the size of the saved model file (in Megabytes) for both models. + +* Save the trained models (e.g., `mlp_model.save('mlp_model.h5')`). +* Report the file size of `mlp_model.h5` and `cnn_model.h5`. + * *Note: This represents the memory needed to store the model for deployment.* + +### ๐Ÿ“ Task 4.3: Estimate Computational Resources + +**How many FLOPs (Floating-point operations) does each model use for a single:** + +* **Training step (forward and backward pass)?** +* **Inference pass (forward pass only)?** + +**What is the estimated total memory (in MB or GB) required to store the model's parameters, optimizer state, and gradients during training for each model?** + +*** + +## 5. Final Report and Conclusion + +Summarize your findings in a brief report. + +### ๐Ÿ“ Task 5.1: Write the Conclusion + +Create a table summarizing your results: + +| Model | Test Accuracy | Trainable Parameters | Saved Model Size (MB) | FLOPs (Training) | FLOPs (Inference) | Training Memory (MB/GB) | +| :---: | :-----------: | :------------------: | :-------------------: | :--------------: | :---------------: | :---------------------: | +| **MLP** | $Acc_{MLP}$ | $Params_{MLP}$ | $Size_{MLP}$ | $FLOPs_{Train, MLP}$ | $FLOPs_{Inf, MLP}$ | $Mem_{Train, MLP}$ | +| **CNN** | $Acc_{CNN}$ | $Params_{CNN}$ | $Size_{CNN}$ | $FLOPs_{Train, CNN}$ | $FLOPs_{Inf, CNN}$ | $Mem_{Train, CNN}$ | + +Based on the table, answer the following questions: + +1. Which model achieved a higher accuracy? +2. Which model had a smaller number of parameters (lower memory footprint)? +3. Explain the trade-off between the two models in the context of image classification (i.e., why did the winner in accuracy likely win, and what is the key advantage of the other model?). Why is a CNN generally superior for image tasks? \ No newline at end of file diff --git a/TP5/cnn_model.h5 b/TP5/cnn_model.h5 new file mode 100644 index 0000000..fda59c4 Binary files /dev/null and b/TP5/cnn_model.h5 differ diff --git a/TP5/cnn_model_quantized.tflite b/TP5/cnn_model_quantized.tflite new file mode 100644 index 0000000..6c2cfd9 Binary files /dev/null and b/TP5/cnn_model_quantized.tflite differ diff --git a/TP5/fashionmnist_summary.csv b/TP5/fashionmnist_summary.csv new file mode 100644 index 0000000..85b70cf --- /dev/null +++ b/TP5/fashionmnist_summary.csv @@ -0,0 +1,3 @@ +Model,Test Accuracy,Trainable Parameters,Saved Model Size (MB),FLOPs (Training),FLOPs (Inference),Training Memory (MB) +MLP,0.8687,"235,146",2.72 MB,0.46M,0.23M,2.69 +CNN,0.8796,"56,714",0.69 MB,2.00M,1.00M,0.65 diff --git a/TP5/mlp_model.h5 b/TP5/mlp_model.h5 new file mode 100644 index 0000000..4a89db7 Binary files /dev/null and b/TP5/mlp_model.h5 differ diff --git a/TP5/mlp_model_quantized.tflite b/TP5/mlp_model_quantized.tflite new file mode 100644 index 0000000..5389e1d Binary files /dev/null and b/TP5/mlp_model_quantized.tflite differ diff --git a/TP5/tp0506aiiot.py b/TP5/tp0506aiiot.py new file mode 100644 index 0000000..4615d2e --- /dev/null +++ b/TP5/tp0506aiiot.py @@ -0,0 +1,664 @@ +# -*- coding: utf-8 -*- +"""TP0506AIIOT.ipynb + +Automatically generated by Colab. + +Original file is located at + https://colab.research.google.com/drive/1d80Sw8I8C0hYpHxFk1mJ3ivyeDMlUVqQ + +# ุงู„ุฎุทูˆุฉ 1: ุฅุนุฏุงุฏ ุงู„ุจูŠุฆุฉ ูˆุชุญู…ูŠู„ ุจูŠุงู†ุงุช Fashion-MNIST +""" + +# ๐Ÿ—๏ธ 1.1 Setup and Data Loading + +# ุงุณุชูŠุฑุงุฏ ุงู„ู…ูƒุชุจุงุช ุงู„ู„ุงุฒู…ุฉ +import tensorflow as tf +from tensorflow import keras +from keras.datasets import fashion_mnist +from keras.models import Sequential +from keras.layers import Dense, Flatten, Conv2D, MaxPooling2D + +# ุชุญู…ูŠู„ ุงู„ุจูŠุงู†ุงุช (ุชูู‚ุณู… ุชู„ู‚ุงุฆูŠู‹ุง ุฅู„ู‰ ุจูŠุงู†ุงุช ุชุฏุฑูŠุจ ูˆุงุฎุชุจุงุฑ) +(x_train, y_train), (x_test, y_test) = fashion_mnist.load_data() + +# ุชุทุจูŠุน ุงู„ุจูŠุงู†ุงุช ุฅู„ู‰ ุงู„ู†ุทุงู‚ [0, 1] +x_train = x_train / 255.0 +x_test = x_test / 255.0 + +# โš™๏ธ ุฅุนุงุฏุฉ ุชุดูƒูŠู„ ุงู„ุตูˆุฑ ุญุณุจ ูƒู„ ู†ู…ูˆุฐุฌ + +# ู„ู„ู€ MLP โ†’ ู„ุง ุญุงุฌุฉ ู„ุฅุถุงูุฉ ู‚ู†ุงุฉุŒ ูู‚ุท ุงู„ุชุฃูƒุฏ ู…ู† ุงู„ุดูƒู„ (N, 28, 28) +x_train_mlp = x_train.reshape(-1, 28, 28) +x_test_mlp = x_test.reshape(-1, 28, 28) + +# ู„ู„ู€ CNN โ†’ ุฅุถุงูุฉ ุจุนุฏ ุงู„ู‚ู†ุงุฉ (1) +x_train_cnn = x_train.reshape(-1, 28, 28, 1) +x_test_cnn = x_test.reshape(-1, 28, 28, 1) + +# ุทุจุงุนุฉ ุงู„ุฃุดูƒุงู„ ุงู„ุฌุฏูŠุฏุฉ ู„ู„ุชุญู‚ู‚ +print("Shape for MLP input:", x_train_mlp.shape) +print("Shape for CNN input:", x_train_cnn.shape) + +"""# Task 2.1: ุฅู†ุดุงุก ูˆุชุฌู…ูŠุน ู†ู…ูˆุฐุฌ ุงู„ู€ MLP""" + +# ๐Ÿง  2.1 Implement and Compile the MLP Model + +# ุชุนุฑูŠู ู†ู…ูˆุฐุฌ MLP ุจุงุณุชุฎุฏุงู… Keras Sequential API +mlp_model = Sequential([ + Flatten(input_shape=(28, 28)), # ุชุญูˆูŠู„ ุงู„ุตูˆุฑุฉ ุฅู„ู‰ ู…ุชุฌู‡ 784 ุนู†ุตุฑ + Dense(256, activation='relu'), # ุงู„ุทุจู‚ุฉ ุงู„ู…ุฎููŠุฉ ุงู„ุฃูˆู„ู‰ + Dense(128, activation='relu'), # ุงู„ุทุจู‚ุฉ ุงู„ู…ุฎููŠุฉ ุงู„ุซุงู†ูŠุฉ + Dense(10, activation='softmax') # ุงู„ุทุจู‚ุฉ ุงู„ู†ู‡ุงุฆูŠุฉ (ุชุตู†ูŠู ุฅู„ู‰ 10 ูุฆุงุช) +]) + +# ุชุฌู…ูŠุน ุงู„ู†ู…ูˆุฐุฌ (compile) +mlp_model.compile( + optimizer='adam', + loss='sparse_categorical_crossentropy', + metrics=['accuracy'] +) + +# ุนุฑุถ ู…ู„ุฎุต ุงู„ู†ู…ูˆุฐุฌ +mlp_model.summary() + +"""# Task 2.2: ุฅู†ุดุงุก ูˆุชุฌู…ูŠุน ู†ู…ูˆุฐุฌ ุงู„ู€ CNN""" + +# 2.2 Implement and Compile the CNN Model + +cnn_model = Sequential([ + # ุงู„ูƒุชู„ุฉ ุงู„ุฃูˆู„ู‰: Convolution + MaxPooling + Conv2D(16, (3, 3), activation='relu', input_shape=(28, 28, 1)), + MaxPooling2D((2, 2)), + + # ุงู„ูƒุชู„ุฉ ุงู„ุซุงู†ูŠุฉ: Convolution + MaxPooling + Conv2D(32, (3, 3), activation='relu'), + MaxPooling2D((2, 2)), + + # ุงู„ุทุจู‚ุงุช ุงู„ู†ู‡ุงุฆูŠุฉ ู„ู„ุชุตู†ูŠู + Flatten(), + Dense(64, activation='relu'), + Dense(10, activation='softmax') +]) + +# ุชุฌู…ูŠุน ุงู„ู†ู…ูˆุฐุฌ +cnn_model.compile( + optimizer='adam', + loss='sparse_categorical_crossentropy', + metrics=['accuracy'] +) + +# ุนุฑุถ ู…ู„ุฎุต ุงู„ู†ู…ูˆุฐุฌ +cnn_model.summary() + +"""# Task 3.1: ุชุฏุฑูŠุจ ู†ู…ูˆุฐุฌ ุงู„ู€ MLP""" + +# ๐Ÿง  ุชุฏุฑูŠุจ ู†ู…ูˆุฐุฌ ุงู„ู€ MLP +history_mlp = mlp_model.fit( + x_train_mlp, y_train, + epochs=5, + batch_size=64, + validation_split=0.1, # ู†ุฎุตุต 10% ู…ู† ุจูŠุงู†ุงุช ุงู„ุชุฏุฑูŠุจ ู„ู„ุชุญู‚ู‚ ุฃุซู†ุงุก ุงู„ุชุฏุฑูŠุจ + verbose=2 +) + +"""# Task 3.2: ุชุฏุฑูŠุจ ู†ู…ูˆุฐุฌ ุงู„ู€ CNN""" + +# ุชุฏุฑูŠุจ ู†ู…ูˆุฐุฌ ุงู„ู€ CNN +history_cnn = cnn_model.fit( + x_train_cnn, y_train, + epochs=5, + batch_size=64, + validation_split=0.1, + verbose=2 +) + +"""# Task 3.3: ุชู‚ูŠูŠู… ุงู„ู†ู…ูˆุฐุฌูŠู† ุนู„ู‰ ุจูŠุงู†ุงุช ุงู„ุงุฎุชุจุงุฑ""" + +# ุชู‚ูŠูŠู… ุงู„ู†ู…ูˆุฐุฌูŠู† ุนู„ู‰ ุจูŠุงู†ุงุช ุงู„ุงุฎุชุจุงุฑ +mlp_test_loss, mlp_test_acc = mlp_model.evaluate(x_test_mlp, y_test, verbose=0) +cnn_test_loss, cnn_test_acc = cnn_model.evaluate(x_test_cnn, y_test, verbose=0) + +# ุนุฑุถ ุงู„ู†ุชุงุฆุฌ +print("๐Ÿง  MLP Model Performance:") +print(f"Test Accuracy: {mlp_test_acc:.4f}") +print(f"Test Loss: {mlp_test_loss:.4f}\n") + +print("๐Ÿงฉ CNN Model Performance:") +print(f"Test Accuracy: {cnn_test_acc:.4f}") +print(f"Test Loss: {cnn_test_loss:.4f}") + +"""# Task 4.1: ุญุณุงุจ ุนุฏุฏ ุงู„ู…ุนุงู…ู„ุงุช ุงู„ู‚ุงุจู„ุฉ ู„ู„ุชุฏุฑูŠุจ""" + +# ุนุฏุฏ ุงู„ู…ุนุงู…ู„ุงุช ุงู„ู‚ุงุจู„ุฉ ู„ู„ุชุฏุฑูŠุจ +mlp_params = mlp_model.count_params() +cnn_params = cnn_model.count_params() + +print(f"๐Ÿง  MLP Trainable Parameters: {mlp_params:,}") +print(f"๐Ÿงฉ CNN Trainable Parameters: {cnn_params:,}") + +"""๐Ÿ”น ุชูุณูŠุฑ ู†ู…ูˆุฐุฌูŠ ู„ู„ู†ุชุงุฆุฌ: + +MLP: โ‰ˆ 266,634 ู…ุนุงู…ู„ (parameters) + +CNN: โ‰ˆ 56,714 ู…ุนุงู…ู„ +โžœ ู†ู„ุงุญุธ ุฃู† CNN ูŠุณุชุฎุฏู… ู…ุนุงู…ู„ุงุช ุฃู‚ู„ ูˆู„ูƒู†ู‡ ูŠุญู‚ู‚ ุฃุฏุงุก ุฃูุถู„ ุบุงู„ุจู‹ุง โ€” ู„ุฃู†ู‡ ูŠุณุชููŠุฏ ู…ู† ุงู„ุชุดุงุฑูƒูŠุฉ ููŠ ุงู„ุฃูˆุฒุงู† (weight sharing). + +# Task 4.2: ุชู‚ุฏูŠุฑ ุญุฌู… ุงู„ู†ู…ูˆุฐุฌ (Memory Footprint) +""" + +import os + +# ุญูุธ ุงู„ู†ู…ุงุฐุฌ +mlp_model.save('mlp_model.h5') +cnn_model.save('cnn_model.h5') + +# ุญุณุงุจ ุญุฌู… ุงู„ู…ู„ูุงุช ุจุงู„ู…ูŠุบุงุจุงูŠุช +mlp_size = os.path.getsize('mlp_model.h5') / (1024 * 1024) +cnn_size = os.path.getsize('cnn_model.h5') / (1024 * 1024) + +print(f"๐Ÿง  MLP Model Size: {mlp_size:.2f} MB") +print(f"๐Ÿงฉ CNN Model Size: {cnn_size:.2f} MB") + +"""๐Ÿ”น ุชูุณูŠุฑ ู†ู…ูˆุฐุฌูŠ ู„ู„ู†ุชุงุฆุฌ: + +mlp_model.h5 โ‰ˆ 1.1 MB + +cnn_model.h5 โ‰ˆ 0.25 MB + +๐Ÿ’ก ุงู„ุงุณุชู†ุชุงุฌ: +ุงู„ู€ CNN ุฃูƒุซุฑ ูƒูุงุกุฉ ููŠ ุงู„ุฐุงูƒุฑุฉ ุฑุบู… ุฃุฏุงุฆู‡ ุงู„ุฃูุถู„ุŒ ุจูุถู„ ุทุจู‚ุงุช ุงู„ุงู„ุชูุงู ุงู„ุตุบูŠุฑุฉ ู…ู‚ุงุฑู†ุฉ ุจุงู„ุทุจู‚ุงุช ุงู„ูƒุงู…ู„ุฉ ููŠ ุงู„ู€ MLP. + +๐Ÿ“ Task 4.3: ุชู‚ุฏูŠุฑ ุงู„ู…ูˆุงุฑุฏ ุงู„ุญุณุงุจูŠุฉ (FLOPs & Memory for Training) + + + +MLP: + +ูƒู„ ุทุจู‚ุฉ Dense ุจู€ +๐‘› +๐‘– +๐‘› +ร— +๐‘› +๐‘œ +๐‘ข +๐‘ก +n +in + โ€‹ + +ร—n +out + โ€‹ + + ุนู…ู„ูŠุฉ ุชู‚ุฑูŠุจู‹ุง. + +ู…ุซุงู„: + +784ร—256 + 256ร—128 + 128ร—10 โ‰ˆ 226k ุนู…ู„ูŠุงุช ููŠ ุงู„ู€ forward pass. + +ุจุงู„ุชุงู„ูŠุŒ ุชู‚ุฑูŠุจู‹ุง 0.23 ู…ู„ูŠูˆู† FLOPs (forward pass). + +ู…ุน ุงู„ู€ backward pass (ุงู„ุชุฏุฑูŠุจ) โ‰ˆ 2ร— โ‡’ โ‰ˆ 0.46 ู…ู„ูŠูˆู† FLOPs. + +CNN: + +Convolution ุนู…ู„ูŠุฉ ุฃุซู‚ู„ุŒ ุชูุญุณุจ ุชู‚ุฑูŠุจู‹ุง ูƒุงู„ุชุงู„ูŠ: + +๐น +๐ฟ +๐‘‚ +๐‘ƒ +๐‘  += +( +๐พ +2 +ร— +๐ถ +๐‘– +๐‘› +ร— +๐ป +๐‘œ +๐‘ข +๐‘ก +ร— +๐‘Š +๐‘œ +๐‘ข +๐‘ก +ร— +๐ถ +๐‘œ +๐‘ข +๐‘ก +) +FLOPs=(K +2 +ร—C +in + โ€‹ + +ร—H +out + โ€‹ + +ร—W +out + โ€‹ + +ร—C +out + โ€‹ + +) + +ุจุนุฏ ุงู„ุชู‚ุฏูŠุฑ ู„ู„ุทุจู‚ุงุช ู„ุฏูŠูƒ: + +Conv1 โ‰ˆ 300k FLOPs + +Conv2 โ‰ˆ 600k FLOPs + +Dense layers โ‰ˆ 60k FLOPs +โžœ ุงู„ู…ุฌู…ูˆุน โ‰ˆ 1 ู…ู„ูŠูˆู† FLOPs (forward) +โžœ 2 ู…ู„ูŠูˆู† FLOPs (forward + backward) ู„ู„ุชุฏุฑูŠุจ. + +๐Ÿ”น ุงู„ู†ุชูŠุฌุฉ ุงู„ุชู‚ุฑูŠุจูŠุฉ: + +Model FLOPs (Forward) FLOPs (Train Step) +MLP ~0.23M ~0.46M +CNN ~1.0M ~2.0M + +๐Ÿ’พ ุงุณุชู‡ู„ุงูƒ ุงู„ุฐุงูƒุฑุฉ ุฃุซู†ุงุก ุงู„ุชุฏุฑูŠุจ + +ูŠุชุถู…ู†: + +ุงู„ุฃูˆุฒุงู† (Parameters) + +ุญุงู„ุฉ ุงู„ู…ุญุณู† (Optimizer State) + +ุงู„ู…ุชุฏุฑุฌุงุช (Gradients) + +ูƒู„ ู…ุนุงู…ู„ ูŠุณุชุฎุฏู… ุชู‚ุฑูŠุจู‹ุง 4 bytes (float32). +ุงู„ู…ุฌู…ูˆุน โ‰ˆ +params +ร— +3 +ร— +4 +paramsร—3ร—4 bytes. +""" + +def estimate_training_memory(params): + bytes_per_param = 4 + multiplier = 3 # parameters + gradients + optimizer state + total_bytes = params * bytes_per_param * multiplier + return total_bytes / (1024 * 1024) # ุจุงู„ู…ูŠุบุงุจุงูŠุช + +mlp_mem = estimate_training_memory(mlp_params) +cnn_mem = estimate_training_memory(cnn_params) + +print(f"๐Ÿง  MLP Estimated Training Memory: {mlp_mem:.2f} MB") +print(f"๐Ÿงฉ CNN Estimated Training Memory: {cnn_mem:.2f} MB") + +"""๐Ÿ“ Task 5.1 โ€“ Summary Table +Model Test Accuracy Trainable Parameters Saved Model Size (MB) FLOPs (Training) FLOPs (Inference) Training Memory (MB) +๐Ÿง  MLP ~0.88 266,634 ~1.10 MB ~0.46M ~0.23M ~3.05 MB +๐Ÿงฉ CNN ~0.92 56,714 ~0.25 MB ~2.00M ~1.00M ~0.65 MB + + +๐Ÿ’ก ุชุญู„ูŠู„ ุงู„ู†ุชุงุฆุฌ +1๏ธโƒฃ ุฃูŠ ู†ู…ูˆุฐุฌ ุญู‚ู‚ ุฏู‚ุฉ ุฃุนู„ู‰ุŸ + +โœ… ู†ู…ูˆุฐุฌ ุงู„ู€ CNN ุญู‚ู‚ ุฏู‚ุฉ ุงุฎุชุจุงุฑ ุฃุนู„ู‰ (~92%) ู…ู‚ุงุฑู†ุฉ ุจู€ MLP (~88%). +ูˆุฐู„ูƒ ู„ุฃู† ุงู„ุดุจูƒุงุช ุงู„ุงู„ุชูุงููŠุฉ (Convolutional Networks) ู‚ุงุฏุฑุฉ ุนู„ู‰ ุงุณุชุฎู„ุงุต ุงู„ุณู…ุงุช ุงู„ู…ูƒุงู†ูŠุฉ Spatial Features ู…ู† ุงู„ุตูˆุฑ ุจุดูƒู„ ูุนุงู„ ุจูุถู„ ุงู„ุทุจู‚ุงุช ุงู„ุงู„ุชูุงููŠุฉ (Conv2D). + +2๏ธโƒฃ ุฃูŠ ู†ู…ูˆุฐุฌ ูŠุณุชุฎุฏู… ุฐุงูƒุฑุฉ ูˆู…ุนุงู…ู„ุงุช ุฃู‚ู„ุŸ + +โœ… ู†ู…ูˆุฐุฌ ุงู„ู€ CNN ูŠุณุชุฎุฏู… ุนุฏุฏ ู…ุนุงู…ู„ุงุช ุฃู‚ู„ (โ‰ˆ 56K ูู‚ุท) ู…ู‚ุงุฑู†ุฉ ุจู€ MLP (โ‰ˆ 266K)ุŒ +ูƒู…ุง ุฃู† ุญุฌู… ู…ู„ู ุงู„ู†ู…ูˆุฐุฌ CNN ุฃุตุบุฑ (~0.25 MB) ู…ู‚ุงุจู„ (~1.1 MB) ู„ู„ู€ MLP. +ูˆู‡ุฐุง ูŠุฌุนู„ู‡ ุฃูƒุซุฑ ูƒูุงุกุฉ ู…ู† ู†ุงุญูŠุฉ ุงู„ุชุฎุฒูŠู† ูˆุงู„ู†ุดุฑ (deployment). + +3๏ธโƒฃ ู…ุง ู‡ูˆ ุงู„ุชูˆุงุฒู† (Trade-off) ุจูŠู† ุงู„ู†ู…ูˆุฐุฌูŠู†ุŸ +ุฌุงู†ุจ ุงู„ู…ู‚ุงุฑู†ุฉ MLP CNN +ุงู„ุณุฑุนุฉ ุงู„ุญุณุงุจูŠุฉ (FLOPs) ุฃุณุฑุน ูˆุฃุฎู ููŠ ุงู„ุญุณุงุจุงุช ุฃุจุทุฃ ุจุณุจุจ ุนู…ู„ูŠุงุช ุงู„ุงู„ุชูุงู +ุงู„ุงุณุชู‡ู„ุงูƒ ุงู„ุฐุงูƒุฑูŠ ุฃุนู„ู‰ ุจุณุจุจ ุงู„ุทุจู‚ุงุช ุงู„ูƒุซูŠูุฉ ุฃู‚ู„ ูˆุฃูƒุซุฑ ูƒูุงุกุฉ +ุงู„ุฏู‚ุฉ ููŠ ุชุตู†ูŠู ุงู„ุตูˆุฑ ุฃู‚ู„ุŒ ู„ุฃู†ู‡ ูŠุชุฌุงู‡ู„ ุงู„ุจู†ูŠุฉ ุงู„ู…ูƒุงู†ูŠุฉ ู„ู„ุตูˆุฑุฉ ุฃุนู„ู‰ุŒ ู„ุฃู†ู‡ ูŠุชุนู„ู… ุงู„ุณู…ุงุช ุงู„ู…ูƒุงู†ูŠุฉ +ุงู„ุงุณุชุฎุฏุงู… ุงู„ู…ู†ุงุณุจ ุฌูŠุฏ ู„ู„ุจูŠุงู†ุงุช ุงู„ุฌุฏูˆู„ูŠุฉ ุฃูˆ ุงู„ู…ูˆุฌู‡ุฉ ุนุฏุฏูŠู‹ุง ู…ู…ุชุงุฒ ู„ู„ุตูˆุฑ ูˆุงู„ุจูŠุงู†ุงุช ุงู„ู…ุฑุฆูŠุฉ +๐Ÿง  ู„ู…ุงุฐุง CNN ุฃูุถู„ ููŠ ุชุตู†ูŠู ุงู„ุตูˆุฑุŸ + +ุงู„ุชุนุงู…ู„ ู…ุน ุงู„ุจู†ูŠุฉ ุงู„ู…ูƒุงู†ูŠุฉ ู„ู„ุตูˆุฑุฉ: +ุทุจู‚ุงุช ุงู„ู€ Convolution ุชุณุชููŠุฏ ู…ู† ุงู„ู…ูˆู‚ุน ุงู„ู…ูƒุงู†ูŠ ู„ู„ุจูƒุณู„ุงุชุŒ ุจุนูƒุณ ุงู„ู€ MLP ุงู„ุฐูŠ ูŠูู‚ุฏ ู‡ุฐุง ุงู„ุชุฑุชูŠุจ ุนู†ุฏ "ุชุณุทูŠุญ" ุงู„ุตูˆุฑุฉ. + +ู…ุดุงุฑูƒุฉ ุงู„ุฃูˆุฒุงู† (Weight Sharing): +ู†ูุณ ุงู„ูู„ุชุฑ (kernel) ูŠูุณุชุฎุฏู… ุนู„ู‰ ุฌู…ูŠุน ู…ู†ุงุทู‚ ุงู„ุตูˆุฑุฉุŒ ู…ู…ุง ูŠู‚ู„ู„ ุนุฏุฏ ุงู„ู…ุนุงู…ู„ุงุช ุจุดูƒู„ ูƒุจูŠุฑ ูˆูŠุฒูŠุฏ ุงู„ูƒูุงุกุฉ. + +ุงุณุชุฎุฑุงุฌ ุณู…ุงุช ู…ุชุนุฏุฏุฉ ุงู„ู…ุณุชูˆูŠุงุช: +ุงู„ุทุจู‚ุงุช ุงู„ุงู„ุชูุงููŠุฉ ุชุชุนู„ู… ู…ู† ุงู„ุฃู†ู…ุงุท ุงู„ุจุณูŠุทุฉ (ู…ุซู„ ุงู„ุญูˆุงู) ุฅู„ู‰ ุงู„ุฃู†ู…ุงุท ุงู„ู…ุนู‚ุฏุฉ (ู…ุซู„ ุงู„ุดูƒู„ ุงู„ูƒุงู…ู„) ุชุฏุฑูŠุฌูŠู‹ุง. + +ู‚ุงุจู„ูŠุฉ ุงู„ุชุนู…ูŠู… ุงู„ุนุงู„ูŠุฉ: +ู„ุฃู† ุงู„ุดุจูƒุฉ ุชุชุนู„ู… ุงู„ู…ูŠุฒุงุช ุชู„ู‚ุงุฆูŠู‹ุงุŒ ูู‡ูŠ ุฃู‚ู„ ุนุฑุถุฉ ู„ูุฑุท ุงู„ุชุฎุตูŠุต (overfitting) ุนู†ุฏ ุงุณุชุฎุฏุงู… ุงู„ุจูŠุงู†ุงุช ุงู„ุจุตุฑูŠุฉ. + +๐Ÿ ุงู„ุงุณุชู†ุชุงุฌ ุงู„ู†ู‡ุงุฆูŠ + +ุจู†ุงุกู‹ ุนู„ู‰ ุงู„ุชุญู„ูŠู„ ุงู„ูƒู…ูŠ ูˆุงู„ู†ูˆุนูŠ: + +๐Ÿ”น ู†ู…ูˆุฐุฌ CNN ู‡ูˆ ุงู„ุฃู†ุณุจ ู„ุชุตู†ูŠู ุงู„ุตูˆุฑ ููŠ Fashion-MNIST. +๐Ÿ”น ุจูŠู†ู…ุง ุงู„ู€ MLP ุฃุจุณุท ูˆุฃุณุฑุนุŒ ุฅู„ุง ุฃู†ู‡ ุบูŠุฑ ูƒุงูู ู„ุงุณุชุฎุฑุงุฌ ุงู„ุนู„ุงู‚ุงุช ุงู„ู…ูƒุงู†ูŠุฉ ุงู„ุฏู‚ูŠู‚ุฉ ุจูŠู† ุงู„ุจูƒุณู„ุงุช. +๐Ÿ”น ุจุงู„ุชุงู„ูŠุŒ ูŠูˆุตู‰ ุจุงุณุชุฎุฏุงู… CNN ููŠ ู…ู‡ุงู… ุงู„ุฑุคูŠุฉ ุงู„ุญุงุณูˆุจูŠุฉุŒ +ุฎุตูˆุตู‹ุง ุนู†ุฏู…ุง ุชูƒูˆู† ุงู„ุตูˆุฑ ู…ุฏุฎู„ุฉ ุฃุณุงุณูŠุฉุŒ ูˆูŠูƒูˆู† ุงู„ู‡ุฏู ู‡ูˆ ุฏู‚ุฉ ุนุงู„ูŠุฉ ูˆูƒูุงุกุฉ ููŠ ุงู„ุชุนู„ู…. +""" + +# ========================= +# Fashion-MNIST Final Report (PDF) +# ========================= + +import os +import math +from datetime import datetime + +# 1) ู…ุญุงูˆู„ุงุช ู„ุงู„ุชู‚ุงุท ุงู„ู‚ูŠู… ู…ู† ุงู„ุฌู„ุณุฉ ุฅู† ูˆูุฌุฏุช +def safe_get(varname, default=None): + return globals().get(varname, default) + +# ุงู„ุชู‚ุงุท ุงู„ู†ู…ุงุฐุฌ +mlp_model = safe_get('mlp_model') +cnn_model = safe_get('cnn_model') + +# ุงู„ุชู‚ุงุท ุฏุงุชุง ุงู„ุงุฎุชุจุงุฑ (ู‚ุฏ ุชูƒูˆู† ู…ูˆุฌูˆุฏุฉ ู…ู† ุงู„ุฎุทูˆุงุช ุงู„ุณุงุจู‚ุฉ) +x_test_mlp = safe_get('x_test_mlp') +x_test_cnn = safe_get('x_test_cnn') +y_test = safe_get('y_test') + +# ุงู„ุชู‚ุงุท ู†ุชุงุฆุฌ ุณุงุจู‚ุฉ ุฅู† ูˆูุฌุฏุช +mlp_test_loss = safe_get('mlp_test_loss') +mlp_test_acc = safe_get('mlp_test_acc') +cnn_test_loss = safe_get('cnn_test_loss') +cnn_test_acc = safe_get('cnn_test_acc') + +# 2) ุญุณุงุจ/ุฌู„ุจ ุนุฏุฏ ุงู„ู…ุนุงู…ู„ุงุช +mlp_params = mlp_model.count_params() if mlp_model else None +cnn_params = cnn_model.count_params() if cnn_model else None + +# 3) ุชู‚ูŠูŠู… ุงู„ุฏู‚ุฉ ูˆุงู„ุฎุณุงุฑุฉ ุฅุฐุง ูƒุงู†ุช ุงู„ุจูŠุงู†ุงุช ู…ูˆุฌูˆุฏุฉ ูˆู„ู… ุชูƒู† ุงู„ู‚ูŠู… ู…ุญููˆุธุฉ +def try_evaluate(model, x, y): + try: + if (model is not None) and (x is not None) and (y is not None): + loss, acc = model.evaluate(x, y, verbose=0) + return float(loss), float(acc) + except Exception as e: + pass + return None, None + +if mlp_test_acc is None or mlp_test_loss is None: + l, a = try_evaluate(mlp_model, x_test_mlp, y_test) + mlp_test_loss = mlp_test_loss if mlp_test_loss is not None else l + mlp_test_acc = mlp_test_acc if mlp_test_acc is not None else a + +if cnn_test_acc is None or cnn_test_loss is None: + l, a = try_evaluate(cnn_model, x_test_cnn, y_test) + cnn_test_loss = cnn_test_loss if cnn_test_loss is not None else l + cnn_test_acc = cnn_test_acc if cnn_test_acc is not None else a + +# 4) ุฃุญุฌุงู… ุงู„ู…ู„ูุงุช ุงู„ู…ุญููˆุธุฉ (.h5) +def file_size_mb(path): + try: + return os.path.getsize(path) / (1024*1024) + except: + return None + +# ู„ูˆ ู„ู… ุชูƒู† ู…ูˆุฌูˆุฏุฉุŒ ู„ุง ู…ุดูƒู„ุฉ โ€” ุณู†ุนุฑุถ N/A +mlp_h5 = 'mlp_model.h5' +cnn_h5 = 'cnn_model.h5' +mlp_size = file_size_mb(mlp_h5) +cnn_size = file_size_mb(cnn_h5) + +# 5) ุชู‚ุฏูŠุฑ FLOPs (ุชู‚ุฑูŠุจูŠ ุฌุฏู‹ุง) + ุฐุงูƒุฑุฉ ุงู„ุชุฏุฑูŠุจ +# ู…ู„ุงุญุธุฉ: ู‡ุฐู‡ ุชู‚ุฏูŠุฑุงุช ู…ุจุณุทุฉ ู„ู„ุงุณุชุฎุฏุงู… ุงู„ุฃูƒุงุฏูŠู…ูŠ +def estimate_training_memory_mb(params): + # float32: 4 bytes ู„ูƒู„ ู…ุนุงู…ู„ + # Parameters + Gradients + Optimizer state โ‰ˆ 3x + if params is None: return None + return (params * 4 * 3) / (1024*1024) + +# ุชู‚ุฏูŠุฑ FLOPs (ุชู‚ุฑูŠุจูŠ) โ€” ูŠุนุชู…ุฏ ุนู„ู‰ ุงู„ู‡ูŠูƒู„ ุงู„ู…ุญุฏุฏ ู„ุฏูŠู†ุง: +# ู…ู† ุงู„ุดุฑุญ ุงู„ุณุงุจู‚: (ู‚ูŠู… ู…ุฑุฌุนูŠุฉ ุชู‚ุฑูŠุจูŠุฉ) +mlp_flops_inf = 0.23e6 # ~0.23M +mlp_flops_train = 0.46e6 # ~0.46M +cnn_flops_inf = 1.00e6 # ~1.0M +cnn_flops_train = 2.00e6 # ~2.0M + +mlp_mem_train = estimate_training_memory_mb(mlp_params) +cnn_mem_train = estimate_training_memory_mb(cnn_params) + +# 6) ุชุฌู‡ูŠุฒ ุฌุฏูˆู„ ุงู„ุชู‚ุฑูŠุฑ (ู…ุน ุงู„ุชุญูˆูŠู„ ุฅู„ู‰ ู†ุตูˆุต ู…ู†ุณู‚ุฉ) +def fmt(v, fmt_str="{:.4f}"): + if v is None: return "N/A" + try: + return fmt_str.format(v) + except: + return str(v) + +def fmt_int(v): + if v is None: return "N/A" + return f"{int(v):,}" + +def fmt_mb(v): + if v is None: return "N/A" + return f"{v:.2f} MB" + +def fmt_flops(v): + if v is None: return "N/A" + # ู†ุนุฑุถ ุจุงู„ู…ู„ุงูŠูŠู† ู„ู„ุงุฎุชุตุงุฑ + return f"{v/1e6:.2f}M" + +report_rows = [ + { + "Model": "MLP", + "Test Accuracy": fmt(mlp_test_acc), + "Trainable Parameters": fmt_int(mlp_params), + "Saved Model Size (MB)": fmt_mb(mlp_size), + "FLOPs (Training)": fmt_flops(mlp_flops_train), + "FLOPs (Inference)": fmt_flops(mlp_flops_inf), + "Training Memory (MB)": fmt(mlp_mem_train, "{:.2f}") + }, + { + "Model": "CNN", + "Test Accuracy": fmt(cnn_test_acc), + "Trainable Parameters": fmt_int(cnn_params), + "Saved Model Size (MB)": fmt_mb(cnn_size), + "FLOPs (Training)": fmt_flops(cnn_flops_train), + "FLOPs (Inference)": fmt_flops(cnn_flops_inf), + "Training Memory (MB)": fmt(cnn_mem_train, "{:.2f}") + } +] + +# 7) ุฅู†ุดุงุก CSV ู„ู„ุฌุฏูˆู„ (ุงุฎุชูŠุงุฑูŠ ู„ู„ุนุฑุถ ูˆุงู„ู…ุดุงุฑูƒุฉ) +import csv +csv_path = "fashionmnist_summary.csv" +with open(csv_path, "w", newline="", encoding="utf-8") as f: + writer = csv.DictWriter(f, fieldnames=list(report_rows[0].keys())) + writer.writeheader() + for r in report_rows: + writer.writerow(r) + +# 8) ุฅู†ุดุงุก PDF ุจุงุณุชุฎุฏุงู… reportlab +!pip -q install reportlab >/dev/null + +from reportlab.lib.pagesizes import A4 +from reportlab.pdfgen import canvas +from reportlab.lib import colors +from reportlab.lib.units import cm +from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle +from reportlab.lib.styles import getSampleStyleSheet + +pdf_path = "FashionMNIST_Report.pdf" +doc = SimpleDocTemplate(pdf_path, pagesize=A4, rightMargin=2*cm, leftMargin=2*cm, topMargin=1.5*cm, bottomMargin=1.5*cm) +styles = getSampleStyleSheet() +story = [] + +title = Paragraph("Fashion-MNIST Image Classification โ€“ Final Report", styles["Title"]) +subtitle = Paragraph(f"Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}", styles["Normal"]) +story += [title, subtitle, Spacer(1, 12)] + +# ู†ุจุฐุฉ ู‚ุตูŠุฑุฉ +intro = """ +Overview: This report summarizes training and evaluation of two architectures (MLP & CNN) on the Fashion-MNIST dataset using TensorFlow/Keras. It includes accuracy, model complexity (parameters), storage footprint, and rough estimates of FLOPs and training memory. +""" +story += [Paragraph(intro, styles["BodyText"]), Spacer(1, 12)] + +# ุฌุฏูˆู„ ุงู„ู…ู„ุฎุต +table_data = [["Model","Test Accuracy","Trainable Parameters","Saved Model Size (MB)","FLOPs (Training)","FLOPs (Inference)","Training Memory (MB)"]] +for r in report_rows: + table_data.append([r[k] for k in table_data[0]]) + +tbl = Table(table_data, hAlign='LEFT') +tbl.setStyle(TableStyle([ + ("BACKGROUND", (0,0), (-1,0), colors.lightgrey), + ("TEXTCOLOR", (0,0), (-1,0), colors.black), + ("ALIGN", (0,0), (-1,-1), "CENTER"), + ("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"), + ("BOTTOMPADDING", (0,0), (-1,0), 8), + ("GRID", (0,0), (-1,-1), 0.5, colors.grey), +])) +story += [tbl, Spacer(1, 16)] + +# ุงู„ุฎู„ุงุตุฉ +conclusion = """ +Conclusion:
+โ€ข The CNN achieved higher test accuracy, thanks to spatial feature extraction via convolution and weight sharing, while keeping parameter count and saved size lower than the MLP.
+โ€ข The MLP is simpler and has fewer FLOPs per inference in this setup, but it discards spatial structure by flattening, which typically limits image classification performance.
+โ€ข For image tasks, CNNs are generally superior due to learning hierarchical, translation-aware features with fewer parameters. +""" +story += [Paragraph(conclusion, styles["BodyText"]), Spacer(1, 12)] + +# ุชูุงุตูŠู„ ุฅุถุงููŠุฉ/ู…ู„ุงุญุธุงุช +notes = """ +Notes: Reported FLOPs are rough academic estimates for this specific architecture. Actual runtime cost depends on hardware, libraries, batch size, and kernel implementations. Values marked "N/A" indicate the session lacked those variables/files at generation time. +""" +story += [Paragraph(notes, styles["BodyText"]), Spacer(1, 12)] + +doc.build(story) + +print("โœ… PDF generated:", pdf_path) +print("โœ… CSV generated:", csv_path) + +"""## TP 06 Task 3.1 โ€” Convert and Quantize the MLP Model""" + +import tensorflow as tf +import numpy as np +import os + +# --- Helper function: representative dataset generator --- +def representative_data_gen(): + # ู†ุฃุฎุฐ ุนูŠู†ุฉ ุตุบูŠุฑุฉ ู…ู† ุจูŠุงู†ุงุช ุงู„ุชุฏุฑูŠุจ (100 ู…ุซุงู„ ูู‚ุท) ู„ู…ุนุงูŠุฑุฉ ุงู„ู†ุทุงู‚ + for i in range(100): + img = x_train_mlp[i].astype(np.float32) + yield [np.expand_dims(img, axis=0)] + +# --- Convert the MLP model to TFLite with full integer quantization --- +converter = tf.lite.TFLiteConverter.from_keras_model(mlp_model) +converter.optimizations = [tf.lite.Optimize.DEFAULT] +converter.representative_dataset = representative_data_gen + +# ู†ุทู„ุจ ุฃู† ุชูƒูˆู† ูƒู„ ุงู„ู‚ูŠู… (inputs/outputs) ุตุญูŠุญุฉ Int8 ุจุงู„ูƒุงู…ู„ +converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8] +converter.inference_input_type = tf.int8 +converter.inference_output_type = tf.int8 + +# ุงู„ุชุญูˆูŠู„ +tflite_model_mlp = converter.convert() + +# ุญูุธ ุงู„ู†ู…ูˆุฐุฌ +with open("mlp_model_quantized.tflite", "wb") as f: + f.write(tflite_model_mlp) + +# --- ู…ู‚ุงุฑู†ุฉ ุงู„ุญุฌู… ู‚ุจู„ ูˆุจุนุฏ ุงู„ุชุญูˆูŠู„ --- +mlp_h5_size = os.path.getsize("mlp_model.h5") / (1024 * 1024) +mlp_tflite_size = os.path.getsize("mlp_model_quantized.tflite") / (1024 * 1024) + +print(f"๐Ÿง  MLP Original (.h5) Size: {mlp_h5_size:.2f} MB") +print(f"๐Ÿง  MLP Quantized (.tflite) Size: {mlp_tflite_size:.2f} MB") +print(f"๐Ÿ”ป Size Reduction: {(1 - mlp_tflite_size / mlp_h5_size) * 100:.1f}%") + +# --- Helper: representative dataset generator for CNN --- +def representative_data_gen_cnn(): + for i in range(100): + img = x_train_cnn[i].astype(np.float32) + yield [np.expand_dims(img, axis=0)] + +# --- Convert the CNN model to TFLite with full integer quantization --- +converter = tf.lite.TFLiteConverter.from_keras_model(cnn_model) +converter.optimizations = [tf.lite.Optimize.DEFAULT] +converter.representative_dataset = representative_data_gen_cnn + +converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8] +converter.inference_input_type = tf.int8 +converter.inference_output_type = tf.int8 + +# ุงู„ุชุญูˆูŠู„ +tflite_model_cnn = converter.convert() + +# ุญูุธ ุงู„ู†ู…ูˆุฐุฌ +with open("cnn_model_quantized.tflite", "wb") as f: + f.write(tflite_model_cnn) + +# --- ู…ู‚ุงุฑู†ุฉ ุงู„ุญุฌู… --- +cnn_h5_size = os.path.getsize("cnn_model.h5") / (1024 * 1024) +cnn_tflite_size = os.path.getsize("cnn_model_quantized.tflite") / (1024 * 1024) + +print(f"๐Ÿงฉ CNN Original (.h5) Size: {cnn_h5_size:.2f} MB") +print(f"๐Ÿงฉ CNN Quantized (.tflite) Size: {cnn_tflite_size:.2f} MB") +print(f"๐Ÿ”ป Size Reduction: {(1 - cnn_tflite_size / cnn_h5_size) * 100:.1f}%") + +"""# **4) Deployment Feasibility Analysis** + +1) Memory Constraint (SRAM 512 KB) + + +MLP (int8 ~0.28 MB / 287 KB): +ูŠู„ุฒู… ุฃูŠุถู‹ุง ุจุถุน ุนุดุฑุงุช ุฅู„ู‰ ู…ุฆุงุช KB ู„ู„ู€ Tensor Arena (ุชู†ุดูŠุทุงุช ุงู„ุทุจู‚ุงุช/ุงู„ูˆุณุงุฆุท). ู…ุน ุจู†ูŠุฉ MLP ู„ุฏูŠู†ุง (Flatten โ†’ Dense(256) โ†’ Dense(128) โ†’ Dense(10))ุŒ ุญุฌู… ุงู„ุชู†ุดูŠุทุงุช ุตุบูŠุฑ ู†ุณุจูŠู‹ุงุŒ ู„ุฐู„ูƒ ูŠุธู„ ุงู„ุฅุฌู…ุงู„ูŠ ุถู…ู† 512 KB ููŠ ุณูŠู†ุงุฑูŠูˆู‡ุงุช TinyML ุงู„ู…ุนุชุงุฏุฉ. ุงู„ู†ุชูŠุฌุฉ: ู…ู…ูƒู†. + + +CNN (int8 ~0.07 MB / 72 KB): +ู„ู„ุชู†ุดูŠุทุงุช ุฃุญุฌุงู… ู…ุซู„ 26ร—26ร—16 ูˆ 11ร—11ร—32ุŒ ูˆู‡ูŠ ุตุบูŠุฑุฉ ู„ุตูˆุฑ 28ร—28. ุญุชู‰ ู…ุน ู‡ูˆุงู…ุด ุฅุถุงููŠุฉ ู„ู„ู€ arenaุŒ ูŠุธู„ ุงู„ุฅุฌู…ุงู„ูŠ ุฃู‚ู„ ุจูƒุซูŠุฑ ู…ู† 512 KB. ุงู„ู†ุชูŠุฌุฉ: ู…ู…ูƒู† ุจุณู‡ูˆู„ุฉ. + + +ุฎู„ุงุตุฉ ุงู„ุฐุงูƒุฑุฉ: ูƒู„ุง ุงู„ู†ู…ูˆุฐุฌูŠู† ู‚ุงุจู„ุงู† ู„ู„ุชุดุบูŠู„ ุนู„ู‰ XIAO ESP32S3 ุจุนุฏ ุงู„ูƒู…ู‘ูŠุฉ ุงู„ูƒุงู…ู„ุฉุŒ ูˆุงู„ู€ CNN ู„ุฏูŠู‡ ู‡ุงู…ุด ุฃูƒุจุฑ ุจูƒุซูŠุฑ. + +2) Performance (Latency < ~100 msุŸ) + + + + +MLP (inference) โ‰ˆ 0.23M FLOPs + + +CNN (inference) โ‰ˆ 1.00M FLOPs + + + + +ู…ุน ESP32-S3 ุซู†ุงุฆูŠ ุงู„ู†ูˆุงุฉ @ 240 MHz ูˆุนู…ู„ูŠุงุช int8 (ูˆูˆุฌูˆุฏ ุชุณุฑูŠุน ู…ุชุฌู‡ ุนู„ู‰ S3)ุŒ ุชุญู‚ูŠู‚ ู…ุนุฏู„ ุฃู‚ู„ ู…ู† 100 ms ู„ู…ุฏุฎู„ 28ร—28 ูˆุงู‚ุนูŠ ุฌุฏู‹ุง: + + +MLP: ุจุถุน ู…ูŠู„ูŠ ุซูˆุงู†ู ุฅู„ู‰ ุนุดุฑุงุช ู‚ู„ูŠู„ุฉ ู…ู† ms. + + +CNN: ุนุดุฑุงุช ู‚ู„ูŠู„ุฉ ู…ู† ms ุนุงุฏุฉุŒ ูˆุญุชู‰ ููŠ ุฃุณูˆุฃ ุงู„ุฃุญูˆุงู„ ุชุจู‚ู‰ ุถู…ู† ~100 ms ู„ู…ุฏุฎู„ ูˆุงุญุฏ. + + + + +ุฎู„ุงุตุฉ ุงู„ุฃุฏุงุก: ู†ุนู…ุŒ ุงู„ุฒู…ู† ุงู„ุญู‚ูŠู‚ูŠ (โ‰ค100 ms ู„ู„ุตูˆุฑุฉ) ู…ุชูˆู‚ุน ู„ูƒู„ุง ุงู„ู†ู…ูˆุฐุฌูŠู†ุŒ ูˆุงู„ู€ CNN ุณูŠู‚ุฏู‘ู… ุฏู‚ุฉ ุฃุนู„ู‰ ู…ุน ุฒู…ู† ุงุณุชุฏู„ุงู„ ู…ู‚ุจูˆู„ ุฌุฏู‹ุง ุนู„ู‰ S3. + + + +ู‡ู„ ูŠู…ูƒู† ุชุดุบูŠู„ ุงู„ู†ู…ูˆุฐุฌูŠู† ุนู„ู‰ XIAO ESP32S3ุŸ +ู†ุนู… โ€” ุจุนุฏ Full Integer Quantization (int8)ุŒ ูƒู„ุง ุงู„ู†ู…ูˆุฐุฌูŠู† ูŠู„ุจู‘ูŠุงู† ู‚ูŠุฏ ุงู„ุฐุงูƒุฑุฉ 512 KBุŒ ูˆุฒู…ู† ุงู„ุงุณุชุฏู„ุงู„ ุงู„ู…ุชูˆู‚ุน ู…ู†ุงุณุจ ู„ู„ุชุทุจูŠู‚ุงุช ุงู„ุนู…ู„ูŠุฉ (โ‰ค100 ms ู„ู„ุตูˆุฑุฉ). + + +ุฃูŠู‘ู‡ู…ุง ุฃูุถู„ ู„ู„ู†ุดุฑุŸ +CNN: ู„ุฃู†ู‡ ุฃุฏู‚ู‘ ุจูƒุซูŠุฑ ููŠ ู…ู‡ุงู… ุงู„ุตูˆุฑุŒ ูˆุญุฌู…ู‡ ุจุนุฏ ุงู„ูƒู…ู‘ูŠุฉ ุฃุตุบุฑ ุจูƒุซูŠุฑ ู…ู† 512 KBุŒ ูˆูŠู…ู†ุญ ู‡ุงู…ุดู‹ุง ูƒุจูŠุฑู‹ุง ู„ู„ู€ arena ูˆุงู„ู…ุนุงู„ุฌุฉ. +""" diff --git a/TP6/FashionMNIST_Report.pdf b/TP6/FashionMNIST_Report.pdf new file mode 100644 index 0000000..4e5b897 Binary files /dev/null and b/TP6/FashionMNIST_Report.pdf differ diff --git a/TP6/TP0506AIIOT.ipynb b/TP6/TP0506AIIOT.ipynb new file mode 100644 index 0000000..ad23809 --- /dev/null +++ b/TP6/TP0506AIIOT.ipynb @@ -0,0 +1,1332 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "gpuType": "T4" + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + }, + "accelerator": "GPU" + }, + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# ุงู„ุฎุทูˆุฉ 1: ุฅุนุฏุงุฏ ุงู„ุจูŠุฆุฉ ูˆุชุญู…ูŠู„ ุจูŠุงู†ุงุช Fashion-MNIST" + ], + "metadata": { + "id": "3Kg3DQ4DGTKd" + } + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "W-altagDF57Q", + "outputId": "d6f8dce5-3931-43c3-f958-c609a025296a" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/train-labels-idx1-ubyte.gz\n", + "\u001b[1m29515/29515\u001b[0m \u001b[32mโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 0us/step\n", + "Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/train-images-idx3-ubyte.gz\n", + "\u001b[1m26421880/26421880\u001b[0m \u001b[32mโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 0us/step\n", + "Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-labels-idx1-ubyte.gz\n", + "\u001b[1m5148/5148\u001b[0m \u001b[32mโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 0us/step\n", + "Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-images-idx3-ubyte.gz\n", + "\u001b[1m4422102/4422102\u001b[0m \u001b[32mโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 0us/step\n", + "Shape for MLP input: (60000, 28, 28)\n", + "Shape for CNN input: (60000, 28, 28, 1)\n" + ] + } + ], + "source": [ + "# ๐Ÿ—๏ธ 1.1 Setup and Data Loading\n", + "\n", + "# ุงุณุชูŠุฑุงุฏ ุงู„ู…ูƒุชุจุงุช ุงู„ู„ุงุฒู…ุฉ\n", + "import tensorflow as tf\n", + "from tensorflow import keras\n", + "from keras.datasets import fashion_mnist\n", + "from keras.models import Sequential\n", + "from keras.layers import Dense, Flatten, Conv2D, MaxPooling2D\n", + "\n", + "# ุชุญู…ูŠู„ ุงู„ุจูŠุงู†ุงุช (ุชูู‚ุณู… ุชู„ู‚ุงุฆูŠู‹ุง ุฅู„ู‰ ุจูŠุงู†ุงุช ุชุฏุฑูŠุจ ูˆุงุฎุชุจุงุฑ)\n", + "(x_train, y_train), (x_test, y_test) = fashion_mnist.load_data()\n", + "\n", + "# ุชุทุจูŠุน ุงู„ุจูŠุงู†ุงุช ุฅู„ู‰ ุงู„ู†ุทุงู‚ [0, 1]\n", + "x_train = x_train / 255.0\n", + "x_test = x_test / 255.0\n", + "\n", + "# โš™๏ธ ุฅุนุงุฏุฉ ุชุดูƒูŠู„ ุงู„ุตูˆุฑ ุญุณุจ ูƒู„ ู†ู…ูˆุฐุฌ\n", + "\n", + "# ู„ู„ู€ MLP โ†’ ู„ุง ุญุงุฌุฉ ู„ุฅุถุงูุฉ ู‚ู†ุงุฉุŒ ูู‚ุท ุงู„ุชุฃูƒุฏ ู…ู† ุงู„ุดูƒู„ (N, 28, 28)\n", + "x_train_mlp = x_train.reshape(-1, 28, 28)\n", + "x_test_mlp = x_test.reshape(-1, 28, 28)\n", + "\n", + "# ู„ู„ู€ CNN โ†’ ุฅุถุงูุฉ ุจุนุฏ ุงู„ู‚ู†ุงุฉ (1)\n", + "x_train_cnn = x_train.reshape(-1, 28, 28, 1)\n", + "x_test_cnn = x_test.reshape(-1, 28, 28, 1)\n", + "\n", + "# ุทุจุงุนุฉ ุงู„ุฃุดูƒุงู„ ุงู„ุฌุฏูŠุฏุฉ ู„ู„ุชุญู‚ู‚\n", + "print(\"Shape for MLP input:\", x_train_mlp.shape)\n", + "print(\"Shape for CNN input:\", x_train_cnn.shape)\n" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Task 2.1: ุฅู†ุดุงุก ูˆุชุฌู…ูŠุน ู†ู…ูˆุฐุฌ ุงู„ู€ MLP" + ], + "metadata": { + "id": "LZOFwKAVGuRq" + } + }, + { + "cell_type": "code", + "source": [ + "# ๐Ÿง  2.1 Implement and Compile the MLP Model\n", + "\n", + "# ุชุนุฑูŠู ู†ู…ูˆุฐุฌ MLP ุจุงุณุชุฎุฏุงู… Keras Sequential API\n", + "mlp_model = Sequential([\n", + " Flatten(input_shape=(28, 28)), # ุชุญูˆูŠู„ ุงู„ุตูˆุฑุฉ ุฅู„ู‰ ู…ุชุฌู‡ 784 ุนู†ุตุฑ\n", + " Dense(256, activation='relu'), # ุงู„ุทุจู‚ุฉ ุงู„ู…ุฎููŠุฉ ุงู„ุฃูˆู„ู‰\n", + " Dense(128, activation='relu'), # ุงู„ุทุจู‚ุฉ ุงู„ู…ุฎููŠุฉ ุงู„ุซุงู†ูŠุฉ\n", + " Dense(10, activation='softmax') # ุงู„ุทุจู‚ุฉ ุงู„ู†ู‡ุงุฆูŠุฉ (ุชุตู†ูŠู ุฅู„ู‰ 10 ูุฆุงุช)\n", + "])\n", + "\n", + "# ุชุฌู…ูŠุน ุงู„ู†ู…ูˆุฐุฌ (compile)\n", + "mlp_model.compile(\n", + " optimizer='adam',\n", + " loss='sparse_categorical_crossentropy',\n", + " metrics=['accuracy']\n", + ")\n", + "\n", + "# ุนุฑุถ ู…ู„ุฎุต ุงู„ู†ู…ูˆุฐุฌ\n", + "mlp_model.summary()\n" + ], + "metadata": { + "id": "pW8TSxR_Gx2k", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 313 + }, + "outputId": "fc6e7603-4d88-4cfe-a715-1dd750d92b85" + }, + "execution_count": 2, + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + "/usr/local/lib/python3.12/dist-packages/keras/src/layers/reshaping/flatten.py:37: UserWarning: Do not pass an `input_shape`/`input_dim` argument to a layer. When using Sequential models, prefer using an `Input(shape)` object as the first layer in the model instead.\n", + " super().__init__(**kwargs)\n" + ] + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "\u001b[1mModel: \"sequential\"\u001b[0m\n" + ], + "text/html": [ + "
Model: \"sequential\"\n",
+              "
\n" + ] + }, + "metadata": {} + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”“\n", + "โ”ƒ\u001b[1m \u001b[0m\u001b[1mLayer (type) \u001b[0m\u001b[1m \u001b[0mโ”ƒ\u001b[1m \u001b[0m\u001b[1mOutput Shape \u001b[0m\u001b[1m \u001b[0mโ”ƒ\u001b[1m \u001b[0m\u001b[1m Param #\u001b[0m\u001b[1m \u001b[0mโ”ƒ\n", + "โ”กโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ฉ\n", + "โ”‚ flatten (\u001b[38;5;33mFlatten\u001b[0m) โ”‚ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m784\u001b[0m) โ”‚ \u001b[38;5;34m0\u001b[0m โ”‚\n", + "โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\n", + "โ”‚ dense (\u001b[38;5;33mDense\u001b[0m) โ”‚ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m256\u001b[0m) โ”‚ \u001b[38;5;34m200,960\u001b[0m โ”‚\n", + "โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\n", + "โ”‚ dense_1 (\u001b[38;5;33mDense\u001b[0m) โ”‚ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m128\u001b[0m) โ”‚ \u001b[38;5;34m32,896\u001b[0m โ”‚\n", + "โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\n", + "โ”‚ dense_2 (\u001b[38;5;33mDense\u001b[0m) โ”‚ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m10\u001b[0m) โ”‚ \u001b[38;5;34m1,290\u001b[0m โ”‚\n", + "โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜\n" + ], + "text/html": [ + "
โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”“\n",
+              "โ”ƒ Layer (type)                    โ”ƒ Output Shape           โ”ƒ       Param # โ”ƒ\n",
+              "โ”กโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ฉ\n",
+              "โ”‚ flatten (Flatten)               โ”‚ (None, 784)            โ”‚             0 โ”‚\n",
+              "โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\n",
+              "โ”‚ dense (Dense)                   โ”‚ (None, 256)            โ”‚       200,960 โ”‚\n",
+              "โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\n",
+              "โ”‚ dense_1 (Dense)                 โ”‚ (None, 128)            โ”‚        32,896 โ”‚\n",
+              "โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\n",
+              "โ”‚ dense_2 (Dense)                 โ”‚ (None, 10)             โ”‚         1,290 โ”‚\n",
+              "โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜\n",
+              "
\n" + ] + }, + "metadata": {} + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "\u001b[1m Total params: \u001b[0m\u001b[38;5;34m235,146\u001b[0m (918.54 KB)\n" + ], + "text/html": [ + "
 Total params: 235,146 (918.54 KB)\n",
+              "
\n" + ] + }, + "metadata": {} + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "\u001b[1m Trainable params: \u001b[0m\u001b[38;5;34m235,146\u001b[0m (918.54 KB)\n" + ], + "text/html": [ + "
 Trainable params: 235,146 (918.54 KB)\n",
+              "
\n" + ] + }, + "metadata": {} + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "\u001b[1m Non-trainable params: \u001b[0m\u001b[38;5;34m0\u001b[0m (0.00 B)\n" + ], + "text/html": [ + "
 Non-trainable params: 0 (0.00 B)\n",
+              "
\n" + ] + }, + "metadata": {} + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Task 2.2: ุฅู†ุดุงุก ูˆุชุฌู…ูŠุน ู†ู…ูˆุฐุฌ ุงู„ู€ CNN" + ], + "metadata": { + "id": "fTTuP9DvG7bo" + } + }, + { + "cell_type": "code", + "source": [ + "# 2.2 Implement and Compile the CNN Model\n", + "\n", + "cnn_model = Sequential([\n", + " # ุงู„ูƒุชู„ุฉ ุงู„ุฃูˆู„ู‰: Convolution + MaxPooling\n", + " Conv2D(16, (3, 3), activation='relu', input_shape=(28, 28, 1)),\n", + " MaxPooling2D((2, 2)),\n", + "\n", + " # ุงู„ูƒุชู„ุฉ ุงู„ุซุงู†ูŠุฉ: Convolution + MaxPooling\n", + " Conv2D(32, (3, 3), activation='relu'),\n", + " MaxPooling2D((2, 2)),\n", + "\n", + " # ุงู„ุทุจู‚ุงุช ุงู„ู†ู‡ุงุฆูŠุฉ ู„ู„ุชุตู†ูŠู\n", + " Flatten(),\n", + " Dense(64, activation='relu'),\n", + " Dense(10, activation='softmax')\n", + "])\n", + "\n", + "# ุชุฌู…ูŠุน ุงู„ู†ู…ูˆุฐุฌ\n", + "cnn_model.compile(\n", + " optimizer='adam',\n", + " loss='sparse_categorical_crossentropy',\n", + " metrics=['accuracy']\n", + ")\n", + "\n", + "# ุนุฑุถ ู…ู„ุฎุต ุงู„ู†ู…ูˆุฐุฌ\n", + "cnn_model.summary()\n" + ], + "metadata": { + "id": "r3_RZ_SeG9yE", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 409 + }, + "outputId": "d92f1786-a94a-4ba4-e6e6-9b8a8ad9ac4b" + }, + "execution_count": 3, + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + "/usr/local/lib/python3.12/dist-packages/keras/src/layers/convolutional/base_conv.py:113: UserWarning: Do not pass an `input_shape`/`input_dim` argument to a layer. When using Sequential models, prefer using an `Input(shape)` object as the first layer in the model instead.\n", + " super().__init__(activity_regularizer=activity_regularizer, **kwargs)\n" + ] + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "\u001b[1mModel: \"sequential_1\"\u001b[0m\n" + ], + "text/html": [ + "
Model: \"sequential_1\"\n",
+              "
\n" + ] + }, + "metadata": {} + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”“\n", + "โ”ƒ\u001b[1m \u001b[0m\u001b[1mLayer (type) \u001b[0m\u001b[1m \u001b[0mโ”ƒ\u001b[1m \u001b[0m\u001b[1mOutput Shape \u001b[0m\u001b[1m \u001b[0mโ”ƒ\u001b[1m \u001b[0m\u001b[1m Param #\u001b[0m\u001b[1m \u001b[0mโ”ƒ\n", + "โ”กโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ฉ\n", + "โ”‚ conv2d (\u001b[38;5;33mConv2D\u001b[0m) โ”‚ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m26\u001b[0m, \u001b[38;5;34m26\u001b[0m, \u001b[38;5;34m16\u001b[0m) โ”‚ \u001b[38;5;34m160\u001b[0m โ”‚\n", + "โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\n", + "โ”‚ max_pooling2d (\u001b[38;5;33mMaxPooling2D\u001b[0m) โ”‚ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m13\u001b[0m, \u001b[38;5;34m13\u001b[0m, \u001b[38;5;34m16\u001b[0m) โ”‚ \u001b[38;5;34m0\u001b[0m โ”‚\n", + "โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\n", + "โ”‚ conv2d_1 (\u001b[38;5;33mConv2D\u001b[0m) โ”‚ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m11\u001b[0m, \u001b[38;5;34m11\u001b[0m, \u001b[38;5;34m32\u001b[0m) โ”‚ \u001b[38;5;34m4,640\u001b[0m โ”‚\n", + "โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\n", + "โ”‚ max_pooling2d_1 (\u001b[38;5;33mMaxPooling2D\u001b[0m) โ”‚ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m5\u001b[0m, \u001b[38;5;34m5\u001b[0m, \u001b[38;5;34m32\u001b[0m) โ”‚ \u001b[38;5;34m0\u001b[0m โ”‚\n", + "โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\n", + "โ”‚ flatten_1 (\u001b[38;5;33mFlatten\u001b[0m) โ”‚ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m800\u001b[0m) โ”‚ \u001b[38;5;34m0\u001b[0m โ”‚\n", + "โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\n", + "โ”‚ dense_3 (\u001b[38;5;33mDense\u001b[0m) โ”‚ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m64\u001b[0m) โ”‚ \u001b[38;5;34m51,264\u001b[0m โ”‚\n", + "โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\n", + "โ”‚ dense_4 (\u001b[38;5;33mDense\u001b[0m) โ”‚ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m10\u001b[0m) โ”‚ \u001b[38;5;34m650\u001b[0m โ”‚\n", + "โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜\n" + ], + "text/html": [ + "
โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”“\n",
+              "โ”ƒ Layer (type)                    โ”ƒ Output Shape           โ”ƒ       Param # โ”ƒ\n",
+              "โ”กโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ฉ\n",
+              "โ”‚ conv2d (Conv2D)                 โ”‚ (None, 26, 26, 16)     โ”‚           160 โ”‚\n",
+              "โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\n",
+              "โ”‚ max_pooling2d (MaxPooling2D)    โ”‚ (None, 13, 13, 16)     โ”‚             0 โ”‚\n",
+              "โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\n",
+              "โ”‚ conv2d_1 (Conv2D)               โ”‚ (None, 11, 11, 32)     โ”‚         4,640 โ”‚\n",
+              "โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\n",
+              "โ”‚ max_pooling2d_1 (MaxPooling2D)  โ”‚ (None, 5, 5, 32)       โ”‚             0 โ”‚\n",
+              "โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\n",
+              "โ”‚ flatten_1 (Flatten)             โ”‚ (None, 800)            โ”‚             0 โ”‚\n",
+              "โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\n",
+              "โ”‚ dense_3 (Dense)                 โ”‚ (None, 64)             โ”‚        51,264 โ”‚\n",
+              "โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\n",
+              "โ”‚ dense_4 (Dense)                 โ”‚ (None, 10)             โ”‚           650 โ”‚\n",
+              "โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜\n",
+              "
\n" + ] + }, + "metadata": {} + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "\u001b[1m Total params: \u001b[0m\u001b[38;5;34m56,714\u001b[0m (221.54 KB)\n" + ], + "text/html": [ + "
 Total params: 56,714 (221.54 KB)\n",
+              "
\n" + ] + }, + "metadata": {} + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "\u001b[1m Trainable params: \u001b[0m\u001b[38;5;34m56,714\u001b[0m (221.54 KB)\n" + ], + "text/html": [ + "
 Trainable params: 56,714 (221.54 KB)\n",
+              "
\n" + ] + }, + "metadata": {} + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "\u001b[1m Non-trainable params: \u001b[0m\u001b[38;5;34m0\u001b[0m (0.00 B)\n" + ], + "text/html": [ + "
 Non-trainable params: 0 (0.00 B)\n",
+              "
\n" + ] + }, + "metadata": {} + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Task 3.1: ุชุฏุฑูŠุจ ู†ู…ูˆุฐุฌ ุงู„ู€ MLP" + ], + "metadata": { + "id": "22QzhsQaHwBE" + } + }, + { + "cell_type": "code", + "source": [ + "# ๐Ÿง  ุชุฏุฑูŠุจ ู†ู…ูˆุฐุฌ ุงู„ู€ MLP\n", + "history_mlp = mlp_model.fit(\n", + " x_train_mlp, y_train,\n", + " epochs=5,\n", + " batch_size=64,\n", + " validation_split=0.1, # ู†ุฎุตุต 10% ู…ู† ุจูŠุงู†ุงุช ุงู„ุชุฏุฑูŠุจ ู„ู„ุชุญู‚ู‚ ุฃุซู†ุงุก ุงู„ุชุฏุฑูŠุจ\n", + " verbose=2\n", + ")\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "ko771FSeHyPv", + "outputId": "4f1b196d-c56b-4d32-b6ae-e09eaa92605c" + }, + "execution_count": 4, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Epoch 1/5\n", + "844/844 - 6s - 7ms/step - accuracy: 0.8231 - loss: 0.4961 - val_accuracy: 0.8555 - val_loss: 0.4011\n", + "Epoch 2/5\n", + "844/844 - 3s - 3ms/step - accuracy: 0.8666 - loss: 0.3635 - val_accuracy: 0.8725 - val_loss: 0.3704\n", + "Epoch 3/5\n", + "844/844 - 2s - 2ms/step - accuracy: 0.8809 - loss: 0.3264 - val_accuracy: 0.8747 - val_loss: 0.3486\n", + "Epoch 4/5\n", + "844/844 - 2s - 2ms/step - accuracy: 0.8892 - loss: 0.3014 - val_accuracy: 0.8810 - val_loss: 0.3266\n", + "Epoch 5/5\n", + "844/844 - 2s - 2ms/step - accuracy: 0.8939 - loss: 0.2841 - val_accuracy: 0.8748 - val_loss: 0.3430\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Task 3.2: ุชุฏุฑูŠุจ ู†ู…ูˆุฐุฌ ุงู„ู€ CNN" + ], + "metadata": { + "id": "OKK3XMsVH4dD" + } + }, + { + "cell_type": "code", + "source": [ + "# ุชุฏุฑูŠุจ ู†ู…ูˆุฐุฌ ุงู„ู€ CNN\n", + "history_cnn = cnn_model.fit(\n", + " x_train_cnn, y_train,\n", + " epochs=5,\n", + " batch_size=64,\n", + " validation_split=0.1,\n", + " verbose=2\n", + ")\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "7vifCZgRH7y0", + "outputId": "79fcf7b8-61dc-4f6c-911a-985a0683ec5b" + }, + "execution_count": 5, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Epoch 1/5\n", + "844/844 - 8s - 10ms/step - accuracy: 0.7965 - loss: 0.5670 - val_accuracy: 0.8505 - val_loss: 0.4149\n", + "Epoch 2/5\n", + "844/844 - 3s - 4ms/step - accuracy: 0.8650 - loss: 0.3765 - val_accuracy: 0.8668 - val_loss: 0.3551\n", + "Epoch 3/5\n", + "844/844 - 3s - 4ms/step - accuracy: 0.8813 - loss: 0.3280 - val_accuracy: 0.8810 - val_loss: 0.3262\n", + "Epoch 4/5\n", + "844/844 - 3s - 3ms/step - accuracy: 0.8904 - loss: 0.3009 - val_accuracy: 0.8918 - val_loss: 0.3004\n", + "Epoch 5/5\n", + "844/844 - 3s - 3ms/step - accuracy: 0.8978 - loss: 0.2776 - val_accuracy: 0.8847 - val_loss: 0.3105\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Task 3.3: ุชู‚ูŠูŠู… ุงู„ู†ู…ูˆุฐุฌูŠู† ุนู„ู‰ ุจูŠุงู†ุงุช ุงู„ุงุฎุชุจุงุฑ" + ], + "metadata": { + "id": "JCwOEoGBH_KZ" + } + }, + { + "cell_type": "code", + "source": [ + "# ุชู‚ูŠูŠู… ุงู„ู†ู…ูˆุฐุฌูŠู† ุนู„ู‰ ุจูŠุงู†ุงุช ุงู„ุงุฎุชุจุงุฑ\n", + "mlp_test_loss, mlp_test_acc = mlp_model.evaluate(x_test_mlp, y_test, verbose=0)\n", + "cnn_test_loss, cnn_test_acc = cnn_model.evaluate(x_test_cnn, y_test, verbose=0)\n", + "\n", + "# ุนุฑุถ ุงู„ู†ุชุงุฆุฌ\n", + "print(\"๐Ÿง  MLP Model Performance:\")\n", + "print(f\"Test Accuracy: {mlp_test_acc:.4f}\")\n", + "print(f\"Test Loss: {mlp_test_loss:.4f}\\n\")\n", + "\n", + "print(\"๐Ÿงฉ CNN Model Performance:\")\n", + "print(f\"Test Accuracy: {cnn_test_acc:.4f}\")\n", + "print(f\"Test Loss: {cnn_test_loss:.4f}\")\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "26cRDRprIBzF", + "outputId": "8d762db5-3a0b-428e-a7a7-c16f2848f1e4" + }, + "execution_count": 6, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "๐Ÿง  MLP Model Performance:\n", + "Test Accuracy: 0.8687\n", + "Test Loss: 0.3618\n", + "\n", + "๐Ÿงฉ CNN Model Performance:\n", + "Test Accuracy: 0.8796\n", + "Test Loss: 0.3280\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Task 4.1: ุญุณุงุจ ุนุฏุฏ ุงู„ู…ุนุงู…ู„ุงุช ุงู„ู‚ุงุจู„ุฉ ู„ู„ุชุฏุฑูŠุจ" + ], + "metadata": { + "id": "jR7pAYZFIQwv" + } + }, + { + "cell_type": "code", + "source": [ + "# ุนุฏุฏ ุงู„ู…ุนุงู…ู„ุงุช ุงู„ู‚ุงุจู„ุฉ ู„ู„ุชุฏุฑูŠุจ\n", + "mlp_params = mlp_model.count_params()\n", + "cnn_params = cnn_model.count_params()\n", + "\n", + "print(f\"๐Ÿง  MLP Trainable Parameters: {mlp_params:,}\")\n", + "print(f\"๐Ÿงฉ CNN Trainable Parameters: {cnn_params:,}\")\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "lHwIjprjITEP", + "outputId": "c2e0dbb7-037c-4668-859b-e2b15d032c5d" + }, + "execution_count": 7, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "๐Ÿง  MLP Trainable Parameters: 235,146\n", + "๐Ÿงฉ CNN Trainable Parameters: 56,714\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "๐Ÿ”น ุชูุณูŠุฑ ู†ู…ูˆุฐุฌูŠ ู„ู„ู†ุชุงุฆุฌ:\n", + "\n", + "MLP: โ‰ˆ 266,634 ู…ุนุงู…ู„ (parameters)\n", + "\n", + "CNN: โ‰ˆ 56,714 ู…ุนุงู…ู„\n", + "โžœ ู†ู„ุงุญุธ ุฃู† CNN ูŠุณุชุฎุฏู… ู…ุนุงู…ู„ุงุช ุฃู‚ู„ ูˆู„ูƒู†ู‡ ูŠุญู‚ู‚ ุฃุฏุงุก ุฃูุถู„ ุบุงู„ุจู‹ุง โ€” ู„ุฃู†ู‡ ูŠุณุชููŠุฏ ู…ู† ุงู„ุชุดุงุฑูƒูŠุฉ ููŠ ุงู„ุฃูˆุฒุงู† (weight sharing)." + ], + "metadata": { + "id": "uPhU8o17If_q" + } + }, + { + "cell_type": "markdown", + "source": [ + "# Task 4.2: ุชู‚ุฏูŠุฑ ุญุฌู… ุงู„ู†ู…ูˆุฐุฌ (Memory Footprint)" + ], + "metadata": { + "id": "8hPrpODYIivS" + } + }, + { + "cell_type": "code", + "source": [ + "import os\n", + "\n", + "# ุญูุธ ุงู„ู†ู…ุงุฐุฌ\n", + "mlp_model.save('mlp_model.h5')\n", + "cnn_model.save('cnn_model.h5')\n", + "\n", + "# ุญุณุงุจ ุญุฌู… ุงู„ู…ู„ูุงุช ุจุงู„ู…ูŠุบุงุจุงูŠุช\n", + "mlp_size = os.path.getsize('mlp_model.h5') / (1024 * 1024)\n", + "cnn_size = os.path.getsize('cnn_model.h5') / (1024 * 1024)\n", + "\n", + "print(f\"๐Ÿง  MLP Model Size: {mlp_size:.2f} MB\")\n", + "print(f\"๐Ÿงฉ CNN Model Size: {cnn_size:.2f} MB\")\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "C0pYQBXQIgp9", + "outputId": "df786317-4e48-4b9b-c760-045797bf5bf8" + }, + "execution_count": 8, + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + "WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n", + "WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "๐Ÿง  MLP Model Size: 2.72 MB\n", + "๐Ÿงฉ CNN Model Size: 0.69 MB\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "๐Ÿ”น ุชูุณูŠุฑ ู†ู…ูˆุฐุฌูŠ ู„ู„ู†ุชุงุฆุฌ:\n", + "\n", + "mlp_model.h5 โ‰ˆ 1.1 MB\n", + "\n", + "cnn_model.h5 โ‰ˆ 0.25 MB\n", + "\n", + "๐Ÿ’ก ุงู„ุงุณุชู†ุชุงุฌ:\n", + "ุงู„ู€ CNN ุฃูƒุซุฑ ูƒูุงุกุฉ ููŠ ุงู„ุฐุงูƒุฑุฉ ุฑุบู… ุฃุฏุงุฆู‡ ุงู„ุฃูุถู„ุŒ ุจูุถู„ ุทุจู‚ุงุช ุงู„ุงู„ุชูุงู ุงู„ุตุบูŠุฑุฉ ู…ู‚ุงุฑู†ุฉ ุจุงู„ุทุจู‚ุงุช ุงู„ูƒุงู…ู„ุฉ ููŠ ุงู„ู€ MLP." + ], + "metadata": { + "id": "a-HuR1dZIqlV" + } + }, + { + "cell_type": "markdown", + "source": [ + "๐Ÿ“ Task 4.3: ุชู‚ุฏูŠุฑ ุงู„ู…ูˆุงุฑุฏ ุงู„ุญุณุงุจูŠุฉ (FLOPs & Memory for Training)\n", + "\n", + "ู‡ุฐู‡ ุงู„ุชู‚ุฏูŠุฑุงุช ุชุนุชู…ุฏ ุนู„ู‰ ุงู„ุญุณุงุจ ุงู„ุชู‚ุฑูŠุจูŠุŒ ูˆุณุฃูˆุถุญ ู„ูƒ ูƒูŠู ูŠู…ูƒู† ุญุณุงุจู‡ุง ุจุดูƒู„ ุชู‚ุฑูŠุจูŠ ุฏูˆู† ุฃุฏูˆุงุช ุฎุงุฑุฌูŠุฉ.\n", + "\n", + "๐Ÿงฎ ุนุฏุฏ ุงู„ุนู…ู„ูŠุงุช (FLOPs)\n", + "\n", + "ูŠู…ูƒู† ุงุณุชุฎุฏุงู… ู…ูƒุชุจุฉ ู…ุซู„ tf.profiler.experimental ุฃูˆ ู…ูƒุชุจุฉ keras-flopsุŒ ู„ูƒู† ููŠ ูƒูˆู„ุงุจ ูŠู…ูƒู†ู†ุง ุชู‚ุฏูŠุฑู‡ุง ุชู‚ุฑูŠุจูŠู‹ุง:\n", + "\n", + "MLP:\n", + "\n", + "ูƒู„ ุทุจู‚ุฉ Dense ุจู€\n", + "๐‘›\n", + "๐‘–\n", + "๐‘›\n", + "ร—\n", + "๐‘›\n", + "๐‘œ\n", + "๐‘ข\n", + "๐‘ก\n", + "n\n", + "in\n", + "\tโ€‹\n", + "\n", + "ร—n\n", + "out\n", + "\tโ€‹\n", + "\n", + " ุนู…ู„ูŠุฉ ุชู‚ุฑูŠุจู‹ุง.\n", + "\n", + "ู…ุซุงู„:\n", + "\n", + "784ร—256 + 256ร—128 + 128ร—10 โ‰ˆ 226k ุนู…ู„ูŠุงุช ููŠ ุงู„ู€ forward pass.\n", + "\n", + "ุจุงู„ุชุงู„ูŠุŒ ุชู‚ุฑูŠุจู‹ุง 0.23 ู…ู„ูŠูˆู† FLOPs (forward pass).\n", + "\n", + "ู…ุน ุงู„ู€ backward pass (ุงู„ุชุฏุฑูŠุจ) โ‰ˆ 2ร— โ‡’ โ‰ˆ 0.46 ู…ู„ูŠูˆู† FLOPs.\n", + "\n", + "CNN:\n", + "\n", + "Convolution ุนู…ู„ูŠุฉ ุฃุซู‚ู„ุŒ ุชูุญุณุจ ุชู‚ุฑูŠุจู‹ุง ูƒุงู„ุชุงู„ูŠ:\n", + "\n", + "๐น\n", + "๐ฟ\n", + "๐‘‚\n", + "๐‘ƒ\n", + "๐‘ \n", + "=\n", + "(\n", + "๐พ\n", + "2\n", + "ร—\n", + "๐ถ\n", + "๐‘–\n", + "๐‘›\n", + "ร—\n", + "๐ป\n", + "๐‘œ\n", + "๐‘ข\n", + "๐‘ก\n", + "ร—\n", + "๐‘Š\n", + "๐‘œ\n", + "๐‘ข\n", + "๐‘ก\n", + "ร—\n", + "๐ถ\n", + "๐‘œ\n", + "๐‘ข\n", + "๐‘ก\n", + ")\n", + "FLOPs=(K\n", + "2\n", + "ร—C\n", + "in\n", + "\tโ€‹\n", + "\n", + "ร—H\n", + "out\n", + "\tโ€‹\n", + "\n", + "ร—W\n", + "out\n", + "\tโ€‹\n", + "\n", + "ร—C\n", + "out\n", + "\tโ€‹\n", + "\n", + ")\n", + "\n", + "ุจุนุฏ ุงู„ุชู‚ุฏูŠุฑ ู„ู„ุทุจู‚ุงุช ู„ุฏูŠูƒ:\n", + "\n", + "Conv1 โ‰ˆ 300k FLOPs\n", + "\n", + "Conv2 โ‰ˆ 600k FLOPs\n", + "\n", + "Dense layers โ‰ˆ 60k FLOPs\n", + "โžœ ุงู„ู…ุฌู…ูˆุน โ‰ˆ 1 ู…ู„ูŠูˆู† FLOPs (forward)\n", + "โžœ 2 ู…ู„ูŠูˆู† FLOPs (forward + backward) ู„ู„ุชุฏุฑูŠุจ.\n", + "\n", + "๐Ÿ”น ุงู„ู†ุชูŠุฌุฉ ุงู„ุชู‚ุฑูŠุจูŠุฉ:\n", + "\n", + "Model\tFLOPs (Forward)\tFLOPs (Train Step)\n", + "MLP\t~0.23M\t~0.46M\n", + "CNN\t~1.0M\t~2.0M" + ], + "metadata": { + "id": "a4vMzLEBIwMi" + } + }, + { + "cell_type": "markdown", + "source": [ + "๐Ÿ’พ ุงุณุชู‡ู„ุงูƒ ุงู„ุฐุงูƒุฑุฉ ุฃุซู†ุงุก ุงู„ุชุฏุฑูŠุจ\n", + "\n", + "ูŠุชุถู…ู†:\n", + "\n", + "ุงู„ุฃูˆุฒุงู† (Parameters)\n", + "\n", + "ุญุงู„ุฉ ุงู„ู…ุญุณู† (Optimizer State)\n", + "\n", + "ุงู„ู…ุชุฏุฑุฌุงุช (Gradients)\n", + "\n", + "ูƒู„ ู…ุนุงู…ู„ ูŠุณุชุฎุฏู… ุชู‚ุฑูŠุจู‹ุง 4 bytes (float32).\n", + "ุงู„ู…ุฌู…ูˆุน โ‰ˆ\n", + "params\n", + "ร—\n", + "3\n", + "ร—\n", + "4\n", + "paramsร—3ร—4 bytes." + ], + "metadata": { + "id": "b9HSkFrYI1pe" + } + }, + { + "cell_type": "code", + "source": [ + "def estimate_training_memory(params):\n", + " bytes_per_param = 4\n", + " multiplier = 3 # parameters + gradients + optimizer state\n", + " total_bytes = params * bytes_per_param * multiplier\n", + " return total_bytes / (1024 * 1024) # ุจุงู„ู…ูŠุบุงุจุงูŠุช\n", + "\n", + "mlp_mem = estimate_training_memory(mlp_params)\n", + "cnn_mem = estimate_training_memory(cnn_params)\n", + "\n", + "print(f\"๐Ÿง  MLP Estimated Training Memory: {mlp_mem:.2f} MB\")\n", + "print(f\"๐Ÿงฉ CNN Estimated Training Memory: {cnn_mem:.2f} MB\")\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "CpI50leLI5vu", + "outputId": "15bed7e0-ae37-4865-b7d4-c4c2cea7b907" + }, + "execution_count": 9, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "๐Ÿง  MLP Estimated Training Memory: 2.69 MB\n", + "๐Ÿงฉ CNN Estimated Training Memory: 0.65 MB\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "๐Ÿ“ Task 5.1 โ€“ Summary Table\n", + "Model\tTest Accuracy\tTrainable Parameters\tSaved Model Size (MB)\tFLOPs (Training)\tFLOPs (Inference)\tTraining Memory (MB)\n", + "๐Ÿง  MLP\t~0.88\t266,634\t~1.10 MB\t~0.46M\t~0.23M\t~3.05 MB\n", + "๐Ÿงฉ CNN\t~0.92\t56,714\t~0.25 MB\t~2.00M\t~1.00M\t~0.65 MB\n", + "\n", + "\n", + "๐Ÿ’ก ุชุญู„ูŠู„ ุงู„ู†ุชุงุฆุฌ\n", + "1๏ธโƒฃ ุฃูŠ ู†ู…ูˆุฐุฌ ุญู‚ู‚ ุฏู‚ุฉ ุฃุนู„ู‰ุŸ\n", + "\n", + "โœ… ู†ู…ูˆุฐุฌ ุงู„ู€ CNN ุญู‚ู‚ ุฏู‚ุฉ ุงุฎุชุจุงุฑ ุฃุนู„ู‰ (~92%) ู…ู‚ุงุฑู†ุฉ ุจู€ MLP (~88%).\n", + "ูˆุฐู„ูƒ ู„ุฃู† ุงู„ุดุจูƒุงุช ุงู„ุงู„ุชูุงููŠุฉ (Convolutional Networks) ู‚ุงุฏุฑุฉ ุนู„ู‰ ุงุณุชุฎู„ุงุต ุงู„ุณู…ุงุช ุงู„ู…ูƒุงู†ูŠุฉ Spatial Features ู…ู† ุงู„ุตูˆุฑ ุจุดูƒู„ ูุนุงู„ ุจูุถู„ ุงู„ุทุจู‚ุงุช ุงู„ุงู„ุชูุงููŠุฉ (Conv2D).\n", + "\n", + "2๏ธโƒฃ ุฃูŠ ู†ู…ูˆุฐุฌ ูŠุณุชุฎุฏู… ุฐุงูƒุฑุฉ ูˆู…ุนุงู…ู„ุงุช ุฃู‚ู„ุŸ\n", + "\n", + "โœ… ู†ู…ูˆุฐุฌ ุงู„ู€ CNN ูŠุณุชุฎุฏู… ุนุฏุฏ ู…ุนุงู…ู„ุงุช ุฃู‚ู„ (โ‰ˆ 56K ูู‚ุท) ู…ู‚ุงุฑู†ุฉ ุจู€ MLP (โ‰ˆ 266K)ุŒ\n", + "ูƒู…ุง ุฃู† ุญุฌู… ู…ู„ู ุงู„ู†ู…ูˆุฐุฌ CNN ุฃุตุบุฑ (~0.25 MB) ู…ู‚ุงุจู„ (~1.1 MB) ู„ู„ู€ MLP.\n", + "ูˆู‡ุฐุง ูŠุฌุนู„ู‡ ุฃูƒุซุฑ ูƒูุงุกุฉ ู…ู† ู†ุงุญูŠุฉ ุงู„ุชุฎุฒูŠู† ูˆุงู„ู†ุดุฑ (deployment).\n", + "\n", + "3๏ธโƒฃ ู…ุง ู‡ูˆ ุงู„ุชูˆุงุฒู† (Trade-off) ุจูŠู† ุงู„ู†ู…ูˆุฐุฌูŠู†ุŸ\n", + "ุฌุงู†ุจ ุงู„ู…ู‚ุงุฑู†ุฉ\tMLP\tCNN\n", + "ุงู„ุณุฑุนุฉ ุงู„ุญุณุงุจูŠุฉ (FLOPs)\tุฃุณุฑุน ูˆุฃุฎู ููŠ ุงู„ุญุณุงุจุงุช\tุฃุจุทุฃ ุจุณุจุจ ุนู…ู„ูŠุงุช ุงู„ุงู„ุชูุงู\n", + "ุงู„ุงุณุชู‡ู„ุงูƒ ุงู„ุฐุงูƒุฑูŠ\tุฃุนู„ู‰ ุจุณุจุจ ุงู„ุทุจู‚ุงุช ุงู„ูƒุซูŠูุฉ\tุฃู‚ู„ ูˆุฃูƒุซุฑ ูƒูุงุกุฉ\n", + "ุงู„ุฏู‚ุฉ ููŠ ุชุตู†ูŠู ุงู„ุตูˆุฑ\tุฃู‚ู„ุŒ ู„ุฃู†ู‡ ูŠุชุฌุงู‡ู„ ุงู„ุจู†ูŠุฉ ุงู„ู…ูƒุงู†ูŠุฉ ู„ู„ุตูˆุฑุฉ\tุฃุนู„ู‰ุŒ ู„ุฃู†ู‡ ูŠุชุนู„ู… ุงู„ุณู…ุงุช ุงู„ู…ูƒุงู†ูŠุฉ\n", + "ุงู„ุงุณุชุฎุฏุงู… ุงู„ู…ู†ุงุณุจ\tุฌูŠุฏ ู„ู„ุจูŠุงู†ุงุช ุงู„ุฌุฏูˆู„ูŠุฉ ุฃูˆ ุงู„ู…ูˆุฌู‡ุฉ ุนุฏุฏูŠู‹ุง\tู…ู…ุชุงุฒ ู„ู„ุตูˆุฑ ูˆุงู„ุจูŠุงู†ุงุช ุงู„ู…ุฑุฆูŠุฉ\n", + "๐Ÿง  ู„ู…ุงุฐุง CNN ุฃูุถู„ ููŠ ุชุตู†ูŠู ุงู„ุตูˆุฑุŸ\n", + "\n", + "ุงู„ุชุนุงู…ู„ ู…ุน ุงู„ุจู†ูŠุฉ ุงู„ู…ูƒุงู†ูŠุฉ ู„ู„ุตูˆุฑุฉ:\n", + "ุทุจู‚ุงุช ุงู„ู€ Convolution ุชุณุชููŠุฏ ู…ู† ุงู„ู…ูˆู‚ุน ุงู„ู…ูƒุงู†ูŠ ู„ู„ุจูƒุณู„ุงุชุŒ ุจุนูƒุณ ุงู„ู€ MLP ุงู„ุฐูŠ ูŠูู‚ุฏ ู‡ุฐุง ุงู„ุชุฑุชูŠุจ ุนู†ุฏ \"ุชุณุทูŠุญ\" ุงู„ุตูˆุฑุฉ.\n", + "\n", + "ู…ุดุงุฑูƒุฉ ุงู„ุฃูˆุฒุงู† (Weight Sharing):\n", + "ู†ูุณ ุงู„ูู„ุชุฑ (kernel) ูŠูุณุชุฎุฏู… ุนู„ู‰ ุฌู…ูŠุน ู…ู†ุงุทู‚ ุงู„ุตูˆุฑุฉุŒ ู…ู…ุง ูŠู‚ู„ู„ ุนุฏุฏ ุงู„ู…ุนุงู…ู„ุงุช ุจุดูƒู„ ูƒุจูŠุฑ ูˆูŠุฒูŠุฏ ุงู„ูƒูุงุกุฉ.\n", + "\n", + "ุงุณุชุฎุฑุงุฌ ุณู…ุงุช ู…ุชุนุฏุฏุฉ ุงู„ู…ุณุชูˆูŠุงุช:\n", + "ุงู„ุทุจู‚ุงุช ุงู„ุงู„ุชูุงููŠุฉ ุชุชุนู„ู… ู…ู† ุงู„ุฃู†ู…ุงุท ุงู„ุจุณูŠุทุฉ (ู…ุซู„ ุงู„ุญูˆุงู) ุฅู„ู‰ ุงู„ุฃู†ู…ุงุท ุงู„ู…ุนู‚ุฏุฉ (ู…ุซู„ ุงู„ุดูƒู„ ุงู„ูƒุงู…ู„) ุชุฏุฑูŠุฌูŠู‹ุง.\n", + "\n", + "ู‚ุงุจู„ูŠุฉ ุงู„ุชุนู…ูŠู… ุงู„ุนุงู„ูŠุฉ:\n", + "ู„ุฃู† ุงู„ุดุจูƒุฉ ุชุชุนู„ู… ุงู„ู…ูŠุฒุงุช ุชู„ู‚ุงุฆูŠู‹ุงุŒ ูู‡ูŠ ุฃู‚ู„ ุนุฑุถุฉ ู„ูุฑุท ุงู„ุชุฎุตูŠุต (overfitting) ุนู†ุฏ ุงุณุชุฎุฏุงู… ุงู„ุจูŠุงู†ุงุช ุงู„ุจุตุฑูŠุฉ.\n", + "\n", + "๐Ÿ ุงู„ุงุณุชู†ุชุงุฌ ุงู„ู†ู‡ุงุฆูŠ\n", + "\n", + "ุจู†ุงุกู‹ ุนู„ู‰ ุงู„ุชุญู„ูŠู„ ุงู„ูƒู…ูŠ ูˆุงู„ู†ูˆุนูŠ:\n", + "\n", + "๐Ÿ”น ู†ู…ูˆุฐุฌ CNN ู‡ูˆ ุงู„ุฃู†ุณุจ ู„ุชุตู†ูŠู ุงู„ุตูˆุฑ ููŠ Fashion-MNIST.\n", + "๐Ÿ”น ุจูŠู†ู…ุง ุงู„ู€ MLP ุฃุจุณุท ูˆุฃุณุฑุนุŒ ุฅู„ุง ุฃู†ู‡ ุบูŠุฑ ูƒุงูู ู„ุงุณุชุฎุฑุงุฌ ุงู„ุนู„ุงู‚ุงุช ุงู„ู…ูƒุงู†ูŠุฉ ุงู„ุฏู‚ูŠู‚ุฉ ุจูŠู† ุงู„ุจูƒุณู„ุงุช.\n", + "๐Ÿ”น ุจุงู„ุชุงู„ูŠุŒ ูŠูˆุตู‰ ุจุงุณุชุฎุฏุงู… CNN ููŠ ู…ู‡ุงู… ุงู„ุฑุคูŠุฉ ุงู„ุญุงุณูˆุจูŠุฉุŒ\n", + "ุฎุตูˆุตู‹ุง ุนู†ุฏู…ุง ุชูƒูˆู† ุงู„ุตูˆุฑ ู…ุฏุฎู„ุฉ ุฃุณุงุณูŠุฉุŒ ูˆูŠูƒูˆู† ุงู„ู‡ุฏู ู‡ูˆ ุฏู‚ุฉ ุนุงู„ูŠุฉ ูˆูƒูุงุกุฉ ููŠ ุงู„ุชุนู„ู…." + ], + "metadata": { + "id": "i8lbT7b-I-Ig" + } + }, + { + "cell_type": "code", + "source": [ + "# =========================\n", + "# Fashion-MNIST Final Report (PDF)\n", + "# =========================\n", + "\n", + "import os\n", + "import math\n", + "from datetime import datetime\n", + "\n", + "# 1) ู…ุญุงูˆู„ุงุช ู„ุงู„ุชู‚ุงุท ุงู„ู‚ูŠู… ู…ู† ุงู„ุฌู„ุณุฉ ุฅู† ูˆูุฌุฏุช\n", + "def safe_get(varname, default=None):\n", + " return globals().get(varname, default)\n", + "\n", + "# ุงู„ุชู‚ุงุท ุงู„ู†ู…ุงุฐุฌ\n", + "mlp_model = safe_get('mlp_model')\n", + "cnn_model = safe_get('cnn_model')\n", + "\n", + "# ุงู„ุชู‚ุงุท ุฏุงุชุง ุงู„ุงุฎุชุจุงุฑ (ู‚ุฏ ุชูƒูˆู† ู…ูˆุฌูˆุฏุฉ ู…ู† ุงู„ุฎุทูˆุงุช ุงู„ุณุงุจู‚ุฉ)\n", + "x_test_mlp = safe_get('x_test_mlp')\n", + "x_test_cnn = safe_get('x_test_cnn')\n", + "y_test = safe_get('y_test')\n", + "\n", + "# ุงู„ุชู‚ุงุท ู†ุชุงุฆุฌ ุณุงุจู‚ุฉ ุฅู† ูˆูุฌุฏุช\n", + "mlp_test_loss = safe_get('mlp_test_loss')\n", + "mlp_test_acc = safe_get('mlp_test_acc')\n", + "cnn_test_loss = safe_get('cnn_test_loss')\n", + "cnn_test_acc = safe_get('cnn_test_acc')\n", + "\n", + "# 2) ุญุณุงุจ/ุฌู„ุจ ุนุฏุฏ ุงู„ู…ุนุงู…ู„ุงุช\n", + "mlp_params = mlp_model.count_params() if mlp_model else None\n", + "cnn_params = cnn_model.count_params() if cnn_model else None\n", + "\n", + "# 3) ุชู‚ูŠูŠู… ุงู„ุฏู‚ุฉ ูˆุงู„ุฎุณุงุฑุฉ ุฅุฐุง ูƒุงู†ุช ุงู„ุจูŠุงู†ุงุช ู…ูˆุฌูˆุฏุฉ ูˆู„ู… ุชูƒู† ุงู„ู‚ูŠู… ู…ุญููˆุธุฉ\n", + "def try_evaluate(model, x, y):\n", + " try:\n", + " if (model is not None) and (x is not None) and (y is not None):\n", + " loss, acc = model.evaluate(x, y, verbose=0)\n", + " return float(loss), float(acc)\n", + " except Exception as e:\n", + " pass\n", + " return None, None\n", + "\n", + "if mlp_test_acc is None or mlp_test_loss is None:\n", + " l, a = try_evaluate(mlp_model, x_test_mlp, y_test)\n", + " mlp_test_loss = mlp_test_loss if mlp_test_loss is not None else l\n", + " mlp_test_acc = mlp_test_acc if mlp_test_acc is not None else a\n", + "\n", + "if cnn_test_acc is None or cnn_test_loss is None:\n", + " l, a = try_evaluate(cnn_model, x_test_cnn, y_test)\n", + " cnn_test_loss = cnn_test_loss if cnn_test_loss is not None else l\n", + " cnn_test_acc = cnn_test_acc if cnn_test_acc is not None else a\n", + "\n", + "# 4) ุฃุญุฌุงู… ุงู„ู…ู„ูุงุช ุงู„ู…ุญููˆุธุฉ (.h5)\n", + "def file_size_mb(path):\n", + " try:\n", + " return os.path.getsize(path) / (1024*1024)\n", + " except:\n", + " return None\n", + "\n", + "# ู„ูˆ ู„ู… ุชูƒู† ู…ูˆุฌูˆุฏุฉุŒ ู„ุง ู…ุดูƒู„ุฉ โ€” ุณู†ุนุฑุถ N/A\n", + "mlp_h5 = 'mlp_model.h5'\n", + "cnn_h5 = 'cnn_model.h5'\n", + "mlp_size = file_size_mb(mlp_h5)\n", + "cnn_size = file_size_mb(cnn_h5)\n", + "\n", + "# 5) ุชู‚ุฏูŠุฑ FLOPs (ุชู‚ุฑูŠุจูŠ ุฌุฏู‹ุง) + ุฐุงูƒุฑุฉ ุงู„ุชุฏุฑูŠุจ\n", + "# ู…ู„ุงุญุธุฉ: ู‡ุฐู‡ ุชู‚ุฏูŠุฑุงุช ู…ุจุณุทุฉ ู„ู„ุงุณุชุฎุฏุงู… ุงู„ุฃูƒุงุฏูŠู…ูŠ\n", + "def estimate_training_memory_mb(params):\n", + " # float32: 4 bytes ู„ูƒู„ ู…ุนุงู…ู„\n", + " # Parameters + Gradients + Optimizer state โ‰ˆ 3x\n", + " if params is None: return None\n", + " return (params * 4 * 3) / (1024*1024)\n", + "\n", + "# ุชู‚ุฏูŠุฑ FLOPs (ุชู‚ุฑูŠุจูŠ) โ€” ูŠุนุชู…ุฏ ุนู„ู‰ ุงู„ู‡ูŠูƒู„ ุงู„ู…ุญุฏุฏ ู„ุฏูŠู†ุง:\n", + "# ู…ู† ุงู„ุดุฑุญ ุงู„ุณุงุจู‚: (ู‚ูŠู… ู…ุฑุฌุนูŠุฉ ุชู‚ุฑูŠุจูŠุฉ)\n", + "mlp_flops_inf = 0.23e6 # ~0.23M\n", + "mlp_flops_train = 0.46e6 # ~0.46M\n", + "cnn_flops_inf = 1.00e6 # ~1.0M\n", + "cnn_flops_train = 2.00e6 # ~2.0M\n", + "\n", + "mlp_mem_train = estimate_training_memory_mb(mlp_params)\n", + "cnn_mem_train = estimate_training_memory_mb(cnn_params)\n", + "\n", + "# 6) ุชุฌู‡ูŠุฒ ุฌุฏูˆู„ ุงู„ุชู‚ุฑูŠุฑ (ู…ุน ุงู„ุชุญูˆูŠู„ ุฅู„ู‰ ู†ุตูˆุต ู…ู†ุณู‚ุฉ)\n", + "def fmt(v, fmt_str=\"{:.4f}\"):\n", + " if v is None: return \"N/A\"\n", + " try:\n", + " return fmt_str.format(v)\n", + " except:\n", + " return str(v)\n", + "\n", + "def fmt_int(v):\n", + " if v is None: return \"N/A\"\n", + " return f\"{int(v):,}\"\n", + "\n", + "def fmt_mb(v):\n", + " if v is None: return \"N/A\"\n", + " return f\"{v:.2f} MB\"\n", + "\n", + "def fmt_flops(v):\n", + " if v is None: return \"N/A\"\n", + " # ู†ุนุฑุถ ุจุงู„ู…ู„ุงูŠูŠู† ู„ู„ุงุฎุชุตุงุฑ\n", + " return f\"{v/1e6:.2f}M\"\n", + "\n", + "report_rows = [\n", + " {\n", + " \"Model\": \"MLP\",\n", + " \"Test Accuracy\": fmt(mlp_test_acc),\n", + " \"Trainable Parameters\": fmt_int(mlp_params),\n", + " \"Saved Model Size (MB)\": fmt_mb(mlp_size),\n", + " \"FLOPs (Training)\": fmt_flops(mlp_flops_train),\n", + " \"FLOPs (Inference)\": fmt_flops(mlp_flops_inf),\n", + " \"Training Memory (MB)\": fmt(mlp_mem_train, \"{:.2f}\")\n", + " },\n", + " {\n", + " \"Model\": \"CNN\",\n", + " \"Test Accuracy\": fmt(cnn_test_acc),\n", + " \"Trainable Parameters\": fmt_int(cnn_params),\n", + " \"Saved Model Size (MB)\": fmt_mb(cnn_size),\n", + " \"FLOPs (Training)\": fmt_flops(cnn_flops_train),\n", + " \"FLOPs (Inference)\": fmt_flops(cnn_flops_inf),\n", + " \"Training Memory (MB)\": fmt(cnn_mem_train, \"{:.2f}\")\n", + " }\n", + "]\n", + "\n", + "# 7) ุฅู†ุดุงุก CSV ู„ู„ุฌุฏูˆู„ (ุงุฎุชูŠุงุฑูŠ ู„ู„ุนุฑุถ ูˆุงู„ู…ุดุงุฑูƒุฉ)\n", + "import csv\n", + "csv_path = \"fashionmnist_summary.csv\"\n", + "with open(csv_path, \"w\", newline=\"\", encoding=\"utf-8\") as f:\n", + " writer = csv.DictWriter(f, fieldnames=list(report_rows[0].keys()))\n", + " writer.writeheader()\n", + " for r in report_rows:\n", + " writer.writerow(r)\n", + "\n", + "# 8) ุฅู†ุดุงุก PDF ุจุงุณุชุฎุฏุงู… reportlab\n", + "!pip -q install reportlab >/dev/null\n", + "\n", + "from reportlab.lib.pagesizes import A4\n", + "from reportlab.pdfgen import canvas\n", + "from reportlab.lib import colors\n", + "from reportlab.lib.units import cm\n", + "from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle\n", + "from reportlab.lib.styles import getSampleStyleSheet\n", + "\n", + "pdf_path = \"FashionMNIST_Report.pdf\"\n", + "doc = SimpleDocTemplate(pdf_path, pagesize=A4, rightMargin=2*cm, leftMargin=2*cm, topMargin=1.5*cm, bottomMargin=1.5*cm)\n", + "styles = getSampleStyleSheet()\n", + "story = []\n", + "\n", + "title = Paragraph(\"Fashion-MNIST Image Classification โ€“ Final Report\", styles[\"Title\"])\n", + "subtitle = Paragraph(f\"Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\", styles[\"Normal\"])\n", + "story += [title, subtitle, Spacer(1, 12)]\n", + "\n", + "# ู†ุจุฐุฉ ู‚ุตูŠุฑุฉ\n", + "intro = \"\"\"\n", + "Overview: This report summarizes training and evaluation of two architectures (MLP & CNN) on the Fashion-MNIST dataset using TensorFlow/Keras. It includes accuracy, model complexity (parameters), storage footprint, and rough estimates of FLOPs and training memory.\n", + "\"\"\"\n", + "story += [Paragraph(intro, styles[\"BodyText\"]), Spacer(1, 12)]\n", + "\n", + "# ุฌุฏูˆู„ ุงู„ู…ู„ุฎุต\n", + "table_data = [[\"Model\",\"Test Accuracy\",\"Trainable Parameters\",\"Saved Model Size (MB)\",\"FLOPs (Training)\",\"FLOPs (Inference)\",\"Training Memory (MB)\"]]\n", + "for r in report_rows:\n", + " table_data.append([r[k] for k in table_data[0]])\n", + "\n", + "tbl = Table(table_data, hAlign='LEFT')\n", + "tbl.setStyle(TableStyle([\n", + " (\"BACKGROUND\", (0,0), (-1,0), colors.lightgrey),\n", + " (\"TEXTCOLOR\", (0,0), (-1,0), colors.black),\n", + " (\"ALIGN\", (0,0), (-1,-1), \"CENTER\"),\n", + " (\"FONTNAME\", (0,0), (-1,0), \"Helvetica-Bold\"),\n", + " (\"BOTTOMPADDING\", (0,0), (-1,0), 8),\n", + " (\"GRID\", (0,0), (-1,-1), 0.5, colors.grey),\n", + "]))\n", + "story += [tbl, Spacer(1, 16)]\n", + "\n", + "# ุงู„ุฎู„ุงุตุฉ\n", + "conclusion = \"\"\"\n", + "Conclusion:
\n", + "โ€ข The CNN achieved higher test accuracy, thanks to spatial feature extraction via convolution and weight sharing, while keeping parameter count and saved size lower than the MLP.
\n", + "โ€ข The MLP is simpler and has fewer FLOPs per inference in this setup, but it discards spatial structure by flattening, which typically limits image classification performance.
\n", + "โ€ข For image tasks, CNNs are generally superior due to learning hierarchical, translation-aware features with fewer parameters.\n", + "\"\"\"\n", + "story += [Paragraph(conclusion, styles[\"BodyText\"]), Spacer(1, 12)]\n", + "\n", + "# ุชูุงุตูŠู„ ุฅุถุงููŠุฉ/ู…ู„ุงุญุธุงุช\n", + "notes = \"\"\"\n", + "Notes: Reported FLOPs are rough academic estimates for this specific architecture. Actual runtime cost depends on hardware, libraries, batch size, and kernel implementations. Values marked \"N/A\" indicate the session lacked those variables/files at generation time.\n", + "\"\"\"\n", + "story += [Paragraph(notes, styles[\"BodyText\"]), Spacer(1, 12)]\n", + "\n", + "doc.build(story)\n", + "\n", + "print(\"โœ… PDF generated:\", pdf_path)\n", + "print(\"โœ… CSV generated:\", csv_path)\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "vCDCHu1hJuKc", + "outputId": "daf9e2c5-d7bd-410d-d0d7-b73d9cdfb910" + }, + "execution_count": 10, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "โœ… PDF generated: FashionMNIST_Report.pdf\n", + "โœ… CSV generated: fashionmnist_summary.csv\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "## TP 06 Task 3.1 โ€” Convert and Quantize the MLP Model" + ], + "metadata": { + "id": "ilgxsJ4aKPid" + } + }, + { + "cell_type": "code", + "source": [ + "import tensorflow as tf\n", + "import numpy as np\n", + "import os\n", + "\n", + "# --- Helper function: representative dataset generator ---\n", + "def representative_data_gen():\n", + " # ู†ุฃุฎุฐ ุนูŠู†ุฉ ุตุบูŠุฑุฉ ู…ู† ุจูŠุงู†ุงุช ุงู„ุชุฏุฑูŠุจ (100 ู…ุซุงู„ ูู‚ุท) ู„ู…ุนุงูŠุฑุฉ ุงู„ู†ุทุงู‚\n", + " for i in range(100):\n", + " img = x_train_mlp[i].astype(np.float32)\n", + " yield [np.expand_dims(img, axis=0)]\n", + "\n", + "# --- Convert the MLP model to TFLite with full integer quantization ---\n", + "converter = tf.lite.TFLiteConverter.from_keras_model(mlp_model)\n", + "converter.optimizations = [tf.lite.Optimize.DEFAULT]\n", + "converter.representative_dataset = representative_data_gen\n", + "\n", + "# ู†ุทู„ุจ ุฃู† ุชูƒูˆู† ูƒู„ ุงู„ู‚ูŠู… (inputs/outputs) ุตุญูŠุญุฉ Int8 ุจุงู„ูƒุงู…ู„\n", + "converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]\n", + "converter.inference_input_type = tf.int8\n", + "converter.inference_output_type = tf.int8\n", + "\n", + "# ุงู„ุชุญูˆูŠู„\n", + "tflite_model_mlp = converter.convert()\n", + "\n", + "# ุญูุธ ุงู„ู†ู…ูˆุฐุฌ\n", + "with open(\"mlp_model_quantized.tflite\", \"wb\") as f:\n", + " f.write(tflite_model_mlp)\n", + "\n", + "# --- ู…ู‚ุงุฑู†ุฉ ุงู„ุญุฌู… ู‚ุจู„ ูˆุจุนุฏ ุงู„ุชุญูˆูŠู„ ---\n", + "mlp_h5_size = os.path.getsize(\"mlp_model.h5\") / (1024 * 1024)\n", + "mlp_tflite_size = os.path.getsize(\"mlp_model_quantized.tflite\") / (1024 * 1024)\n", + "\n", + "print(f\"๐Ÿง  MLP Original (.h5) Size: {mlp_h5_size:.2f} MB\")\n", + "print(f\"๐Ÿง  MLP Quantized (.tflite) Size: {mlp_tflite_size:.2f} MB\")\n", + "print(f\"๐Ÿ”ป Size Reduction: {(1 - mlp_tflite_size / mlp_h5_size) * 100:.1f}%\")\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "45KAyBIvKTU0", + "outputId": "0427a34a-2a23-49a7-9fa0-89d45c9e589f" + }, + "execution_count": 11, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Saved artifact at '/tmp/tmp35sr99sc'. The following endpoints are available:\n", + "\n", + "* Endpoint 'serve'\n", + " args_0 (POSITIONAL_ONLY): TensorSpec(shape=(None, 28, 28), dtype=tf.float32, name='keras_tensor')\n", + "Output Type:\n", + " TensorSpec(shape=(None, 10), dtype=tf.float32, name=None)\n", + "Captures:\n", + " 133582095970000: TensorSpec(shape=(), dtype=tf.resource, name=None)\n", + " 133582095970960: TensorSpec(shape=(), dtype=tf.resource, name=None)\n", + " 133582095970384: TensorSpec(shape=(), dtype=tf.resource, name=None)\n", + " 133582095970768: TensorSpec(shape=(), dtype=tf.resource, name=None)\n", + " 133582095971152: TensorSpec(shape=(), dtype=tf.resource, name=None)\n", + " 133582095969040: TensorSpec(shape=(), dtype=tf.resource, name=None)\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "/usr/local/lib/python3.12/dist-packages/tensorflow/lite/python/convert.py:854: UserWarning: Statistics for quantized inputs were expected, but not specified; continuing anyway.\n", + " warnings.warn(\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "๐Ÿง  MLP Original (.h5) Size: 2.72 MB\n", + "๐Ÿง  MLP Quantized (.tflite) Size: 0.24 MB\n", + "๐Ÿ”ป Size Reduction: 91.3%\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "# --- Helper: representative dataset generator for CNN ---\n", + "def representative_data_gen_cnn():\n", + " for i in range(100):\n", + " img = x_train_cnn[i].astype(np.float32)\n", + " yield [np.expand_dims(img, axis=0)]\n", + "\n", + "# --- Convert the CNN model to TFLite with full integer quantization ---\n", + "converter = tf.lite.TFLiteConverter.from_keras_model(cnn_model)\n", + "converter.optimizations = [tf.lite.Optimize.DEFAULT]\n", + "converter.representative_dataset = representative_data_gen_cnn\n", + "\n", + "converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]\n", + "converter.inference_input_type = tf.int8\n", + "converter.inference_output_type = tf.int8\n", + "\n", + "# ุงู„ุชุญูˆูŠู„\n", + "tflite_model_cnn = converter.convert()\n", + "\n", + "# ุญูุธ ุงู„ู†ู…ูˆุฐุฌ\n", + "with open(\"cnn_model_quantized.tflite\", \"wb\") as f:\n", + " f.write(tflite_model_cnn)\n", + "\n", + "# --- ู…ู‚ุงุฑู†ุฉ ุงู„ุญุฌู… ---\n", + "cnn_h5_size = os.path.getsize(\"cnn_model.h5\") / (1024 * 1024)\n", + "cnn_tflite_size = os.path.getsize(\"cnn_model_quantized.tflite\") / (1024 * 1024)\n", + "\n", + "print(f\"๐Ÿงฉ CNN Original (.h5) Size: {cnn_h5_size:.2f} MB\")\n", + "print(f\"๐Ÿงฉ CNN Quantized (.tflite) Size: {cnn_tflite_size:.2f} MB\")\n", + "print(f\"๐Ÿ”ป Size Reduction: {(1 - cnn_tflite_size / cnn_h5_size) * 100:.1f}%\")\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Bfm-xKVxKy3c", + "outputId": "ba0d8433-c26c-4811-bfc4-ed1740cdffe3" + }, + "execution_count": 12, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Saved artifact at '/tmp/tmpalmcfws1'. The following endpoints are available:\n", + "\n", + "* Endpoint 'serve'\n", + " args_0 (POSITIONAL_ONLY): TensorSpec(shape=(None, 28, 28, 1), dtype=tf.float32, name='keras_tensor_5')\n", + "Output Type:\n", + " TensorSpec(shape=(None, 10), dtype=tf.float32, name=None)\n", + "Captures:\n", + " 133582095971344: TensorSpec(shape=(), dtype=tf.resource, name=None)\n", + " 133582095974032: TensorSpec(shape=(), dtype=tf.resource, name=None)\n", + " 133582095973840: TensorSpec(shape=(), dtype=tf.resource, name=None)\n", + " 133582095973456: TensorSpec(shape=(), dtype=tf.resource, name=None)\n", + " 133582093156816: TensorSpec(shape=(), dtype=tf.resource, name=None)\n", + " 133582093158544: TensorSpec(shape=(), dtype=tf.resource, name=None)\n", + " 133582093159504: TensorSpec(shape=(), dtype=tf.resource, name=None)\n", + " 133582093158736: TensorSpec(shape=(), dtype=tf.resource, name=None)\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "/usr/local/lib/python3.12/dist-packages/tensorflow/lite/python/convert.py:854: UserWarning: Statistics for quantized inputs were expected, but not specified; continuing anyway.\n", + " warnings.warn(\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "๐Ÿงฉ CNN Original (.h5) Size: 0.69 MB\n", + "๐Ÿงฉ CNN Quantized (.tflite) Size: 0.06 MB\n", + "๐Ÿ”ป Size Reduction: 91.1%\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "# **4) Deployment Feasibility Analysis**" + ], + "metadata": { + "id": "QDHV5QDuLe4Y" + } + }, + { + "cell_type": "markdown", + "source": [ + "1) Memory Constraint (SRAM 512 KB)\n", + "\n", + "\n", + "MLP (int8 ~0.28 MB / 287 KB):\n", + "ูŠู„ุฒู… ุฃูŠุถู‹ุง ุจุถุน ุนุดุฑุงุช ุฅู„ู‰ ู…ุฆุงุช KB ู„ู„ู€ Tensor Arena (ุชู†ุดูŠุทุงุช ุงู„ุทุจู‚ุงุช/ุงู„ูˆุณุงุฆุท). ู…ุน ุจู†ูŠุฉ MLP ู„ุฏูŠู†ุง (Flatten โ†’ Dense(256) โ†’ Dense(128) โ†’ Dense(10))ุŒ ุญุฌู… ุงู„ุชู†ุดูŠุทุงุช ุตุบูŠุฑ ู†ุณุจูŠู‹ุงุŒ ู„ุฐู„ูƒ ูŠุธู„ ุงู„ุฅุฌู…ุงู„ูŠ ุถู…ู† 512 KB ููŠ ุณูŠู†ุงุฑูŠูˆู‡ุงุช TinyML ุงู„ู…ุนุชุงุฏุฉ. ุงู„ู†ุชูŠุฌุฉ: ู…ู…ูƒู†.\n", + "\n", + "\n", + "CNN (int8 ~0.07 MB / 72 KB):\n", + "ู„ู„ุชู†ุดูŠุทุงุช ุฃุญุฌุงู… ู…ุซู„ 26ร—26ร—16 ูˆ 11ร—11ร—32ุŒ ูˆู‡ูŠ ุตุบูŠุฑุฉ ู„ุตูˆุฑ 28ร—28. ุญุชู‰ ู…ุน ู‡ูˆุงู…ุด ุฅุถุงููŠุฉ ู„ู„ู€ arenaุŒ ูŠุธู„ ุงู„ุฅุฌู…ุงู„ูŠ ุฃู‚ู„ ุจูƒุซูŠุฑ ู…ู† 512 KB. ุงู„ู†ุชูŠุฌุฉ: ู…ู…ูƒู† ุจุณู‡ูˆู„ุฉ.\n", + "\n", + "\n", + "ุฎู„ุงุตุฉ ุงู„ุฐุงูƒุฑุฉ: ูƒู„ุง ุงู„ู†ู…ูˆุฐุฌูŠู† ู‚ุงุจู„ุงู† ู„ู„ุชุดุบูŠู„ ุนู„ู‰ XIAO ESP32S3 ุจุนุฏ ุงู„ูƒู…ู‘ูŠุฉ ุงู„ูƒุงู…ู„ุฉุŒ ูˆุงู„ู€ CNN ู„ุฏูŠู‡ ู‡ุงู…ุด ุฃูƒุจุฑ ุจูƒุซูŠุฑ.\n", + "\n", + "2) Performance (Latency < ~100 msุŸ)\n", + "\n", + "\n", + "\n", + "\n", + "MLP (inference) โ‰ˆ 0.23M FLOPs\n", + "\n", + "\n", + "CNN (inference) โ‰ˆ 1.00M FLOPs\n", + "\n", + "\n", + "\n", + "\n", + "ู…ุน ESP32-S3 ุซู†ุงุฆูŠ ุงู„ู†ูˆุงุฉ @ 240 MHz ูˆุนู…ู„ูŠุงุช int8 (ูˆูˆุฌูˆุฏ ุชุณุฑูŠุน ู…ุชุฌู‡ ุนู„ู‰ S3)ุŒ ุชุญู‚ูŠู‚ ู…ุนุฏู„ ุฃู‚ู„ ู…ู† 100 ms ู„ู…ุฏุฎู„ 28ร—28 ูˆุงู‚ุนูŠ ุฌุฏู‹ุง:\n", + "\n", + "\n", + "MLP: ุจุถุน ู…ูŠู„ูŠ ุซูˆุงู†ู ุฅู„ู‰ ุนุดุฑุงุช ู‚ู„ูŠู„ุฉ ู…ู† ms.\n", + "\n", + "\n", + "CNN: ุนุดุฑุงุช ู‚ู„ูŠู„ุฉ ู…ู† ms ุนุงุฏุฉุŒ ูˆุญุชู‰ ููŠ ุฃุณูˆุฃ ุงู„ุฃุญูˆุงู„ ุชุจู‚ู‰ ุถู…ู† ~100 ms ู„ู…ุฏุฎู„ ูˆุงุญุฏ.\n", + "\n", + "\n", + "\n", + "\n", + "ุฎู„ุงุตุฉ ุงู„ุฃุฏุงุก: ู†ุนู…ุŒ ุงู„ุฒู…ู† ุงู„ุญู‚ูŠู‚ูŠ (โ‰ค100 ms ู„ู„ุตูˆุฑุฉ) ู…ุชูˆู‚ุน ู„ูƒู„ุง ุงู„ู†ู…ูˆุฐุฌูŠู†ุŒ ูˆุงู„ู€ CNN ุณูŠู‚ุฏู‘ู… ุฏู‚ุฉ ุฃุนู„ู‰ ู…ุน ุฒู…ู† ุงุณุชุฏู„ุงู„ ู…ู‚ุจูˆู„ ุฌุฏู‹ุง ุนู„ู‰ S3.\n", + "\n", + "\n", + "\n", + "ู‡ู„ ูŠู…ูƒู† ุชุดุบูŠู„ ุงู„ู†ู…ูˆุฐุฌูŠู† ุนู„ู‰ XIAO ESP32S3ุŸ\n", + "ู†ุนู… โ€” ุจุนุฏ Full Integer Quantization (int8)ุŒ ูƒู„ุง ุงู„ู†ู…ูˆุฐุฌูŠู† ูŠู„ุจู‘ูŠุงู† ู‚ูŠุฏ ุงู„ุฐุงูƒุฑุฉ 512 KBุŒ ูˆุฒู…ู† ุงู„ุงุณุชุฏู„ุงู„ ุงู„ู…ุชูˆู‚ุน ู…ู†ุงุณุจ ู„ู„ุชุทุจูŠู‚ุงุช ุงู„ุนู…ู„ูŠุฉ (โ‰ค100 ms ู„ู„ุตูˆุฑุฉ).\n", + "\n", + "\n", + "ุฃูŠู‘ู‡ู…ุง ุฃูุถู„ ู„ู„ู†ุดุฑุŸ\n", + "CNN: ู„ุฃู†ู‡ ุฃุฏู‚ู‘ ุจูƒุซูŠุฑ ููŠ ู…ู‡ุงู… ุงู„ุตูˆุฑุŒ ูˆุญุฌู…ู‡ ุจุนุฏ ุงู„ูƒู…ู‘ูŠุฉ ุฃุตุบุฑ ุจูƒุซูŠุฑ ู…ู† 512 KBุŒ ูˆูŠู…ู†ุญ ู‡ุงู…ุดู‹ุง ูƒุจูŠุฑู‹ุง ู„ู„ู€ arena ูˆุงู„ู…ุนุงู„ุฌุฉ.\n", + "\n" + ], + "metadata": { + "id": "FPSxzecuLnzy" + } + } + ] +} \ No newline at end of file diff --git a/TP6/TP6.md b/TP6/TP6.md new file mode 100644 index 0000000..f8b7d96 --- /dev/null +++ b/TP6/TP6.md @@ -0,0 +1,76 @@ +๐Ÿš€ Practical Work: Deploying TinyML Models with TensorFlow Lite + +This practical work focuses on converting the trained Keras models (MLP and CNN from the previous session) into TinyML models using TensorFlow Lite (TFLite), analyzing the conversion process, and assessing their deployment readiness for resource-constrained devices like the Seeed Studio XIAO ESP32S3. + +--- + +### 1. Understanding the Target Hardware: Seeed Studio XIAO ESP32S3 + +Before deployment, it's essential to understand the target device. + +๐Ÿ“ **Task 1.1: Describe the XIAO ESP32S3** +Explain the key specifications of the Seeed Studio XIAO ESP32S3 that make it suitable (or challenging) for TinyML deployment. + +| Feature | Specification (Key Detail) | Importance for TinyML | +|--------|----------------------------|------------------------| +| Microcontroller | ESP32-S3 Dual-core LX7 | Provides the computational power for inference. | +| Operating Frequency | Up to 240 MHz | Faster clock speed means faster inference time. | +| SRAM (Static RAM) | 512 KB | Critical for holding the model's weights, input data, and intermediate results. This is a major constraint. | +| Flash Memory | 8 MB (PSRAM) / 16 MB (Flash) | Used for storing the compiled TFLite model file and the application code. | +| Power Consumption | Low-power modes | Essential for battery-operated IoT devices. | + +--- + +### 2. Introducing TFLite and Model Quantization + +The process of model conversion is key to enabling deployment on the XIAO's limited memory. + +๐Ÿ“ **Task 2.1: The Role of TensorFlow Lite (TFLite)** +Explain what TensorFlow Lite (TFLite) does and why it is necessary when moving a Keras model from a PC/cloud environment to an edge device like the XIAO. + +TFLite is a set of tools designed to enable on-device machine learning. It takes a standard TensorFlow/Keras model and performs two main actions: +- **Optimization**: It prunes unnecessary nodes and optimizes the graph for high-performance, low-latency execution on edge hardware. +- **Format Conversion**: It converts the model into a flattened, smaller `.tflite` file that can be loaded and interpreted by the specialized TFLite runtime engine, which is much smaller than the full TensorFlow library. + +๐Ÿ“ **Task 2.2: The Need for Quantization** +Define Quantization and explain what happens to the model when you apply Post-Training Quantization (PTQ). + +- **Definition**: Quantization is the process of reducing the numerical precision of the model's parameters (weights and biases) and sometimes the activation values. +- **What happens?** The model's standard 32-bit floating-point numbers ($\text{float}32$) are converted to 8-bit integers ($\text{int}8$). + - **Model Size**: The model file size is reduced by up to 75% (a factor of $\frac{32}{8}=4$). + - **Inference Speed**: Inference speed generally increases because integer operations are faster and less power-intensive than floating-point operations on microcontrollers. + - **Accuracy**: There is a potential, usually small, loss in model accuracy due to the precision reduction. + +--- + +### 3. TFLite Conversion and Quantization (Code) + +Convert both the MLP and CNN models using TFLite's conversion tool. + +๐Ÿ“ **Task 3.1: Convert and Quantize the MLP Model** +Use the `tf.lite.TFLiteConverter.from_keras_model()` method to convert and then apply Full Integer Quantization to the `mlp_model`. +**Note**: For full integer quantization, you must provide a Representative Dataset for calibrating the quantization range. +Report the size difference between the original Keras model (`.h5` size) and the quantized TFLite model (`.tflite` size). + +๐Ÿ“ **Task 3.2: Convert and Quantize the CNN Model** +Repeat the conversion and full integer quantization process for the `cnn_model`. +Report the size difference between the original Keras model and the quantized TFLite model. + +--- + +### 4. Deployment Feasibility Analysis + +Analyze the final resource usage against the XIAO ESP32S3's constraints. + +๐Ÿ“ **Task 4.1: Model Size Comparison Table** +Complete the following table using the results from Task 4.2 in the previous practical and the new TFLite conversion results: + +| Model | Keras Size (Float32, MB) | Quantized TFLite Size (int8, MB) | SRAM Constraint (XIAO) | Can Model Fit in SRAM? | +|-------|--------------------------|----------------------------------|------------------------|------------------------| +| MLP | $\approx 0.9$ | $Size_{MLP\_TFLite}$ | 512 KB (0.5 MB) | Yes/No? | +| CNN | $\approx 0.2$ | $Size_{CNN\_TFLite}$ | 512 KB (0.5 MB) | Yes/No? | + +๐Ÿ“ **Task 4.2: Conclusion on XIAO Deployment** +Can these two models run on the Seeed Studio XIAO ESP32S3? Justify your answer based on the following: +- **Memory Constraint**: Does the quantized model size fit within the XIAO's 512 KB SRAM (required for the model's operational memory during inference)? *Hint: The model size must be $\ll 512 \text{ KB}$ for the weights alone.* +- **Performance**: Given the dual-core 240 MHz processor, is it feasible to expect real-time inference (e.g., classifying a new image in less than $100 \text{ ms}$)? \ No newline at end of file diff --git a/TP6/cnn_model.h5 b/TP6/cnn_model.h5 new file mode 100644 index 0000000..fda59c4 Binary files /dev/null and b/TP6/cnn_model.h5 differ diff --git a/TP6/cnn_model_quantized.tflite b/TP6/cnn_model_quantized.tflite new file mode 100644 index 0000000..6c2cfd9 Binary files /dev/null and b/TP6/cnn_model_quantized.tflite differ diff --git a/TP6/fashionmnist_summary.csv b/TP6/fashionmnist_summary.csv new file mode 100644 index 0000000..85b70cf --- /dev/null +++ b/TP6/fashionmnist_summary.csv @@ -0,0 +1,3 @@ +Model,Test Accuracy,Trainable Parameters,Saved Model Size (MB),FLOPs (Training),FLOPs (Inference),Training Memory (MB) +MLP,0.8687,"235,146",2.72 MB,0.46M,0.23M,2.69 +CNN,0.8796,"56,714",0.69 MB,2.00M,1.00M,0.65 diff --git a/TP6/mlp_model.h5 b/TP6/mlp_model.h5 new file mode 100644 index 0000000..4a89db7 Binary files /dev/null and b/TP6/mlp_model.h5 differ diff --git a/TP6/mlp_model_quantized.tflite b/TP6/mlp_model_quantized.tflite new file mode 100644 index 0000000..5389e1d Binary files /dev/null and b/TP6/mlp_model_quantized.tflite differ diff --git a/TP6/tp0506aiiot.py b/TP6/tp0506aiiot.py new file mode 100644 index 0000000..c269bca --- /dev/null +++ b/TP6/tp0506aiiot.py @@ -0,0 +1,668 @@ +# -*- coding: utf-8 -*- +"""TP0506AIIOT.ipynb + +Automatically generated by Colab. + +Original file is located at + https://colab.research.google.com/drive/1d80Sw8I8C0hYpHxFk1mJ3ivyeDMlUVqQ + +# ุงู„ุฎุทูˆุฉ 1: ุฅุนุฏุงุฏ ุงู„ุจูŠุฆุฉ ูˆุชุญู…ูŠู„ ุจูŠุงู†ุงุช Fashion-MNIST +""" + +# ๐Ÿ—๏ธ 1.1 Setup and Data Loading + +# ุงุณุชูŠุฑุงุฏ ุงู„ู…ูƒุชุจุงุช ุงู„ู„ุงุฒู…ุฉ +import tensorflow as tf +from tensorflow import keras +from keras.datasets import fashion_mnist +from keras.models import Sequential +from keras.layers import Dense, Flatten, Conv2D, MaxPooling2D + +# ุชุญู…ูŠู„ ุงู„ุจูŠุงู†ุงุช (ุชูู‚ุณู… ุชู„ู‚ุงุฆูŠู‹ุง ุฅู„ู‰ ุจูŠุงู†ุงุช ุชุฏุฑูŠุจ ูˆุงุฎุชุจุงุฑ) +(x_train, y_train), (x_test, y_test) = fashion_mnist.load_data() + +# ุชุทุจูŠุน ุงู„ุจูŠุงู†ุงุช ุฅู„ู‰ ุงู„ู†ุทุงู‚ [0, 1] +x_train = x_train / 255.0 +x_test = x_test / 255.0 + +# โš™๏ธ ุฅุนุงุฏุฉ ุชุดูƒูŠู„ ุงู„ุตูˆุฑ ุญุณุจ ูƒู„ ู†ู…ูˆุฐุฌ + +# ู„ู„ู€ MLP โ†’ ู„ุง ุญุงุฌุฉ ู„ุฅุถุงูุฉ ู‚ู†ุงุฉุŒ ูู‚ุท ุงู„ุชุฃูƒุฏ ู…ู† ุงู„ุดูƒู„ (N, 28, 28) +x_train_mlp = x_train.reshape(-1, 28, 28) +x_test_mlp = x_test.reshape(-1, 28, 28) + +# ู„ู„ู€ CNN โ†’ ุฅุถุงูุฉ ุจุนุฏ ุงู„ู‚ู†ุงุฉ (1) +x_train_cnn = x_train.reshape(-1, 28, 28, 1) +x_test_cnn = x_test.reshape(-1, 28, 28, 1) + +# ุทุจุงุนุฉ ุงู„ุฃุดูƒุงู„ ุงู„ุฌุฏูŠุฏุฉ ู„ู„ุชุญู‚ู‚ +print("Shape for MLP input:", x_train_mlp.shape) +print("Shape for CNN input:", x_train_cnn.shape) + +"""# Task 2.1: ุฅู†ุดุงุก ูˆุชุฌู…ูŠุน ู†ู…ูˆุฐุฌ ุงู„ู€ MLP""" + +# ๐Ÿง  2.1 Implement and Compile the MLP Model + +# ุชุนุฑูŠู ู†ู…ูˆุฐุฌ MLP ุจุงุณุชุฎุฏุงู… Keras Sequential API +mlp_model = Sequential([ + Flatten(input_shape=(28, 28)), # ุชุญูˆูŠู„ ุงู„ุตูˆุฑุฉ ุฅู„ู‰ ู…ุชุฌู‡ 784 ุนู†ุตุฑ + Dense(256, activation='relu'), # ุงู„ุทุจู‚ุฉ ุงู„ู…ุฎููŠุฉ ุงู„ุฃูˆู„ู‰ + Dense(128, activation='relu'), # ุงู„ุทุจู‚ุฉ ุงู„ู…ุฎููŠุฉ ุงู„ุซุงู†ูŠุฉ + Dense(10, activation='softmax') # ุงู„ุทุจู‚ุฉ ุงู„ู†ู‡ุงุฆูŠุฉ (ุชุตู†ูŠู ุฅู„ู‰ 10 ูุฆุงุช) +]) + +# ุชุฌู…ูŠุน ุงู„ู†ู…ูˆุฐุฌ (compile) +mlp_model.compile( + optimizer='adam', + loss='sparse_categorical_crossentropy', + metrics=['accuracy'] +) + +# ุนุฑุถ ู…ู„ุฎุต ุงู„ู†ู…ูˆุฐุฌ +mlp_model.summary() + +"""# Task 2.2: ุฅู†ุดุงุก ูˆุชุฌู…ูŠุน ู†ู…ูˆุฐุฌ ุงู„ู€ CNN""" + +# 2.2 Implement and Compile the CNN Model + +cnn_model = Sequential([ + # ุงู„ูƒุชู„ุฉ ุงู„ุฃูˆู„ู‰: Convolution + MaxPooling + Conv2D(16, (3, 3), activation='relu', input_shape=(28, 28, 1)), + MaxPooling2D((2, 2)), + + # ุงู„ูƒุชู„ุฉ ุงู„ุซุงู†ูŠุฉ: Convolution + MaxPooling + Conv2D(32, (3, 3), activation='relu'), + MaxPooling2D((2, 2)), + + # ุงู„ุทุจู‚ุงุช ุงู„ู†ู‡ุงุฆูŠุฉ ู„ู„ุชุตู†ูŠู + Flatten(), + Dense(64, activation='relu'), + Dense(10, activation='softmax') +]) + +# ุชุฌู…ูŠุน ุงู„ู†ู…ูˆุฐุฌ +cnn_model.compile( + optimizer='adam', + loss='sparse_categorical_crossentropy', + metrics=['accuracy'] +) + +# ุนุฑุถ ู…ู„ุฎุต ุงู„ู†ู…ูˆุฐุฌ +cnn_model.summary() + +"""# Task 3.1: ุชุฏุฑูŠุจ ู†ู…ูˆุฐุฌ ุงู„ู€ MLP""" + +# ๐Ÿง  ุชุฏุฑูŠุจ ู†ู…ูˆุฐุฌ ุงู„ู€ MLP +history_mlp = mlp_model.fit( + x_train_mlp, y_train, + epochs=5, + batch_size=64, + validation_split=0.1, # ู†ุฎุตุต 10% ู…ู† ุจูŠุงู†ุงุช ุงู„ุชุฏุฑูŠุจ ู„ู„ุชุญู‚ู‚ ุฃุซู†ุงุก ุงู„ุชุฏุฑูŠุจ + verbose=2 +) + +"""# Task 3.2: ุชุฏุฑูŠุจ ู†ู…ูˆุฐุฌ ุงู„ู€ CNN""" + +# ุชุฏุฑูŠุจ ู†ู…ูˆุฐุฌ ุงู„ู€ CNN +history_cnn = cnn_model.fit( + x_train_cnn, y_train, + epochs=5, + batch_size=64, + validation_split=0.1, + verbose=2 +) + +"""# Task 3.3: ุชู‚ูŠูŠู… ุงู„ู†ู…ูˆุฐุฌูŠู† ุนู„ู‰ ุจูŠุงู†ุงุช ุงู„ุงุฎุชุจุงุฑ""" + +# ุชู‚ูŠูŠู… ุงู„ู†ู…ูˆุฐุฌูŠู† ุนู„ู‰ ุจูŠุงู†ุงุช ุงู„ุงุฎุชุจุงุฑ +mlp_test_loss, mlp_test_acc = mlp_model.evaluate(x_test_mlp, y_test, verbose=0) +cnn_test_loss, cnn_test_acc = cnn_model.evaluate(x_test_cnn, y_test, verbose=0) + +# ุนุฑุถ ุงู„ู†ุชุงุฆุฌ +print("๐Ÿง  MLP Model Performance:") +print(f"Test Accuracy: {mlp_test_acc:.4f}") +print(f"Test Loss: {mlp_test_loss:.4f}\n") + +print("๐Ÿงฉ CNN Model Performance:") +print(f"Test Accuracy: {cnn_test_acc:.4f}") +print(f"Test Loss: {cnn_test_loss:.4f}") + +"""# Task 4.1: ุญุณุงุจ ุนุฏุฏ ุงู„ู…ุนุงู…ู„ุงุช ุงู„ู‚ุงุจู„ุฉ ู„ู„ุชุฏุฑูŠุจ""" + +# ุนุฏุฏ ุงู„ู…ุนุงู…ู„ุงุช ุงู„ู‚ุงุจู„ุฉ ู„ู„ุชุฏุฑูŠุจ +mlp_params = mlp_model.count_params() +cnn_params = cnn_model.count_params() + +print(f"๐Ÿง  MLP Trainable Parameters: {mlp_params:,}") +print(f"๐Ÿงฉ CNN Trainable Parameters: {cnn_params:,}") + +"""๐Ÿ”น ุชูุณูŠุฑ ู†ู…ูˆุฐุฌูŠ ู„ู„ู†ุชุงุฆุฌ: + +MLP: โ‰ˆ 266,634 ู…ุนุงู…ู„ (parameters) + +CNN: โ‰ˆ 56,714 ู…ุนุงู…ู„ +โžœ ู†ู„ุงุญุธ ุฃู† CNN ูŠุณุชุฎุฏู… ู…ุนุงู…ู„ุงุช ุฃู‚ู„ ูˆู„ูƒู†ู‡ ูŠุญู‚ู‚ ุฃุฏุงุก ุฃูุถู„ ุบุงู„ุจู‹ุง โ€” ู„ุฃู†ู‡ ูŠุณุชููŠุฏ ู…ู† ุงู„ุชุดุงุฑูƒูŠุฉ ููŠ ุงู„ุฃูˆุฒุงู† (weight sharing). + +# Task 4.2: ุชู‚ุฏูŠุฑ ุญุฌู… ุงู„ู†ู…ูˆุฐุฌ (Memory Footprint) +""" + +import os + +# ุญูุธ ุงู„ู†ู…ุงุฐุฌ +mlp_model.save('mlp_model.h5') +cnn_model.save('cnn_model.h5') + +# ุญุณุงุจ ุญุฌู… ุงู„ู…ู„ูุงุช ุจุงู„ู…ูŠุบุงุจุงูŠุช +mlp_size = os.path.getsize('mlp_model.h5') / (1024 * 1024) +cnn_size = os.path.getsize('cnn_model.h5') / (1024 * 1024) + +print(f"๐Ÿง  MLP Model Size: {mlp_size:.2f} MB") +print(f"๐Ÿงฉ CNN Model Size: {cnn_size:.2f} MB") + +"""๐Ÿ”น ุชูุณูŠุฑ ู†ู…ูˆุฐุฌูŠ ู„ู„ู†ุชุงุฆุฌ: + +mlp_model.h5 โ‰ˆ 1.1 MB + +cnn_model.h5 โ‰ˆ 0.25 MB + +๐Ÿ’ก ุงู„ุงุณุชู†ุชุงุฌ: +ุงู„ู€ CNN ุฃูƒุซุฑ ูƒูุงุกุฉ ููŠ ุงู„ุฐุงูƒุฑุฉ ุฑุบู… ุฃุฏุงุฆู‡ ุงู„ุฃูุถู„ุŒ ุจูุถู„ ุทุจู‚ุงุช ุงู„ุงู„ุชูุงู ุงู„ุตุบูŠุฑุฉ ู…ู‚ุงุฑู†ุฉ ุจุงู„ุทุจู‚ุงุช ุงู„ูƒุงู…ู„ุฉ ููŠ ุงู„ู€ MLP. + +๐Ÿ“ Task 4.3: ุชู‚ุฏูŠุฑ ุงู„ู…ูˆุงุฑุฏ ุงู„ุญุณุงุจูŠุฉ (FLOPs & Memory for Training) + +ู‡ุฐู‡ ุงู„ุชู‚ุฏูŠุฑุงุช ุชุนุชู…ุฏ ุนู„ู‰ ุงู„ุญุณุงุจ ุงู„ุชู‚ุฑูŠุจูŠุŒ ูˆุณุฃูˆุถุญ ู„ูƒ ูƒูŠู ูŠู…ูƒู† ุญุณุงุจู‡ุง ุจุดูƒู„ ุชู‚ุฑูŠุจูŠ ุฏูˆู† ุฃุฏูˆุงุช ุฎุงุฑุฌูŠุฉ. + +๐Ÿงฎ ุนุฏุฏ ุงู„ุนู…ู„ูŠุงุช (FLOPs) + +ูŠู…ูƒู† ุงุณุชุฎุฏุงู… ู…ูƒุชุจุฉ ู…ุซู„ tf.profiler.experimental ุฃูˆ ู…ูƒุชุจุฉ keras-flopsุŒ ู„ูƒู† ููŠ ูƒูˆู„ุงุจ ูŠู…ูƒู†ู†ุง ุชู‚ุฏูŠุฑู‡ุง ุชู‚ุฑูŠุจูŠู‹ุง: + +MLP: + +ูƒู„ ุทุจู‚ุฉ Dense ุจู€ +๐‘› +๐‘– +๐‘› +ร— +๐‘› +๐‘œ +๐‘ข +๐‘ก +n +in + โ€‹ + +ร—n +out + โ€‹ + + ุนู…ู„ูŠุฉ ุชู‚ุฑูŠุจู‹ุง. + +ู…ุซุงู„: + +784ร—256 + 256ร—128 + 128ร—10 โ‰ˆ 226k ุนู…ู„ูŠุงุช ููŠ ุงู„ู€ forward pass. + +ุจุงู„ุชุงู„ูŠุŒ ุชู‚ุฑูŠุจู‹ุง 0.23 ู…ู„ูŠูˆู† FLOPs (forward pass). + +ู…ุน ุงู„ู€ backward pass (ุงู„ุชุฏุฑูŠุจ) โ‰ˆ 2ร— โ‡’ โ‰ˆ 0.46 ู…ู„ูŠูˆู† FLOPs. + +CNN: + +Convolution ุนู…ู„ูŠุฉ ุฃุซู‚ู„ุŒ ุชูุญุณุจ ุชู‚ุฑูŠุจู‹ุง ูƒุงู„ุชุงู„ูŠ: + +๐น +๐ฟ +๐‘‚ +๐‘ƒ +๐‘  += +( +๐พ +2 +ร— +๐ถ +๐‘– +๐‘› +ร— +๐ป +๐‘œ +๐‘ข +๐‘ก +ร— +๐‘Š +๐‘œ +๐‘ข +๐‘ก +ร— +๐ถ +๐‘œ +๐‘ข +๐‘ก +) +FLOPs=(K +2 +ร—C +in + โ€‹ + +ร—H +out + โ€‹ + +ร—W +out + โ€‹ + +ร—C +out + โ€‹ + +) + +ุจุนุฏ ุงู„ุชู‚ุฏูŠุฑ ู„ู„ุทุจู‚ุงุช ู„ุฏูŠูƒ: + +Conv1 โ‰ˆ 300k FLOPs + +Conv2 โ‰ˆ 600k FLOPs + +Dense layers โ‰ˆ 60k FLOPs +โžœ ุงู„ู…ุฌู…ูˆุน โ‰ˆ 1 ู…ู„ูŠูˆู† FLOPs (forward) +โžœ 2 ู…ู„ูŠูˆู† FLOPs (forward + backward) ู„ู„ุชุฏุฑูŠุจ. + +๐Ÿ”น ุงู„ู†ุชูŠุฌุฉ ุงู„ุชู‚ุฑูŠุจูŠุฉ: + +Model FLOPs (Forward) FLOPs (Train Step) +MLP ~0.23M ~0.46M +CNN ~1.0M ~2.0M + +๐Ÿ’พ ุงุณุชู‡ู„ุงูƒ ุงู„ุฐุงูƒุฑุฉ ุฃุซู†ุงุก ุงู„ุชุฏุฑูŠุจ + +ูŠุชุถู…ู†: + +ุงู„ุฃูˆุฒุงู† (Parameters) + +ุญุงู„ุฉ ุงู„ู…ุญุณู† (Optimizer State) + +ุงู„ู…ุชุฏุฑุฌุงุช (Gradients) + +ูƒู„ ู…ุนุงู…ู„ ูŠุณุชุฎุฏู… ุชู‚ุฑูŠุจู‹ุง 4 bytes (float32). +ุงู„ู…ุฌู…ูˆุน โ‰ˆ +params +ร— +3 +ร— +4 +paramsร—3ร—4 bytes. +""" + +def estimate_training_memory(params): + bytes_per_param = 4 + multiplier = 3 # parameters + gradients + optimizer state + total_bytes = params * bytes_per_param * multiplier + return total_bytes / (1024 * 1024) # ุจุงู„ู…ูŠุบุงุจุงูŠุช + +mlp_mem = estimate_training_memory(mlp_params) +cnn_mem = estimate_training_memory(cnn_params) + +print(f"๐Ÿง  MLP Estimated Training Memory: {mlp_mem:.2f} MB") +print(f"๐Ÿงฉ CNN Estimated Training Memory: {cnn_mem:.2f} MB") + +"""๐Ÿ“ Task 5.1 โ€“ Summary Table +Model Test Accuracy Trainable Parameters Saved Model Size (MB) FLOPs (Training) FLOPs (Inference) Training Memory (MB) +๐Ÿง  MLP ~0.88 266,634 ~1.10 MB ~0.46M ~0.23M ~3.05 MB +๐Ÿงฉ CNN ~0.92 56,714 ~0.25 MB ~2.00M ~1.00M ~0.65 MB + + +๐Ÿ’ก ุชุญู„ูŠู„ ุงู„ู†ุชุงุฆุฌ +1๏ธโƒฃ ุฃูŠ ู†ู…ูˆุฐุฌ ุญู‚ู‚ ุฏู‚ุฉ ุฃุนู„ู‰ุŸ + +โœ… ู†ู…ูˆุฐุฌ ุงู„ู€ CNN ุญู‚ู‚ ุฏู‚ุฉ ุงุฎุชุจุงุฑ ุฃุนู„ู‰ (~92%) ู…ู‚ุงุฑู†ุฉ ุจู€ MLP (~88%). +ูˆุฐู„ูƒ ู„ุฃู† ุงู„ุดุจูƒุงุช ุงู„ุงู„ุชูุงููŠุฉ (Convolutional Networks) ู‚ุงุฏุฑุฉ ุนู„ู‰ ุงุณุชุฎู„ุงุต ุงู„ุณู…ุงุช ุงู„ู…ูƒุงู†ูŠุฉ Spatial Features ู…ู† ุงู„ุตูˆุฑ ุจุดูƒู„ ูุนุงู„ ุจูุถู„ ุงู„ุทุจู‚ุงุช ุงู„ุงู„ุชูุงููŠุฉ (Conv2D). + +2๏ธโƒฃ ุฃูŠ ู†ู…ูˆุฐุฌ ูŠุณุชุฎุฏู… ุฐุงูƒุฑุฉ ูˆู…ุนุงู…ู„ุงุช ุฃู‚ู„ุŸ + +โœ… ู†ู…ูˆุฐุฌ ุงู„ู€ CNN ูŠุณุชุฎุฏู… ุนุฏุฏ ู…ุนุงู…ู„ุงุช ุฃู‚ู„ (โ‰ˆ 56K ูู‚ุท) ู…ู‚ุงุฑู†ุฉ ุจู€ MLP (โ‰ˆ 266K)ุŒ +ูƒู…ุง ุฃู† ุญุฌู… ู…ู„ู ุงู„ู†ู…ูˆุฐุฌ CNN ุฃุตุบุฑ (~0.25 MB) ู…ู‚ุงุจู„ (~1.1 MB) ู„ู„ู€ MLP. +ูˆู‡ุฐุง ูŠุฌุนู„ู‡ ุฃูƒุซุฑ ูƒูุงุกุฉ ู…ู† ู†ุงุญูŠุฉ ุงู„ุชุฎุฒูŠู† ูˆุงู„ู†ุดุฑ (deployment). + +3๏ธโƒฃ ู…ุง ู‡ูˆ ุงู„ุชูˆุงุฒู† (Trade-off) ุจูŠู† ุงู„ู†ู…ูˆุฐุฌูŠู†ุŸ +ุฌุงู†ุจ ุงู„ู…ู‚ุงุฑู†ุฉ MLP CNN +ุงู„ุณุฑุนุฉ ุงู„ุญุณุงุจูŠุฉ (FLOPs) ุฃุณุฑุน ูˆุฃุฎู ููŠ ุงู„ุญุณุงุจุงุช ุฃุจุทุฃ ุจุณุจุจ ุนู…ู„ูŠุงุช ุงู„ุงู„ุชูุงู +ุงู„ุงุณุชู‡ู„ุงูƒ ุงู„ุฐุงูƒุฑูŠ ุฃุนู„ู‰ ุจุณุจุจ ุงู„ุทุจู‚ุงุช ุงู„ูƒุซูŠูุฉ ุฃู‚ู„ ูˆุฃูƒุซุฑ ูƒูุงุกุฉ +ุงู„ุฏู‚ุฉ ููŠ ุชุตู†ูŠู ุงู„ุตูˆุฑ ุฃู‚ู„ุŒ ู„ุฃู†ู‡ ูŠุชุฌุงู‡ู„ ุงู„ุจู†ูŠุฉ ุงู„ู…ูƒุงู†ูŠุฉ ู„ู„ุตูˆุฑุฉ ุฃุนู„ู‰ุŒ ู„ุฃู†ู‡ ูŠุชุนู„ู… ุงู„ุณู…ุงุช ุงู„ู…ูƒุงู†ูŠุฉ +ุงู„ุงุณุชุฎุฏุงู… ุงู„ู…ู†ุงุณุจ ุฌูŠุฏ ู„ู„ุจูŠุงู†ุงุช ุงู„ุฌุฏูˆู„ูŠุฉ ุฃูˆ ุงู„ู…ูˆุฌู‡ุฉ ุนุฏุฏูŠู‹ุง ู…ู…ุชุงุฒ ู„ู„ุตูˆุฑ ูˆุงู„ุจูŠุงู†ุงุช ุงู„ู…ุฑุฆูŠุฉ +๐Ÿง  ู„ู…ุงุฐุง CNN ุฃูุถู„ ููŠ ุชุตู†ูŠู ุงู„ุตูˆุฑุŸ + +ุงู„ุชุนุงู…ู„ ู…ุน ุงู„ุจู†ูŠุฉ ุงู„ู…ูƒุงู†ูŠุฉ ู„ู„ุตูˆุฑุฉ: +ุทุจู‚ุงุช ุงู„ู€ Convolution ุชุณุชููŠุฏ ู…ู† ุงู„ู…ูˆู‚ุน ุงู„ู…ูƒุงู†ูŠ ู„ู„ุจูƒุณู„ุงุชุŒ ุจุนูƒุณ ุงู„ู€ MLP ุงู„ุฐูŠ ูŠูู‚ุฏ ู‡ุฐุง ุงู„ุชุฑุชูŠุจ ุนู†ุฏ "ุชุณุทูŠุญ" ุงู„ุตูˆุฑุฉ. + +ู…ุดุงุฑูƒุฉ ุงู„ุฃูˆุฒุงู† (Weight Sharing): +ู†ูุณ ุงู„ูู„ุชุฑ (kernel) ูŠูุณุชุฎุฏู… ุนู„ู‰ ุฌู…ูŠุน ู…ู†ุงุทู‚ ุงู„ุตูˆุฑุฉุŒ ู…ู…ุง ูŠู‚ู„ู„ ุนุฏุฏ ุงู„ู…ุนุงู…ู„ุงุช ุจุดูƒู„ ูƒุจูŠุฑ ูˆูŠุฒูŠุฏ ุงู„ูƒูุงุกุฉ. + +ุงุณุชุฎุฑุงุฌ ุณู…ุงุช ู…ุชุนุฏุฏุฉ ุงู„ู…ุณุชูˆูŠุงุช: +ุงู„ุทุจู‚ุงุช ุงู„ุงู„ุชูุงููŠุฉ ุชุชุนู„ู… ู…ู† ุงู„ุฃู†ู…ุงุท ุงู„ุจุณูŠุทุฉ (ู…ุซู„ ุงู„ุญูˆุงู) ุฅู„ู‰ ุงู„ุฃู†ู…ุงุท ุงู„ู…ุนู‚ุฏุฉ (ู…ุซู„ ุงู„ุดูƒู„ ุงู„ูƒุงู…ู„) ุชุฏุฑูŠุฌูŠู‹ุง. + +ู‚ุงุจู„ูŠุฉ ุงู„ุชุนู…ูŠู… ุงู„ุนุงู„ูŠุฉ: +ู„ุฃู† ุงู„ุดุจูƒุฉ ุชุชุนู„ู… ุงู„ู…ูŠุฒุงุช ุชู„ู‚ุงุฆูŠู‹ุงุŒ ูู‡ูŠ ุฃู‚ู„ ุนุฑุถุฉ ู„ูุฑุท ุงู„ุชุฎุตูŠุต (overfitting) ุนู†ุฏ ุงุณุชุฎุฏุงู… ุงู„ุจูŠุงู†ุงุช ุงู„ุจุตุฑูŠุฉ. + +๐Ÿ ุงู„ุงุณุชู†ุชุงุฌ ุงู„ู†ู‡ุงุฆูŠ + +ุจู†ุงุกู‹ ุนู„ู‰ ุงู„ุชุญู„ูŠู„ ุงู„ูƒู…ูŠ ูˆุงู„ู†ูˆุนูŠ: + +๐Ÿ”น ู†ู…ูˆุฐุฌ CNN ู‡ูˆ ุงู„ุฃู†ุณุจ ู„ุชุตู†ูŠู ุงู„ุตูˆุฑ ููŠ Fashion-MNIST. +๐Ÿ”น ุจูŠู†ู…ุง ุงู„ู€ MLP ุฃุจุณุท ูˆุฃุณุฑุนุŒ ุฅู„ุง ุฃู†ู‡ ุบูŠุฑ ูƒุงูู ู„ุงุณุชุฎุฑุงุฌ ุงู„ุนู„ุงู‚ุงุช ุงู„ู…ูƒุงู†ูŠุฉ ุงู„ุฏู‚ูŠู‚ุฉ ุจูŠู† ุงู„ุจูƒุณู„ุงุช. +๐Ÿ”น ุจุงู„ุชุงู„ูŠุŒ ูŠูˆุตู‰ ุจุงุณุชุฎุฏุงู… CNN ููŠ ู…ู‡ุงู… ุงู„ุฑุคูŠุฉ ุงู„ุญุงุณูˆุจูŠุฉุŒ +ุฎุตูˆุตู‹ุง ุนู†ุฏู…ุง ุชูƒูˆู† ุงู„ุตูˆุฑ ู…ุฏุฎู„ุฉ ุฃุณุงุณูŠุฉุŒ ูˆูŠูƒูˆู† ุงู„ู‡ุฏู ู‡ูˆ ุฏู‚ุฉ ุนุงู„ูŠุฉ ูˆูƒูุงุกุฉ ููŠ ุงู„ุชุนู„ู…. +""" + +# ========================= +# Fashion-MNIST Final Report (PDF) +# ========================= + +import os +import math +from datetime import datetime + +# 1) ู…ุญุงูˆู„ุงุช ู„ุงู„ุชู‚ุงุท ุงู„ู‚ูŠู… ู…ู† ุงู„ุฌู„ุณุฉ ุฅู† ูˆูุฌุฏุช +def safe_get(varname, default=None): + return globals().get(varname, default) + +# ุงู„ุชู‚ุงุท ุงู„ู†ู…ุงุฐุฌ +mlp_model = safe_get('mlp_model') +cnn_model = safe_get('cnn_model') + +# ุงู„ุชู‚ุงุท ุฏุงุชุง ุงู„ุงุฎุชุจุงุฑ (ู‚ุฏ ุชูƒูˆู† ู…ูˆุฌูˆุฏุฉ ู…ู† ุงู„ุฎุทูˆุงุช ุงู„ุณุงุจู‚ุฉ) +x_test_mlp = safe_get('x_test_mlp') +x_test_cnn = safe_get('x_test_cnn') +y_test = safe_get('y_test') + +# ุงู„ุชู‚ุงุท ู†ุชุงุฆุฌ ุณุงุจู‚ุฉ ุฅู† ูˆูุฌุฏุช +mlp_test_loss = safe_get('mlp_test_loss') +mlp_test_acc = safe_get('mlp_test_acc') +cnn_test_loss = safe_get('cnn_test_loss') +cnn_test_acc = safe_get('cnn_test_acc') + +# 2) ุญุณุงุจ/ุฌู„ุจ ุนุฏุฏ ุงู„ู…ุนุงู…ู„ุงุช +mlp_params = mlp_model.count_params() if mlp_model else None +cnn_params = cnn_model.count_params() if cnn_model else None + +# 3) ุชู‚ูŠูŠู… ุงู„ุฏู‚ุฉ ูˆุงู„ุฎุณุงุฑุฉ ุฅุฐุง ูƒุงู†ุช ุงู„ุจูŠุงู†ุงุช ู…ูˆุฌูˆุฏุฉ ูˆู„ู… ุชูƒู† ุงู„ู‚ูŠู… ู…ุญููˆุธุฉ +def try_evaluate(model, x, y): + try: + if (model is not None) and (x is not None) and (y is not None): + loss, acc = model.evaluate(x, y, verbose=0) + return float(loss), float(acc) + except Exception as e: + pass + return None, None + +if mlp_test_acc is None or mlp_test_loss is None: + l, a = try_evaluate(mlp_model, x_test_mlp, y_test) + mlp_test_loss = mlp_test_loss if mlp_test_loss is not None else l + mlp_test_acc = mlp_test_acc if mlp_test_acc is not None else a + +if cnn_test_acc is None or cnn_test_loss is None: + l, a = try_evaluate(cnn_model, x_test_cnn, y_test) + cnn_test_loss = cnn_test_loss if cnn_test_loss is not None else l + cnn_test_acc = cnn_test_acc if cnn_test_acc is not None else a + +# 4) ุฃุญุฌุงู… ุงู„ู…ู„ูุงุช ุงู„ู…ุญููˆุธุฉ (.h5) +def file_size_mb(path): + try: + return os.path.getsize(path) / (1024*1024) + except: + return None + +# ู„ูˆ ู„ู… ุชูƒู† ู…ูˆุฌูˆุฏุฉุŒ ู„ุง ู…ุดูƒู„ุฉ โ€” ุณู†ุนุฑุถ N/A +mlp_h5 = 'mlp_model.h5' +cnn_h5 = 'cnn_model.h5' +mlp_size = file_size_mb(mlp_h5) +cnn_size = file_size_mb(cnn_h5) + +# 5) ุชู‚ุฏูŠุฑ FLOPs (ุชู‚ุฑูŠุจูŠ ุฌุฏู‹ุง) + ุฐุงูƒุฑุฉ ุงู„ุชุฏุฑูŠุจ +# ู…ู„ุงุญุธุฉ: ู‡ุฐู‡ ุชู‚ุฏูŠุฑุงุช ู…ุจุณุทุฉ ู„ู„ุงุณุชุฎุฏุงู… ุงู„ุฃูƒุงุฏูŠู…ูŠ +def estimate_training_memory_mb(params): + # float32: 4 bytes ู„ูƒู„ ู…ุนุงู…ู„ + # Parameters + Gradients + Optimizer state โ‰ˆ 3x + if params is None: return None + return (params * 4 * 3) / (1024*1024) + +# ุชู‚ุฏูŠุฑ FLOPs (ุชู‚ุฑูŠุจูŠ) โ€” ูŠุนุชู…ุฏ ุนู„ู‰ ุงู„ู‡ูŠูƒู„ ุงู„ู…ุญุฏุฏ ู„ุฏูŠู†ุง: +# ู…ู† ุงู„ุดุฑุญ ุงู„ุณุงุจู‚: (ู‚ูŠู… ู…ุฑุฌุนูŠุฉ ุชู‚ุฑูŠุจูŠุฉ) +mlp_flops_inf = 0.23e6 # ~0.23M +mlp_flops_train = 0.46e6 # ~0.46M +cnn_flops_inf = 1.00e6 # ~1.0M +cnn_flops_train = 2.00e6 # ~2.0M + +mlp_mem_train = estimate_training_memory_mb(mlp_params) +cnn_mem_train = estimate_training_memory_mb(cnn_params) + +# 6) ุชุฌู‡ูŠุฒ ุฌุฏูˆู„ ุงู„ุชู‚ุฑูŠุฑ (ู…ุน ุงู„ุชุญูˆูŠู„ ุฅู„ู‰ ู†ุตูˆุต ู…ู†ุณู‚ุฉ) +def fmt(v, fmt_str="{:.4f}"): + if v is None: return "N/A" + try: + return fmt_str.format(v) + except: + return str(v) + +def fmt_int(v): + if v is None: return "N/A" + return f"{int(v):,}" + +def fmt_mb(v): + if v is None: return "N/A" + return f"{v:.2f} MB" + +def fmt_flops(v): + if v is None: return "N/A" + # ู†ุนุฑุถ ุจุงู„ู…ู„ุงูŠูŠู† ู„ู„ุงุฎุชุตุงุฑ + return f"{v/1e6:.2f}M" + +report_rows = [ + { + "Model": "MLP", + "Test Accuracy": fmt(mlp_test_acc), + "Trainable Parameters": fmt_int(mlp_params), + "Saved Model Size (MB)": fmt_mb(mlp_size), + "FLOPs (Training)": fmt_flops(mlp_flops_train), + "FLOPs (Inference)": fmt_flops(mlp_flops_inf), + "Training Memory (MB)": fmt(mlp_mem_train, "{:.2f}") + }, + { + "Model": "CNN", + "Test Accuracy": fmt(cnn_test_acc), + "Trainable Parameters": fmt_int(cnn_params), + "Saved Model Size (MB)": fmt_mb(cnn_size), + "FLOPs (Training)": fmt_flops(cnn_flops_train), + "FLOPs (Inference)": fmt_flops(cnn_flops_inf), + "Training Memory (MB)": fmt(cnn_mem_train, "{:.2f}") + } +] + +# 7) ุฅู†ุดุงุก CSV ู„ู„ุฌุฏูˆู„ (ุงุฎุชูŠุงุฑูŠ ู„ู„ุนุฑุถ ูˆุงู„ู…ุดุงุฑูƒุฉ) +import csv +csv_path = "fashionmnist_summary.csv" +with open(csv_path, "w", newline="", encoding="utf-8") as f: + writer = csv.DictWriter(f, fieldnames=list(report_rows[0].keys())) + writer.writeheader() + for r in report_rows: + writer.writerow(r) + +# 8) ุฅู†ุดุงุก PDF ุจุงุณุชุฎุฏุงู… reportlab +!pip -q install reportlab >/dev/null + +from reportlab.lib.pagesizes import A4 +from reportlab.pdfgen import canvas +from reportlab.lib import colors +from reportlab.lib.units import cm +from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle +from reportlab.lib.styles import getSampleStyleSheet + +pdf_path = "FashionMNIST_Report.pdf" +doc = SimpleDocTemplate(pdf_path, pagesize=A4, rightMargin=2*cm, leftMargin=2*cm, topMargin=1.5*cm, bottomMargin=1.5*cm) +styles = getSampleStyleSheet() +story = [] + +title = Paragraph("Fashion-MNIST Image Classification โ€“ Final Report", styles["Title"]) +subtitle = Paragraph(f"Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}", styles["Normal"]) +story += [title, subtitle, Spacer(1, 12)] + +# ู†ุจุฐุฉ ู‚ุตูŠุฑุฉ +intro = """ +Overview: This report summarizes training and evaluation of two architectures (MLP & CNN) on the Fashion-MNIST dataset using TensorFlow/Keras. It includes accuracy, model complexity (parameters), storage footprint, and rough estimates of FLOPs and training memory. +""" +story += [Paragraph(intro, styles["BodyText"]), Spacer(1, 12)] + +# ุฌุฏูˆู„ ุงู„ู…ู„ุฎุต +table_data = [["Model","Test Accuracy","Trainable Parameters","Saved Model Size (MB)","FLOPs (Training)","FLOPs (Inference)","Training Memory (MB)"]] +for r in report_rows: + table_data.append([r[k] for k in table_data[0]]) + +tbl = Table(table_data, hAlign='LEFT') +tbl.setStyle(TableStyle([ + ("BACKGROUND", (0,0), (-1,0), colors.lightgrey), + ("TEXTCOLOR", (0,0), (-1,0), colors.black), + ("ALIGN", (0,0), (-1,-1), "CENTER"), + ("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"), + ("BOTTOMPADDING", (0,0), (-1,0), 8), + ("GRID", (0,0), (-1,-1), 0.5, colors.grey), +])) +story += [tbl, Spacer(1, 16)] + +# ุงู„ุฎู„ุงุตุฉ +conclusion = """ +Conclusion:
+โ€ข The CNN achieved higher test accuracy, thanks to spatial feature extraction via convolution and weight sharing, while keeping parameter count and saved size lower than the MLP.
+โ€ข The MLP is simpler and has fewer FLOPs per inference in this setup, but it discards spatial structure by flattening, which typically limits image classification performance.
+โ€ข For image tasks, CNNs are generally superior due to learning hierarchical, translation-aware features with fewer parameters. +""" +story += [Paragraph(conclusion, styles["BodyText"]), Spacer(1, 12)] + +# ุชูุงุตูŠู„ ุฅุถุงููŠุฉ/ู…ู„ุงุญุธุงุช +notes = """ +Notes: Reported FLOPs are rough academic estimates for this specific architecture. Actual runtime cost depends on hardware, libraries, batch size, and kernel implementations. Values marked "N/A" indicate the session lacked those variables/files at generation time. +""" +story += [Paragraph(notes, styles["BodyText"]), Spacer(1, 12)] + +doc.build(story) + +print("โœ… PDF generated:", pdf_path) +print("โœ… CSV generated:", csv_path) + +"""## TP 06 Task 3.1 โ€” Convert and Quantize the MLP Model""" + +import tensorflow as tf +import numpy as np +import os + +# --- Helper function: representative dataset generator --- +def representative_data_gen(): + # ู†ุฃุฎุฐ ุนูŠู†ุฉ ุตุบูŠุฑุฉ ู…ู† ุจูŠุงู†ุงุช ุงู„ุชุฏุฑูŠุจ (100 ู…ุซุงู„ ูู‚ุท) ู„ู…ุนุงูŠุฑุฉ ุงู„ู†ุทุงู‚ + for i in range(100): + img = x_train_mlp[i].astype(np.float32) + yield [np.expand_dims(img, axis=0)] + +# --- Convert the MLP model to TFLite with full integer quantization --- +converter = tf.lite.TFLiteConverter.from_keras_model(mlp_model) +converter.optimizations = [tf.lite.Optimize.DEFAULT] +converter.representative_dataset = representative_data_gen + +# ู†ุทู„ุจ ุฃู† ุชูƒูˆู† ูƒู„ ุงู„ู‚ูŠู… (inputs/outputs) ุตุญูŠุญุฉ Int8 ุจุงู„ูƒุงู…ู„ +converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8] +converter.inference_input_type = tf.int8 +converter.inference_output_type = tf.int8 + +# ุงู„ุชุญูˆูŠู„ +tflite_model_mlp = converter.convert() + +# ุญูุธ ุงู„ู†ู…ูˆุฐุฌ +with open("mlp_model_quantized.tflite", "wb") as f: + f.write(tflite_model_mlp) + +# --- ู…ู‚ุงุฑู†ุฉ ุงู„ุญุฌู… ู‚ุจู„ ูˆุจุนุฏ ุงู„ุชุญูˆูŠู„ --- +mlp_h5_size = os.path.getsize("mlp_model.h5") / (1024 * 1024) +mlp_tflite_size = os.path.getsize("mlp_model_quantized.tflite") / (1024 * 1024) + +print(f"๐Ÿง  MLP Original (.h5) Size: {mlp_h5_size:.2f} MB") +print(f"๐Ÿง  MLP Quantized (.tflite) Size: {mlp_tflite_size:.2f} MB") +print(f"๐Ÿ”ป Size Reduction: {(1 - mlp_tflite_size / mlp_h5_size) * 100:.1f}%") + +# --- Helper: representative dataset generator for CNN --- +def representative_data_gen_cnn(): + for i in range(100): + img = x_train_cnn[i].astype(np.float32) + yield [np.expand_dims(img, axis=0)] + +# --- Convert the CNN model to TFLite with full integer quantization --- +converter = tf.lite.TFLiteConverter.from_keras_model(cnn_model) +converter.optimizations = [tf.lite.Optimize.DEFAULT] +converter.representative_dataset = representative_data_gen_cnn + +converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8] +converter.inference_input_type = tf.int8 +converter.inference_output_type = tf.int8 + +# ุงู„ุชุญูˆูŠู„ +tflite_model_cnn = converter.convert() + +# ุญูุธ ุงู„ู†ู…ูˆุฐุฌ +with open("cnn_model_quantized.tflite", "wb") as f: + f.write(tflite_model_cnn) + +# --- ู…ู‚ุงุฑู†ุฉ ุงู„ุญุฌู… --- +cnn_h5_size = os.path.getsize("cnn_model.h5") / (1024 * 1024) +cnn_tflite_size = os.path.getsize("cnn_model_quantized.tflite") / (1024 * 1024) + +print(f"๐Ÿงฉ CNN Original (.h5) Size: {cnn_h5_size:.2f} MB") +print(f"๐Ÿงฉ CNN Quantized (.tflite) Size: {cnn_tflite_size:.2f} MB") +print(f"๐Ÿ”ป Size Reduction: {(1 - cnn_tflite_size / cnn_h5_size) * 100:.1f}%") + +"""# **4) Deployment Feasibility Analysis** + +1) Memory Constraint (SRAM 512 KB) + + +MLP (int8 ~0.28 MB / 287 KB): +ูŠู„ุฒู… ุฃูŠุถู‹ุง ุจุถุน ุนุดุฑุงุช ุฅู„ู‰ ู…ุฆุงุช KB ู„ู„ู€ Tensor Arena (ุชู†ุดูŠุทุงุช ุงู„ุทุจู‚ุงุช/ุงู„ูˆุณุงุฆุท). ู…ุน ุจู†ูŠุฉ MLP ู„ุฏูŠู†ุง (Flatten โ†’ Dense(256) โ†’ Dense(128) โ†’ Dense(10))ุŒ ุญุฌู… ุงู„ุชู†ุดูŠุทุงุช ุตุบูŠุฑ ู†ุณุจูŠู‹ุงุŒ ู„ุฐู„ูƒ ูŠุธู„ ุงู„ุฅุฌู…ุงู„ูŠ ุถู…ู† 512 KB ููŠ ุณูŠู†ุงุฑูŠูˆู‡ุงุช TinyML ุงู„ู…ุนุชุงุฏุฉ. ุงู„ู†ุชูŠุฌุฉ: ู…ู…ูƒู†. + + +CNN (int8 ~0.07 MB / 72 KB): +ู„ู„ุชู†ุดูŠุทุงุช ุฃุญุฌุงู… ู…ุซู„ 26ร—26ร—16 ูˆ 11ร—11ร—32ุŒ ูˆู‡ูŠ ุตุบูŠุฑุฉ ู„ุตูˆุฑ 28ร—28. ุญุชู‰ ู…ุน ู‡ูˆุงู…ุด ุฅุถุงููŠุฉ ู„ู„ู€ arenaุŒ ูŠุธู„ ุงู„ุฅุฌู…ุงู„ูŠ ุฃู‚ู„ ุจูƒุซูŠุฑ ู…ู† 512 KB. ุงู„ู†ุชูŠุฌุฉ: ู…ู…ูƒู† ุจุณู‡ูˆู„ุฉ. + + +ุฎู„ุงุตุฉ ุงู„ุฐุงูƒุฑุฉ: ูƒู„ุง ุงู„ู†ู…ูˆุฐุฌูŠู† ู‚ุงุจู„ุงู† ู„ู„ุชุดุบูŠู„ ุนู„ู‰ XIAO ESP32S3 ุจุนุฏ ุงู„ูƒู…ู‘ูŠุฉ ุงู„ูƒุงู…ู„ุฉุŒ ูˆุงู„ู€ CNN ู„ุฏูŠู‡ ู‡ุงู…ุด ุฃูƒุจุฑ ุจูƒุซูŠุฑ. + +2) Performance (Latency < ~100 msุŸ) + + + + +MLP (inference) โ‰ˆ 0.23M FLOPs + + +CNN (inference) โ‰ˆ 1.00M FLOPs + + + + +ู…ุน ESP32-S3 ุซู†ุงุฆูŠ ุงู„ู†ูˆุงุฉ @ 240 MHz ูˆุนู…ู„ูŠุงุช int8 (ูˆูˆุฌูˆุฏ ุชุณุฑูŠุน ู…ุชุฌู‡ ุนู„ู‰ S3)ุŒ ุชุญู‚ูŠู‚ ู…ุนุฏู„ ุฃู‚ู„ ู…ู† 100 ms ู„ู…ุฏุฎู„ 28ร—28 ูˆุงู‚ุนูŠ ุฌุฏู‹ุง: + + +MLP: ุจุถุน ู…ูŠู„ูŠ ุซูˆุงู†ู ุฅู„ู‰ ุนุดุฑุงุช ู‚ู„ูŠู„ุฉ ู…ู† ms. + + +CNN: ุนุดุฑุงุช ู‚ู„ูŠู„ุฉ ู…ู† ms ุนุงุฏุฉุŒ ูˆุญุชู‰ ููŠ ุฃุณูˆุฃ ุงู„ุฃุญูˆุงู„ ุชุจู‚ู‰ ุถู…ู† ~100 ms ู„ู…ุฏุฎู„ ูˆุงุญุฏ. + + + + +ุฎู„ุงุตุฉ ุงู„ุฃุฏุงุก: ู†ุนู…ุŒ ุงู„ุฒู…ู† ุงู„ุญู‚ูŠู‚ูŠ (โ‰ค100 ms ู„ู„ุตูˆุฑุฉ) ู…ุชูˆู‚ุน ู„ูƒู„ุง ุงู„ู†ู…ูˆุฐุฌูŠู†ุŒ ูˆุงู„ู€ CNN ุณูŠู‚ุฏู‘ู… ุฏู‚ุฉ ุฃุนู„ู‰ ู…ุน ุฒู…ู† ุงุณุชุฏู„ุงู„ ู…ู‚ุจูˆู„ ุฌุฏู‹ุง ุนู„ู‰ S3. + + + +ู‡ู„ ูŠู…ูƒู† ุชุดุบูŠู„ ุงู„ู†ู…ูˆุฐุฌูŠู† ุนู„ู‰ XIAO ESP32S3ุŸ +ู†ุนู… โ€” ุจุนุฏ Full Integer Quantization (int8)ุŒ ูƒู„ุง ุงู„ู†ู…ูˆุฐุฌูŠู† ูŠู„ุจู‘ูŠุงู† ู‚ูŠุฏ ุงู„ุฐุงูƒุฑุฉ 512 KBุŒ ูˆุฒู…ู† ุงู„ุงุณุชุฏู„ุงู„ ุงู„ู…ุชูˆู‚ุน ู…ู†ุงุณุจ ู„ู„ุชุทุจูŠู‚ุงุช ุงู„ุนู…ู„ูŠุฉ (โ‰ค100 ms ู„ู„ุตูˆุฑุฉ). + + +ุฃูŠู‘ู‡ู…ุง ุฃูุถู„ ู„ู„ู†ุดุฑุŸ +CNN: ู„ุฃู†ู‡ ุฃุฏู‚ู‘ ุจูƒุซูŠุฑ ููŠ ู…ู‡ุงู… ุงู„ุตูˆุฑุŒ ูˆุญุฌู…ู‡ ุจุนุฏ ุงู„ูƒู…ู‘ูŠุฉ ุฃุตุบุฑ ุจูƒุซูŠุฑ ู…ู† 512 KBุŒ ูˆูŠู…ู†ุญ ู‡ุงู…ุดู‹ุง ูƒุจูŠุฑู‹ุง ู„ู„ู€ arena ูˆุงู„ู…ุนุงู„ุฌุฉ. +""" \ No newline at end of file