Text Classification
Transformers
Safetensors
yield-weather-soil
crop-yield
multi-temporal
regression
yield-estimation
custom_code
Instructions to use ICICLE-AI/yield-estimation with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use ICICLE-AI/yield-estimation with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-classification", model="ICICLE-AI/yield-estimation", trust_remote_code=True)# Load model directly from transformers import AutoModelForSequenceClassification model = AutoModelForSequenceClassification.from_pretrained("ICICLE-AI/yield-estimation", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
| import sys | |
| from pathlib import Path | |
| PROJECT_ROOT = Path(__file__).resolve().parents[1] | |
| sys.path.insert(0, str(PROJECT_ROOT)) | |
| import argparse | |
| import json | |
| import numpy as np | |
| import pandas as pd | |
| import torch | |
| from torch.utils.data import DataLoader | |
| from transformers import AutoModel | |
| from data.dataset import YieldDataset | |
| from data.preprocessing import daily_to_cumulative_weekly, DEFAULT_WEATHER_AGG_RULES | |
| from hf.auto import register_yield_autoclass | |
| def parse_args(): | |
| p = argparse.ArgumentParser() | |
| p.add_argument("--hf_model_dir", required=True) | |
| p.add_argument("--input_file", default=None) | |
| p.add_argument("--single_sample_json", default=None) | |
| p.add_argument("--cutoff", type=int, required=True) | |
| p.add_argument("--batch_size", type=int, default=64) | |
| p.add_argument("--output_csv", default="inference_predictions.csv") | |
| return p.parse_args() | |
| def load_single_sample_json(path, cfg, cutoff): | |
| with open(path, "r") as f: | |
| sample = json.load(f) | |
| weather_format = sample.get("weather_format", "weekly_cumulative") | |
| weather_cols = [] | |
| for v in cfg.weather_vars: | |
| if v not in sample["weather"]: | |
| raise ValueError(f"Missing weather variable in JSON: {v}") | |
| arr = np.asarray(sample["weather"][v], dtype=np.float32) | |
| if weather_format == "daily": | |
| agg = DEFAULT_WEATHER_AGG_RULES.get(v, "mean") | |
| arr = daily_to_cumulative_weekly(arr, agg=agg, week_len=7) | |
| elif weather_format in ("weekly", "weekly_cumulative"): | |
| pass | |
| else: | |
| raise ValueError( | |
| "weather_format must be 'daily', 'weekly', " | |
| "or 'weekly_cumulative'." | |
| ) | |
| weather_cols.append(arr) | |
| lengths = [len(x) for x in weather_cols] | |
| if len(set(lengths)) != 1: | |
| raise ValueError(f"Weather variable lengths do not match after aggregation: {lengths}") | |
| weather = np.stack(weather_cols, axis=1).astype(np.float32) | |
| soil = [] | |
| for v in cfg.soil_vars: | |
| if v not in sample["soil"]: | |
| raise ValueError(f"Missing soil variable in JSON: {v}") | |
| soil.append(float(sample["soil"][v])) | |
| soil = np.asarray(soil, dtype=np.float32) | |
| w_mean = np.asarray(cfg.w_mean, dtype=np.float32) | |
| w_std = np.asarray(cfg.w_std, dtype=np.float32) | |
| s_mean = np.asarray(cfg.s_mean, dtype=np.float32) | |
| s_std = np.asarray(cfg.s_std, dtype=np.float32) | |
| weather = np.where(np.isnan(weather), w_mean[None, :], weather) | |
| weather = (weather - w_mean[None, :]) / w_std[None, :] | |
| soil = np.where(np.isnan(soil), s_mean, soil) | |
| soil = (soil - s_mean) / s_std | |
| crop_map = {"corn": 0, "maize": 0, "soybean": 1, "soy": 1} | |
| crop = str(sample.get("crop", "corn")).strip().lower() | |
| crop_id = crop_map.get(crop, 0) | |
| t_eff = min(cutoff, weather.shape[0]) | |
| return { | |
| "weather": torch.from_numpy(weather[:t_eff]).unsqueeze(0), | |
| "soil": torch.from_numpy(soil).unsqueeze(0), | |
| "crop_id": torch.tensor([crop_id], dtype=torch.long), | |
| "t_eff": t_eff, | |
| } | |
| def main(): | |
| args = parse_args() | |
| register_yield_autoclass() | |
| if args.input_file is None and args.single_sample_json is None: | |
| raise ValueError("Provide either --input_file or --single_sample_json.") | |
| if args.input_file is not None and args.single_sample_json is not None: | |
| raise ValueError("Use only one: --input_file OR --single_sample_json.") | |
| device = torch.device("cuda" if torch.cuda.is_available() else "cpu") | |
| model = AutoModel.from_pretrained(args.hf_model_dir).to(device) | |
| model.eval() | |
| cfg = model.config | |
| if args.single_sample_json is not None: | |
| sample = load_single_sample_json(args.single_sample_json, cfg, args.cutoff) | |
| weather = sample["weather"].to(device) | |
| soil = sample["soil"].to(device) | |
| crop_id = sample["crop_id"].to(device) | |
| t_eff = sample["t_eff"] | |
| out = model( | |
| weather=weather, | |
| soil=soil, | |
| crop_id=crop_id, | |
| horizon_idx=t_eff, | |
| causal=True, | |
| return_sequence=False, | |
| ) | |
| pred = float(out.predictions.item()) | |
| Path(args.output_csv).parent.mkdir(parents=True, exist_ok=True) | |
| pd.DataFrame([{ | |
| "sample_idx": 0, | |
| "cutoff": int(args.cutoff), | |
| "y_pred": pred, | |
| }]).to_csv(args.output_csv, index=False) | |
| print(f"Predicted yield: {pred:.4f}") | |
| print(f"Saved inference prediction to {args.output_csv}") | |
| return | |
| ds = YieldDataset( | |
| data_file=args.input_file, | |
| weather_vars=cfg.weather_vars, | |
| soil_vars=cfg.soil_vars, | |
| split="all", | |
| seed=1234, | |
| crop=None, | |
| years=None, | |
| require_yield=False, | |
| ) | |
| ds.set_normalization( | |
| cfg.w_mean, | |
| cfg.w_std, | |
| cfg.s_mean, | |
| cfg.s_std, | |
| ) | |
| loader = DataLoader(ds, batch_size=args.batch_size, shuffle=False) | |
| rows = [] | |
| sample_idx = 0 | |
| for batch in loader: | |
| weather = batch["weather"].to(device) | |
| soil = batch["soil"].to(device) | |
| crop_id = batch["crop_id"].to(device) | |
| t_eff = min(args.cutoff, weather.size(1)) | |
| out = model( | |
| weather=weather[:, :t_eff, :], | |
| soil=soil, | |
| crop_id=crop_id, | |
| horizon_idx=t_eff, | |
| causal=True, | |
| return_sequence=False, | |
| ) | |
| for pred in out.predictions.detach().cpu().numpy().tolist(): | |
| rows.append({ | |
| "sample_idx": sample_idx, | |
| "cutoff": int(args.cutoff), | |
| "y_pred": float(pred), | |
| }) | |
| sample_idx += 1 | |
| Path(args.output_csv).parent.mkdir(parents=True, exist_ok=True) | |
| pd.DataFrame(rows).to_csv(args.output_csv, index=False) | |
| print(f"Saved inference predictions to {args.output_csv}") | |
| if __name__ == "__main__": | |
| main() |