DeepJSCC vs. Capacity-Matched JPEG over AWGN#

Train an image encoder and decoder jointly over an additive white Gaussian noise (AWGN) channel, then compare the learned system with a capacity-matched JPEG reference at a fixed bandwidth ratio.

Use this page for a compact implementation and training check. For a research-facing comparison with no-CSI slow fading and a bandwidth sweep, use DeepJSCC over slow Rayleigh fading.

Warning

Experimental tutorial evidence. The completed result on this page uses one trained model, four Kodak crops, and three channel-noise seeds. It is not a paper-grade population claim or a publication-ready result. Authoritative Kodak redistribution terms have not been archived, so this site does not publish the source crop or reconstruction gallery.

What this demo measures#

The two paths are:

Capacity-matched JPEG: image → highest JPEG quality fitting the capacity budget
                              → ideal error-free delivery → JPEG decode
DeepJSCC:              image → 0.5 learned complex symbols/pixel → AWGN
                              → learned reconstruction

The bandwidth ratio is κ = 0.5 complex channel uses per source pixel. For an SNR coordinate in decibels, γ = 10^(SNR_dB/10) and the ideal complex-AWGN budget is capacity bpp = κ × log2(1 + γ).

At each SNR, the JPEG reference searches qualities 1–95 and chooses the highest native bitstream that fits this budget. If quality 1 does not fit, it records an outage and returns the benchmark’s declared gray reconstruction. This is an optimistic channel-coding assumption for one fixed JPEG implementation, not an upper bound over digital separation or all source codecs. The comparison is modeled on the protocol in the DeepJSCC paper.

PSNR, measured in decibels, and MS-SSIM, reported on an approximately 0–1 scale here, both increase with reconstruction quality. Training minimizes image mean squared error (MSE); the benchmark reports all three measures. This experiment varies SNR at one fixed κ, so it is not a rate-distortion sweep.

Before you start#

You need:

  • a Git clone of Noema, a supported Python version (3.11–3.13), and uv;

  • network access for dependencies and the 24 hash-verified Kodak PNGs;

  • port 8766 available if you choose the Workbench route;

  • enough time for an 80-epoch starter-model training run and a 32-run benchmark.

The starter selects CUDA when available and otherwise uses CPU. Seeds and file hashes reproduce the protocol, but training is not guaranteed to be bit-identical across hardware and library builds. Your result ID and exact metrics may therefore differ from the reference result below.

Fetch the dataset once before choosing a workflow:

cd "$(git rev-parse --show-toplevel)"
uv sync --extra onnx --extra wireless
uv run --extra onnx noema data fetch kodak \
  --directory .noema/datasets/kodak

Caution

The fetcher records the mirror URL and file hashes, but the repository currently records the Kodak usage statement as an unverified third-party statement. Confirm the applicable terms before using the data, and do not redistribute the images or their reconstructions from this tutorial.

How the Noema pieces fit#

recipe
  → exported training bundle and interface contract
  → hash-verified data contract and train/validation split
  → paired encoder/decoder artifact
  → frozen benchmark pack
  → result bundle with metrics and provenance

The recipe defines the communication problem and replaceable interfaces. The exported bundle contains the trainer-neutral contract plus a PyTorch starter. Training returns the encoder and decoder together, and the benchmark evaluates that frozen pair without changing the declared resource budget.

Choose one workflow#

The CLI quick start and the guided Workbench route are alternatives. Do not run both into the same bundle directory. The exporter rejects a non-empty output directory unless overwrite is explicitly enabled, so choose a fresh bundle path for each attempt.

Option A — CLI training summary#

Run this block from any directory inside the Git clone after fetching Kodak. It exports the bundle, attaches the starter, validates the contract, trains and evaluates the pair, and runs the benchmark.

(
  set -euo pipefail
  ROOT="$(git rev-parse --show-toplevel)"
  BUNDLE="$ROOT/.noema/training_exports/deepjscc_image"
  cd "$ROOT"

  uv run --project "$ROOT" --extra onnx --extra wireless noema differentiable export \
    "$ROOT/recipes/deepjscc_kodak_awgn_train.yaml" \
    --training-plan \
    "$ROOT/demo_trainings/deepjscc_image_reconstruction/training_plan.yaml" \
    --out "$BUNDLE"
  uv run --project "$ROOT" --extra onnx --extra wireless python \
    "$ROOT/demo_trainings/prepare_example.py" deepjscc-image "$BUNDLE" \
    --project-root "$ROOT"

  cd "$BUNDLE"
  uv run --project "$ROOT" --extra onnx --extra wireless python validate_contract.py
  uv run --project "$ROOT" --extra onnx --extra wireless python train_demo.py
  uv run --project "$ROOT" --extra onnx --extra wireless python evaluate_demo.py

  cd "$BUNDLE/reference_training"
  uv run --project "$ROOT" --extra onnx --extra wireless python build_benchmark.py
  cd "$ROOT"
  uv run --project "$ROOT" --extra onnx --extra wireless noema benchmark validate \
    "$BUNDLE/reference_training/benchmark_pack.yaml"
  uv run --project "$ROOT" --extra onnx --extra wireless noema benchmark run \
    "$BUNDLE/reference_training/benchmark_pack.yaml"
)

