Posts

Showing posts with the label Machine Learning

Apollo Spatial VLM: From One Photo and One Sentence to 3D

Image
One photo, one sentence. “Locate the Sydney Opera House”, and a few seconds later the scene is in 3D, as Gaussian splats you can tilt around. Recently I came across a small project called Odyseus Spatial VLM by Mercurius Technologies. Two things grabbed me right away. The first was the name. I grew up on Greek mythology, and seeing Odysseus on a GitHub page brought back a lot of childhood memories. The second was the idea: take a vision language model (VLM), the kind of model that can look at a picture and answer questions about it, and ask it not just what is in the photo, but where it is, in 3D, in meters. I liked it so much that I forked it, played with it for a while, and kept adding things. It grew into its own project, which I named Apollo Spatial VLM . (Why Apollo? Mercury and Apollo have a lovely story together. I tell it at the end of the README.) How it works You upload a photo and type what you are looking for, someth...

FELN Decisions: Teaching a Small Model Which Layers a Question Needs

Image
When Unsloth published its guide on how to train your own decision model , I immediately thought of the North Sea. In Lunar Laya , I argued that a model should take a state and some text, and return a structured, measurable answer. Here was a way to turn any small LLM into exactly that kind of model, with a probability attached to every answer. So I had to try it on FELN. A quick recap for new readers. FELN (Find Existing Location with N layers) is the little query language behind my RAG , LoRA , Liquid and WebGPU experiments. A question such as “Find gas wells within 5 km of oil pipelines” becomes a plan with three parallel lists: layers , where and relations . The first layer is the one returned; any other layer only filters it through a spatial relation. All those projects generate the whole plan in one go. This time, I wanted to pull out the very first decision and give it to a model that does nothing else: which layers does this question need, and which one is primary? One...

Lunar CLM: From 869 ms to 20 ms per Decision on a Mac

Image
In my last lander post I spent a few paragraphs on Jev , the System One decision model TypeSafe AI opened to early access this month. You hand it a block of state and typed questions, and it returns a probability for every choice. No text to parse. I also made a claim I had not tested: my lander talks to its model through one call, agent.predict(prompt, QUESTIONS) , so swapping in a different decision model should be an adapter, not a redesign. Then I read about Contrastive Language Models (CLM). It takes the same contract and builds it in the open: a block of state in, typed questions, a probability per choice out, with source code and released 8B heads you can run yourself. Its server even answers on an endpoint called /v1/systemone . Jev I can only read about. CLM I could actually test. I had to find out. The adapter part turned out to be true. It was everything after that which kept me busy. The small CLM I trained on my Mac, with no overrides. The lander starts upside do...

The Trainee Got Better. It Still Cannot Fly Alone.

Image
I ended The Engineer and the Trainee with a plan: roll out the shielded pilot, relabel every visited state with MPC, retrain, and see whether the trainee could finally fly on its own. That is still the plan. But before getting there I did something lazier, and the result was more interesting than I expected. I also fixed something that had been bothering me every time I watched a flight. The same recorded flight as last time, re-run with a smoother controller and a retrained model. The engine loses 60% of its thrust at ten seconds, the estimate falls to 40%, and the shield now steps in on about one command in eight instead of one in three. The lander had the shakes Watching a descent, the ship twitched. Not a rendering artifact — the controller really was changing its mind. I measured it: over 30 flights the beam search picked a different command on 77.7% of decisions. Every fifth of a second it re-derived the whole plan from scratch, and when two commands were nearly tie...

The Engineer and the Trainee: Adaptive MPC Guiding and Shielding Laya

Image
Two of my recent lander experiments kept nagging at me. In One Lander, Three Controllers , an adaptive MPC learned its engine during the flight and landed through a power loss with no training data at all. In Lunar Laya , a small decision model on Apple MLX turned a text description of the flight into structured choices, but the text carried hints from a fixed feedback law that assumed a healthy engine. Cut the engine power and that model crashed every time, faithfully following bad advice. So I asked the obvious question: what happens if the engineer writes the hints for the trainee? The result is Lunar MPC + Laya . An actual recorded flight. Laya proposes every command from telemetry alone; adaptive MPC vetoes about one in three. The engine loses 60% of its thrust at ten seconds, the estimate drops to 40%, and the lander touches down at seventy. The engineer and the trainee The game is the same arcade-style lander from Lunar Laya: three pads on bumpy terrain, a tilt control, a...

Lunar Laya: From State and Text to Decisions on a Mac

Image
I keep coming back to Lunar Lander. It gives me a very visible way to ask a simple question: what does a model actually decide? Turn too much, burn too late, or miss the pad, and the result is right there on the screen. After exploring learning and control approaches to this problem, I wanted to try another angle: give a small model the current state and a text instruction, then ask it for a decision that the application can execute and measure. That experiment is now public as Lunar Laya , an Atari-inspired lander using Laya with local inference on Apple MLX. I believe the input should be a state and a text, even a structured text. The output should always be structured and very deterministic, so it can be controlled and measured. This implementation is a representation of that idea. The fact that the model can be small enough to run locally in an MLX environment is proof that it can be done for this kind of bounded decision task. An actual trained-model flight using FP16 MLX ...

Nano FEL: GPT-2 and nanoGPT on the North Sea

