Cache Sessions Guide
Version: 2.5.1
What Problem Does Cache Isolation Solve?
Section titled “What Problem Does Cache Isolation Solve?”When running multiple MMM configurations sequentially (especially with different numbers of media channels), users encounter PyTensor errors:
RuntimeError: Incompatible Elemwise input shapes [(208,), (208, 3)]This occurs because PyTensor caches compiled functions with specific tensor shapes. When configuration changes (e.g., 2 channels to 3 channels), PyTensor attempts to reuse cached functions with incompatible shapes.
Traditional workaround: Restart Python kernel between configuration changes.
AMMM solution: Automatic cache isolation per configuration using AMMM_CACHE_MODE.
How Cache Isolation Works
Section titled “How Cache Isolation Works”AMMM’s SessionManager creates separate compilation directories for each unique model configuration based on a configuration hash including:
- Number and names of media channels
- Control variables (extra_features_cols)
- Prophet seasonality features
- Adstock lag
When configurations switch, AMMM automatically uses different cache directories, preventing shape contamination.
Enabling Cache Isolation
Section titled “Enabling Cache Isolation”Cache isolation is controlled by the AMMM_CACHE_MODE environment variable.
AMMM_CACHE_MODE Values
Section titled “AMMM_CACHE_MODE Values”off (Default)
Section titled “off (Default)”No cache isolation. Uses PyTensor’s default behaviour.
export AMMM_CACHE_MODE=offpython your_script.pyUse when: Running a single configuration.
reuse (Persistent Cache)
Section titled “reuse (Persistent Cache)”Creates persistent cache directories at ~/.ammm/compiled/.
export AMMM_CACHE_MODE=reusepython your_script.pyUse when:
- Repeatedly experimenting with different configurations
- Want to reuse compiled graphs across sessions
- Working with limited compute resources
Advantages:
- Faster subsequent runs with the same configuration
- Caches persist across sessions
- Suitable for development/research
Disadvantages:
- Caches accumulate over time
- Requires manual pruning
temp (Temporary Cache)
Section titled “temp (Temporary Cache)”Creates temporary cache directories deleted after model fitting.
export AMMM_CACHE_MODE=temppython your_script.pyUse when:
- CI/CD pipelines
- One-off model runs
- Want automatic cleanup
- Limited disk space
Advantages:
- Automatic cleanup
- No cache accumulation
- Suitable for production/automation
Disadvantages:
- No cache reuse across runs
- Slightly slower for repeated runs
AMMM_CACHE_VERBOSE
Section titled “AMMM_CACHE_VERBOSE”Enable detailed cache logging:
export AMMM_CACHE_VERBOSE=1export AMMM_CACHE_MODE=reusepython your_script.pyOutput:
[SessionManager] Using cache: /home/user/.ammm/compiled/pytensor_cache_abc12345[SessionManager] Config hash: abc12345[SessionManager] Cleaned up cache: /home/user/.ammm/compiled/pytensor_cache_abc12345Where Caches Live
Section titled “Where Caches Live”Persistent Mode (reuse)
Section titled “Persistent Mode (reuse)”~/.ammm/compiled/├── pytensor_cache_abc12345/ # Config 1 (2 channels)├── pytensor_cache_def67890/ # Config 2 (3 channels)└── pytensor_cache_ghi11121/ # Config 3 (4 channels)Each directory is named with an 8-character hash of the configuration.
Temporary Mode (temp)
Section titled “Temporary Mode (temp)”/tmp/├── pytensor_cache_abc12345/ # Deleted after run└── pytensor_cache_def67890/ # Deleted after runCache Management (ammm-cache CLI)
Section titled “Cache Management (ammm-cache CLI)”View Statistics
Section titled “View Statistics”ammm-cache infoOutput:
============================================================AMMM Cache Information============================================================Cache root: /home/user/.ammm/compiledExists: TrueCache count: 12Total size: 2847.3 MBOldest cache: abc12345 (15.2 days old)Newest cache: xyz98765 (0.3 days old)============================================================Verbose Output
Section titled “Verbose Output”ammm-cache info --verbosePrune Old Caches
Section titled “Prune Old Caches”Remove caches exceeding specified limits using LRU (Least Recently Used) strategy.
# Use default limits (5GB total, 50 caches, 30 days max age)ammm-cache prune
# Custom limitsammm-cache prune --max-size 3000 --max-count 20 --max-age 14
# Dry runammm-cache prune --dry-run --verboseParameters:
--max-size <MB>: Maximum total cache size in megabytes (default: 5000)--max-count <N>: Maximum number of cache directories (default: 50)--max-age <days>: Maximum cache age in days (default: 30)--dry-run: Show what would be removed without removing--verbose: Show detailed list of removed caches
Clear All Caches
Section titled “Clear All Caches”Remove all cache directories:
# Interactive confirmationammm-cache clear
# Force (skip confirmation)ammm-cache clear --force
# Dry runammm-cache clear --dry-runWarning: This removes all cached compilation results. Next runs will recompile from scratch.
Custom Cache Root
Section titled “Custom Cache Root”ammm-cache info --cache-root /custom/pathammm-cache prune --cache-root /custom/pathUsage Examples
Section titled “Usage Examples”Example 1: Sequential Experimentation
Section titled “Example 1: Sequential Experimentation”Testing different channel combinations without kernel restarts:
import osos.environ["AMMM_CACHE_MODE"] = "reuse"
from src.driver import MMMBaseDriverV2
# Run 1: 2 channelsconfig_2ch = {...}driver1 = MMMBaseDriverV2(config_2ch, ...)driver1.fit_model()
# Run 2: 3 channels (same session)config_3ch = {...}driver2 = MMMBaseDriverV2(config_3ch, ...)driver2.fit_model() # No tensor shape error
# Run 3: Back to 2 channelsdriver3 = MMMBaseDriverV2(config_2ch, ...)driver3.fit_model() # Reuses cache from Run 1Example 2: CI/CD Pipeline
Section titled “Example 2: CI/CD Pipeline”Automated model fitting with automatic cleanup:
#!/bin/bashexport AMMM_CACHE_MODE=temp
python fit_model_config_a.pypython fit_model_config_b.pypython fit_model_config_c.py
# Caches automatically cleaned upExample 3: Cache Monitoring
Section titled “Example 3: Cache Monitoring”#!/bin/bashammm-cache prune --max-age 7 --verboseecho "Pruned old AMMM caches" | mail -s "Cache Cleanup" admin@company.comExample 4: Debug Mode
Section titled “Example 4: Debug Mode”import os
os.environ["AMMM_CACHE_MODE"] = "reuse"os.environ["AMMM_CACHE_VERBOSE"] = "1"
from src.driver import MMMBaseDriverV2
driver = MMMBaseDriverV2(...)driver.fit_model()Troubleshooting
Section titled “Troubleshooting”Issue: “Cannot change compiledir after PyTensor initialization”
Section titled “Issue: “Cannot change compiledir after PyTensor initialization””Symptom: Warning about compiledir not being set effectively.
Cause: Some environments lock PyTensor settings after first import.
Solution:
- Restart the kernel/session
- Set
AMMM_CACHE_MODEbefore any PyTensor/PyMC imports - MMMBaseDriverV2 handles cache management automatically
Issue: Cache Growing Too Large
Section titled “Issue: Cache Growing Too Large”ammm-cache infoammm-cache prune --max-size 2000# Or clear allammm-cache clear --forceIssue: Cache Write Permission Denied
Section titled “Issue: Cache Write Permission Denied”# Check permissionsls -ld ~/.ammm/compiled/
# Fix permissionschmod 755 ~/.ammm/compiled/
# Or use custom cache rootexport AMMM_CACHE_ROOT=/tmp/ammm_cacheIssue: Still Getting Tensor Shape Errors
Section titled “Issue: Still Getting Tensor Shape Errors”Diagnostic Steps:
-
Verify environment variable:
import osprint(os.getenv("AMMM_CACHE_MODE")) -
Check if cache isolation is active (look for log messages)
-
Restart the Python kernel
Best Practices
Section titled “Best Practices”Development/Research
Section titled “Development/Research”- Use
AMMM_CACHE_MODE=reusefor iterative work - Enable
AMMM_CACHE_VERBOSE=1when debugging - Periodically prune caches (weekly/monthly)
Production/Automation
Section titled “Production/Automation”- Use
AMMM_CACHE_MODE=tempfor CI/CD - Monitor disk usage in long-running systems
- Set up automated pruning for persistent caches
Shared Environments
Section titled “Shared Environments”- Use custom cache roots per user:
Terminal window export AMMM_CACHE_ROOT=/shared/caches/$USER - Implement disk quotas
- Schedule regular cleanup jobs
Performance Optimisation
Section titled “Performance Optimisation”- For repeated runs with same config, use
reusemode - First run compiles graphs (slower)
- Subsequent runs reuse cache (faster)
- Balance cache size vs recompilation time
Technical Details
Section titled “Technical Details”Configuration Hash Algorithm
Section titled “Configuration Hash Algorithm”Only shape-impacting parameters contribute to the hash:
{ 'media': ['tv_spend', 'radio_spend'], 'extra_features_cols': ['control_1', 'promo'], 'prophet_cols': ['trend', 'yearly'], 'ad_stock_max_lag': 4}Hash: md5(json.dumps(config, sort_keys=True))[:8]
Cache Directory Structure
Section titled “Cache Directory Structure”pytensor_cache_{hash}/├── compiledir_<platform>/│ ├── <function_hash_1>/│ │ ├── mod.c│ │ ├── mod.so│ │ └── key.pkl│ └── <function_hash_2>/│ ├── mod.c│ ├── mod.so│ └── key.pkl└── lock_dir/Each cached function includes:
mod.c: Generated C codemod.so: Compiled shared objectkey.pkl: Function signature/metadata
Q: Does cache isolation slow down model fitting?
A: First run compiles (same speed). Subsequent runs with same config are faster in reuse mode.
Q: How much disk space do caches use?
A: Typically 50-200 MB per configuration. Use ammm-cache info to check.
Q: Can I use cache isolation in notebooks?
A: Yes. Set environment variables before importing AMMM:
import osos.environ["AMMM_CACHE_MODE"] = "reuse"
from src.driver import MMMBaseDriverV2Q: What happens if I change priors but keep channels the same?
A: The cache hash is based only on shape-impacting parameters. Changed priors use the same cache (safe, as model structure is identical).
Q: Can I manually clear a specific cache?
A: Yes, delete the directory:
rm -rf ~/.ammm/compiled/pytensor_cache_abc12345Q: Does this work with hierarchical models?
A: Yes, cache isolation works with all AMMM model types.