File size: 4,431 Bytes
41bf89a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
---

license: mit
library_name: keras
pipeline_tag: image-classification
tags:
  - image-classification
  - astronomy
  - tensorflow
  - keras
  - transfer-learning
  - ensemble
---


# 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.

```python

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.