Skip to content

Commit ca5fa04

Browse files
committed
WIP
1 parent 021d7d0 commit ca5fa04

File tree

7 files changed

+209
-184
lines changed

7 files changed

+209
-184
lines changed

docs/examples/README.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Infera Examples
2+
3+
This directory contains DuckDB SQL scripts that show usage patterns of the Infera extension.
4+
Each file is self‑contained and can be executed in the DuckDB shell (or via `duckdb < file.sql`).
5+
6+
## Prerequisites
7+
8+
1. Build the extension:
9+
```bash
10+
make release
11+
```
12+
2. Start the DuckDB shell from the project root directory:
13+
```bash
14+
./build/release/duckdb
15+
```
16+
3. Inside the shell, load a script:
17+
```sql
18+
.read docs/examples/e1_core_functionality.sql
19+
```
20+
21+
## Example Index
22+
23+
| File | Topic | Functionalities |
24+
|---------------------------------|--------------------------------------|-----------------------------------------------------------------------------------------------------------|
25+
| `e1_core_functionality.sql` | Core lifecycle | Version, load, inspect model info, single prediction, unload, autoload directory reuse |
26+
| `e2_advanced_features.sql` | Remote and BLOB inference | Remote model load (GitHub), large vision model, constructing a zero‑filled BLOB for inference |
27+
| `e3_integration_and_errors.sql` | Integration patterns and errors | Deterministic batch table, aggregation, null feature detection, missing model handling |
28+
| `e4_multi_output.sql` | Multi‑output models | Uses `multi_output.onnx`, shows `infera_predict_multi` vs (commented) single‑output mismatch |
29+
| `e5_autoload_and_json.sql` | Autoload and lightweight JSON checks | Error JSON from missing dir, loading multiple models via directory scan, simple substring presence checks |
30+
| `e6_blob_diagnostics.sql` | BLOB diagnostics | Shows correct BLOB sizing for mobilenet; commented invalid case to illustrate error path |
31+
32+
## Running All Examples
33+
34+
```bash
35+
make examples
36+
```
Lines changed: 32 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,35 @@
1-
-- Tests the core, end-to-end functionality of the extension.
1+
-- core functionality walkthrough (load -> info -> predict -> unload)
22
.echo on
3-
LOAD infera;
4-
5-
-- =============================================================================
6-
-- Test 1: Version and Initial State
7-
-- =============================================================================
8-
SELECT '--- Testing Version and Initial State ---';
9-
10-
-- Check that the version function returns a valid JSON.
11-
SELECT infera_get_version();
12-
13-
-- Check that no models are loaded initially.
14-
SELECT infera_get_loaded_models() AS initial_models;
15-
16-
17-
-- =============================================================================
18-
-- Test 2: Local Model Roundtrip (Load -> Info -> Predict -> Unload)
19-
-- =============================================================================
20-
SELECT '--- Testing Local Model Roundtrip ---';
21-
22-
-- Load the simple linear model.
23-
SELECT infera_load_model('linear', 'test/models/linear.onnx') AS loaded;
24-
25-
-- Verify the model appears in the list.
26-
SELECT instr(infera_get_loaded_models(), 'linear') > 0 AS after_load;
27-
28-
-- Retrieve model info and check for expected input shape.
29-
SELECT infera_get_model_info('linear') AS metadata;
30-
SELECT position('"input_shape":[1,3]' IN infera_get_model_info('linear')) > 0 AS metadata_ok;
31-
32-
-- Run deterministic predictions. Model is y = 2*x1 - 1*x2 + 0.5*x3 + 0.25
33-
-- For (1.0, 2.0, 3.0), expected y = 1.75
34-
SELECT infera_predict('linear', 1.0, 2.0, 3.0) AS single_prediction;
35-
SELECT abs(infera_predict('linear', 1.0, 2.0, 3.0) - 1.75) < 1e-5 AS single_predict_ok;
36-
37-
-- Test the multi-output prediction function.
38-
SELECT infera_predict_multi('linear', 1.0, 2.0, 3.0) as multi_prediction;
39-
SELECT instr(infera_predict_multi('linear', 1.0, 2.0, 3.0), '1.75') > 0 AS multi_predict_ok;
40-
41-
-- Unload the model and confirm its removal.
42-
SELECT infera_unload_model('linear') AS unloaded;
43-
SELECT infera_get_loaded_models() AS after_unload;
44-
45-
46-
-- =============================================================================
47-
-- Test 3: Autoload Directory
48-
-- =============================================================================
49-
SELECT '--- Testing Autoload Directory ---';
50-
51-
-- Create a temporary directory and copy the model into it.
52-
.shell mkdir -p test/temp_models
53-
.shell cp test/models/linear.onnx test/temp_models/
54-
55-
-- Run the autoload function.
56-
SELECT infera_set_autoload_dir('test/temp_models');
57-
58-
-- Verify the model was loaded automatically.
59-
SELECT instr(infera_get_loaded_models(), 'linear') > 0 AS autoloaded_model_is_listed;
60-
61-
-- Run a prediction to confirm it's functional.
62-
SELECT abs(infera_predict('linear', 1.0, 2.0, 3.0) - 1.75) < 1e-5 AS autoload_predict_ok;
63-
64-
-- Clean up.
65-
SELECT infera_unload_model('linear');
66-
.shell rm -rf test/temp_models
67-
3+
load infera;
4+
5+
-- section 1: version & initial state
6+
select '## version & initial state';
7+
select infera_get_version() as version_json; -- shows version, backend, cache dir
8+
select infera_get_loaded_models() as initial_models; -- expect []
9+
10+
-- section 2: load model and inspect
11+
select '## load model';
12+
select infera_load_model('linear', 'test/models/linear.onnx') as loaded; -- expect true
13+
select instr(infera_get_loaded_models(), 'linear') > 0 as is_listed; -- expect 1/true
14+
select infera_get_model_info('linear') as model_info; -- contains input/output shapes
15+
select position('"input_shape"' in infera_get_model_info('linear')) > 0 as has_input_shape; -- expect true
16+
17+
-- section 3: prediction
18+
-- model formula documented in tests: y = 2*f1 - 1*f2 + 0.5*f3 + 0.25
19+
select '## prediction';
20+
select infera_predict('linear', 1.0, 2.0, 3.0) as prediction; -- expect 1.75
21+
select abs(infera_predict('linear', 1.0, 2.0, 3.0) - 1.75) < 1e-5 as prediction_ok; -- expect true
22+
select infera_predict_multi('linear', 1.0, 2.0, 3.0) as predict_multi; -- single value inside list-like string
23+
24+
-- section 4: unload
25+
select '## unload';
26+
select infera_unload_model('linear') as unloaded; -- expect true
27+
select infera_get_loaded_models() as after_unload; -- expect []
28+
29+
-- section 5: autoload (reuse existing test/models directory)
30+
select '## autoload';
31+
select infera_set_autoload_dir('test/models') as autoload_result; -- loads linear (& others if added)
32+
select instr(infera_get_loaded_models(), 'linear') > 0 as autoload_contains_linear; -- expect true
33+
select infera_unload_model('linear') as unload_after_autoload; -- true (idempotent)
6834

