Akash8150 commited on
Commit
b17d851
·
1 Parent(s): cc9042f

Fix: rebuild model architecture and load weights only to bypass Keras deserialization

Browse files
Files changed (2) hide show
  1. app.py +71 -81
  2. requirements-hf.txt +2 -4
app.py CHANGED
@@ -1,49 +1,53 @@
1
- """
2
- Flask Web Application for Image Denoising
3
- """
4
- import os
5
- import sys
6
- import numpy as np
7
- import json
8
-
9
- # Use tf-keras (Keras 2 compatibility layer) to load old .h5 models
10
- os.environ["TF_USE_LEGACY_KERAS"] = "1"
11
-
12
  from flask import Flask, render_template, request, jsonify
13
- import tf_keras as keras
14
- from tf_keras.models import load_model
15
  from PIL import Image
16
- import io
17
- import base64
18
-
19
- # Add src directory to path
20
- sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src'))
21
 
 
22
  app = Flask(__name__)
23
- app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 # 16MB max file size
24
 
25
- # Load the trained model
26
- MODEL_PATH = 'best_autoencoder_model.h5'
27
- MODEL_INFO_PATH = 'model_info.json'
28
  model = None
29
  model_info = None
30
 
 
31
  def load_trained_model():
32
- """Load the trained autoencoder model"""
33
  global model
34
- if os.path.exists(MODEL_PATH):
35
- model = load_model(MODEL_PATH)
36
- print(f"Model loaded from {MODEL_PATH}")
37
- else:
38
- print(f"Warning: Model file {MODEL_PATH} not found!")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
 
40
  def load_model_info():
41
- """Load model information from JSON file"""
42
  global model_info
43
  if os.path.exists(MODEL_INFO_PATH):
44
- with open(MODEL_INFO_PATH, 'r') as f:
45
  model_info = json.load(f)
46
- print(f"Model info loaded from {MODEL_INFO_PATH}")
47
  else:
48
  model_info = {
49
  "model_name": "CNN Autoencoder",
@@ -53,70 +57,56 @@ def load_model_info():
53
  "test_loss": "N/A"
54
  }
55
 
 
56
  def preprocess_image(image):
57
- """Preprocess uploaded image for model"""
58
- img = image.convert('L')
59
- img = img.resize((28, 28))
60
- img_array = np.array(img) / 255.0
61
- img_array = img_array.reshape(1, 28, 28, 1)
62
- return img_array
63
-
64
- def array_to_base64(img_array):
65
- """Convert numpy array to base64 string for display"""
66
- img_array = img_array.squeeze()
67
- img_array = (img_array * 255).astype(np.uint8)
68
- img = Image.fromarray(img_array, mode='L')
69
- buffer = io.BytesIO()
70
- img.save(buffer, format='PNG')
71
- img_str = base64.b64encode(buffer.getvalue()).decode()
72
- return f"data:image/png;base64,{img_str}"
73
-
74
- # Load model and info at module level so it works with Docker
75
  load_trained_model()
76
  load_model_info()
77
 
78
 
79
- @app.route('/')
80
  def index():
81
- """Render main page"""
82
- return render_template('index.html', model_info=model_info)
83
 
84
- @app.route('/api/model-info', methods=['GET'])
85
  def get_model_info():
86
- """Return model information"""
87
  if model_info:
88
  return jsonify(model_info)
89
- return jsonify({'error': 'Model info not available'}), 404
90
 
91
- @app.route('/denoise', methods=['POST'])
 
92
  def denoise():
93
- """Handle image denoising request"""
94
  if model is None:
95
- return jsonify({'error': 'Model not loaded'}), 500
96
-
97
- if 'image' not in request.files:
98
- return jsonify({'error': 'No image uploaded'}), 400
99
-
100
- file = request.files['image']
101
- if file.filename == '':
102
- return jsonify({'error': 'No image selected'}), 400
103
-
104
  try:
105
  image = Image.open(file.stream)
106
- processed_img = preprocess_image(image)
107
- denoised_img = model.predict(processed_img, verbose=0)
108
-
109
- original_b64 = array_to_base64(processed_img)
110
- denoised_b64 = array_to_base64(denoised_img)
111
-
112
- return jsonify({
113
- 'original': original_b64,
114
- 'denoised': denoised_b64
115
- })
116
-
117
  except Exception as e:
118
- return jsonify({'error': str(e)}), 500
 
119
 
120
- if __name__ == '__main__':
121
- port = int(os.environ.get('PORT', 7860))
122
- app.run(debug=False, host='0.0.0.0', port=port)
 
1
+ import os, sys, numpy as np, json, io, base64
2
+ os.environ["TF_ENABLE_ONEDNN_OPTS"] = "0"
3
+ os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3"
 
 
 
 
 
 
 
 
4
  from flask import Flask, render_template, request, jsonify
 
 
5
  from PIL import Image
 
 
 
 
 
6
 
7
+ sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "src"))
8
  app = Flask(__name__)
