Gurdaan commited on
Commit
2412b89
Β·
verified Β·
1 Parent(s): 99d4a2f

Upload 4 files

Browse files
Files changed (4) hide show
  1. best.onnx +3 -0
  2. dockerfile +36 -0
  3. environment.yml +24 -0
  4. scoring_Yolo_Model_Gunicorn.py +184 -0
best.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:df578069444060f03d01d85bd83fcce2bc9d49f1984243233b4dd839d6af3437
3
+ size 10535464
dockerfile ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use a base image from Microsoft that includes Conda, Python, and GPU drivers.
2
+ # This image is a great starting point for ML workloads on Azure.
3
+ FROM mcr.microsoft.com/azureml/openmpi4.1.0-ubuntu20.04:latest
4
+
5
+ # Set the working directory inside the container. All subsequent commands
6
+ # will be executed from this directory.
7
+ WORKDIR /app
8
+
9
+ # Copy the Conda environment file into the container.
10
+ COPY environment.yml .
11
+
12
+ # Create the Conda environment using the provided YAML file.
13
+ # The name of the environment will be `yolo-onnx-cpu-env` as defined in the file.
14
+ RUN conda env create -f environment.yml
15
+
16
+ # We need to install `gunicorn` and `Flask` or a similar web server to serve the model.
17
+ # Azure Container Apps uses HTTP to trigger scaling.
18
+ # We'll install these into the new Conda environment.
19
+ SHELL ["conda", "run", "-n", "yolo-onnx-cpu-env", "/bin/bash", "-c"]
20
+ RUN pip install gunicorn flask
21
+
22
+ # Copy the scoring script, the ONNX model file, and any other necessary files
23
+ # into the container's working directory.
24
+ COPY scoring_Yolo_Model.py .
25
+ COPY best.onnx .
26
+ # Assuming `class_names` or other static files are also present, copy them here.
27
+ # COPY class_names.txt .
28
+
29
+ # Expose the port that the web server will listen on.
30
+ # Azure Container Apps will route traffic to this port.
31
+ EXPOSE 8080
32
+
33
+ # The CMD instruction defines the command to run when the container starts.
34
+ # We use Gunicorn to serve our Flask app, which will be defined in the scoring script.
35
+ # The `conda run` command ensures the script is executed within the correct Conda environment.
36
+ CMD ["conda", "run", "-n", "yolo-onnx-cpu-env", "gunicorn", "--bind", "0.0.0.0:8080", "scoring_Yolo_Model_Gunicorn:app"]
environment.yml ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ channels:
2
+ - defaults
3
+ - conda-forge
4
+ - pytorch
5
+ dependencies:
6
+ - python=3.10
7
+ - pip
8
+ - numpy=2.2.6
9
+ - opencv=4.12.0
10
+ - 'pytorch::pytorch=2.2.2'
11
+ - 'pytorch::torchvision=0.17.2'
12
+ - pip:
13
+ - azureml-defaults==1.54.0
14
+ - onnxruntime==1.22.1
15
+ - Pillow==11.3.0
16
+ - ultralytics==8.3.166
17
+ - coloredlogs==15.0.1
18
+ - flatbuffers==25.2.10
19
+ - humanfriendly==10.0
20
+ - mpmath==1.3.0
21
+ - packaging==24.0
22
+ - protobuf==6.31.1
23
+ - sympy==1.14.0
24
+ name: yolo-onnx-cpu-env
scoring_Yolo_Model_Gunicorn.py ADDED
@@ -0,0 +1,184 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Flask/Gunicorn wrapper for YOLO ONNX scoring script
4
+ This file wraps the existing scoring_Yolo_Model.py for containerized deployment
5
+ """
6
+
7
+ import os
8
+ import sys
9
+ import json
10
+ import logging
11
+ from flask import Flask, request, jsonify
12
+ import traceback
13
+
14
+ # Import your existing scoring script
15
+ try:
16
+ from scoring_Yolo_Model import init as model_init, run as model_run
17
+ except ImportError as e:
18
+ print(f"Error importing scoring_Yolo_Model: {e}")
19
+ sys.exit(1)
20
+
21
+ # Configure logging for container environment
22
+ logging.basicConfig(
23
+ level=logging.INFO,
24
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
25
+ )
26
+ logger = logging.getLogger(__name__)
27
+
28
+ # Create Flask app
29
+ app = Flask(__name__)
30
+
31
+ # Global variable to track initialization
32
+ model_initialized = False
33
+
34
+ def initialize_model():
35
+ """Initialize the ONNX model on startup"""
36
+ global model_initialized
37
+
38
+ try:
39
+ logger.info("πŸ”„ Initializing YOLO ONNX model...")
40
+ model_init()
41
+ model_initialized = True
42
+ logger.info("βœ… Model initialized successfully")
43
+ return True
44
+ except Exception as e:
45
+ logger.error(f"❌ Failed to initialize model: {e}")
46
+ logger.error(traceback.format_exc())
47
+ return False
48
+
49
+ @app.route('/health', methods=['GET'])
50
+ def health_check():
51
+ """Health check endpoint for container orchestration"""
52
+ return jsonify({
53
+ 'status': 'healthy' if model_initialized else 'unhealthy',
54
+ 'model_initialized': model_initialized,
55
+ 'service': 'yolo-onnx-scoring'
56
+ }), 200 if model_initialized else 503
57
+
58
+ @app.route('/ready', methods=['GET'])
59
+ def readiness_check():
60
+ """Readiness check endpoint"""
61
+ return jsonify({
62
+ 'status': 'ready' if model_initialized else 'not_ready',
63
+ 'model_initialized': model_initialized
64
+ }), 200 if model_initialized else 503
65
+
66
+ @app.route('/score', methods=['POST'])
67
+ def score():
68
+ """Main scoring endpoint that calls your existing scoring script"""
69
+ if not model_initialized:
70
+ return jsonify({
71
+ 'error': 'Model not initialized',
72
+ 'status': 'error'
73
+ }), 503
74
+
75
+ try:
76
+ # Get raw JSON data from request
77
+ raw_data = request.get_data(as_text=True)
78
+
79
+ if not raw_data:
80
+ return jsonify({
81
+ 'error': 'No data provided',
82
+ 'status': 'error'
83
+ }), 400
84
+
85
+ # Log request info (without logging sensitive data)
86
+ logger.info(f"πŸ“₯ Received scoring request")
87
+
88
+ # Call your existing scoring function
89
+ result = model_run(raw_data)
90
+
91
+ # Log response info
92
+ if isinstance(result, dict) and 'num_detections' in result:
93
+ logger.info(f"πŸ“€ Returning {result.get('num_detections', 0)} detections")
94
+
95
+ return jsonify(result), 200
96
+
97
+ except json.JSONDecodeError as e:
98
+ error_msg = f"Invalid JSON format: {e}"
99
+ logger.error(f"❌ {error_msg}")
100
+ return jsonify({
101
+ 'error': error_msg,
102
+ 'status': 'error'
103
+ }), 400
104
+
105
+ except Exception as e:
106
+ error_msg = f"Scoring error: {str(e)}"
107
+ logger.error(f"❌ {error_msg}")
108
+ logger.error(traceback.format_exc())
109
+ return jsonify({
110
+ 'error': error_msg,
111
+ 'status': 'error'
112
+ }), 500
113
+
114
+ @app.route('/info', methods=['GET'])
115
+ def model_info():
116
+ """Get model information"""
117
+ return jsonify({
118
+ 'model_type': 'YOLO ONNX',
119
+ 'classes': ['Wall', 'Detail', 'Wall2'],
120
+ 'input_size': [640, 640],
121
+ 'confidence_threshold': 0.055,
122
+ 'iou_threshold': 0.45,
123
+ 'initialized': model_initialized
124
+ })
125
+
126
+ @app.errorhandler(404)
127
+ def not_found(error):
128
+ """Handle 404 errors"""
129
+ return jsonify({
130
+ 'error': 'Endpoint not found',
131
+ 'available_endpoints': ['/health', '/ready', '/score', '/info'],
132
+ 'status': 'error'
133
+ }), 404
134
+
135
+ @app.errorhandler(500)
136
+ def internal_error(error):
137
+ """Handle 500 errors"""
138
+ logger.error(f"Internal server error: {error}")
139
+ return jsonify({
140
+ 'error': 'Internal server error',
141
+ 'status': 'error'
142
+ }), 500
143
+
144
+ # Initialize model when the module is imported
145
+ @app.before_first_request
146
+ def startup():
147
+ """Initialize model before handling first request"""
148
+ if not model_initialized:
149
+ success = initialize_model()
150
+ if not success:
151
+ logger.error("❌ Failed to initialize model on startup")
152
+
153
+ # For Gunicorn compatibility
154
+ def create_app():
155
+ """Application factory for Gunicorn"""
156
+ # Initialize model if not already done
157
+ if not model_initialized:
158
+ success = initialize_model()
159
+ if not success:
160
+ raise RuntimeError("Failed to initialize YOLO model")
161
+
162
+ return app
163
+
164
+ # Entry point for development/testing
165
+ if __name__ == '__main__':
166
+ # Initialize model
167
+ success = initialize_model()
168
+ if not success:
169
+ print("❌ Failed to initialize model. Exiting.")
170
+ sys.exit(1)
171
+
172
+ # Run development server
173
+ print("πŸš€ Starting development server...")
174
+ app.run(
175
+ host='0.0.0.0',
176
+ port=int(os.environ.get('PORT', 8080)),
177
+ debug=False,
178
+ threaded=True
179
+ )
180
+ else:
181
+ # For Gunicorn deployment
182
+ # Initialize model when imported by Gunicorn
183
+ if not model_initialized:
184
+ initialize_model()