6935
.echo off
Lines changed: 29 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,34 @@
1-
-- Tests advanced features like remote model loading and BLOB inputs.
1+
-- advanced features: remote loading & blob inference
22
.echo on
3-
LOAD infera;
4-
5-
-- =============================================================================
6-
-- Test 1: Remote Model Loading
7-
-- =============================================================================
8-
SELECT '--- Testing Remote Model Loading ---';
9-
10-
-- Define macros for the model name and URL for clarity.
11-
CREATE OR REPLACE MACRO model_name() AS 'remote_linear_model';
12-
CREATE OR REPLACE MACRO model_url() AS 'https://github.com/CogitatorTech/infera/raw/refs/heads/main/test/models/linear.onnx';
13-
14-
-- Load the model from the URL.
15-
SELECT infera_load_model(model_name(), model_url()) AS loaded_from_url;
16-
17-
-- Verify the model appears in the list.
18-
SELECT instr(infera_get_loaded_models(), model_name()) > 0 AS model_is_listed;
19-
20-
-- Run a prediction to confirm it's functional (y = 1.75 for these features).
21-
SELECT abs(infera_predict(model_name(), 1.0, 2.0, 3.0) - 1.75) < 1e-5 AS prediction_is_correct;
22-
23-
-- Unload the model to clean up.
24-
SELECT infera_unload_model(model_name()) AS unloaded;
25-
SELECT instr(infera_get_loaded_models(), model_name()) = 0 AS model_is_removed;
26-
27-
28-
-- =============================================================================
29-
-- Test 2: BLOB Input Prediction
30-
-- =============================================================================
31-
SELECT '--- Testing BLOB Input Prediction ---';
32-
33-
-- Load a model that expects a large tensor input.
34-
SELECT infera_load_model(
35-
'mobilenet',
36-
'https://huggingface.co/onnxmodelzoo/tf_mobilenetv3_small_075_Opset17/resolve/main/tf_mobilenetv3_small_075_Opset17.onnx'
37-
);
38-
39-
-- Test error handling with an incorrectly sized BLOB.
40-
-- This is expected to fail.
41-
SELECT infera_predict_from_blob('mobilenet', 'dummy_bytes');
42-
43-
-- Test with a correctly sized, zero-filled BLOB.
44-
-- Model input is 1*224*224*3 floats. A float is 4 bytes. Total size = 602112 bytes.
45-
WITH const AS (
46-
SELECT CAST(REPEAT(CHR(0), 602112) AS BLOB) AS zero_blob
3+
load infera;
4+
5+
-- section 1: remote model loading (small linear model hosted on github)
6+
select '## remote model';
7+
create or replace macro model_name() as 'remote_linear_model';
8+
create or replace macro model_url() as 'https://github.com/CogitatorTech/infera/raw/refs/heads/main/test/models/linear.onnx';
9+
select infera_load_model(model_name(), model_url()) as loaded_remote; -- expect true
10+
select instr(infera_get_loaded_models(), model_name()) > 0 as remote_listed; -- expect true
11+
select abs(infera_predict(model_name(), 1.0, 2.0, 3.0) - 1.75) < 1e-5 as remote_predict_ok; -- expect true
12+
select infera_unload_model(model_name()) as remote_unloaded; -- expect true
13+
14+
-- section 2: blob inference (mobilenet example)
15+
select '## blob inference';
16+
-- Load a vision model from huggingface (size & load time depend on network).
17+
select infera_load_model(
18+
'mobilenet',
19+
'https://huggingface.co/onnxmodelzoo/tf_mobilenetv3_small_075_Opset17/resolve/main/tf_mobilenetv3_small_075_Opset17.onnx'
20+
) as mobilenet_loaded;
21+
22+
-- (optional) to see an error for an invalid blob size, you could run:
23+
-- select infera_predict_from_blob('mobilenet', cast('abc' as blob)); -- would error (invalid BLOB size)
24+
25+
-- construct zero-filled blob of correct size: 1*224*224*3 floats * 4 bytes = 602112
26+
with zeros as (
27+
select cast(repeat(chr(0), 602112) as blob) as zero_blob
4728
)
48-
SELECT len(infera_predict_from_blob('mobilenet', zero_blob)) as output_length
49-
FROM const;
29+
select len(infera_predict_from_blob('mobilenet', zero_blob)) as mobilenet_blob_output_len from zeros; -- length of output list
5030

51-
-- Clean up.
52-
SELECT infera_unload_model('mobilenet');
31+
select infera_unload_model('mobilenet') as mobilenet_unloaded;
5332

33+
-- optional: remote multi-output or larger models could be added similarly.
5434
.echo off
Lines changed: 44 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,47 @@
1-
-- Tests error handling and integration with larger SQL queries.
1+
-- integration & error handling demo
22
.echo on
3-
LOAD infera;
4-
5-
-- =============================================================================
6-
-- Test 1: Error Handling for Non-existent Models
7-
-- =============================================================================
8-
SELECT '--- Testing Error Handling ---';
9-
10-
-- Check info for a model that is not loaded.
11-
SELECT infera_get_model_info('nonexistent_model');
12-
13-
-- Try to unload a model that is not loaded.
14-
SELECT infera_unload_model('nonexistent_model');
15-
16-
17-
-- =============================================================================
18-
-- Test 2: Batch Processing and Aggregation
19-
-- =============================================================================
20-
SELECT '--- Testing Batch Processing and Aggregation ---';
21-
22-
-- Load a model to use for batch tests.
23-
SELECT infera_load_model('linear', 'test/models/linear.onnx');
24-
25-
-- Create a table with sample feature data, casting to FLOAT.
26-
CREATE OR REPLACE TABLE features AS
27-
SELECT
28-
row_number() OVER () as id,
29-
(random() * 10)::FLOAT as f1,
30-
(random() * 10)::FLOAT as f2,
31-
(random() * 10)::FLOAT as f3
32-
FROM generate_series(1, 100);
33-
34-
-- Run prediction on a single row from the table to test integration.
35-
-- This will now pass because the batch size is 1.
36-
SELECT
37-
id,
38-
f1, f2, f3,
39-
infera_predict('linear', f1, f2, f3) as prediction
40-
FROM features
41-
WHERE id = 1;
42-
43-
-- Use the prediction function on a single row for an aggregate query.
44-
SELECT
45-
AVG(infera_predict('linear', f1, f2, f3)) as avg_prediction,
46-
COUNT(*) as total_rows
47-
FROM features
48-
WHERE id = 1;
49-
50-
51-
-- =============================================================================
52-
-- Test 3: NULL Value Handling
53-
-- =============================================================================
54-
SELECT '--- Testing NULL Value Handling ---';
55-
56-
-- The current implementation should throw an error when a feature is NULL.
57-
-- This test verifies that behavior.
58-
CREATE OR REPLACE TABLE features_with_nulls AS
59-
SELECT 1 as id, 1.0::FLOAT as f1, 2.0::FLOAT as f2, NULL::FLOAT as f3;
60-
61-
SELECT infera_predict('linear', f1, f2, f3) FROM features_with_nulls;
62-
63-
64-
-- =============================================================================
65-
-- Cleanup
66-
-- =============================================================================
67-
SELECT '--- Cleaning Up ---';
68-
DROP TABLE features;
69-
DROP TABLE features_with_nulls;
70-
SELECT infera_unload_model('linear');
3+
load infera;
4+
5+
-- section 1: missing model behavior
6+
select '## missing model behavior';
7+
select infera_get_model_info('nonexistent_model') as missing_model_info; -- returns JSON with error
8+
select infera_unload_model('nonexistent_model') as unload_missing; -- idempotent true
9+
10+
-- section 2: batch style predictions (deterministic)
11+
select '## batch predictions';
12+
select infera_load_model('linear', 'test/models/linear.onnx') as loaded_linear;
13+
-- deterministic feature set (3 rows)
14+
create or replace table features as
15+
values
16+
(1, 1.0::float, 2.0::float, 3.0::float),
17+
(2, 0.5::float, 1.0::float, 1.5::float),
18+
(3, -1.0::float, 0.0::float, 2.0::float)
19+
;
20+
-- compute predictions row-wise
21+
select column0 as id, column1 as f1, column2 as f2, column3 as f3,
22+
infera_predict('linear', column1, column2, column3) as prediction
23+
from features
24+
order by 1;
25+
-- aggregate over the small batch
26+
select avg(infera_predict('linear', column1, column2, column3)) as avg_prediction,
27+
count(*) as n
28+
from features;
29+
30+
-- section 3: null feature error
31+
select '## null feature error';
32+
create or replace table features_with_nulls as values (1, 1.0::float, 2.0::float, null::float);
33+
-- this will raise an error if executed directly; kept commented for demonstration
34+
-- select infera_predict('linear', column1, column2, column3) from features_with_nulls;
35+
36+
-- instead, show detection:
37+
select column0 as id,
38+
(column3 is null) as has_null_feature
39+
from features_with_nulls;
40+
41+
-- section 4: cleanup
42+
select '## cleanup';
43+
drop table features;
44+
drop table features_with_nulls;
45+
select infera_unload_model('linear') as unloaded_linear;
7146

7247
.echo off

docs/examples/e4_multi_output.sql

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
-- multi-output model demonstration
2+
.echo on
3+
load infera;
4+
5+
select '## load multi-output model';
6+
-- expects test/models/multi_output.onnx (identity: [1,4] -> [1,4])
7+
select infera_load_model('multi_output', 'test/models/multi_output.onnx') as loaded_multi;
8+
9+
select '## model info';
10+
select infera_get_model_info('multi_output') as multi_model_info; -- shows output_shape [1,4]
11+
12+
select '## predict_multi (returns all four values)';
13+
select infera_predict_multi('multi_output', 1.0, 2.0, 3.0, 4.0) as multi_output_prediction; -- expect [1,2,3,4]
14+
15+
select '## predict (single-output API) will raise mismatch error if executed';
16+
-- the following is intentionally commented because it raises an error:
17+
-- select infera_predict('multi_output', 1.0, 2.0, 3.0, 4.0);
18+
19+
select '## cleanup';
20+
select infera_unload_model('multi_output') as unloaded_multi;
21+
.echo off
22+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
-- autoload directory & lightweight json string inspection
2+
.echo on
3+
load infera;
4+
5+
select '## autoload non-existent directory (expect error in json)';
6+
select infera_set_autoload_dir('nonexistent_dir___unlikely') as autoload_error_json; -- contains "error"
7+
8+
select '## autoload existing models directory';
9+
select infera_set_autoload_dir('test/models') as autoload_result; -- loads linear, multi_output (if present & valid)
10+
select infera_get_loaded_models() as loaded_models_json; -- e.g. ["linear","multi_output"]
11+
12+
select '## list each loaded model info';
13+
-- simple split-like exploration using instr; not parsing full json to avoid extension dependency
14+
select 'has_linear' as label, instr(infera_get_loaded_models(), 'linear') > 0 as present
15+
union all
16+
select 'has_multi_output', instr(infera_get_loaded_models(), 'multi_output') > 0;
17+
18+
select '## cleanup';
19+
select infera_unload_model('linear') as unload_linear;
20+
select infera_unload_model('multi_output') as unload_multi_output;
21+
.echo off
22+

0 commit comments

Comments
 (0)