Build models that predict pasture biomass from images, ground-truth measurements, and publicly available datasets. Farmers will use these models to determine when and how to graze their livestock.
The Image2Biomass competition challenges participants to develop machine learning models that can accurately predict pasture biomass from RGB images of Australian pastures. The goal is to help farmers optimize grazing times and methods by providing reliable biomass estimates.
Predict five biomass components per pasture image:
- Dry_Green_g: Dry green vegetation biomass (grams)
- Dry_Dead_g: Dry dead material biomass (grams)
- Dry_Clover_g: Dry clover biomass (grams)
- GDM_g: Green dry matter (calculated as Dry_Green_g + Dry_Clover_g)
- Dry_Total_g: Total dry biomass (calculated as Dry_Green_g + Dry_Dead_g + Dry_Clover_g)
Models are evaluated using a globally weighted coefficient of determination (RΒ²) across all predictions:
RΒ² = 1 - (SS_res / SS_tot)
Where:
- SS_res (Residual Sum of Squares) = Ξ£(w_j Γ (y_j - Ε·_j)Β²)
- SS_tot (Total Sum of Squares) = Ξ£(w_j Γ (y_j - Θ³_w)Β²)
Target Weights:
- Dry_Green_g: 0.1
- Dry_Dead_g: 0.1
- Dry_Clover_g: 0.1
- GDM_g: 0.2
- Dry_Total_g: 0.5 (most important!)
- 357 unique pasture images (1,785 rows in CSV)
- Format: Long format with 5 rows per image (one per biomass target)
- Images: RGB JPEGs (2000Γ1000 pixels, resized to 1024Γ512 for training)
- Metadata: State, species, NDVI, average height
- Targets: Continuous values in grams (0.0 to 185.7g, mean ~24.8g)
- ~800 images (hidden during development)
- Same format as training data but without target values
- Metadata available at test time
sample_id,image_path,Sampling_Date,State,Species,Pre_GSHH_NDVI,Height_Ave_cm,target_name,target
ID1011485656__Dry_Clover_g,train/ID1011485656.jpg,2015/9/4,Tas,Ryegrass_Clover,0.62,4.6667,Dry_Clover_g,0.0
ID1011485656__Dry_Dead_g,train/ID1011485656.jpg,2015/9/4,Tas,Ryegrass_Clover,0.62,4.6667,Dry_Dead_g,31.9984
...# Clone repository
git clone <repository-url>
cd kaggle-image2biomass
# Create virtual environment
python -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
# Install dependencies
pip install -r requirements.txtpython test_pipeline.pypython train.pypython evaluate.py <experiment_name>python create_submission.py models/<experiment_name>/model_best.pthkaggle-image2biomass/
βββ config.py # Hyperparameters and configuration
βββ dataloader.py # Data loading and preprocessing
βββ model.py # SimpleCNN model architecture
βββ train.py # Training loop with WandB logging
βββ evaluate.py # Model evaluation and metrics
βββ create_submission.py # Kaggle submission generation
βββ test_pipeline.py # Pipeline testing and validation
βββ eda.ipynb # Exploratory data analysis notebook
βββ QUICK_REFERENCE.py # Quick reference guide
βββ requirements.txt # Python dependencies
βββ README.md # This file
βββ LICENSE # GNU AGPL v3 License
βββ diagrams/ # Architecture diagrams (SVG)
βββ dataset/
β βββ train.csv # Training data (long format)
β βββ test.csv # Test data (long format)
β βββ sample_submission.csv
β βββ train/ # Training images
β βββ test/ # Test images
βββ models/ # Saved model checkpoints (created during training)
Standard Architecture (Multi-Output): Predicts all 3 biomass targets simultaneously from a single forward pass.
Conditioned Architecture (Single-Output): Predicts one biomass target at a time, conditioned on which target to predict. Requires 3 forward passes per image (one per target).
Auxiliary Metadata Prediction: Optional additional prediction heads for metadata (species, state, NDVI, height) trained jointly with biomass targets.
Feature Extractors: Choice between custom SimpleCNN or pretrained Timm models (ResNet, EfficientNet, etc.).
- 5 convolutional blocks: Conv2D β BatchNorm β ReLU β MaxPool
- Global Average Pooling
- Fully Connected layers: 256 β 128 β 3 outputs
- Total parameters: ~2.7M
- Input: 512Γ1024Γ3 RGB images
- Output: 3 biomass predictions (Dry_Green_g, Dry_Dead_g, Dry_Clover_g)
- Uses any pretrained backbone from the
timmlibrary (e.g., ResNet, EfficientNet) - Custom regression head: Backbone features β 512 β 256 β 3 outputs
- Supports pretrained weights for transfer learning
- Optional backbone freezing for feature extraction only
The target-conditioned architecture is a new approach where the model predicts one biomass component at a time, conditioned on which component it should predict.
- Architecture: Same as SimpleCNN but with target conditioning
- Input:
- RGB image (3 channels)
- One-hot encoded target name (3-dimensional: Dry_Clover_g, Dry_Dead_g, Dry_Green_g)
- Output: Single biomass value (regression)
- Feature fusion: Target encoding is concatenated to conv features before FC layers
- Architecture: Timm backbone + target conditioning
- Input: Same as ConditionedSimpleCNN
- Output: Single biomass value
- Feature fusion: Target encoding is concatenated to backbone features
Training:
- Dataset filters out
Dry_Total_gandGDM_grows (we don't predict these directly) - Each training sample is one image + one target type
- Model receives image and one-hot encoding of which target to predict
- Model outputs a single biomass value
- Training loss is computed on this single value
Inference/Evaluation:
- For each image, run the model 3 times:
- Once with target_name = "Dry_Clover_g"
- Once with target_name = "Dry_Dead_g"
- Once with target_name = "Dry_Green_g"
- Calculate derived targets:
GDM_g = Dry_Green_g + Dry_Clover_gDry_Total_g = Dry_Green_g + Dry_Dead_g + Dry_Clover_g
Benefits:
- β Better performance: RΒ² 0.45 vs 0.30 for standard models
- β More training data: 3x more samples per image
- β Specialization: Model focuses on one component at a time
- β Correct derived targets: GDM and Dry_Total are exact sums
- β Flexible inference: Can predict any subset of targets
- ReLU Activation on the final layers since the target values are positive
- Dropout regularization (0.3) prevents overfitting
- Batch normalization for stable training
- Auxiliary task support for metadata prediction (optional)
- Mixed precision training with FP16/BF16 for faster training
- Gradient accumulation for large effective batch sizes
| Architecture | Validation RΒ² (5 epochs) | Training Speed | Model Size |
|---|---|---|---|
| ConditionedTimmModel | 0.45 | ~5.8s/epoch | 30.9M params |
| TimmModel | ~0.30 | ~5.5s/epoch | 30.9M params |
| ConditionedSimpleCNN | ~0.25 | ~6.2s/epoch | 11.2M params |
ConditionedTimmModel with regnety_064 backbone achieves the best performance on validation set.
BATCH_SIZE = 8
NUM_EPOCHS = 200
LEARNING_RATE = 1e-4
WEIGHT_DECAY = 1e-5
EARLY_STOPPING_PATIENCE = 20- Horizontal/vertical flips
- Random rotations (Β±15Β°)
- Brightness/contrast adjustments
- ImageNet normalization
- Weights & Biases integration with live training dashboard
- Real-time monitoring at: wandb.ai/animikhaich/kaggle-image2biomass
- Automatic logging of metrics, losses, and hyperparameters
- Model checkpoints saved every 5 epochs
- Best model saved based on validation RΒ²
python train.py- Weighted RΒ² (competition metric)
- MAE (Mean Absolute Error)
- RMSE (Root Mean Squared Error)
- MAPE (Mean Absolute Percentage Error)
- Per-target metrics for all 5 biomass components
# Evaluate on validation set
python evaluate.py <experiment_name> val
# Evaluate on training set (check overfitting)
python evaluate.py <experiment_name> trainpython create_submission.py models/<experiment_name>/model_best.pth submission.csvsample_id,target
ID1001187975__Dry_Clover_g,0.0
ID1001187975__Dry_Dead_g,15.2
ID1001187975__Dry_Green_g,8.7
ID1001187975__Dry_Total_g,23.9
ID1001187975__GDM_g,8.7All hyperparameters are centralized in config.py:
- Data settings: Image dimensions, batch size, splits
- Model settings: Architecture parameters, output dimensions
- Training settings: Learning rate, epochs, early stopping
- Augmentation: Transformation parameters
- WandB settings: Project name, entity
# Standard architectures (predict all 3 targets at once)
USE_TARGET_CONDITIONING = False
ARCHITECTURE = "SimpleCNN" # Simple custom CNN
# or
ARCHITECTURE = "TimmModel" # Pretrained backbone
TIMM_BACKBONE = "resnet34.a1_in1k"
# Target-conditioned architectures (RECOMMENDED - best performance)
USE_TARGET_CONDITIONING = True
ARCHITECTURE = "ConditionedTimmModel" # Pretrained backbone with target conditioning
TIMM_BACKBONE = "regnety_064" # Best performing backbone
# or
ARCHITECTURE = "ConditionedSimpleCNN" # Simple CNN with target conditioningTo use the new target-conditioned architecture:
-
Update
config.py:USE_TARGET_CONDITIONING = True ARCHITECTURE = "ConditionedSimpleCNN" # or "ConditionedTimmModel" # If using ConditionedTimmModel, also specify the backbone: TIMM_BACKBONE = "regnety_064" # or any other timm model
Important: The
ARCHITECTUREandUSE_TARGET_CONDITIONINGsettings must match:- If
USE_TARGET_CONDITIONING = True, use"ConditionedSimpleCNN"or"ConditionedTimmModel" - If
USE_TARGET_CONDITIONING = False, use"SimpleCNN"or"TimmModel"
The training script will raise an error if these settings don't match.
- If
-
Train the model:
python train.py
- Training data will automatically filter out
Dry_Total_gandGDM_grows - Each sample will be (image, target_name, single_biomass_value)
- Model will learn to predict the correct component based on target_name input
- Training data will automatically filter out
-
Evaluate the model:
python evaluate.py <experiment_name>
- Evaluation will automatically run 3x inference per image
- Derived targets (GDM_g, Dry_Total_g) will be calculated from predictions
-
Create submission:
python create_submission.py --checkpoint models/<experiment_name>/model_best.pth
- Submission generation will automatically run 3x inference
- All 5 targets will be calculated correctly
Note: The conditioned architecture is fully compatible with:
- All training configurations (learning rate, batch size, etc.)
- Cross-validation
- Auxiliary metadata prediction
- All available backbones (for ConditionedTimmModel)
- Mixed precision training
LEARNING_RATE: Most important hyperparameter (start with 1e-4)BATCH_SIZE: 8 for RTX 3090, adjust based on GPU memoryARCHITECTURE: ConditionedTimmModel with regnety_064 is recommendedUSE_METADATA_AUX: Set to True for small performance boostMIXED_PRECISION_TYPE: Use "fp16" for faster training (if GPU supports)
# Target-conditioned setup - best performance
USE_TARGET_CONDITIONING = True
ARCHITECTURE = "ConditionedTimmModel"
TIMM_BACKBONE = "regnety_064"
USE_METADATA_AUX = True
MIXED_PRECISION_TYPE = "fp16"
LEARNING_RATE = 1e-4
BATCH_SIZE = 8# 1. Configure for target conditioning
# Edit config.py with the settings above
# 2. Train model
python train.py
# 3. Evaluate on validation set
python evaluate.py <experiment_name> val
# 4. Generate submission
python create_submission.py models/<experiment_name>/model_best.pthThis configuration typically achieves RΒ² β 0.45 on validation after just 5 epochs.
Run the EDA notebook to understand the data:
jupyter notebook eda.ipynbKey insights:
- Biomass distributions by state and species
- Correlation between targets
- Image characteristics
- Metadata relationships
pandas
numpy
matplotlib
seaborn
pillow
opencv-python
wandb
ipython
scikit-learn
torch>=2.0
torchvision
albumentations- Fixed random seed (42) for all operations
- Deterministic PyTorch operations
- Same train/validation split
- Version-controlled code and data
| Feature | Standard Models | Target-Conditioned Models |
|---|---|---|
| Training samples | 1 per image (357 total) | 3 per image (1,071 total) |
| Model inputs | Image only | Image + target_name encoding |
| Model outputs | 3 values at once | 1 value at a time |
| Inference | 1 forward pass per image | 3 forward passes per image |
| Derived targets | Calculated from 3 predictions | Calculated from 3 predictions |
| Training time | Faster (fewer forward passes) | Slower (more samples, but simpler task) |
| Use case | Standard multi-output regression | Specialized per-component prediction |
Modify model.py to implement:
- Transfer learning (ResNet, EfficientNet)
- Attention mechanisms
- Multi-scale features
- Advanced pooling strategies
Use WandB sweeps for systematic tuning:
# Example sweep configuration
sweep_config = {
'method': 'bayes',
'metric': {'name': 'val/weighted_r2', 'goal': 'maximize'},
'parameters': {
'learning_rate': {'min': 1e-5, 'max': 1e-3},
'batch_size': {'values': [4, 8, 16]},
'dropout': {'min': 0.1, 'max': 0.5}
}
}- Train multiple models with different seeds
- Average predictions for improved performance
- Use different architectures
This implementation provides K-fold cross-validation for robust model evaluation.
-
Enable cross-validation in
config.py:USE_CROSS_VALIDATION = True N_FOLDS = 5 # Number of folds
-
Train all folds:
python train.py
-
Train specific fold only:
FOLD_TO_TRAIN = 2 # Train fold 2 (0-indexed)
python train.py
config.py parameters:
-
USE_CROSS_VALIDATION: bool (default: False)
Set to True to enable K-fold cross-validation -
N_FOLDS: int (default: 5)
Number of folds for cross-validation -
FOLD_TO_TRAIN: int or None (default: None)- None: Train all folds sequentially
- 0 to N_FOLDS-1: Train only specific fold
-
CROSS_VAL_SEED: int (default: same as SEED)
Random seed for reproducible fold splits -
SAVE_FOLD_MODELS: bool (default: True)
Save best model for each fold in separate directories
When USE_CROSS_VALIDATION = True:
models/
βββ experiment-name/
βββ fold_0/
β βββ model_best.pth
β βββ model_epoch_*.pth
βββ fold_1/
β βββ model_best.pth
β βββ model_epoch_*.pth
...
βββ cv_results.json # Summary of all folds
Cross-validation metrics are logged with fold-specific prefixes:
- fold_0/train/loss
- fold_0/val/weighted_r2
- fold_1/train/loss
- fold_1/val/weighted_r2 ...
Summary metrics:
- cv/avg_r2: Average RΒ² across all folds
- cv/std_r2: Standard deviation of RΒ²
- cv/min_r2: Minimum RΒ² across folds
- cv/max_r2: Maximum RΒ² across folds
-
Use same seed (
CROSS_VAL_SEED = SEED) for reproducibility -
For final model selection:
- Train all folds to get robust performance estimate
- Use average metrics across folds
- Select best fold's model or ensemble predictions
-
For faster experimentation:
- Set
FOLD_TO_TRAINto specific fold - Useful for hyperparameter tuning
- Set
-
Recommended folds:
- Small dataset (<500 samples): N_FOLDS = 5
- Medium dataset (500-5000): N_FOLDS = 5-10
- Large dataset (>5000): N_FOLDS = 3-5
To create ensemble predictions from all folds:
- Train all folds (
FOLD_TO_TRAIN = None) - Load each fold's best model
- Average predictions across folds
Example:
import torch
from model import load_model
fold_models = []
for fold_idx in range(N_FOLDS):
checkpoint = f"models/experiment/fold_{fold_idx}/model_best.pth"
model, *_ = load_model(checkpoint, device)
fold_models.append(model)
# Make predictions
predictions = []
for model in fold_models:
pred = model(images)
predictions.append(pred)
# Ensemble (average)
final_pred = torch.mean(torch.stack(predictions), dim=0)Single Split (USE_CROSS_VALIDATION = False):
- Faster training (train once)
- May overfit to specific validation set
- Less reliable performance estimate
Cross-Validation (USE_CROSS_VALIDATION = True):
- More robust performance estimate
- Reduces validation set selection bias
- Longer training time (train N_FOLDS models)
- Better for model selection and hyperparameter tuning
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit changes (
git commit -m 'Add amazing feature') - Push to branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the GNU Affero General Public License v3.0 - see the LICENSE file for details.
- Kaggle for hosting the competition
- Agriculture Victoria for providing the dataset
- PyTorch and Albumentations communities
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Competition Forum: Kaggle Discussion
Happy modeling! πΎ