# AgML: agricultural datasets that arrive as Hugging Face columns

> A UC Davis library for agricultural machine learning that publishes its datasets on the Hugging Face Hub as plain DatasetDict objects, then hands you to datasets and transformers for everything past loading and splitting. The annotation columns and the empty console-script table are the two details that shape how it is used.

**Project-AgML/AgML** — AgML is a centralized framework for agricultural machine learning. AgML provides access to public agricultural datasets for common agricultural deep learning tasks, with standard benchmarks and pretrained models, as well the ability to generate synthetic data and annotations.

- Repository: https://github.com/Project-AgML/AgML
- Website: https://project-agml.github.io
- Stars: 347 · Forks: 54
- Language: Python
- License: Apache-2.0
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/project-agml-agml

## pip install agml is the whole install story

Installation is one line, and the readme does not add a second path to it:

```shell
pip install agml
```

The library covers agricultural machine learning and states support for both TensorFlow and PyTorch, which is unusual for a package whose datasets are hosted as Hugging Face objects. The default branch is main and the licence is Apache-2.0. Browsing is expected to happen away from the repository: the homepage at project-agml.github.io is where the dataset list, the documentation and comparisons of model performance on a crop or task of interest are meant to be read.

The project comes out of the AI Institute for Food Systems at UC Davis, which is also named as a partial funder. The package metadata credits the UC Davis Plant AI and Biophysics Lab as the authors, jmearles@ucdavis.edu, with Jared Smith, jrssmith@ucdavis.edu, as a maintainer.

## Datasets arrive as a Hugging Face DatasetDict

Every dataset lives on the Hugging Face Hub under the Project-AgML organization, and one loader class pulls it down:

```python
from agml.data import HuggingFaceDataLoader

# Load a dataset from the Hub
loader = HuggingFaceDataLoader("Project-AgML/apple_flower_segmentation")

# Load a specific config/subset (e.g. an augmented variant)
loader = HuggingFaceDataLoader("Project-AgML/apple_flower_segmentation", config="augmented")
```

The second argument is the one to notice. A dataset name plus a config name is how you reach an augmented variant of the same underlying data, so the choice between the base and the augmented version is a parameter rather than a different identifier to look up.

One convenience is automatic: HuggingFaceDataLoader casts the image, mask and image-typed label columns to the Hugging Face Image type, which is what gives decoded pixel access. You do not write that conversion yourself, and it applies to any image-like column, not only to columns with conventional names.

## split() returns train, val and test, and then AgML steps aside

Splitting is the last thing AgML asks you to call:

```python
dataset = loader.split(val_size=0.1, test_size=0.1, stratify_cols="label")
# Returns a DatasetDict with 'train', 'val', and 'test' splits

# Access the underlying DatasetDict at any time
dataset = loader.dataset
```

Stratification takes one column or several, so a split can be balanced on the label itself or on any other column you name. After that call the readme is unusually explicit: for any preprocessing, inference or training beyond loading and splitting, use the datasets and transformers libraries directly.

The reason is visible in the next snippet. Because loader.dataset is a native DatasetDict, map, filter and with_transform work on it, and a Trainer trains against it:

```python
processor = AutoImageProcessor.from_pretrained("google/vit-base-patch16-224")
model = AutoModelForImageClassification.from_pretrained(
    "google/vit-base-patch16-224",
    num_labels=dataset["train"].features["label"].num_classes,
)
```

So the number of classes is read from the split you just built, and there is no AgML-specific processing API to learn beyond this point.

## Three tasks share one annotation format

The reason datasets on the Hub are usable together is that annotations are columns with a fixed convention per task. Image classification uses a label column of type ClassLabel. Object detection uses an objects column holding COCO-style bounding boxes and the matching category IDs, with the boxes given as un-normalized x_min, y_min, width, height and the category IDs carried as a ClassLabel per image. Semantic segmentation uses a mask column, a single-channel image in L mode, the same size as the image it belongs to.

Two things follow from that. The un-normalized box format means your own transform has to divide by the image dimensions, since a pipeline expecting coordinates in 0 to 1 will not accept these as they arrive. And because the mask is an image of matching size rather than a class index, a segmentation consumer gets pixel values from the same access path as the picture itself.

The stated aim is that multiple datasets can be synthesised into a single training pipeline, and column-based annotations are the mechanism. Task and modality filters are available programmatically through agml.data.public_data_sources(...), with filtering and previews in the browser on the Dataset Search page.

## iNatAg filters by family name or common name

The collection with its own API is iNatAg, alongside a smaller variant called iNatAg-mini for smaller-scale applications. It is described as one of the largest collections of agricultural images dedicated to image classification, holding over 4 million images with detailed species classifications, and the filters select taxonomic groups rather than dataset names:

```python
# To select a collection of scientific family names.
loader = agml.data.AgMLDataLoader.from_parent("iNatAg", filters={"family_name": ["...", "..."]})

# To select common names.
loader = agml.data.AgMLDataLoader.from_parent("iNatAg", filters={"common_name": "..."})
```