After LoRA on a 4B model and a 1.2B model on the Mac , I kept asking myself a simpler question. How small can the model be, and how plain can the training loop be, before this North Sea task stops working? So I went back to the basics: GPT-2 medium, 355 million parameters, fully fine-tuned with Andrej Karpathy's nanoGPT . No adapters, no chat template, no grammar, no catalog in the prompt. Just a question in, a JSON query out. That is nanofel . The task is the same FELN translation: a question about wells, pipelines, and discoveries becomes a plan with layers , where , and relations . The twist here is the data format. nanoGPT trains on one flat stream of tokens and samples random windows from it, so each training pair is simply: Q: Which gas wells in Norway are within 2 kilometers of an oil pipeline? A: {"layers":["Wells","Pipelines"], "where":["content_type = cast(2 as SMALLINT) and (country = 'NO')","Pipelin...

FELN Qwen: Train on RTX, Run on Jetson Orin

Image
After teaching a small model to query the North Sea , I wanted to take the experiment onto a Jetson. Could I train on a powerful workstation, then move the model, application, and spatial database onto an NVIDIA Jetson Orin? And could it produce the expected FELN JSON accurately enough to be useful? That is the experiment behind feln-qwen . The job is specific: translate a question about wells, pipelines, and discoveries into FELN. The JSON identifies the layers, their attribute filters, and the spatial relationships between them. Layer order matters. Finding pipelines near discoveries is a different request from finding discoveries near pipelines! A huge thank you to Geodata for the beautiful NorthSea data . It gave this experiment a rich geospatial vocabulary and meaningful relationships to work with. I deeply appreciate the work and care behind this dataset. I chose Qwen3.5-9B and first verified stock-model inference on the Orin. The target machine had to support the model b...

FELN Liquid: Fine-Tuning a GIS Model on a Mac

I have been experimenting with small language models that translate everyday questions into structured GIS queries. With FELN Liquid , I wanted to explore the training side on the Mac itself. Could I take a compact model, teach it the conventions of a North Sea catalog, and complete the experiment locally? The first complete run used LiquidAI's LFM2.5-1.2B-Instruct with LoRA through MLX on an Apple M4 Max. Training took 48 minutes and 37 seconds. Including checkpoint evaluation and the final test, the workflow finished in just under an hour. That is a practical turnaround for trying an idea and inspecting what it learned. The task is familiar from the other FELN projects: turn a request into a JSON plan containing layers , where , and relations . A compact Layers.json catalog accompanies each request, supplying the names, types, aliases, codes, and hints that make the data meaningful. For example, “Show all wells with water depth > 350 meters” should produce: { ...

FELN WebGPU: A Language Model, a Database, and a Map in One Browser Tab

Image
I have been exploring how small language models can turn a plain-English question into a useful GIS query. With FELN LoRA, that meant training a model on a GPU and running it locally on my Mac. For feln-webgpu , I wanted to bring the language model, the database, and the map into the web application itself. Type “Give me all oil discoveries,” and the browser generates a query plan, compiles it to SQL, executes it, and draws the results. The example in the repository finds 562 discoveries, with 200 displayed. We can inspect the plan and SQL beside the map. I like being able to see what the model actually asked the database! The question, query plan, SQL, and resulting features in one browser tab. The pieces are a fine-tuned LiquidAI LFM2-350M model, Transformers.js running on WebGPU, DuckDB-Wasm with its spatial extension, and the ArcGIS Maps SDK for JavaScript. Once the assets have loaded, query generation and database execution happen on the user's machine. There is ...

FELN LoRA: Teaching a Small Model to Query the North Sea

In the FELN RAG experiment , I used a few relevant examples to help a language model translate a question into a spatial query. That got me interested in taking the next step: teaching a small model to do this particular job, then running it locally. I believe small language models have a big role to play in GIS. We have plenty of tasks with a well-defined vocabulary, a known catalog, and a very specific output. Turning a North Sea question into a query over wells, pipelines, and discoveries is one of them. That is the experiment behind feln-lora . The model is NVIDIA's Nemotron-3-Nano-4B, fine-tuned using LoRA and QLoRA through NeMo AutoModel . Training happens on an NVIDIA GPU. The resulting model runs on my Mac through llama.cpp and Metal, with the question staying on the machine. Now the best part: the latest local models produce a query in about 1.2 seconds at the warm median. That is a useful place to start for an interactive GIS workflow :-) Consider this question fr...

Teaching a Lunar Lander to Stop Hovering: DQN, Prioritized Replay, and n-Step Returns

Image
LunarLander looks simple: observe eight numbers, choose one of four engine actions, and guide a small craft between two flags. In practice, it exposes several failure modes that make Deep Q-Learning interesting. My first promising agents learned to approach the landing pad, then hovered above it until the episode timed out. Other runs climbed past a score of 100 and later collapsed. I built LunarLanderDRL to work through those problems in a compact PyTorch implementation. The final agent combines a Deep Q-Network (DQN), proportional prioritized experience replay, Double DQN, Huber loss, Polyak target updates, and three-step returns. Across three training seeds, the resulting checkpoints averaged 265.7 on 90 held-out episodes and recorded zero crashes . Two consecutive rollouts of the shipped policy, scoring 308.1 and 272.1. The problem Gymnasium's LunarLander-v3 returns an eight-dimensional observation: horizontal and vertical position, ...