Skip to content
AI360XpertBeta

ADMM

Split a hard problem into an easy smooth piece and an easy kinked piece, solve each alone, and let a price nudge them into agreement. Repeating that deal solves Lasso and distributed fits neither half can solve alone.

ADMM walks x from 0.45 to 0.29 and z from 0.0 to 0.29 in three steps toward the shared 0.4 Lasso point while the price settles at 0.5
ADMM walks x from 0.45 to 0.29 and z from 0.0 to 0.29 in three steps toward the shared 0.4 Lasso point while the price settles at 0.5

Why Does This Exist?

Lasso couples a smooth square with a kinky absolute value, so neither pure gradient descent nor pure thresholding applies. A Lasso with 10,000 features has the same structure repeated 10,000 times, and a distributed fit across 10 machines couples 10 local losses through one consensus variable. Solving jointly wastes the separability that makes each piece easy.

ADMM splits min⁡f(x)+g(z)\min f(x) + g(z) subject to Ax+Bz=cAx + Bz = c, where ff is the smooth part, gg is the possibly nonsmooth part, and Ax+Bz=cAx + Bz = c is the linear coupling, via the augmented Lagrangian and alternates an xx solve, a zz solve, and a price update. Each subproblem uses its best solver while the price negotiates agreement.

This page covers the splitting mechanism and its residuals. Convex structure lives in convex optimization, prices in Lagrangian duality, kinks in subgradients, and optimality certificates in optimality conditions.

The one idea you need first

The scaled form iterates x←arg⁡min⁡f+(ρ/2)∥Ax+Bz−c+u∥2x \leftarrow \arg\min f + (\rho/2)\lVert Ax + Bz - c + u \rVert^2, then z←arg⁡min⁡g+(ρ/2)∥⋅∥2z \leftarrow \arg\min g + (\rho/2)\lVert \cdot \rVert^2, then u←u+Ax+Bz−cu \leftarrow u + Ax + Bz - c, where ρ\rho is the penalty pace and uu is the scaled price. The primal residual r=Ax+Bz−cr = Ax + Bz - c measures disagreement and the dual residual ss measures suboptimality, and both must vanish. Background prices are in Lagrangian duality.

Think of It Like This

Two shops and a mediator

A baker with smooth oven costs and a florist with kinked staffing rules share one storefront window. The mediator proposes a split, each optimizes privately with the current rent added, then the mediator adjusts the rent by the disagreement and repeats.

The baker maps to the smooth xx solve, the florist maps to the thresholding zz solve, and the rent maps to the price uu. Neither shop solves the joint problem. The rent does.

Where it stops: a stubborn fixed rent stalls haggling when one residual dominates. Adaptive rents that rebalance residuals keep the deal moving.

How It Actually Works

For closed convex ff and gg, ADMM converges in residual, objective, and dual value. The xx update is often a ridge-like linear solve, the zz update is often a proximal soft threshold, and over-relaxation with α\alpha in [1.5,1.8][1.5, 1.8] often halves iterations. The consensus form gives each machine its own xix_i with one global zz, which is how distributed Lasso and distributed SVM train without moving raw data.

Concretely for Lasso split as (1/2)∥Ax−b∥2+λ∥z∥1(1/2)\lVert Ax - b \rVert^2 + \lambda \lVert z \rVert_1 subject to x−z=0x - z = 0, where AA is the feature matrix, bb is the target, and λ\lambda is the penalty: xx solves a linear system, zz soft-thresholds x+ux + u at λ/ρ\lambda/\rho, and uu accumulates x−zx - z.

Worked example

Scalar Lasso (1/2)(x−0.9)2+0.5∣x∣(1/2)(x - 0.9)^2 + 0.5\lvert x \rvert with split x−z=0x - z = 0, where 0.90.9 is the least-squares target and 0.50.5 is the penalty. The optimum soft-thresholds 0.9−0.5=0.40.9 - 0.5 = 0.4, since the target exceeds the penalty. Run ADMM with ρ=1.0\rho = 1.0, z0=0.0z_0 = 0.0, u0=0.0u_0 = 0.0, where ρ\rho paces agreement. Updates are x←(b+ρ(z−u))/(1+ρ)x \leftarrow (b + \rho(z - u))/(1 + \rho) and z←S0.5(x+u)z \leftarrow S_{0.5}(x + u), where SS is soft thresholding Sκ(v)=sign(v)max⁡(∣v∣−κ,0)S_{\kappa}(v) = \mathrm{sign}(v)\max(\lvert v \rvert - \kappa, 0).

