=============
DP-SGD module
=============

.. automodule:: gdpnum.dpsgd
   :members:
   :undoc-members:
   :show-inheritance:

Overview
========

The ``dpsgd`` module provides specialized functionality for analyzing Differentially
Private Stochastic Gradient Descent (DP-SGD) with Gaussian Differential Privacy (GDP).
It includes both standalone functions for one-shot analysis and a privacy accountant
class for tracking the privacy guarantees during training.

Functions
=========

get_mu_and_regret_for_dpsgd
--------------------------

.. autofunction:: gdpnum.dpsgd.get_mu_and_regret_for_dpsgd

Classes
=======

CTDAccountant
-----------

.. autoclass:: gdpnum.dpsgd.CTDAccountant
   :members:
   :undoc-members:
   :special-members: __init__

Example Usage
=============

One-shot Analysis
-----------------

.. code-block:: python

    import gdpnum

    mu, regret = gdpnum.dpsgd.get_mu_and_regret_for_dpsgd(
        noise_multiplier=9.4,
        sample_rate=0.328,
        num_steps=2000
    )
    
    print(f"GDP parameter μ: {mu:.6f}")
    print(f"Regret: {regret:.6f}")

Opacus-Compatible Accountant
----------------------------

.. code-block:: python

    import gdpnum
    
    # Create accountant
    accountant = gdpnum.dpsgd.CTDAccountant()
    
    # During training loop
    for epoch in range(num_epochs):
        for batch in dataloader:
            # Update privacy accounting
            accountant.step(
                noise_multiplier=noise_multiplier,
                sample_rate=batch_size/len(dataset)
            )
            
            # Train model...
            
        # Check privacy after each epoch
        mu, regret = accountant.get_mu_and_regret()
        print(f"After epoch {epoch+1}: μ = {mu:.6f}, regret = {regret:.6f}")

Integration with Opacus
-----------------------

.. code-block:: python

    from opacus import PrivacyEngine
    import gdpnum

    # Standard Opacus pipeline. 
    privacy_engine = PrivacyEngine()
    model, optimizer, train_loader = privacy_engine.make_private(
        module=model,
        optimizer=optimizer,
        data_loader=train_loader,
        noise_multiplier=1.0,
        max_grad_norm=1.0,
    )
    
    # Create GDP accountant
    accountant = gdpnum.dpsgd.CTDAccountant()
    
    # Connect accountant to optimizer
    optimizer.attach_step_hook(
        accountant.get_optimizer_hook_fn(
            sample_rate=train_loader.sample_rate
        )
    )