I. Stakes

Famines, conflicts, and refugee surges are usually visible in the news weeks or months before relief organizations mobilize. The pattern is in the coverage. The hard part is reading it at scale.

Existing crisis-response systems are reactive. By the time UNHCR, WHO, or a national government acts, the crisis has already cost lives. Forecasting tools exist, FEWS NET and ACAPS among them, but they rely on hand-curated indicators and operate on monthly cadences, while more than 100 million people were displaced globally as of 2024, per UNHCR.

Can a model trained on the language of crisis reporting predict when the next one will surface?

ForeHumanity asks that simpler question. If the answer is yes, even by a few weeks, the lead time is enough to pre-position aid.

II. Constraints

  • DataEvery NYT article, 2000 to 2024, roughly 2 million, via the Archive API
  • SignalSupervised, against a labeled crisis ledger
  • ComputeOne consumer GPU for fine-tuning; CPU-only inference
  • Explainer65 MB of LoRA adapters on a 14 GB base model
  • ProductNo forecast ships without a rationale attached

III. Decisions

Structure the archive before learning from it

Every article from the NYT archive between 2000 and 2024, parsed for keywords, section, and timestamp. Multi-hot encoded, time normalized to [0, 1], then used as supervised signal against the crisis ledger. The pipeline is four stages, and the last one, labeling, is where the real work is.

  • 01 · SourceNYT Archive API · 2000 to 2024
  • 02 · CleanKeyword + section parse · drop boilerplate, dedupe, lemmatize
  • 03 · EncodeMulti-hot vectors · timestamps normalized to [0, 1]
  • 04 · LabelCrisis ledger · UNHCR, OCHA, ACLED merge

Two models, one pipeline

A TensorFlow/Keras classifier predicts when the next crisis tied to a keyword will surface; a LoRA-fine-tuned Mistral 7B explains why. The forecaster is a dense network over multi-hot keyword vectors plus section embeddings, trained with MSE loss on labeled crisis events. Its output is a normalized timestamp in [0, 1] that denormalizes back into a real date.

The explainer is Mistral 7B base with adapters trained on prompt-completion pairs derived from the crisis ledger plus surrounding NYT context. It runs on CPU with the peft and transformers stack, and it generates a natural-language rationale for each prediction.

LoRA over full fine-tuning

The choice was deliberate. The adapters are 65 MB against Mistral's 14 GB, training ran on a single consumer GPU, and the explainer can be retrained as new crisis data lands without touching the base model.

65 MBLoRA adapters on disk
14 GBMistral 7B base weights
1 GPUConsumer card, full fine-tune run

IV. What shipped

A Streamlit app that runs the whole inference path on CPU. A bare classifier output, a date, is not a useful product for a humanitarian operator, so every forecast ships wrapped in a generated rationale that names the keywords driving the prediction and the historical patterns the model is matching against.

Enter famine and the system predicts a date, then writes a paragraph explaining which historical episodes the prediction resembles and which early-warning indicators are most active. The prediction becomes something an operator can interrogate instead of a number to take on faith.

app.pyStreamlit inference path · CPU
# app.py · Streamlit forecasting interface
from transformers import AutoTokenizer, AutoModelForCausalLM
from data_preprocessing import (load_and_clean_data, parse_keywords,
                                normalize_timestamp, create_multi_hot_vectors)

@st.cache_resource
def load_lora_model(lora_path="./lora_mistral_ckpt"):
    tokenizer = AutoTokenizer.from_pretrained(lora_path)
    model = AutoModelForCausalLM.from_pretrained(lora_path).to("cpu")
    return tokenizer, model

def denormalize_timestamp(norm_val, min_ts, max_ts):
    pred_ts = norm_val * (max_ts - min_ts) + min_ts
    return datetime.datetime.utcfromtimestamp(pred_ts)
Listing 01 — The Streamlit inference path. CPU-only; the adapters load from lora_mistral_ckpt/.

V. Results

The money result

84.6% pattern detection, and 88% of crises dated within four weeks.

Measured on the held-out 20% of crisis ledger events, the events the model never saw during training. Tighten the window to two weeks and the number drops to 71%; the drop is the finding.

84.6%Pattern detection · holdout
88%Dated within ±4 wk · holdout
71%Dated within ±2 wk · holdout

The honest reading: the model knows a crisis is coming well before it can say precisely when. 88% of held-out events land inside a four-week window but only 71% inside two, and closing that gap is the future work. The judges read it the same way; the project took the Betterment of Humanity Award at the Synopsys Championship 2025 and third place in Mathematical Sciences at CSEF 2025.

VI. What I learned

  • An unexplained forecast is not a product. A date alone is unusable for a humanitarian operator; the LoRA explainer is what turns a classifier into a tool. Wrapping the prediction in language was as much work as making it, and worth more.
  • The label ledger is the model. Merging UNHCR, OCHA, and ACLED records into one crisis ledger was the real research; the network just compresses it. Supervised learning is only as honest as its labels.

Colophon