afrim3000 commited on
Commit
0294483
·
verified ·
1 Parent(s): db5c416

Delete README.md

Browse files
Files changed (1) hide show
  1. README.md +0 -288
README.md DELETED
@@ -1,288 +0,0 @@
1
- ---
2
- license: mit
3
- datasets:
4
- - Bingsu/Gameplay_Images
5
- language:
6
- - en
7
- metrics:
8
- - accuracy
9
- - precision
10
- - recall
11
- - f1
12
- - roc_auc
13
- - confusion_matrix
14
- base_model:
15
- - google/efficientnet-b0
16
- pipeline_tag: image-classification
17
- tags:
18
- - game-detection
19
- - image-classification
20
- - efficientnet
21
- - hashtag-generation
22
- - computer-vision
23
- - gaming
24
- ---
25
- # Game_Detection
26
- ### Automated Video Game Recognition for Hashtag Suggestion on Live Streaming Platforms
27
- A 10-class image classifier that identifies which video game is being played from a gameplay
28
- screenshot. Built on a fine-tuned [`google/efficientnet-b0`](https://huggingface.co/google/efficientnet-b0)
29
- backbone, trained at a custom, aspect-ratio-preserving **180×320** input resolution (instead of the
30
- standard 224×224 square crop) on the [`Bingsu/Gameplay_Images`](https://huggingface.co/datasets/Bingsu/Gameplay_Images)
31
- dataset.
32
- This model was built as part of a university course project (AI Lab, SE334) — *"Automated Video Game
33
- Recognition and Hashtag Suggestion for Live Streaming Platforms Using Image Classification"* — and
34
- powers the [GameSense](https://gamesense-h456.onrender.com/) demo app.
35
- **Authors:** S. M. Nihal Ahmed, Afrim Hossen Khan
36
- ## Model Details
37
- - **Base model:** `google/efficientnet-b0`
38
- - **Task:** Multi-class image classification (10 classes)
39
- - **License:** MIT
40
- - **Architecture:** EfficientNet-B0 backbone (ImageNet-pretrained), fine-tuned end-to-end with the
41
- final classifier layer replaced for 10 output classes. Trained at a custom **180×320** input
42
- resolution — half of the source dataset's native 640×360, preserving the true 16:9 aspect ratio —
43
- made possible without architectural changes since EfficientNet's `AdaptiveAvgPool2d` head is
44
- resolution-agnostic.
45
- - **Fine-tuning objective:** Cross-entropy loss with label smoothing (0.1), `sklearn` balanced class
46
- weights applied in the loss (the source dataset is already perfectly balanced at 1,000 images/class)
47
- - **Training regime:** Mixed-precision (AMP) training on dual CUDA T4 GPUs, AdamW optimizer with a
48
- OneCycleLR schedule, up to 25 epochs with early stopping (patience = 6, monitored on validation loss)
49
- ## Classes
50
- `Among Us, Apex Legends, Fortnite, Forza Horizon, Free Fire, Genshin Impact, God of War, Minecraft,
51
- Roblox, Terraria`
52
- ## Intended Use
53
- This model is intended for identifying which video game is shown in a gameplay screenshot. Example use
54
- cases:
55
- - Auto-generating hashtags/tags for gameplay clips, stream thumbnails, and social posts
56
- - Categorizing or organizing gameplay footage/screenshots by game on a content platform
57
- - A component in a larger stream metadata or content-tagging pipeline
58
- - Research and coursework on multi-class visual classification
59
- **Out of scope:** This model only recognizes the 10 games listed above — any other game will be forced
60
- into one of these 10 labels rather than correctly rejected. It has been evaluated on one dataset only,
61
- and has not been validated against real-world production streaming footage, unusual camera angles,
62
- menu/loading screens, or extensive in-game cosmetic content (e.g. crossover skins) that may visually
63
- resemble a different game in the label set.
64
- ## How to Use
65
- This model is distributed in two formats — pick whichever fits your stack.
66
- ### Option A: ONNX (lightweight, CPU-friendly)
67
- Download both files and keep them in the same folder — the `.onnx` graph loads its weights from the
68
- `.onnx.data` file alongside it at runtime:
69
- - [`efficientnet_b0_gameplay.onnx`](https://huggingface.co/nihal4/Game_Detection/resolve/main/efficientnet_b0_gameplay.onnx) — the ONNX graph
70
- - [`efficientnet_b0_gameplay.onnx.data`](https://huggingface.co/nihal4/Game_Detection/resolve/main/efficientnet_b0_gameplay.onnx.data) — the external weights file
71
- Install dependencies:
72
- ```bash
73
- pip install onnxruntime huggingface_hub pillow numpy
74
- ```
75
- #### Single-image prediction
76
- ```python
77
- import numpy as np
78
- import onnxruntime as ort
79
- from PIL import Image
80
- from huggingface_hub import hf_hub_download
81
- REPO_ID = "nihal4/Game_Detection"
82
- IMG_SIZE = (320, 180) # PIL resize takes (width, height)
83
- IMAGENET_MEAN = np.array([0.485, 0.456, 0.406], dtype=np.float32)
84
- IMAGENET_STD = np.array([0.229, 0.224, 0.225], dtype=np.float32)
85
- CLASS_NAMES = ['Among Us', 'Apex Legends', 'Fortnite', 'Forza Horizon', 'Free Fire',
86
- 'Genshin Impact', 'God of War', 'Minecraft', 'Roblox', 'Terraria']
87
- # Downloads both files into the same local cache folder — required, since the
88
- # .onnx graph references .onnx.data by relative path at load time.
89
- onnx_path = hf_hub_download(repo_id=REPO_ID, filename="efficientnet_b0_gameplay.onnx")
90
- hf_hub_download(repo_id=REPO_ID, filename="efficientnet_b0_gameplay.onnx.data")
91
-
92
- session = ort.InferenceSession(onnx_path, providers=["CPUExecutionProvider"])
93
- input_name = session.get_inputs()[0].name
94
- output_name = session.get_outputs()[0].name
95
- def preprocess_pil(img: Image.Image) -> np.ndarray:
96
- img = img.convert("RGB").resize(IMG_SIZE)
97
- arr = np.asarray(img, dtype=np.float32) / 255.0 # HWC, [0,1]
98
- arr = (arr - IMAGENET_MEAN) / IMAGENET_STD # normalize, same stats as training
99
- return arr.transpose(2, 0, 1) # HWC -> CHW
100
- def softmax(x: np.ndarray) -> np.ndarray:
101
- e = np.exp(x - x.max(axis=1, keepdims=True))
102
- return e / e.sum(axis=1, keepdims=True)
103
- def predict(image_path: str):
104
- image = Image.open(image_path)
105
- x = preprocess_pil(image)[np.newaxis, ...].astype(np.float32)
106
- logits = session.run([output_name], {input_name: x})[0]
107
- probs = softmax(logits)[0]
108
- top_idx = int(probs.argmax())
109
- return CLASS_NAMES[top_idx], probs
110
- label, probs = predict("path/to/screenshot.jpg")
111
- print(f"Prediction: {label}")
112
- for name, p in sorted(zip(CLASS_NAMES, probs), key=lambda t: -t[1]):
113
- print(f" {name:<16} {p*100:5.1f}%")
114
- ```
115
- #### Batch prediction
116
- ```python
117
- image_paths = ["shot1.jpg", "shot2.jpg", "shot3.jpg"]
118
-
119
- batch = np.stack([preprocess_pil(Image.open(p)) for p in image_paths]).astype(np.float32)
120
- logits = session.run([output_name], {input_name: batch})[0]
121
- probs = softmax(logits)
122
- preds = probs.argmax(axis=1)
123
-
124
- for path, pred, p in zip(image_paths, preds, probs):
125
- print(f"{path}: {CLASS_NAMES[int(pred)]} ({p[int(pred)]*100:.1f}%)")
126
- ```
127
- > For GPU inference, install `onnxruntime-gpu` instead and pass
128
- > `providers=["CUDAExecutionProvider", "CPUExecutionProvider"]` when creating the session.
129
- ### Option B: PyTorch (.pth checkpoint)
130
- Download the checkpoint:
131
- - [`efficientnet_b0_gameplay_final.pth`](https://huggingface.co/nihal4/Game_Detection/resolve/main/efficientnet_b0_gameplay_final.pth)
132
- Install dependencies:
133
- ```bash
134
- pip install torch torchvision huggingface_hub pillow numpy
135
- ```
136
- #### Single-image prediction
137
- ```python
138
- import torch
139
- import torch.nn as nn
140
- import numpy as np
141
- from torchvision import models, transforms
142
- from PIL import Image
143
- from huggingface_hub import hf_hub_download
144
- REPO_ID = "nihal4/Game_Detection"
145
- IMG_SIZE = (180, 320) # (H, W) — torchvision transforms convention
146
- CLASS_NAMES = ['Among Us', 'Apex Legends', 'Fortnite', 'Forza Horizon', 'Free Fire',
147
- 'Genshin Impact', 'God of War', 'Minecraft', 'Roblox', 'Terraria']
148
- ckpt_path = hf_hub_download(repo_id=REPO_ID, filename="efficientnet_b0_gameplay_final.pth")
149
- checkpoint = torch.load(ckpt_path, map_location="cpu")
150
- device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
151
- model = models.efficientnet_b0(weights=None)
152
- in_features = model.classifier[1].in_features
153
- model.classifier[1] = nn.Linear(in_features, len(CLASS_NAMES))
154
- model.load_state_dict(checkpoint["model_state_dict"])
155
- model.to(device).eval()
156
- transform = transforms.Compose([
157
- transforms.Resize(IMG_SIZE),
158
- transforms.ToTensor(),
159
- transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
160
- ])
161
- @torch.no_grad()
162
- def predict(image_path: str):
163
- image = Image.open(image_path).convert("RGB")
164
- x = transform(image).unsqueeze(0).to(device)
165
- logits = model(x)
166
- probs = torch.softmax(logits, dim=1)[0]
167
- top_idx = int(probs.argmax())
168
- return CLASS_NAMES[top_idx], probs.cpu().numpy()
169
- label, probs = predict("path/to/screenshot.jpg")
170
- print(f"Prediction: {label}")
171
- for name, p in sorted(zip(CLASS_NAMES, probs), key=lambda t: -t[1]):
172
- print(f" {name:<16} {p*100:5.1f}%")
173
- ```
174
- #### Batch prediction
175
- ```python
176
- from torch.utils.data import Dataset, DataLoader
177
-
178
- class ImageListDataset(Dataset):
179
- def __init__(self, paths, transform):
180
- self.paths = paths
181
- self.transform = transform
182
- def __len__(self):
183
- return len(self.paths)
184
- def __getitem__(self, i):
185
- img = Image.open(self.paths[i]).convert("RGB")
186
- return self.transform(img), self.paths[i]
187
- image_paths = ["shot1.jpg", "shot2.jpg", "shot3.jpg"]
188
- loader = DataLoader(ImageListDataset(image_paths, transform), batch_size=8)
189
- model.eval()
190
- with torch.no_grad():
191
- for images, paths in loader:
192
- images = images.to(device)
193
- logits = model(images)
194
- probs = torch.softmax(logits, dim=1)
195
- preds = probs.argmax(dim=1)
196
- for path, pred, p in zip(paths, preds, probs):
197
- print(f"{path}: {CLASS_NAMES[int(pred)]} ({p[int(pred)]*100:.1f}%)")
198
- ```
199
- ## Training Data
200
-
201
- The model was fine-tuned on the [`Bingsu/Gameplay_Images`](https://huggingface.co/datasets/Bingsu/Gameplay_Images)
202
- dataset — 10,000 gameplay screenshots (1,000 per class) at native 640×360 resolution, PNG format.
203
-
204
- - **Labels:** 10 classes (see [Classes](#classes) above)
205
- - **Splits:** Stratified 70 / 15 / 15 train / validation / test (the source dataset ships a single
206
- `train` split only; the split above was carved out manually, preserving per-class balance)
207
- - **Preprocessing:** Resize to 180×320 (custom, aspect-ratio-preserving resolution), ImageNet
208
- normalization (mean `[0.485, 0.456, 0.406]`, std `[0.229, 0.224, 0.225]`)
209
- - **Training augmentation:** Random horizontal flip, color jitter, random rotation (±8°), random
210
- erasing
211
- - **Class balancing:** The dataset is already perfectly balanced (1,000 images/class); `sklearn`
212
- balanced class weights are still computed and applied in the loss as a safeguard
213
-
214
- ## Training Procedure
215
-
216
- <!-- PLACEHOLDER: training curves (loss/accuracy per epoch) — image to be uploaded -->
217
-
218
- ![training_curves](https://cdn-uploads.huggingface.co/production/uploads/661d43ec3cf2981df52d0756/lBckExVfa7nctNBbRq36B.png)
219
-
220
-
221
- - **Framework:** PyTorch
222
- - **Hardware:** Kaggle free-tier T4 x2 GPUs
223
- - **Loss:** Cross-entropy with label smoothing (0.1)
224
- - **Mixed precision:** Enabled (AMP)
225
-
226
-
227
- ## Evaluation
228
-
229
- Evaluated on the held-out test split (n = 1,500) at a decision threshold of 0.5.
230
-
231
- ### Classification Report
232
-
233
- | Class | Precision | Recall | F1-score | Support |
234
- |----------------|:---------:|:------:|:--------:|:-------:|
235
- | Among Us | 1.0000 | 1.0000 | 1.0000 | 150 |
236
- | Apex Legends | 1.0000 | 0.9933 | 0.9967 | 150 |
237
- | Fortnite | 1.0000 | 1.0000 | 1.0000 | 150 |
238
- | Forza Horizon | 1.0000 | 1.0000 | 1.0000 | 150 |
239
- | Free Fire | 1.0000 | 1.0000 | 1.0000 | 150 |
240
- | Genshin Impact | 0.9934 | 1.0000 | 0.9967 | 150 |
241
- | God of War | 1.0000 | 1.0000 | 1.0000 | 150 |
242
- | Minecraft | 1.0000 | 1.0000 | 1.0000 | 150 |
243
- | Roblox | 1.0000 | 1.0000 | 1.0000 | 150 |
244
- | Terraria | 1.0000 | 1.0000 | 1.0000 | 150 |
245
- | **accuracy** | | | **0.9993** | 1,500 |
246
- | macro avg | 0.9993 | 0.9993 | 0.9993 | 1,500 |
247
- | weighted avg | 0.9993 | 0.9993 | 0.9993 | 1,500 |
248
-
249
- **Test ROC-AUC:** 1.0000 (macro average; per-class AUC is also 1.0000 across all 10 classes)
250
-
251
- ### Confusion Matrix
252
-
253
- <!-- PLACEHOLDER: image to be uploaded -->
254
-
255
-
256
- ![confusion_matrix](https://cdn-uploads.huggingface.co/production/uploads/661d43ec3cf2981df52d0756/GgkCX5ir4A12Iip96hrQy.png)
257
-
258
- ### ROC Curve
259
-
260
- <!-- PLACEHOLDER: image to be uploaded -->
261
-
262
-
263
- ![roc_auc_curves](https://cdn-uploads.huggingface.co/production/uploads/661d43ec3cf2981df52d0756/Q0J0IoHtaHhkq_IaTP-Qf.png)
264
-
265
- ## Limitations
266
-
267
- - Performance is reported on a single dataset; generalization to other capture sources, image
268
- qualities, camera angles, or game versions/UI updates is not guaranteed.
269
- - The classifier is closed-set — it will always assign one of the 10 trained classes, even to games or
270
- content it has never seen, rather than rejecting out-of-distribution input.
271
- - Confidence can be lower on visually ambiguous content, such as games with extensive cosmetic/skin
272
- systems whose art style can resemble another class in the label set.
273
- - The model has not been evaluated as a standalone production guardrail; low-confidence predictions
274
- should be handled with a confidence threshold or human review rather than trusted outright.
275
-
276
- ## Citation
277
-
278
- If you use this model, please cite this repository and reference this course project:
279
-
280
- ```
281
- @misc{game-detection-classifier,
282
- title = {Automated Video Game Recognition and Hashtag Suggestion for Live Streaming Platforms
283
- Using Image Classification},
284
- author = {S. M. Nihal Ahmed and Afrim Hossen Khan},
285
- year = {2026},
286
- note = {Course project, AI Lab (SE334), Daffodil International University}
287
- }
288
- ```