Instructions to use MA29/astro-image-classifier with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Keras
How to use MA29/astro-image-classifier with Keras:
# Available backend options are: "jax", "torch", "tensorflow". import os os.environ["KERAS_BACKEND"] = "jax" import keras model = keras.saving.load_model("hf://MA29/astro-image-classifier") - Notebooks
- Google Colab
- Kaggle
Astro Image Classifier
An ensemble of two transfer-learned CNN branches that classifies astronomical images into 11 classes.
- Demo: https://huggingface.co/spaces/MA29/astro-image-classifier
- Code: https://github.com/Majd1029/Astro-Image-Classifier
Architecture
vgg_ensemble_input [None,224,224,3] -> vgg_branch_model -> softmax(11)
densenet_ensemble_input [None,224,224,3] -> densenet_branch_model -> softmax(11)
-> Average
- VGG19 and DenseNet201 backbones, ImageNet-initialised and partially unfrozen
- Custom heads: global average pooling, dense + batch norm, dropout
- The VGG branch includes a data-augmentation block, inactive at inference
- 40,056,982 parameters
- Saved with Keras 3.10; optimizer state stripped, so this file is inference-only
Classes
black_hole, earth, galaxy, jupiter, mars, mercury, neptune,
pluto, saturn, uranus, venus
Usage
Both branches preprocess internally โ the densenet branch through a
Lambda(preprocess_input), the vgg branch through a channel-swap and
mean-subtraction chain. Feed raw 0-255 RGB. Applying
vgg19.preprocess_input or densenet.preprocess_input beforehand preprocesses
twice and degrades predictions badly on some classes.
custom_objects is required: the densenet Lambda is serialised under the name
preprocess_input, and Keras resolves it by that name at load time.
import numpy as np, tensorflow as tf, keras
from huggingface_hub import hf_hub_download
from PIL import Image
from tensorflow.keras.applications.densenet import preprocess_input
keras.mixed_precision.set_global_policy("float32") # saved under mixed_float16
path = hf_hub_download("MA29/astro-image-classifier", "ensemble_model.keras")
model = tf.keras.models.load_model(
path, custom_objects={"preprocess_input": preprocess_input}, compile=False
)
CLASSES = ["black_hole", "earth", "galaxy", "jupiter", "mars", "mercury",
"neptune", "pluto", "saturn", "uranus", "venus"]
img = Image.open("example.jpg").convert("RGB").resize((224, 224))
x = np.expand_dims(np.array(img, dtype="float32"), 0) # raw 0-255
names = [t.name.split(":")[0].split("/")[0] for t in model.inputs]
probs = model.predict({n: x for n in names}, verbose=0)[0]
print(CLASSES[int(np.argmax(probs))], probs.max())
Evaluation
Held-out test split: 446 images, reconstructed from the training notebook's
image_dataset_from_directory(validation_split=0.3, seed=42) then
temp_ds.skip(14). Per-class supports match the notebook's own reports.
| Model | Test accuracy |
|---|---|
| DenseNet201 branch alone | 0.9888 |
| VGG19 branch alone | 0.9888 |
| Ensemble (this model) | 0.9910 (442/446) |
Macro F1 0.990, weighted F1 0.991, mean confidence 98.4%.
| class | precision | recall | f1 | support |
|---|---|---|---|---|
| black_hole | 1.000 | 0.952 | 0.976 | 21 |
| earth | 1.000 | 1.000 | 1.000 | 35 |
| galaxy | 0.962 | 1.000 | 0.980 | 25 |
| jupiter | 1.000 | 1.000 | 1.000 | 39 |
| mars | 0.978 | 0.957 | 0.967 | 46 |
| mercury | 1.000 | 1.000 | 1.000 | 50 |
| neptune | 1.000 | 1.000 | 1.000 | 52 |
| pluto | 1.000 | 1.000 | 1.000 | 37 |
| saturn | 1.000 | 1.000 | 1.000 | 41 |
| uranus | 1.000 | 1.000 | 1.000 | 48 |
| venus | 0.962 | 0.981 | 0.971 | 52 |
All four errors: three venus/mars confusions, and one black_hole predicted as galaxy at 100% confidence โ worth knowing that high confidence is not a reliable correctness signal here.
Note the test split is drawn from the same curated dataset as training, so this figure reflects in-distribution performance only.
Limitations
- Trained on a curated, fairly clean dataset of planet and deep-sky imagery; it has not been evaluated on telescope captures, noisy frames or unusual crops.
- Closed-world over 11 classes โ every input is forced into one of them. There is no "none of the above", so out-of-distribution images get confident and meaningless labels.
- Several classes are visually similar under poor lighting or low resolution; treat single-image predictions as indicative.
- Downloads last month
- 22