Step 1: x1=(0.9+0.0)/2=0.45x_1 = (0.9 + 0.0)/2 = 0.45. Then x1+u0=0.45x_1 + u_0 = 0.45, which is below 0.50.5, so z1=0.0z_1 = 0.0. Price becomes u1=0.0+0.45−0.0=0.45u_1 = 0.0 + 0.45 - 0.0 = 0.45. Primal residual is 0.450.45.

Step 2: x2=(0.9+0.0−0.45)/2=0.225x_2 = (0.9 + 0.0 - 0.45)/2 = 0.225. Then x2+u1=0.675x_2 + u_1 = 0.675, minus 0.50.5 gives z2=0.175z_2 = 0.175. Price becomes u2=0.45+0.225−0.175=0.5u_2 = 0.45 + 0.225 - 0.175 = 0.5. Residual falls to 0.050.05.

Step 3: x3=(0.9+0.175−0.5)/2=0.2875x_3 = (0.9 + 0.175 - 0.5)/2 = 0.2875. Then x3+u2=0.7875x_3 + u_2 = 0.7875, minus 0.50.5 gives z3=0.2875z_3 = 0.2875. Price stays u3=0.5u_3 = 0.5. Residual is 0.00.0 and both halves sit at 0.28750.2875, walking up toward the shared 0.40.4 with uu settled at 0.50.5. About 15 such steps land within 0.010.01 of 0.40.4.

Code

The point is the check: the same three steps and the same 0.40.4 landing, in plain Python.

import math

def soft_threshold(v: float, kappa: float) -> float:    return math.copysign(max(abs(v) - kappa, 0.0), v)

def admm_lasso(b: float, lam: float, rho: float, steps: int) -> tuple[float, float, float]:    x: float = 0.0    z: float = 0.0    u: float = 0.0    for _ in range(steps):        x = (b + rho * (z - u)) / (1.0 + rho)        z = soft_threshold(x + u, lam / rho)        u = u + x - z    return (x, z, u)

x1, z1, u1 = admm_lasso(0.9, 0.5, 1.0, 1)print((round(x1, 4), round(z1, 4), round(u1, 4)))  # -> (0.45, 0.0, 0.45)
x2, z2, u2 = admm_lasso(0.9, 0.5, 1.0, 2)print((round(x2, 4), round(z2, 4), round(u2, 4)))  # -> (0.225, 0.175, 0.5)
x3, z3, u3 = admm_lasso(0.9, 0.5, 1.0, 3)print((round(x3, 4), round(z3, 4), round(u3, 4)))  # -> (0.2875, 0.2875, 0.5)
x50, z50, _ = admm_lasso(0.9, 0.5, 1.0, 50)print((round(x50, 3), round(z50, 3)))  # -> (0.4, 0.4)

Fifty rounds land both halves at 0.40.4. The price absorbs the 0.50.5 threshold shift and parks at 0.50.5.

Watch Out For

Stopping on one residual

Primal small with dual large means the halves agree but prices are wrong, so the point is feasible yet suboptimal. Dual small with primal large means each piece is optimal alone but they disagree, as after step 1 above where x1=0.45x_1 = 0.45 and z1=0.0z_1 = 0.0 look agreed only if you ignore the 0.450.45 gap.

Stop when both sit under tolerance with scaling. If one stalls while the other shrinks, retune ρ\rho instead of iterating.

Fixing rho forever

The default ρ=1.0\rho = 1.0 on badly scaled problems imbalances residuals 100-to-1 and crawls toward 0.40.4 sideways. Practitioners blame ADMM while the pace parameter idles.

Adapt ρ\rho to balance residuals, the residual-balancing rule. If the ratio exceeds 10 for many steps, rescale ρ\rho and rescale uu with it, then continue.

The Quick Version

  • ADMM splits smooth ff from kinked gg and alternates private solves with a price update.
  • Scalar Lasso with target 0.90.9 and penalty 0.50.5 converges both halves to 0.40.4.
  • Three steps give (0.45,0.0)(0.45, 0.0), then (0.225,0.175)(0.225, 0.175), then (0.2875,0.2875)(0.2875, 0.2875) with price 0.50.5.
  • The xx update ridge-solves, the zz update soft-thresholds, and uu accumulates the gap.
  • Both primal and dual residuals must vanish, and ρ\rho paces them.
  • Consensus form distributes learning with per-node solves and one global zz.
  • Adapt ρ\rho and over-relax near 1.71.7 for speed.