9
+ app.config["MAX_CONTENT_LENGTH"] = 16 * 1024 * 1024
10
 
11
+ MODEL_PATH = "best_autoencoder_model.h5"
12
+ MODEL_INFO_PATH = "model_info.json"
 
13
  model = None
14
  model_info = None
15
 
16
+
17
  def load_trained_model():
 
18
  global model
19
+ if not os.path.exists(MODEL_PATH):
20
+ print(f"Warning: {MODEL_PATH} not found")
21
+ return
22
+ import tensorflow as tf
23
+ from tensorflow.keras.models import Model
24
+ from tensorflow.keras.layers import Input, Conv2D, MaxPooling2D, UpSampling2D
25
+ try:
26
+ # Rebuild the exact same architecture, then load weights only.
27
+ # This bypasses Keras version deserialization issues with InputLayer config.
28
+ inp = Input(shape=(28, 28, 1))
29
+ x = Conv2D(32, (3, 3), activation="relu", padding="same")(inp)
30
+ x = MaxPooling2D((2, 2), padding="same")(x)
31
+ x = Conv2D(16, (3, 3), activation="relu", padding="same")(x)
32
+ enc = MaxPooling2D((2, 2), padding="same")(x)
33
+ x = Conv2D(16, (3, 3), activation="relu", padding="same")(enc)
34
+ x = UpSampling2D((2, 2))(x)
35
+ x = Conv2D(32, (3, 3), activation="relu", padding="same")(x)
36
+ x = UpSampling2D((2, 2))(x)
37
+ out = Conv2D(1, (3, 3), activation="sigmoid", padding="same")(x)
38
+ rebuilt = Model(inp, out)
39
+ rebuilt.load_weights(MODEL_PATH)
40
+ model = rebuilt
41
+ print("Model loaded via weights-only approach")
42
+ except Exception as e:
43
+ print(f"Model load failed: {e}")
44
+
45
 
46
  def load_model_info():
 
47
  global model_info
48
  if os.path.exists(MODEL_INFO_PATH):
49
+ with open(MODEL_INFO_PATH) as f:
50
  model_info = json.load(f)
 
51
  else:
52
  model_info = {
53
  "model_name": "CNN Autoencoder",
 
57
  "test_loss": "N/A"
58
  }
59
 
60
+
61
  def preprocess_image(image):
62
+ img = image.convert("L").resize((28, 28))
63
+ arr = np.array(img) / 255.0
64
+ return arr.reshape(1, 28, 28, 1)
65
+
66
+
67
+ def array_to_base64(arr):
68
+ arr = arr.squeeze()
69
+ arr = (arr * 255).astype(np.uint8)
70
+ img = Image.fromarray(arr, mode="L")
71
+ buf = io.BytesIO()
72
+ img.save(buf, format="PNG")
73
+ return "data:image/png;base64," + base64.b64encode(buf.getvalue()).decode()
74
+
75
+
 
 
 
 
76
  load_trained_model()
77
  load_model_info()
78
 
79
 
80
+ @app.route("/")
81
  def index():
82
+ return render_template("index.html", model_info=model_info)
83
+
84
 
85
+ @app.route("/api/model-info")
86
  def get_model_info():
 
87
  if model_info:
88
  return jsonify(model_info)
89
+ return jsonify({"error": "not available"}), 404
90
 
91
+
92
+ @app.route("/denoise", methods=["POST"])
93
  def denoise():
 
94
  if model is None:
95
+ return jsonify({"error": "Model not loaded"}), 500
96
+ if "image" not in request.files:
97
+ return jsonify({"error": "No image uploaded"}), 400
98
+ file = request.files["image"]
99
+ if not file.filename:
100
+ return jsonify({"error": "No image selected"}), 400
 
 
 
101
  try:
102
  image = Image.open(file.stream)
103
+ proc = preprocess_image(image)
104
+ denoised = model.predict(proc, verbose=0)
105
+ return jsonify({"original": array_to_base64(proc), "denoised": array_to_base64(denoised)})
 
 
 
 
 
 
 
 
106
  except Exception as e:
107
+ return jsonify({"error": str(e)}), 500
108
+
109
 
110
+ if __name__ == "__main__":
111
+ port = int(os.environ.get("PORT", 7860))
112
+ app.run(debug=False, host="0.0.0.0", port=port)
requirements-hf.txt CHANGED
@@ -1,7 +1,5 @@
1
- # Inference-only requirements for Hugging Face deployment
2
- # tf-keras provides Keras 2.x compatibility for loading old .h5 models with TF 2.16+
3
  tensorflow-cpu==2.16.1
4
- tf-keras==2.16.0
5
  numpy==1.26.4
6
  flask==3.0.3
7
- pillow==10.3.0
 
1
+ # Inference-only requirements for Hugging Face deployment
 
2
  tensorflow-cpu==2.16.1
 
3
  numpy==1.26.4
4
  flask==3.0.3
5
+ pillow==10.3.0