This example reads a file-backed dataset directly, so it does not need a tensor-capture stage. The final command prints the result ID and paths to result.json, metrics.csv, recipes.csv, and summary.md.

Option B — guided Workbench workflow#

1. Open the template#

Start Noema in Terminal 1 and leave the process running:

cd "$(git rev-parse --show-toplevel)"
uv run --extra onnx --extra wireless noema ui serve --port 8766

Open http://127.0.0.1:8766, select Browse template recipes, then open Semantic communication > Image reconstruction > Image reconstruction — DeepJSCC over AWGN.

The recipe declares:

  • Kodak images 01–20 for the deterministic train/validation partition;

  • Kodak images 21–24 for the benchmark only;

  • a training SNR grid of [-4, 0, 4, 8, 12, 16] dB;

  • unit average transmitted complex-symbol power;

  • paired trainable Sender and Receiver interfaces.

2. Export from Workbench#

Configure Workbench:

  1. Under Operation Training Capabilities, select Train/replace for Sender and Receiver.

  2. Set Bundle directory to .noema/training_exports/deepjscc_image_workbench.

  3. Select PyTorch under Support framework.

  4. Leave Overwrite generated files disabled for a new bundle. Enable it only when you intentionally want to regenerate Noema-owned contract files in an existing bundle.

  5. Select Export training bundle.

In Terminal 2, attach the included starter:

cd "$(git rev-parse --show-toplevel)"
uv run --extra onnx --extra wireless python demo_trainings/prepare_example.py \
  deepjscc-image .noema/training_exports/deepjscc_image_workbench

Inspect data_contract.yaml to confirm the selected files, hashes, split, and crop policy.

3. Train and return the endpoint pair#

cd "$(git rev-parse --show-toplevel)/.noema/training_exports/deepjscc_image_workbench"
uv run --project ../../.. --extra onnx --extra wireless python validate_contract.py
uv run --project ../../.. --extra onnx --extra wireless python train_demo.py
uv run --project ../../.. --extra onnx --extra wireless python evaluate_demo.py

The residual convolutional model downsamples each spatial dimension by eight and emits 32 complex feature maps, giving 32 / (8 × 8) = 0.5 complex channel uses per source pixel. Crops, flips, and rotations augment the 16 training images while the recorded source files and hashes remain fixed.

The paired artifact contains:

  • artifacts/encoder.onnx and artifacts/decoder.onnx;

  • trained_artifact.yaml, which binds the pair to its interfaces;

  • reference_training/training_history.json;

  • reference_training/evaluation_metrics.json.

Workbench discovers the pair automatically. Select Validate returned model and continue only after the interface validation succeeds.

4. Build and run the benchmark#

cd "$(git rev-parse --show-toplevel)"
cd .noema/training_exports/deepjscc_image_workbench/reference_training
uv run --project ../../../.. --extra onnx --extra wireless python build_benchmark.py
cd ../../../..
uv run --extra onnx --extra wireless noema benchmark validate \
  .noema/training_exports/deepjscc_image_workbench/reference_training/benchmark_pack.yaml
uv run --extra onnx --extra wireless noema benchmark run \
  .noema/training_exports/deepjscc_image_workbench/reference_training/benchmark_pack.yaml

Progress and recovery#

Stage

Successful checkpoint

Safe recovery

Dataset fetch

24 Kodak files pass the recorded hashes

Rerun the fetch command

Export

data_contract.yaml and starter support files exist

Choose a fresh bundle, or deliberately enable overwrite

Contract validation

validate_contract.py reports a valid contract

Fix the reported file, hash, or interface error before training

Training/evaluation

Both ONNX files and trained_artifact.yaml exist

Rerun from the bundle; training does not resume an interrupted epoch sequence

Benchmark

The CLI prints RESULT_ID and result paths

Rebuild the pack only if its inputs changed; otherwise rerun the benchmark

Method and benchmark protocol#

The benchmark grid is [-6, -4, -2, 0, 4, 8, 12, 16] dB. The model trains on [-4, 0, 4, 8, 12, 16] dB, so −2 dB is an unseen interpolation point and −6 dB tests extrapolation below the training range.

The same channel-noise seeds—71001, 72001, and 73001—are reused at every SNR. This common-random-number design pairs the SNR comparisons; the seeds are not fresh independent draws at each coordinate. The capacity-matched JPEG reference is deterministic and runs once per SNR.

Both methods receive a maximum budget of 0.5 complex channel uses per source pixel. DeepJSCC emits that number directly. The JPEG model reserves the same full block even when its native bitstream uses less of the ideal capacity or the run is in outage.

