Metadata-Version: 2.4
Name: resriv-net
Version: 0.2.2
Summary: ResRiv-Net: a station-conditioned residual correction network trained on top of a base model's predictions.
Author: Aisyah Amani Nurhasanah
License: MIT
Project-URL: Homepage, https://github.com/yourusername/resriv-net
Keywords: pytorch,residual-learning,time-series,hydrology
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Intended Audience :: Science/Research
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Requires-Dist: torch>=2.0
Requires-Dist: numpy>=1.23
Provides-Extra: test
Requires-Dist: pytest; extra == "test"

# ResRiv-Net

Station-conditioned residual correction network (PyTorch). Learns to correct a base
model's prediction (`base_pred`) using per-sample features (`x_honest`) and a station
identity embedding:

```
final_prediction = base_pred + ResidualNet(x_honest, station_id)
```

## Install

```bash
pip install resriv-net
```

For local development, from this directory:

```bash
pip install -e .
```

## Usage

```python
from resriv_net import ResRivNet

model = ResRivNet(
    n_features=len(honest_feat_cols),
    n_stations=n_stations,
    dim=128,
    cond_dim=16,
)

model.fit(
    Xtr_honest, sid_tr, base_train, ytr_all,
    fit_idx=fit_idx, val_idx=val_idx,
    epochs=200, batch_size=2048, lr=1e-3,
)

model.save("modelhasil.pt")
```

## Bundled base model (frozen embedding + head)

This build ships the project's own base-model checkpoint (`base_predictions.pt`) as
package data — a frozen "leaky" row-embedding + MLP head, indexed by row position
(val rows first, then test rows) — so it can be loaded without keeping a separate
local file:

```python
from resriv_net import load_resriv_model
import torch

emb_pretrained, head, n_val, n_test = load_resriv_model()

idx_val_local = torch.arange(0, n_val)
idx_test_local = torch.arange(n_val, n_val + n_test)

with torch.no_grad():
    pred_val_final = head(emb_pretrained(idx_val_local)).numpy()
    pred_test_final = head(emb_pretrained(idx_test_local)).numpy()
```

Both `emb_pretrained` and `head` are returned with `requires_grad=False` (frozen),
matching how the original training script uses them.

## Loading a checkpoint and fine-tuning further

```python
from resriv_net import ResRivNet

model = ResRivNet.load("modelhasil.pt")          # or ResRivNet.from_pretrained("modelhasil.pt")

# straight inference
preds = model.predict(Xte_honest, sid_te, base_test)

# or keep training on new/more data
model.fit(Xtr_honest, sid_tr, base_train, ytr_all, fit_idx=fit_idx, val_idx=val_idx, epochs=50)
model.save("modelhasil_v2.pt")
```

`ResRivNet.save()` bundles the learned weights together with the architecture
metadata (`n_features`, `n_stations`, `dim`, `cond_dim`) in one `.pt` file, so
`ResRivNet.load(...)` can reconstruct the model without you having to remember
those numbers separately.

## What the checkpoint does and does not contain

- `model.save("modelhasil.pt")` writes the **ResidualNet's learned weights**
  (`state_dict`) plus its architecture sizes. This is a real, loadable,
  fine-tunable model checkpoint.
- It does **not** contain the base model or `base_pred` itself — `base_pred` is
  always supplied separately at `fit`/`predict` time (whatever base model you
  used upstream to produce those numbers stays external to this package).

## Development

```bash
pip install -e ".[test]"
pytest
```
