Aryagm commited on
Commit
1c19b2e
·
verified ·
1 Parent(s): 187fe66

Upload folder using huggingface_hub

Browse files
Files changed (8) hide show
  1. Dockerfile +32 -0
  2. README.md +26 -4
  3. app.py +235 -0
  4. model18cls/colormap.json +6 -0
  5. model18cls/model.bin +3 -0
  6. model18cls/model.json +808 -0
  7. requirements.txt +7 -0
  8. setup.sh +18 -0
Dockerfile ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM tensorflow/tensorflow:2.15.0-gpu
2
+
3
+ WORKDIR /app
4
+
5
+ # Install system dependencies
6
+ RUN apt-get update && apt-get install -y \
7
+ libgl1-mesa-glx \
8
+ libglib2.0-0 \
9
+ && rm -rf /var/lib/apt/lists/*
10
+
11
+ # Copy requirements and install Python dependencies
12
+ COPY requirements.txt .
13
+ RUN pip install --no-cache-dir -r requirements.txt
14
+
15
+ # Copy application code
16
+ COPY app.py .
17
+
18
+ # Copy model files (you'll need to add these)
19
+ COPY model18cls/ ./model18cls/
20
+
21
+ # Create non-root user for HF Spaces
22
+ RUN useradd -m -u 1000 user
23
+ USER user
24
+
25
+ # Set environment variables
26
+ ENV HOME=/home/user \
27
+ PATH=/home/user/.local/bin:$PATH \
28
+ PYTHONUNBUFFERED=1
29
+
30
+ EXPOSE 7860
31
+
32
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
README.md CHANGED
@@ -1,11 +1,33 @@
1
  ---
2
- title: Shia Brain
3
- emoji: 🏆
4
- colorFrom: purple
5
  colorTo: purple
6
  sdk: docker
 
7
  pinned: false
8
  license: mit
9
  ---
10
 
11
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: SHIA - Brain MRI Segmentation
3
+ emoji: 🧠
4
+ colorFrom: blue
5
  colorTo: purple
6
  sdk: docker
7
+ app_port: 7860
8
  pinned: false
9
  license: mit
10
  ---
11
 
12
+ # SHIA - Structured Health Intelligence for Alzheimer's
13
+
14
+ Fast GPU-accelerated brain MRI segmentation API.
15
+
16
+ ## API Endpoints
17
+
18
+ ### POST /segment
19
+ Upload a NIfTI file (.nii or .nii.gz) for segmentation.
20
+
21
+ ```bash
22
+ curl -X POST -F "file=@brain.nii.gz" https://YOUR-SPACE.hf.space/segment
23
+ ```
24
+
25
+ ### POST /segment/compact
26
+ Same as above but returns base64-gzipped results (more efficient for large volumes).
27
+
28
+ ### GET /health
29
+ Check API status and GPU availability.
30
+
31
+ ## Credits
32
+
33
+ Based on [BrainChop](https://github.com/neuroneural/brainchop) by the Neuroneural Lab.
app.py ADDED
@@ -0,0 +1,235 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import io
3
+ import time
4
+ import json
5
+ import numpy as np
6
+ import tensorflow as tf
7
+ import nibabel as nib
8
+ from fastapi import FastAPI, UploadFile, File, HTTPException
9
+ from fastapi.middleware.cors import CORSMiddleware
10
+ from fastapi.responses import JSONResponse
11
+ import gzip
12
+
13
+ app = FastAPI(title="SHIA - Brain MRI Segmentation API")
14
+
15
+ # Enable CORS for frontend
16
+ app.add_middleware(
17
+ CORSMiddleware,
18
+ allow_origins=["*"],
19
+ allow_credentials=True,
20
+ allow_methods=["*"],
21
+ allow_headers=["*"],
22
+ )
23
+
24
+ # Global model cache
25
+ model = None
26
+ MODEL_PATH = "model18cls"
27
+
28
+ def load_tfjs_model(model_path):
29
+ """
30
+ Load a TensorFlow.js LayersModel from model.json + weight shards.
31
+ Converts it to a Keras model for inference.
32
+ """
33
+ import tensorflowjs as tfjs
34
+
35
+ # Load the tfjs model and convert to Keras
36
+ model = tfjs.converters.load_keras_model(os.path.join(model_path, "model.json"))
37
+ return model
38
+
39
+ def load_model():
40
+ """Load TensorFlow model on startup"""
41
+ global model
42
+ if model is None:
43
+ print(f"Loading model from {MODEL_PATH}...")
44
+
45
+ # Check if it's a tfjs model (has model.json) or SavedModel
46
+ model_json_path = os.path.join(MODEL_PATH, "model.json")
47
+ if os.path.exists(model_json_path):
48
+ print("Detected TensorFlow.js format, converting...")
49
+ model = load_tfjs_model(MODEL_PATH)
50
+ else:
51
+ print("Loading as SavedModel format...")
52
+ model = tf.keras.models.load_model(MODEL_PATH)
53
+
54
+ print("Model loaded successfully!")
55
+ print(f"Input shape: {model.input_shape}")
56
+ print(f"Output shape: {model.output_shape}")
57
+ return model
58
+
59
+ def parse_nifti(file_bytes: bytes):
60
+ """Parse NIfTI file from bytes"""
61
+ # Check if gzipped
62
+ if file_bytes[:2] == b'\x1f\x8b':
63
+ file_bytes = gzip.decompress(file_bytes)
64
+
65
+ # Use nibabel with BytesIO
66
+ fh = nib.FileHolder(fileobj=io.BytesIO(file_bytes))
67
+ img = nib.Nifti1Image.from_file_map({'header': fh, 'image': fh})
68
+
69
+ return img.get_fdata(), img.header
70
+
71
+ def min_max_normalize(data):
72
+ """Normalize data to 0-1 range"""
73
+ data_min = data.min()
74
+ data_max = data.max()
75
+ if data_max - data_min == 0:
76
+ return data
77
+ return (data - data_min) / (data_max - data_min)
78
+
79
+ def preprocess_volume(data):
80
+ """Preprocess MRI volume for model input"""
81
+ # Normalize
82
+ data = min_max_normalize(data)
83
+
84
+ # Ensure float32
85
+ data = data.astype(np.float32)
86
+
87
+ # Transpose if needed (depends on model training)
88
+ # Model expects [batch, D, H, W, channels]
89
+ data = np.transpose(data, (2, 1, 0)) # Adjust axes as needed
90
+
91
+ # Add batch and channel dimensions
92
+ data = np.expand_dims(data, axis=0) # batch
93
+ data = np.expand_dims(data, axis=-1) # channel
94
+
95
+ return data
96
+
97
+ def run_inference(data):
98
+ """Run model inference on preprocessed data"""
99
+ loaded_model = load_model()
100
+
101
+ # Run prediction
102
+ prediction = loaded_model.predict(data, verbose=0)
103
+
104
+ # Get argmax for segmentation labels
105
+ segmentation = np.argmax(prediction, axis=-1)
106
+
107
+ # Remove batch dimension and transpose back
108
+ segmentation = segmentation[0]
109
+ segmentation = np.transpose(segmentation, (2, 1, 0))
110
+
111
+ return segmentation
112
+
113
+ @app.on_event("startup")
114
+ async def startup_event():
115
+ """Load model on startup"""
116
+ load_model()
117
+
118
+ @app.get("/")
119
+ async def root():
120
+ """Health check endpoint"""
121
+ return {
122
+ "status": "ok",
123
+ "service": "SHIA - Brain MRI Segmentation",
124
+ "model_loaded": model is not None
125
+ }
126
+
127
+ @app.get("/health")
128
+ async def health():
129
+ """Health check"""
130
+ return {"status": "healthy", "gpu": tf.config.list_physical_devices('GPU')}
131
+
132
+ @app.post("/segment")
133
+ async def segment(file: UploadFile = File(...)):
134
+ """
135
+ Segment a brain MRI scan.
136
+
137
+ Upload a NIfTI file (.nii or .nii.gz) and receive segmentation results.
138
+ """
139
+ try:
140
+ start_time = time.time()
141
+
142
+ # Validate file type
143
+ if not file.filename.endswith(('.nii', '.nii.gz')):
144
+ raise HTTPException(400, "File must be a NIfTI file (.nii or .nii.gz)")
145
+
146
+ # Read file
147
+ print(f"Processing: {file.filename}")
148
+ file_bytes = await file.read()
149
+
150
+ # Parse NIfTI
151
+ parse_start = time.time()
152
+ data, header = parse_nifti(file_bytes)
153
+ parse_time = time.time() - parse_start
154
+ print(f"Volume shape: {data.shape}, Parse time: {parse_time:.2f}s")
155
+
156
+ # Preprocess
157
+ preprocess_start = time.time()
158
+ processed = preprocess_volume(data)
159
+ preprocess_time = time.time() - preprocess_start
160
+ print(f"Preprocessed shape: {processed.shape}, Time: {preprocess_time:.2f}s")
161
+
162
+ # Run inference
163
+ inference_start = time.time()
164
+ segmentation = run_inference(processed)
165
+ inference_time = time.time() - inference_start
166
+ print(f"Inference time: {inference_time:.2f}s")
167
+
168
+ total_time = time.time() - start_time
169
+
170
+ # Get unique labels found
171
+ unique_labels = np.unique(segmentation).tolist()
172
+
173
+ return JSONResponse({
174
+ "success": True,
175
+ "filename": file.filename,
176
+ "original_shape": list(data.shape),
177
+ "segmentation_shape": list(segmentation.shape),
178
+ "unique_labels": unique_labels,
179
+ "num_labels": len(unique_labels),
180
+ "timing": {
181
+ "parse": round(parse_time, 3),
182
+ "preprocess": round(preprocess_time, 3),
183
+ "inference": round(inference_time, 3),
184
+ "total": round(total_time, 3)
185
+ },
186
+ # Return segmentation as nested list (can be large!)
187
+ "segmentation": segmentation.astype(np.uint8).tolist()
188
+ })
189
+
190
+ except Exception as e:
191
+ print(f"Error: {str(e)}")
192
+ raise HTTPException(500, f"Segmentation failed: {str(e)}")
193
+
194
+ @app.post("/segment/compact")
195
+ async def segment_compact(file: UploadFile = File(...)):
196
+ """
197
+ Segment a brain MRI scan and return compressed results.
198
+
199
+ Returns base64-encoded gzipped segmentation for efficiency.
200
+ """
201
+ import base64
202
+
203
+ try:
204
+ start_time = time.time()
205
+
206
+ if not file.filename.endswith(('.nii', '.nii.gz')):
207
+ raise HTTPException(400, "File must be a NIfTI file (.nii or .nii.gz)")
208
+
209
+ file_bytes = await file.read()
210
+ data, header = parse_nifti(file_bytes)
211
+ processed = preprocess_volume(data)
212
+ segmentation = run_inference(processed)
213
+
214
+ total_time = time.time() - start_time
215
+
216
+ # Compress segmentation
217
+ seg_bytes = segmentation.astype(np.uint8).tobytes()
218
+ compressed = gzip.compress(seg_bytes)
219
+ encoded = base64.b64encode(compressed).decode('utf-8')
220
+
221
+ return JSONResponse({
222
+ "success": True,
223
+ "shape": list(segmentation.shape),
224
+ "dtype": "uint8",
225
+ "encoding": "base64_gzip",
226
+ "inference_time": round(total_time, 3),
227
+ "data": encoded
228
+ })
229
+
230
+ except Exception as e:
231
+ raise HTTPException(500, f"Segmentation failed: {str(e)}")
232
+
233
+ if __name__ == "__main__":
234
+ import uvicorn
235
+ uvicorn.run(app, host="0.0.0.0", port=7860)
model18cls/colormap.json ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ {
2
+ "R": [ 0, 245, 205, 120, 196, 220, 230, 0, 122, 236, 12, 204, 42, 119, 220, 103, 255, 165],
3
+ "G": [ 0, 245, 62, 18, 58, 248, 148, 118, 186, 13, 48, 182, 204, 159, 216, 255, 165, 42],
4
+ "B": [ 0, 245, 78, 134, 250, 164, 34, 14, 220, 176, 255, 142, 164, 176, 20, 255, 0, 42],
5
+ "labels": [ "Unknown", "Cerebral-White-Matter", "Cerebral-Cortex", "Lateral-Ventricle", "Inferior-Lateral-Ventricle", "Cerebellum-White-Matter", "Cerebellum-Cortex", "Thalamus", "Caudate", "Putamen", "Pallidum", "3rd-Ventricle", "4th-Ventricle", "Brain-Stem", "Hippocampus", "Amygdala", "Accumbens-area", "VentralDC"]
6
+ }
model18cls/model.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:725096439f64ece1ca45ec3c5115c9fa6004f6538cac3032b85966d3772b605e
3
+ size 385632
model18cls/model.json ADDED
@@ -0,0 +1,808 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "format": "layers-model",
3
+ "generatedBy": "keras v2.7.0",
4
+ "convertedBy": "TensorFlow.js Converter v3.9.0",
5
+ "modelTopology": {
6
+ "keras_version": "2.6.0",
7
+ "backend": "tensorflow",
8
+ "model_config": {
9
+ "class_name": "Functional",
10
+ "config": {
11
+ "name": "model",
12
+ "layers": [
13
+ {
14
+ "class_name": "InputLayer",
15
+ "config": {
16
+ "batch_input_shape": [
17
+ null,
18
+ 256,
19
+ 256,
20
+ 256,
21
+ 1
22
+ ],
23
+ "dtype": "float32",
24
+ "sparse": false,
25
+ "ragged": false,
26
+ "name": "input"
27
+ },
28
+ "name": "input",
29
+ "inbound_nodes": []
30
+ },
31
+ {
32
+ "class_name": "Conv3D",
33
+ "config": {
34
+ "name": "conv3d_0",
35
+ "trainable": false,
36
+ "filters": 21,
37
+ "kernel_size": [
38
+ 3,
39
+ 3,
40
+ 3
41
+ ],
42
+ "strides": [
43
+ 1,
44
+ 1,
45
+ 1
46
+ ],
47
+ "dilation_rate": [
48
+ 1,
49
+ 1,
50
+ 1
51
+ ],
52
+ "padding": "same",
53
+ "data_format": "channels_last",
54
+ "activation": "linear",
55
+ "use_bias": true,
56
+ "dtype": "float32"
57
+ },
58
+ "name": "conv3d_0",
59
+ "inbound_nodes": [
60
+ [
61
+ [
62
+ "input",
63
+ 0,
64
+ 0,
65
+ {}
66
+ ]
67
+ ]
68
+ ]
69
+ },
70
+ {
71
+ "class_name": "Activation",
72
+ "config": {
73
+ "name": "activation_1",
74
+ "trainable": false,
75
+ "dtype": "float32",
76
+ "activation": "elu"
77
+ },
78
+ "name": "activation_1",
79
+ "inbound_nodes": [
80
+ [
81
+ [
82
+ "conv3d_0",
83
+ 0,
84
+ 0,
85
+ {}
86
+ ]
87
+ ]
88
+ ]
89
+ },
90
+ {
91
+ "class_name": "Conv3D",
92
+ "config": {
93
+ "name": "conv3d_2",
94
+ "trainable": false,
95
+ "filters": 21,
96
+ "kernel_size": [
97
+ 3,
98
+ 3,
99
+ 3
100
+ ],
101
+ "strides": [
102
+ 1,
103
+ 1,
104
+ 1
105
+ ],
106
+ "dilation_rate": [
107
+ 2,
108
+ 2,
109
+ 2
110
+ ],
111
+ "padding": "same",
112
+ "data_format": "channels_last",
113
+ "activation": "linear",
114
+ "use_bias": true,
115
+ "dtype": "float32"
116
+ },
117
+ "name": "conv3d_2",
118
+ "inbound_nodes": [
119
+ [
120
+ [
121
+ "activation_1",
122
+ 0,
123
+ 0,
124
+ {}
125
+ ]
126
+ ]
127
+ ]
128
+ },
129
+ {
130
+ "class_name": "Activation",
131
+ "config": {
132
+ "name": "activation_3",
133
+ "trainable": false,
134
+ "dtype": "float32",
135
+ "activation": "elu"
136
+ },
137
+ "name": "activation_3",
138
+ "inbound_nodes": [
139
+ [
140
+ [
141
+ "conv3d_2",
142
+ 0,
143
+ 0,
144
+ {}
145
+ ]
146
+ ]
147
+ ]
148
+ },
149
+ {
150
+ "class_name": "Conv3D",
151
+ "config": {
152
+ "name": "conv3d_4",
153
+ "trainable": false,
154
+ "filters": 21,
155
+ "kernel_size": [
156
+ 3,
157
+ 3,
158
+ 3
159
+ ],
160
+ "strides": [
161
+ 1,
162
+ 1,
163
+ 1
164
+ ],
165
+ "dilation_rate": [
166
+ 4,
167
+ 4,
168
+ 4
169
+ ],
170
+ "padding": "same",
171
+ "data_format": "channels_last",
172
+ "activation": "linear",
173
+ "use_bias": true,
174
+ "dtype": "float32"
175
+ },
176
+ "name": "conv3d_4",
177
+ "inbound_nodes": [
178
+ [
179
+ [
180
+ "activation_3",
181
+ 0,
182
+ 0,
183
+ {}
184
+ ]
185
+ ]
186
+ ]
187
+ },
188
+ {
189
+ "class_name": "Activation",
190
+ "config": {
191
+ "name": "activation_5",
192
+ "trainable": false,
193
+ "dtype": "float32",
194
+ "activation": "elu"
195
+ },
196
+ "name": "activation_5",
197
+ "inbound_nodes": [
198
+ [
199
+ [
200
+ "conv3d_4",
201
+ 0,
202
+ 0,
203
+ {}
204
+ ]
205
+ ]
206
+ ]
207
+ },
208
+ {
209
+ "class_name": "Conv3D",
210
+ "config": {
211
+ "name": "conv3d_6",
212
+ "trainable": false,
213
+ "filters": 21,
214
+ "kernel_size": [
215
+ 3,
216
+ 3,
217
+ 3
218
+ ],
219
+ "strides": [
220
+ 1,
221
+ 1,
222
+ 1
223
+ ],
224
+ "dilation_rate": [
225
+ 8,
226
+ 8,
227
+ 8
228
+ ],
229
+ "padding": "same",
230
+ "data_format": "channels_last",
231
+ "activation": "linear",
232
+ "use_bias": true,
233
+ "dtype": "float32"
234
+ },
235
+ "name": "conv3d_6",
236
+ "inbound_nodes": [
237
+ [
238
+ [
239
+ "activation_5",
240
+ 0,
241
+ 0,
242
+ {}
243
+ ]
244
+ ]
245
+ ]
246
+ },
247
+ {
248
+ "class_name": "Activation",
249
+ "config": {
250
+ "name": "activation_7",
251
+ "trainable": false,
252
+ "dtype": "float32",
253
+ "activation": "elu"
254
+ },
255
+ "name": "activation_7",
256
+ "inbound_nodes": [
257
+ [
258
+ [
259
+ "conv3d_6",
260
+ 0,
261
+ 0,
262
+ {}
263
+ ]
264
+ ]
265
+ ]
266
+ },
267
+ {
268
+ "class_name": "Conv3D",
269
+ "config": {
270
+ "name": "conv3d_8",
271
+ "trainable": false,
272
+ "filters": 21,
273
+ "kernel_size": [
274
+ 3,
275
+ 3,
276
+ 3
277
+ ],
278
+ "strides": [
279
+ 1,
280
+ 1,
281
+ 1
282
+ ],
283
+ "dilation_rate": [
284
+ 16,
285
+ 16,
286
+ 16
287
+ ],
288
+ "padding": "same",
289
+ "data_format": "channels_last",
290
+ "activation": "linear",
291
+ "use_bias": true,
292
+ "dtype": "float32"
293
+ },
294
+ "name": "conv3d_8",
295
+ "inbound_nodes": [
296
+ [
297
+ [
298
+ "activation_7",
299
+ 0,
300
+ 0,
301
+ {}
302
+ ]
303
+ ]
304
+ ]
305
+ },
306
+ {
307
+ "class_name": "Activation",
308
+ "config": {
309
+ "name": "activation_9",
310
+ "trainable": false,
311
+ "dtype": "float32",
312
+ "activation": "elu"
313
+ },
314
+ "name": "activation_9",
315
+ "inbound_nodes": [
316
+ [
317
+ [
318
+ "conv3d_8",
319
+ 0,
320
+ 0,
321
+ {}
322
+ ]
323
+ ]
324
+ ]
325
+ },
326
+ {
327
+ "class_name": "Conv3D",
328
+ "config": {
329
+ "name": "conv3d_10",
330
+ "trainable": false,
331
+ "filters": 21,
332
+ "kernel_size": [
333
+ 3,
334
+ 3,
335
+ 3
336
+ ],
337
+ "strides": [
338
+ 1,
339
+ 1,
340
+ 1
341
+ ],
342
+ "dilation_rate": [
343
+ 8,
344
+ 8,
345
+ 8
346
+ ],
347
+ "padding": "same",
348
+ "data_format": "channels_last",
349
+ "activation": "linear",
350
+ "use_bias": true,
351
+ "dtype": "float32"
352
+ },
353
+ "name": "conv3d_10",
354
+ "inbound_nodes": [
355
+ [
356
+ [
357
+ "activation_9",
358
+ 0,
359
+ 0,
360
+ {}
361
+ ]
362
+ ]
363
+ ]
364
+ },
365
+ {
366
+ "class_name": "Activation",
367
+ "config": {
368
+ "name": "activation_11",
369
+ "trainable": false,
370
+ "dtype": "float32",
371
+ "activation": "elu"
372
+ },
373
+ "name": "activation_11",
374
+ "inbound_nodes": [
375
+ [
376
+ [
377
+ "conv3d_10",
378
+ 0,
379
+ 0,
380
+ {}
381
+ ]
382
+ ]
383
+ ]
384
+ },
385
+ {
386
+ "class_name": "Conv3D",
387
+ "config": {
388
+ "name": "conv3d_12",
389
+ "trainable": false,
390
+ "filters": 21,
391
+ "kernel_size": [
392
+ 3,
393
+ 3,
394
+ 3
395
+ ],
396
+ "strides": [
397
+ 1,
398
+ 1,
399
+ 1
400
+ ],
401
+ "dilation_rate": [
402
+ 4,
403
+ 4,
404
+ 4
405
+ ],
406
+ "padding": "same",
407
+ "data_format": "channels_last",
408
+ "activation": "linear",
409
+ "use_bias": true,
410
+ "dtype": "float32"
411
+ },
412
+ "name": "conv3d_12",
413
+ "inbound_nodes": [
414
+ [
415
+ [
416
+ "activation_11",
417
+ 0,
418
+ 0,
419
+ {}
420
+ ]
421
+ ]
422
+ ]
423
+ },
424
+ {
425
+ "class_name": "Activation",
426
+ "config": {
427
+ "name": "activation_13",
428
+ "trainable": false,
429
+ "dtype": "float32",
430
+ "activation": "elu"
431
+ },
432
+ "name": "activation_13",
433
+ "inbound_nodes": [
434
+ [
435
+ [
436
+ "conv3d_12",
437
+ 0,
438
+ 0,
439
+ {}
440
+ ]
441
+ ]
442
+ ]
443
+ },
444
+ {
445
+ "class_name": "Conv3D",
446
+ "config": {
447
+ "name": "conv3d_14",
448
+ "trainable": false,
449
+ "filters": 21,
450
+ "kernel_size": [
451
+ 3,
452
+ 3,
453
+ 3
454
+ ],
455
+ "strides": [
456
+ 1,
457
+ 1,
458
+ 1
459
+ ],
460
+ "dilation_rate": [
461
+ 2,
462
+ 2,
463
+ 2
464
+ ],
465
+ "padding": "same",
466
+ "data_format": "channels_last",
467
+ "activation": "linear",
468
+ "use_bias": true,
469
+ "dtype": "float32"
470
+ },
471
+ "name": "conv3d_14",
472
+ "inbound_nodes": [
473
+ [
474
+ [
475
+ "activation_13",
476
+ 0,
477
+ 0,
478
+ {}
479
+ ]
480
+ ]
481
+ ]
482
+ },
483
+ {
484
+ "class_name": "Activation",
485
+ "config": {
486
+ "name": "activation_15",
487
+ "trainable": false,
488
+ "dtype": "float32",
489
+ "activation": "elu"
490
+ },
491
+ "name": "activation_15",
492
+ "inbound_nodes": [
493
+ [
494
+ [
495
+ "conv3d_14",
496
+ 0,
497
+ 0,
498
+ {}
499
+ ]
500
+ ]
501
+ ]
502
+ },
503
+ {
504
+ "class_name": "Conv3D",
505
+ "config": {
506
+ "name": "conv3d_16",
507
+ "trainable": false,
508
+ "filters": 21,
509
+ "kernel_size": [
510
+ 3,
511
+ 3,
512
+ 3
513
+ ],
514
+ "strides": [
515
+ 1,
516
+ 1,
517
+ 1
518
+ ],
519
+ "dilation_rate": [
520
+ 1,
521
+ 1,
522
+ 1
523
+ ],
524
+ "padding": "same",
525
+ "data_format": "channels_last",
526
+ "activation": "linear",
527
+ "use_bias": true,
528
+ "dtype": "float32"
529
+ },
530
+ "name": "conv3d_16",
531
+ "inbound_nodes": [
532
+ [
533
+ [
534
+ "activation_15",
535
+ 0,
536
+ 0,
537
+ {}
538
+ ]
539
+ ]
540
+ ]
541
+ },
542
+ {
543
+ "class_name": "Activation",
544
+ "config": {
545
+ "name": "activation_17",
546
+ "trainable": false,
547
+ "dtype": "float32",
548
+ "activation": "elu"
549
+ },
550
+ "name": "activation_17",
551
+ "inbound_nodes": [
552
+ [
553
+ [
554
+ "conv3d_16",
555
+ 0,
556
+ 0,
557
+ {}
558
+ ]
559
+ ]
560
+ ]
561
+ },
562
+ {
563
+ "class_name": "Conv3D",
564
+ "config": {
565
+ "name": "output",
566
+ "trainable": false,
567
+ "filters": 18,
568
+ "kernel_size": [
569
+ 1,
570
+ 1,
571
+ 1
572
+ ],
573
+ "strides": [
574
+ 1,
575
+ 1,
576
+ 1
577
+ ],
578
+ "dilation_rate": [
579
+ 1,
580
+ 1,
581
+ 1
582
+ ],
583
+ "padding": "same",
584
+ "data_format": "channels_last",
585
+ "activation": "linear",
586
+ "use_bias": true,
587
+ "dtype": "float32"
588
+ },
589
+ "name": "output",
590
+ "inbound_nodes": [
591
+ [
592
+ [
593
+ "activation_17",
594
+ 0,
595
+ 0,
596
+ {}
597
+ ]
598
+ ]
599
+ ]
600
+ }
601
+ ],
602
+ "input_layers": [
603
+ [
604
+ "input",
605
+ 0,
606
+ 0
607
+ ]
608
+ ],
609
+ "output_layers": [
610
+ [
611
+ "output",
612
+ 0,
613
+ 0
614
+ ]
615
+ ]
616
+ }
617
+ }
618
+ },
619
+ "weightsManifest": [
620
+ {
621
+ "paths": [
622
+ "model.bin"
623
+ ],
624
+ "weights": [
625
+ {
626
+ "name": "conv3d_0/kernel",
627
+ "shape": [
628
+ 3,
629
+ 3,
630
+ 3,
631
+ 1,
632
+ 21
633
+ ],
634
+ "dtype": "float32"
635
+ },
636
+ {
637
+ "name": "conv3d_0/bias",
638
+ "shape": [
639
+ 21
640
+ ],
641
+ "dtype": "float32"
642
+ },
643
+ {
644
+ "name": "conv3d_2/kernel",
645
+ "shape": [
646
+ 3,
647
+ 3,
648
+ 3,
649
+ 21,
650
+ 21
651
+ ],
652
+ "dtype": "float32"
653
+ },
654
+ {
655
+ "name": "conv3d_2/bias",
656
+ "shape": [
657
+ 21
658
+ ],
659
+ "dtype": "float32"
660
+ },
661
+ {
662
+ "name": "conv3d_4/kernel",
663
+ "shape": [
664
+ 3,
665
+ 3,
666
+ 3,
667
+ 21,
668
+ 21
669
+ ],
670
+ "dtype": "float32"
671
+ },
672
+ {
673
+ "name": "conv3d_4/bias",
674
+ "shape": [
675
+ 21
676
+ ],
677
+ "dtype": "float32"
678
+ },
679
+ {
680
+ "name": "conv3d_6/kernel",
681
+ "shape": [
682
+ 3,
683
+ 3,
684
+ 3,
685
+ 21,
686
+ 21
687
+ ],
688
+ "dtype": "float32"
689
+ },
690
+ {
691
+ "name": "conv3d_6/bias",
692
+ "shape": [
693
+ 21
694
+ ],
695
+ "dtype": "float32"
696
+ },
697
+ {
698
+ "name": "conv3d_8/kernel",
699
+ "shape": [
700
+ 3,
701
+ 3,
702
+ 3,
703
+ 21,
704
+ 21
705
+ ],
706
+ "dtype": "float32"
707
+ },
708
+ {
709
+ "name": "conv3d_8/bias",
710
+ "shape": [
711
+ 21
712
+ ],
713
+ "dtype": "float32"
714
+ },
715
+ {
716
+ "name": "conv3d_10/kernel",
717
+ "shape": [
718
+ 3,
719
+ 3,
720
+ 3,
721
+ 21,
722
+ 21
723
+ ],
724
+ "dtype": "float32"
725
+ },
726
+ {
727
+ "name": "conv3d_10/bias",
728
+ "shape": [
729
+ 21
730
+ ],
731
+ "dtype": "float32"
732
+ },
733
+ {
734
+ "name": "conv3d_12/kernel",
735
+ "shape": [
736
+ 3,
737
+ 3,
738
+ 3,
739
+ 21,
740
+ 21
741
+ ],
742
+ "dtype": "float32"
743
+ },
744
+ {
745
+ "name": "conv3d_12/bias",
746
+ "shape": [
747
+ 21
748
+ ],
749
+ "dtype": "float32"
750
+ },
751
+ {
752
+ "name": "conv3d_14/kernel",
753
+ "shape": [
754
+ 3,
755
+ 3,
756
+ 3,
757
+ 21,
758
+ 21
759
+ ],
760
+ "dtype": "float32"
761
+ },
762
+ {
763
+ "name": "conv3d_14/bias",
764
+ "shape": [
765
+ 21
766
+ ],
767
+ "dtype": "float32"
768
+ },
769
+ {
770
+ "name": "conv3d_16/kernel",
771
+ "shape": [
772
+ 3,
773
+ 3,
774
+ 3,
775
+ 21,
776
+ 21
777
+ ],
778
+ "dtype": "float32"
779
+ },
780
+ {
781
+ "name": "conv3d_16/bias",
782
+ "shape": [
783
+ 21
784
+ ],
785
+ "dtype": "float32"
786
+ },
787
+ {
788
+ "name": "output/kernel",
789
+ "shape": [
790
+ 1,
791
+ 1,
792
+ 1,
793
+ 21,
794
+ 18
795
+ ],
796
+ "dtype": "float32"
797
+ },
798
+ {
799
+ "name": "output/bias",
800
+ "shape": [
801
+ 18
802
+ ],
803
+ "dtype": "float32"
804
+ }
805
+ ]
806
+ }
807
+ ]
808
+ }
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ fastapi==0.104.1
2
+ uvicorn[standard]==0.24.0
3
+ python-multipart==0.0.6
4
+ tensorflow==2.15.0
5
+ tensorflowjs==4.15.0
6
+ nibabel==5.2.0
7
+ numpy==1.26.2
setup.sh ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ # Setup script for Hugging Face Space
3
+
4
+ # Copy model files to huggingface directory
5
+ echo "Copying model files..."
6
+ cp -r ../public/models/model18cls ./model18cls
7
+
8
+ echo "Done! Now you can:"
9
+ echo "1. Create a new Space on huggingface.co/new-space"
10
+ echo "2. Select 'Docker' as the SDK"
11
+ echo "3. Select 'GPU' hardware (T4 is free)"
12
+ echo "4. Upload all files from this directory"
13
+ echo ""
14
+ echo "Or use the HF CLI:"
15
+ echo " huggingface-cli login"
16
+ echo " huggingface-cli repo create shia-brain --type space --space_sdk docker"
17
+ echo " cd huggingface && git init && git remote add origin https://huggingface.co/spaces/YOUR_USERNAME/shia-brain"
18
+ echo " git add . && git commit -m 'Initial commit' && git push"