The current JPEG recipe fixes the encoder configuration, including 4:2:0 subsampling, non-progressive output, and qualities 1–95. The current recipe template may evolve; the snapshot manifest records hashes for the exact per-run recipes used by the completed result.

Checks before interpretation#

Before interpreting a new result, verify that:

  1. every learned run uses the same paired-artifact identity;

  2. images 21–24 do not appear in the training contract;

  3. both methods are admitted under the 0.5-use resource limit;

  4. every selected JPEG bitstream is at or below its ideal capacity budget;

  5. quality 0 in the operating-point table is interpreted as the declared outage sentinel.

Completed reference result#

Warning

This stored result is descriptive tutorial evidence. Its 95% intervals cover three channel-noise seeds for one frozen model and the same four crops. They do not cover training initialization, model-selection, or image-population uncertainty.

Reference result identity

20260727T235925Z_semantic_comm.digital_vs_deepjscc_post_training_v3 contains 32 runs: one deterministic capacity-matched JPEG run and three learned noise realizations at each of eight SNR coordinates.

PSNR chart unavailable. The accessible quality table below contains the plotted means; the downloadable chart data contains interval bounds.

MS-SSIM chart unavailable. The accessible quality table below contains the plotted means; the downloadable chart data contains interval bounds.

Reconstruction-quality means#

SNR (dB)

JPEG PSNR (dB)

DeepJSCC PSNR (dB)

JPEG MS-SSIM

DeepJSCC MS-SSIM

-6

13.72

21.99

0.270

0.745

-4

17.64

23.14

0.509

0.805

-2

25.34

24.01

0.871

0.849

0

27.94

24.65

0.928

0.880

4

31.35

25.44

0.972

0.916

8

33.86

25.81

0.985

0.931

12

35.87

25.96

0.990

0.938

16

37.50

26.02

0.993

0.940

Capacity-matched JPEG operating points#

SNR (dB)

JPEG quality mean

JPEG quality range

JPEG native bpp

Ideal capacity bpp

-6

0.00

0–0

0.000

0.162

-4

1.25

0–3

0.118

0.242

-2

7.75

6–10

0.344

0.353

0

16.00

12–24

0.494

0.500

4

44.00

33–65

0.900

0.906

8

72.50

65–84

1.421

1.435

12

84.75

81–91

2.006

2.037

16

90.50

88–94

2.601

2.675

Communication-resource audit#

Method

Budgeted channel uses/source pixel

Maximum per-image channel uses/source pixel

Budget limit

Admitted

Capacity-matched JPEG

0.5

0.5

0.5

yes

Learned DeepJSCC

0.5

0.5

0.5

yes

In this completed run, DeepJSCC reaches 21.99 dB PSNR at −6 dB versus 13.72 dB for the JPEG reference, and 23.14 versus 17.64 dB at −4 dB. The ordering reverses at −2 dB, where JPEG reaches 25.34 dB and DeepJSCC 24.01 dB. At 16 dB, JPEG reaches 37.50 dB and DeepJSCC 26.02 dB. MS-SSIM follows the same ordering. These observations illustrate low-SNR graceful degradation for this artifact, dataset slice, and fixed bandwidth ratio; they do not establish universal learned superiority or rate-distortion optimality.

The reader-facing tables are rounded for comparison. Download the full-precision summary, per-run benchmark projection, chart data, and snapshot manifest for the stored values, run IDs, recipe hashes, resource checks, and statistical design. The manifest identifies the local raw result files by hash; the raw result bundle is not distributed by this documentation snapshot.

Verify your local result#

Set the variable to the ID printed by your benchmark:

cd "$(git rev-parse --show-toplevel)"
RESULT_ID="<paste-the-result-id>"
uv run --extra onnx --extra wireless noema benchmark verify "$RESULT_ID"

Read every verification warning before using the result outside a local experiment. Do not suppress warnings to make an experimental result appear publication-ready.

Publication status#

This benchmark remains experimental, the stored result is not paper-grade evidence, and the Kodak rights record is unresolved. A future publication path should require:

  1. authoritative dataset terms and an archived dataset citation;

  2. a canonical benchmark with traceability_profile_requested: true and the exact current profile binding;

  3. substantially more held-out images and channel seeds;

  4. independently trained models when making population-level claims;

  5. a persistently archived result bundle, environment identity, and verification report;

  6. publication without --allow-warnings.

References and implementation notes#

  • Bourtsoulatze, Kurka, and Gündüz, “Deep Joint Source-Channel Coding for Wireless Image Transmission”.

  • This tutorial preserves the paper’s fixed-bandwidth AWGN comparison idea but uses Noema’s CPU-sized residual model, Kodak split, training grid, and metric implementations. It is not a reproduction of the paper’s reported numbers.

  • JPEG thresholds depend on the Pillow/libjpeg build and the recipe’s exact encoder settings. MS-SSIM uses Noema’s configured pytorch-msssim implementation. The local result bundle and lock file provide the implementation context for a reproduced run.