File size: 3,516 Bytes
8539646
 
 
 
 
 
17c84c4
8539646
17c84c4
8539646
 
17c84c4
f844563
8539646
 
 
f844563
8539646
 
 
 
 
 
 
 
 
4aaac8f
8539646
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f844563
8539646
 
 
 
 
045deae
 
 
 
 
8539646
 
 
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
import os
import importlib.util
import numpy as np
import torch
import gradio as gr
from huggingface_hub import hf_hub_download

REPO_ID = "c1tr0n75/VoxelPathFinder"

# 1) Make sure torch is imported, then define device BEFORE using it anywhere
DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")

# 2) Download model code and weights from the model repo
PY_PATH = hf_hub_download(repo_id=REPO_ID, filename="pathfinding_nn.py")
CKPT_PATH = hf_hub_download(repo_id=REPO_ID, filename="training_outputs/final_model.pth")

# 3) Dynamically import the model definitions
spec = importlib.util.spec_from_file_location("pathfinding_nn", PY_PATH)
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
PathfindingNetwork = mod.PathfindingNetwork
create_voxel_input = mod.create_voxel_input

# 4) Build and load model
MODEL = PathfindingNetwork().to(DEVICE).eval()
ckpt = torch.load(CKPT_PATH, map_location=DEVICE)
state = ckpt.get("model_state_dict", ckpt)
MODEL.load_state_dict(state)

ACTION_NAMES = ['FORWARD','BACK','LEFT','RIGHT','UP','DOWN']

def decode(actions):
    return [ACTION_NAMES[a] for a in actions if 0 <= a < 6]

def infer_random(obstacle_prob=0.2, seed=None):
    if seed is not None:
        np.random.seed(int(seed))
    voxel_dim = MODEL.voxel_dim
    D, H, W = voxel_dim
    obstacles = (np.random.rand(D, H, W) < float(obstacle_prob)).astype(np.float32)
    free = np.argwhere(obstacles == 0)
    if len(free) < 2:
        return {"error": "Not enough free cells; lower obstacle_prob."}
    s_idx, g_idx = np.random.choice(len(free), size=2, replace=False)
    start = tuple(free[s_idx]); goal = tuple(free[g_idx])

    voxel_np = create_voxel_input(obstacles, start, goal, voxel_dim=voxel_dim)
    voxel = torch.from_numpy(voxel_np).float().unsqueeze(0).to(DEVICE)
    pos = torch.tensor([[start, goal]], dtype=torch.long, device=DEVICE)

    with torch.no_grad():
        actions = MODEL(voxel, pos)[0].tolist()

    return {
        "start": start,
        "goal": goal,
        "num_actions": len([a for a in actions if 0 <= a < 6]),
        "actions_ids": actions,
        "actions_decoded": decode(actions)[:50],
    }

#def infer_npz(npz_file):
#    if npz_file is None:
#        return {"error": "Upload a .npz with 'voxel_data' and 'positions'."}
#    data = np.load(npz_file.name)
#    voxel = torch.from_numpy(data['voxel_data']).float().unsqueeze(0).to(DEVICE)
#    pos = torch.from_numpy(data['positions']).long().unsqueeze(0).to(DEVICE)
#    with torch.no_grad():
#        actions = MODEL(voxel, pos)[0].tolist()
#    return {
#        "num_actions": len([a for a in actions if 0 <= a < 6]),
#        "actions_ids": actions,
#        "actions_decoded": decode(actions)[:50],
#    }

with gr.Blocks(title="Voxel Path Finder") as demo:
    gr.Markdown("## 3D Voxel Path Finder — Inference")
    with gr.Tab("Random environment"):
        obstacle = gr.Slider(0.0, 1.0, value=0.2, step=0.05, label="Obstacle probability")
        seed = gr.Number(value=None, label="Seed (optional)")
        btn = gr.Button("Run inference")
        out = gr.JSON(label="Result")
        btn.click(infer_random, inputs=[obstacle, seed], outputs=out)

#    with gr.Tab("Upload .npz sample"):
#        file = gr.File(file_types=[".npz"], label="Upload sample (voxel_data, positions)")
#        btn2 = gr.Button("Run inference")
#        out2 = gr.JSON(label="Result")
#        btn2.click(infer_npz, inputs=file, outputs=out2)

if __name__ == "__main__":
    demo.launch()