Time Series Forecasting
MLX
Safetensors
apple-silicon
timestral
time-series
forecasting
quantile-regression
Instructions to use jbilcke/timestral-mlx with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- MLX
How to use jbilcke/timestral-mlx with MLX:
# Download the model from the Hub pip install huggingface_hub[hf_xet] hf download jbilcke/timestral-mlx --local-dir timestral-mlx
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- LM Studio
- Atomic Chat
File size: 5,520 Bytes
d35e174 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | """Build an explicit Timestral release inventory and reject stale validation."""
import hashlib
import json
import shutil
from pathlib import Path
ROOT=Path(__file__).resolve().parents[1]
VARIANTS=("5M","28M","123M","209M")
def sha256(path):
h=hashlib.sha256()
with Path(path).open('rb') as f:
for block in iter(lambda:f.read(8*1024*1024),b''): h.update(block)
return h.hexdigest()
def excluded(path):
return any(p.startswith('._') or p in {'.DS_Store','__MACOSX','.AppleDouble','__pycache__','.pytest_cache','.cache','.venv'}
or p.endswith(('.pyc','.tmp','.swp')) for p in Path(path).parts)
def assemble():
files=[]
def add(name,path):
if excluded(name) or excluded(path):
raise ValueError(f'forbidden release path: {name}')
if path.is_symlink() or not path.is_file():
raise ValueError(f'missing or symlinked file: {path}')
files.append((name,path))
runtime={p.name:sha256(p) for p in sorted((ROOT/'timestral_mlx').glob('*.py')) if not excluded(p)}
inventory=[]
for size in VARIANTS:
bundle=ROOT/'models'/size
manifest=json.loads((bundle/'manifest.json').read_text())
report=json.loads((ROOT/'reports'/f'{size}.json').read_text())
if not report['passed'] or len(report['fixtures'])!=7 or not all(r['passed'] for r in report['fixtures']):
raise ValueError(f'{size}: incomplete or failed validation')
if report['bundle_manifest_sha256']!=sha256(bundle/'manifest.json') or report['runtime_sha256']!=runtime:
raise ValueError(f'{size}: validation is stale')
for name,entry in manifest['files'].items():
if sha256(bundle/name)!=entry['sha256'] or (bundle/name).stat().st_size!=entry['bytes']:
raise ValueError(f'{size}: bundle hash/size mismatch for {name}')
source=manifest['source']
license_bytes=(bundle/'LICENSE').read_bytes()
if license_bytes!=(ROOT/'LICENSE-WEIGHTS').read_bytes():
raise ValueError('original variant licences differ; review required')
shutil.copyfile(ROOT/'models'/'source'/size/'README.md',bundle/'upstream-model-card.md')
if sha256(bundle/'upstream-model-card.md')!=source['files']['README.md']['sha256']:
raise ValueError('upstream model-card hash mismatch')
(bundle/'README.md').write_text(f'''# Timestral-{size} MLX FP32
Independent MLX conversion of [{source['repo_id']}](https://huggingface.co/{source['repo_id']})
at revision `{source['revision']}`. No training or quantization; original FP32 tensor
values verified unchanged after serialization. See [manifest.json](manifest.json).
Install the `timestral_mlx` package from the repository root, then:
```python
from timestral_mlx import TimestralForecaster
forecaster = TimestralForecaster.from_pretrained("./{size}")
forecast = forecaster.forecast(context, prediction_length=96)
```
The original Modified MIT weight licence and Mistral AI attribution are preserved
verbatim in [LICENSE](LICENSE). Runtime code is separately Apache-2.0.
See the [main model card](../README.md) and [parity report](../reports/{size}.json).
''')
for name in ('config.json','model.safetensors','LICENSE','manifest.json','README.md','upstream-model-card.md'):
add(f'{size}/{name}',bundle/name)
inventory.append(dict(variant=size,path=size,source=source['repo_id'],source_revision=source['revision'],
parameters=manifest['conversion']['parameter_count'],
weight_bytes=manifest['files']['model.safetensors']['bytes'],
manifest_sha256=sha256(bundle/'manifest.json'),validation=f'reports/{size}.json',passed=True))
full_context=json.loads((ROOT/'reports'/'full-context.json').read_text())
if {r['variant'] for r in full_context if r['passed']}!=set(VARIANTS):
raise ValueError('full-context smoke checks are incomplete')
installation=json.loads((ROOT/'reports'/'installation.json').read_text())
if not installation['offline'] or installation['torch_installed'] or {r['variant'] for r in installation['results'] if r['passed']}!=set(VARIANTS):
raise ValueError('clean offline wheel installation checks are incomplete')
if not json.loads((ROOT/'reports'/'tests.json').read_text())['passed']:
raise ValueError('test suite did not pass')
(ROOT/'models.json').write_text(json.dumps(dict(format='timestral-mlx-collection-v1',models=inventory),indent=2)+'\n')
for name in ('README.md','LICENSE','LICENSE-WEIGHTS','NOTICE','pyproject.toml','requirements.txt',
'requirements-validation.txt','.gitignore','MANIFEST.in','models.json','pins.json'):
add(name,ROOT/name)
for folder,pattern in (('timestral_mlx','*.py'),('scripts','*.py'),('examples','*.py'),('tests','*.py'),('reports','*.json'),('dist','*.whl')):
for path in sorted((ROOT/folder).glob(pattern)):
if not excluded(path): add(f'{folder}/{path.name}',path)
if not any(name.startswith('dist/') for name,_ in files):
raise ValueError('build the installable wheel before publishing')
(ROOT/'SHA256SUMS').write_text(''.join(f'{sha256(path)} {name}\n' for name,path in sorted(files)))
add('SHA256SUMS',ROOT/'SHA256SUMS')
return sorted(files)
if __name__=='__main__':
files=assemble()
print(json.dumps(dict(files=len(files),bytes=sum(p.stat().st_size for _,p in files)),indent=2))
|