Differential privacy for aggregates - add dp_laplace and dp_gaussian built-in functions with budget accounting - #2539
Differential privacy for aggregates - add dp_laplace and dp_gaussian built-in functions with budget accounting#2539andersonm-ibm wants to merge 30 commits into
Conversation
…ransformation matrix T internally, returning T %*% X with noise fused into a single matrix multiply.
…ng to David's suggestion
Lets a DML script declare its session-wide differential-privacy budget once at the top, instead of always falling back to the hardcoded default. Resolved entirely at compile time: epsilon/delta must be literals, validated in BuiltinFunctionExpression and stored on DMLProgram during HOP construction, then read by ExecutionContext.getDPBudgetAccountant().
Four federated workers simulated on localhost, a logistic regression FedAvg loop in DML where the coordinator applies dp_gaussian to the aggregated gradient, a sweep over ε ∈ {0.5, 1, 4, 8} plus a non-private baseline, and a matplotlib accuracy-vs-ε plot saved as a PNG.
Add clip_norm (default 4.0) as a script parameter. Inside the private == 1 branch, each row's gradient contribution is clipped to L2-norm less than clip_norm.
12a37d5 to
d8912b1
Compare
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #2539 +/- ##
=============================================
- Coverage 71.61% 17.24% -54.37%
+ Complexity 49867 11450 -38417
=============================================
Files 1602 1625 +23
Lines 193054 194562 +1508
Branches 37792 38005 +213
=============================================
- Hits 138247 33553 -104694
- Misses 44031 155193 +111162
+ Partials 10776 5816 -4960 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
ywcb00
left a comment
There was a problem hiding this comment.
Hi @andersonm-ibm,
I did a pass through the code and left some comments inline related to code style and integration in SystemDS.
The failing Java Test workflow was not caused by the changes of this PR.
All the best,
David
| MMChain, | ||
| Union, | ||
| EINSUM, | ||
| DPBuiltin, |
There was a problem hiding this comment.
Do we need a separate instruction type or could we also use the already existing ParameterizedBuiltin type?
| DP_LAPLACE("dp_laplace", false), | ||
| DP_GAUSSIAN("dp_gaussian", false), | ||
| DP_SET_BUDGET("dp_set_budget", false), |
There was a problem hiding this comment.
Keep the alphabetical order.
| String dpLaplaceQuery = getDPQueryLiteral(getSecondExpr()); | ||
| long[] dpLaplaceDims = getDPOutputDims(dpLaplaceQuery, | ||
| getFirstExpr().getOutput().getDim1(), getFirstExpr().getOutput().getDim2()); |
There was a problem hiding this comment.
Since these two functions are always called together, can we merge them to have a single function call to get the output dimensions?
| case DECOMPRESS: | ||
| currBuiltinOp = new UnaryOp(target.getName(), target.getDataType(), ValueType.FP64, OpOp1.DECOMPRESS, expr); | ||
| break; | ||
| case DP_LAPLACE: { |
There was a problem hiding this comment.
Move these cases to the method processParameterizedBuiltinFunctionExpression above to simplify the parameter parsing.
| * analysis that derives sensitivity from {@code T}'s column norms and a declared per-record bound on {@code X}; every | ||
| * other line in this class would stay unchanged. | ||
| */ | ||
| public class DPBuiltinCPInstruction extends ComputationCPInstruction { |
There was a problem hiding this comment.
Can we extend from ParameterizedBuiltinCPInstruction, since the DP builtins belong to the parameterized builtin functions?
| private static final double EPS = 1e-9; | ||
|
|
||
| // ======================================================================= | ||
| // 1. DPBudgetAccountant unit tests |
There was a problem hiding this comment.
What does the '1.' refer to?
| } | ||
|
|
||
| // ======================================================================= | ||
| // 1b. DMLProgram / ExecutionContext.getDPBudgetAccountant() (dp_set_budget) |
| * | ||
| * Full integration tests extend AutomatedTestBase and drive the DML runner. | ||
| * Each test: | ||
| * (a) Writes a DML script to a temp file. |
There was a problem hiding this comment.
Create the DML scripts directly as files under test/scripts, similar to other unit tests.
| * Full integration tests extend AutomatedTestBase and drive the DML runner. | ||
| * Each test: | ||
| * (a) Writes a DML script to a temp file. | ||
| * (b) Provides input matrices via TestUtils. |
There was a problem hiding this comment.
Use the method getRandomMatrix() from AutomatedTestBase for generating random test matrices.
| <artifactId>maven-surefire-plugin</artifactId> | ||
| <version>${maven-surefire-plugin.version}</version> | ||
| <configuration> | ||
| <reportFormat>plain</reportFormat> |
There was a problem hiding this comment.
What is the reason for this change? What is it needed for?
Wire them through the full compilation pipeline:
Builtins → BuiltinFunctionExpression → ParameterizedBuiltinOp HOP → ParameterizedBuiltin LOP → DPBuiltinCPInstruction.
Introduce DPBudgetAccountant, a session-scoped privacy budget tracker stored on ExecutionContext. Laplace releases use exact pure-ε composition; Gaussian releases use Rényi DP composition (Mironov 2017) with RDP → (ε,δ) conversion for tighter bounds. Raises DMLRuntimeException if cumulative spend exceeds the budget.
Unit tests covering constructor validation, Laplace/Gaussian composition, budget exhaustion for both mechanisms, mixed composition, release counting, and RDP mathematical invariants (sensitivity cancellation, ε-monotonicity).
End-to-end DML integration tests in DPBuiltinDMLTest verify noisy output differs from clean means by a statistically plausible amount.
Differential Privacy Benchmark:
Four federated workers simulated on localhost, a logistic regression FedAvg loop in DML where the coordinator applies dp_gaussian to the aggregated gradient, a sweep over ε ∈ {0.5, 1, 4, 8} plus a non-private baseline, and a matplotlib accuracy-vs-ε plot saved as a PNG.
CC @ywcb00