So iNatAg goes through a different constructor from the Hub loader. from_parent takes the collection name and a filters dictionary keyed by family_name or common_name, and iNatAg-mini is chosen by the same call. Anything you do with the result afterwards goes through the same split and DatasetDict path as the apple flower dataset, which is the point of putting both behind one loader core.

## The wheel installs no console command

The packaging metadata is worth reading before you plan an installation. The build backend is hatchling, the package name is agml, and requires-python is set to >=3.10 with classifiers covering 3.10 through 3.13. The status is declared as Beta, and Typing :: Typed is claimed. The internal package agml/_internal is excluded from the distribution.

The part that surprises people is [project.scripts]. The table exists in pyproject.toml and is empty, so pip install agml puts no executable on your PATH. Everything in the readme is a Python import, and there is no command to learn, which also means no CLI to fall back on when a script misbehaves.

The version appears in three separate places that have to agree: the version field in pyproject.toml, a version variable in the Makefile, and the release tag itself. All three currently read 0.8.1, and the release dates are 12 September 2026, 10 July 2026 and 22 April 2025 for v0.8.1, v0.8.0 and v0.7.4.

## make test hands the suite to uv and pytest

Development runs through uv, and the Makefile is the entry point. Two targets matter:

```text
build: $(build.wheel) ## Build the distribution wheel.
test: $(test.python) $(src.python) # Run tests
```

The wheel target runs uv build -o dist, and the test target runs pytest through uv with an explicit configuration path, config/pytest.ini, against every Python file found under tests/. Both depend on file lists built by find over agml/ and tests/, so the targets rebuild when sources change without a manual clean step.

Two rough edges are visible in the file. The wheel variable is named for a .tar.gz path while the recipe is a uv build, which produces a wheel and a source distribution, and the help target is a grep over lines carrying a double-hash comment rather than a maintained list. Neither breaks a build, but both mean the Makefile is a thin wrapper around uv rather than a build system of its own. The repository also carries both uv.lock and environment.yml, so a conda-based workflow and a uv-based workflow sit side by side.

## Four notebooks name the four things AgML does

The examples directory spells out the intended surface area: AgML-Data.ipynb, AgML-Detector.ipynb, AgML-Models.ipynb and AgML-Synthetic.ipynb. Data, detector, models, synthetic. The readme documents the first of those in detail and points at the rest, so the loader and split path is the part you can follow from the page, while object detection, pretrained models and synthetic data are where you have to open the notebooks.

The rest of the top level supports that reading. There is an agml package directory, config/ for the pytest configuration and whatever else the tools need, docs/, experiments/, scripts/ and tests/, plus AUTHORS, CODE_OF_CONDUCT.md, CONTRIBUTING.md, MANIFEST.in and a Makefile. The project description mentions synthetic data generation, standard benchmarks and pretrained models alongside the public datasets; none of those three is explained on this page.

Two contribution paths are named. Feature and bug reports go through the Issues tab, the general guidelines sit at project-agml.github.io/docs/development, and there is a separate guide at project-agml.github.io/docs/contributing-results for people with benchmark results to submit.

## Conclusion

AgML is worth adopting for the dataset layer and nothing else. If your work starts from public agricultural images and you already use datasets and transformers, the loader adds a Hub location, a split with stratification and three annotation conventions without asking you to learn a second API. If you want synthetic data generation, pretrained models or benchmark numbers, the description promises them and this page documents none of them, so treat that as something to check rather than assume. Before building on it, check that the split you need is reachable through agml.data.public_data_sources and confirm the Python version against the 3.10 floor.

## FAQ

### How do I install AgML and load one of its datasets?

Run pip install agml, then use HuggingFaceDataLoader with a Hub identifier under the Project-AgML organization, for example HuggingFaceDataLoader("Project-AgML/apple_flower_segmentation"). Add config="augmented" to load an augmented variant of the same dataset.

### Does AgML have its own preprocessing and training API?

No. Loading and splitting are the AgML steps, and loader.split returns a native Hugging Face DatasetDict, so datasets map, filter and with_transform plus the transformers Trainer and Pipeline work on it directly.

### How are AgML annotations stored for detection and segmentation?

Object detection uses an objects column with COCO-style boxes given as un-normalized x_min, y_min, width, height and category IDs as a ClassLabel per image. Semantic segmentation uses a mask column holding a single-channel image the same size as the picture.

### How do I filter AgML datasets without browsing the website?

Call agml.data.public_data_sources(...) with task and modality filters. The iNatAg collection has its own entry point, AgMLDataLoader.from_parent, taking filters keyed by family_name or common_name.

## Sources

- [License: Apache-2.0](https://github.com/Project-AgML/AgML/blob/main/LICENSE)
- [Project-AgML/AgML on GitHub](https://github.com/Project-AgML/AgML)
- [Project website](https://project-agml.github.io)
- [README](https://github.com/Project-AgML/AgML/blob/main/README.md)
- [Releases](https://github.com/Project-AgML/AgML/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/project-agml-agml
