humancompatible-train 0.3.0__tar.gz → 0.3.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. {humancompatible_train-0.3.0/src/humancompatible_train.egg-info → humancompatible_train-0.3.2}/PKG-INFO +2 -4
  2. {humancompatible_train-0.3.0 → humancompatible_train-0.3.2}/README.md +0 -2
  3. {humancompatible_train-0.3.0 → humancompatible_train-0.3.2}/pyproject.toml +2 -2
  4. humancompatible_train-0.3.2/src/humancompatible/train/dual_optim/__init__.py +4 -0
  5. humancompatible_train-0.3.2/src/humancompatible/train/dual_optim/alm.py +369 -0
  6. {humancompatible_train-0.3.0 → humancompatible_train-0.3.2}/src/humancompatible/train/dual_optim/barrier.py +19 -20
  7. humancompatible_train-0.3.2/src/humancompatible/train/dual_optim/ialm.py +330 -0
  8. {humancompatible_train-0.3.0 → humancompatible_train-0.3.2}/src/humancompatible/train/dual_optim/moreau.py +24 -14
  9. humancompatible_train-0.3.2/src/humancompatible/train/dual_optim/nupi.py +357 -0
  10. humancompatible_train-0.3.2/src/humancompatible/train/dual_optim/pbm.py +503 -0
  11. {humancompatible_train-0.3.0 → humancompatible_train-0.3.2}/src/humancompatible/train/fairness/utils/balanced_batch_sampler.py +7 -5
  12. {humancompatible_train-0.3.0 → humancompatible_train-0.3.2}/src/humancompatible/train/optim/PBM.py +1 -1
  13. {humancompatible_train-0.3.0 → humancompatible_train-0.3.2/src/humancompatible_train.egg-info}/PKG-INFO +2 -4
  14. {humancompatible_train-0.3.0 → humancompatible_train-0.3.2}/src/humancompatible_train.egg-info/SOURCES.txt +2 -1
  15. {humancompatible_train-0.3.0 → humancompatible_train-0.3.2}/tests/test_alm.py +3 -3
  16. {humancompatible_train-0.3.0 → humancompatible_train-0.3.2}/tests/test_balanced_batch_sampler.py +30 -26
  17. humancompatible_train-0.3.2/tests/test_pbm.py +532 -0
  18. humancompatible_train-0.3.0/src/humancompatible/train/dual_optim/__init__.py +0 -3
  19. humancompatible_train-0.3.0/src/humancompatible/train/dual_optim/alm.py +0 -204
  20. humancompatible_train-0.3.0/src/humancompatible/train/dual_optim/pbm.py +0 -307
  21. humancompatible_train-0.3.0/src/humancompatible/train/fairness/__init__.py +0 -0
  22. humancompatible_train-0.3.0/tests/test_pbm.py +0 -94
  23. {humancompatible_train-0.3.0 → humancompatible_train-0.3.2}/LICENCE.txt +0 -0
  24. {humancompatible_train-0.3.0 → humancompatible_train-0.3.2}/setup.cfg +0 -0
  25. {humancompatible_train-0.3.0/src/humancompatible → humancompatible_train-0.3.2/src/humancompatible/train}/__init__.py +0 -0
  26. {humancompatible_train-0.3.0/src/humancompatible/train → humancompatible_train-0.3.2/src/humancompatible/train/benchmark}/__init__.py +0 -0
  27. {humancompatible_train-0.3.0 → humancompatible_train-0.3.2}/src/humancompatible/train/benchmark/algorithms/Algorithm.py +0 -0
  28. {humancompatible_train-0.3.0 → humancompatible_train-0.3.2}/src/humancompatible/train/benchmark/algorithms/__init__.py +0 -0
  29. {humancompatible_train-0.3.0 → humancompatible_train-0.3.2}/src/humancompatible/train/benchmark/algorithms/ghost.py +0 -0
  30. {humancompatible_train-0.3.0 → humancompatible_train-0.3.2}/src/humancompatible/train/benchmark/algorithms/optim_wrapper.py +0 -0
  31. {humancompatible_train-0.3.0 → humancompatible_train-0.3.2}/src/humancompatible/train/benchmark/algorithms/sgd.py +0 -0
  32. {humancompatible_train-0.3.0 → humancompatible_train-0.3.2}/src/humancompatible/train/benchmark/algorithms/ssl_alm.py +0 -0
  33. {humancompatible_train-0.3.0 → humancompatible_train-0.3.2}/src/humancompatible/train/benchmark/algorithms/switching_subgradient.py +0 -0
  34. {humancompatible_train-0.3.0 → humancompatible_train-0.3.2}/src/humancompatible/train/benchmark/algorithms/utils.py +0 -0
  35. {humancompatible_train-0.3.0 → humancompatible_train-0.3.2}/src/humancompatible/train/benchmark/constraints/__init__.py +0 -0
  36. {humancompatible_train-0.3.0 → humancompatible_train-0.3.2}/src/humancompatible/train/benchmark/constraints/constraint.py +0 -0
  37. {humancompatible_train-0.3.0 → humancompatible_train-0.3.2}/src/humancompatible/train/benchmark/constraints/constraint_fns.py +0 -0
  38. {humancompatible_train-0.3.0 → humancompatible_train-0.3.2}/src/humancompatible/train/benchmark/constraints/torch/__init__.py +0 -0
  39. {humancompatible_train-0.3.0 → humancompatible_train-0.3.2}/src/humancompatible/train/benchmark/constraints/torch/constraints.py +0 -0
  40. {humancompatible_train-0.3.0/src/humancompatible/train/benchmark → humancompatible_train-0.3.2/src/humancompatible/train/fairness}/__init__.py +0 -0
  41. {humancompatible_train-0.3.0 → humancompatible_train-0.3.2}/src/humancompatible/train/fairness/utils/__init__.py +0 -0
  42. {humancompatible_train-0.3.0 → humancompatible_train-0.3.2}/src/humancompatible/train/optim/__init__.py +0 -0
  43. {humancompatible_train-0.3.0 → humancompatible_train-0.3.2}/src/humancompatible/train/optim/barrier.py +0 -0
  44. {humancompatible_train-0.3.0 → humancompatible_train-0.3.2}/src/humancompatible/train/optim/ssl_alm.py +0 -0
  45. {humancompatible_train-0.3.0 → humancompatible_train-0.3.2}/src/humancompatible/train/optim/ssl_alm_adam.py +0 -0
  46. {humancompatible_train-0.3.0 → humancompatible_train-0.3.2}/src/humancompatible/train/optim/ssl_alm_adam_moment.py +0 -0
  47. {humancompatible_train-0.3.0 → humancompatible_train-0.3.2}/src/humancompatible/train/optim/ssw.py +0 -0
  48. {humancompatible_train-0.3.0 → humancompatible_train-0.3.2}/src/humancompatible/train/optim/ssw_barrier.py +0 -0
  49. {humancompatible_train-0.3.0 → humancompatible_train-0.3.2}/src/humancompatible_train.egg-info/dependency_links.txt +0 -0
  50. {humancompatible_train-0.3.0 → humancompatible_train-0.3.2}/src/humancompatible_train.egg-info/requires.txt +0 -0
  51. {humancompatible_train-0.3.0 → humancompatible_train-0.3.2}/src/humancompatible_train.egg-info/top_level.txt +0 -0
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: humancompatible-train
3
- Version: 0.3.0
3
+ Version: 0.3.2
4
4
  Summary: PyTorch-based package for constrained training of neural networks
5
5
  Author: Gilles Bareilles, Adam Bosak, Jana Lepsova, Jakub Marecek
6
6
  Author-email: Andrii Kliachkin <kliacand@fel.cvut.cz>
7
7
  Maintainer-email: Andrii Kliachkin <kliacand@fel.cvut.cz>
8
- Requires-Python: <3.14,>=3.11
8
+ Requires-Python: >=3.11
9
9
  Description-Content-Type: text/markdown
10
10
  License-File: LICENCE.txt
11
11
  Requires-Dist: torch
@@ -156,8 +156,6 @@ The constraint options are:
156
156
  - `equalized_odds_vec`: constraint on the Positive Rate of each group as defined by `fairret.NormLoss`;
157
157
  - `weight_norm`: constraint on the Frobenius norm of the weights and biases of each layer of the neural network.
158
158
 
159
- The above command will run the benchmark and save the logs and models in the `benchmark/results/[dataset]_[task]` directory; it will also plot the trajectories into a .png file saved in the same location.
160
-
161
159
  The benchmarking code (all of which is contained in the `benchmark` directory) is easy to parse and extend with other datasets and constraints.
162
160
 
163
161
 
@@ -124,8 +124,6 @@ The constraint options are:
124
124
  - `equalized_odds_vec`: constraint on the Positive Rate of each group as defined by `fairret.NormLoss`;
125
125
  - `weight_norm`: constraint on the Frobenius norm of the weights and biases of each layer of the neural network.
126
126
 
127
- The above command will run the benchmark and save the logs and models in the `benchmark/results/[dataset]_[task]` directory; it will also plot the trajectories into a .png file saved in the same location.
128
-
129
127
  The benchmarking code (all of which is contained in the `benchmark` directory) is easy to parse and extend with other datasets and constraints.
130
128
 
131
129
 
@@ -4,12 +4,12 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "humancompatible-train"
7
- version = "0.3.0"
7
+ version = "0.3.2"
8
8
  dependencies = [
9
9
  "torch",
10
10
  "numpy",
11
11
  ]
12
- requires-python = ">= 3.11, <3.14"
12
+ requires-python = ">= 3.11"
13
13
  authors = [
14
14
  {name = "Andrii Kliachkin", email = "kliacand@fel.cvut.cz"},
15
15
  {name = "Gilles Bareilles"},
@@ -0,0 +1,4 @@
1
+ from .alm import ALM
2
+ from .ialm import iALM
3
+ from .pbm import PBM
4
+ from .moreau import MoreauEnvelope
@@ -0,0 +1,369 @@
1
+ import torch
2
+ from torch.nn import Parameter
3
+ from torch.optim import Optimizer
4
+ from typing import Any, Tuple
5
+ from torch import clamp_, Tensor
6
+
7
+ # cite: Stochastic Smoothed Primal-Dual Algorithms for Nonconvex Optimization with Linear Inequality Constraints
8
+ # https://arxiv.org/pdf/2504.07607
9
+
10
+
11
+ class ALM(Optimizer):
12
+ def __init__(
13
+ self,
14
+ m: int = None,
15
+ lr: float = 0.01,
16
+ init_duals: float | Tensor = None,
17
+ penalty: float = 1.0,
18
+ *,
19
+ dual_range: Tuple[float, float] = (-100.0, 100.0),
20
+ momentum: float = 0.0,
21
+ dampening: float = 0.0,
22
+ is_ineq: bool = False,
23
+ ctol: float = 0.,
24
+ device=None,
25
+ ) -> None:
26
+
27
+ if momentum > 0 and dampening == 0:
28
+ dampening = momentum
29
+
30
+ # self.dual_range = dual_range
31
+ # self.ctol = ctol
32
+
33
+ self.penalty = penalty
34
+ duals, defaults = _init_constraint_group(
35
+ m, lr, momentum, dampening, init_duals, dual_range, is_ineq, device
36
+ )
37
+
38
+ super().__init__(duals, defaults)
39
+
40
+ @property
41
+ def duals(self) -> Tensor:
42
+ """
43
+ :return: Dual variables, concatenated into a single tensor.
44
+ :rtype: Tensor
45
+ """
46
+ return torch.cat([group["params"][0] for group in self.param_groups])
47
+
48
+ def add_constraint_group(
49
+ self,
50
+ m: int,
51
+ lr: float = None,
52
+ momentum: float = None,
53
+ dampening: float = None,
54
+ init_duals: Tensor = None,
55
+ dual_range: tuple[float, float] = None,
56
+ is_ineq: bool = False,
57
+ device = None
58
+ ) -> None:
59
+ """
60
+ Allows to add a group of dual variables with separate initial values and learning rates.
61
+
62
+ :param m: Size of group (number of dual variables to add)
63
+ :type m: int
64
+ :param lr: Dual variable update rate.
65
+ :type lr: float
66
+ :param momentum: Momentum/Smoothing factor for dual variables. Equivalent to SGD momentum. Set to `0` to disable.
67
+ :type momentum: float
68
+ :param dampening: Dampening for momentum. Equivalent to SGD dampening. Set to `0` to disable.
69
+ :type dampening: float
70
+ :param init_duals: Initial values for the new dual variables. Defaults to the value set when creating the optimizer.
71
+ :type init_duals: Tensor
72
+ :param dual_range: After each dual update, the dual variables will be clamped to this range.
73
+ :type dual_range: Tuple[float, float]
74
+ :param is_ineq: Whether to treat the constraints as equality or inequality. If`True`, dual variables will be relaxed on strict satisfaction and lower-bounded by `max(dual_range[0], 0)`.
75
+ :type is_ineq: bool
76
+
77
+ .. note::
78
+ Parameters here will default to values set when initializing the dual optimizer.
79
+
80
+ """
81
+ duals, settings_dict = _init_constraint_group(
82
+ m, lr, momentum, dampening, init_duals, dual_range, is_ineq, device
83
+ )
84
+ param_group_dict = {"params": duals, **settings_dict}
85
+ self.add_param_group(param_group_dict)
86
+
87
+ def _add_penalty_term(self, lagrangian: Tensor, constraints: Tensor) -> None:
88
+ """Add penalty term to lagrangian in-place."""
89
+ if self.penalty == 0:
90
+ return
91
+ elif constraints.ndim > 0:
92
+ lagrangian.add_(
93
+ 0.5
94
+ * self.penalty
95
+ * torch.dot(constraints, constraints)
96
+ )
97
+ else:
98
+ lagrangian.add_(
99
+ 0.5
100
+ * self.penalty
101
+ * torch.square(constraints)
102
+ )
103
+
104
+
105
+ def forward(self, loss: Tensor, constraints: Tensor) -> Tensor:
106
+ """
107
+ Calculates and returns the Augmented Lagrangian.
108
+
109
+ Computes the augmented Lagrangian::
110
+
111
+ L = loss + sum(duals_i @ constraints_i for all groups) + 0.5 * penalty * ||constraints||^2
112
+
113
+ where `loss` is the objective value, `duals_i` are the dual variables, `constraints_i` are constraint values,
114
+ `penalty` is the penalty parameter, and the sum is over all constraint groups.
115
+
116
+ :param loss: Loss (objective function) value
117
+ :type loss: Tensor
118
+ :param constraints: Tensor of constraint values
119
+ :type constraints: Tensor
120
+ :return: Lagrangian
121
+ :rtype: Tensor
122
+ """
123
+ lagrangian = torch.zeros_like(loss)
124
+ lagrangian.add_(loss)
125
+
126
+ for i in range(len(self.param_groups)):
127
+ duals, group_constraints = _process_constraint_group(
128
+ self.param_groups[i], i, constraints, update_duals=False
129
+ )
130
+ lagrangian.add_(duals @ group_constraints)
131
+
132
+ self._add_penalty_term(lagrangian, constraints)
133
+ return lagrangian
134
+
135
+
136
+ def update(self, constraints: Tensor) -> None:
137
+ """
138
+ Updates the dual variables using constrained gradient ascent with optional momentum.
139
+
140
+ For each constraint group, performs the dual variable update.
141
+
142
+ First, update the momentum buffer (if momentum > 0)::
143
+
144
+ if momentum > 0:
145
+ buffer_i = momentum * buffer_i + (1 - dampening) * constraints_i
146
+ else:
147
+ buffer_i = constraints_i
148
+
149
+ Then, update the dual variables with clamping::
150
+
151
+ duals_i = clamp(duals_i + lr * buffer_i, lower_bound, upper_bound)
152
+
153
+ where `buffer_i` is the momentum buffer, `constraints_i` are constraint values, `duals_i` are dual variables,
154
+ and `clamp(x, lb, ub)` projects to the dual range.
155
+
156
+ :param constraints: Tensor of constraint values
157
+ :type constraints: Tensor
158
+ """
159
+ for i in range(len(self.param_groups)):
160
+ _process_constraint_group(
161
+ self.param_groups[i], i, constraints, update_duals=True
162
+ )
163
+
164
+ # evaluate the Lagrangian and update the dual variables
165
+ def forward_update(self, loss: Tensor, constraints: Tensor) -> Tensor:
166
+ """
167
+ Combines `forward` and `update`; slightly faster than calling both separately.
168
+
169
+ Updates dual variables::
170
+
171
+ duals_i = clamp(duals_i + lr * buffer_i, lower_bound, upper_bound)
172
+
173
+ Then computes the augmented Lagrangian::
174
+
175
+ L = loss + sum(duals_i @ constraints_i for all groups) + 0.5 * penalty * ||constraints||^2
176
+
177
+
178
+ where the momentum buffer is updated as in :meth:`update`.
179
+
180
+ :param loss: Loss (objective function) value
181
+ :type loss: Tensor
182
+ :param constraints: Tensor of constraint values
183
+ :type constraints: Tensor
184
+ :return: Lagrangian
185
+ :rtype: Tensor
186
+ """
187
+ lagrangian = torch.zeros_like(loss)
188
+ lagrangian.add_(loss)
189
+
190
+ for i in range(len(self.param_groups)):
191
+ duals, group_constraints = _process_constraint_group(
192
+ self.param_groups[i], i, constraints, update_duals=True
193
+ )
194
+ lagrangian.add_(duals @ group_constraints)
195
+
196
+ self._add_penalty_term(lagrangian, constraints)
197
+ return lagrangian
198
+
199
+ def state_dict(self) -> dict[str, Any]:
200
+ """"""
201
+ state_dict = super().state_dict()
202
+ state_dict["state"]["penalty"] = self.penalty
203
+ # save params themselves in state_dict instead of param ID in default PyTorch
204
+ for id_pg, pg in enumerate(state_dict["param_groups"]):
205
+ pg["params"] = [
206
+ self.param_groups[id_pg]["params"][param_id]
207
+ for param_id in pg["params"]
208
+ ]
209
+ return state_dict
210
+
211
+ def load_state_dict(self, state_dict: dict[str, Any]) -> None:
212
+ """"""
213
+ self.penalty = state_dict["state"]["penalty"]
214
+ # self.dual_range = state_dict["state"]["dual_range"]
215
+ params = state_dict["param_groups"]
216
+ self.param_groups = []
217
+ for param in params:
218
+ self.param_groups.append(param)
219
+
220
+
221
+ def _process_constraint_group(
222
+ group: dict[str, Any],
223
+ group_idx: int,
224
+ constraints: Tensor,
225
+ update_duals: bool = False,
226
+ ) -> Tuple[Tensor, Tensor]:
227
+ """
228
+ Process a single constraint group: extract duals/constraints and optionally update duals.
229
+
230
+ :param group: The constraint group dictionary
231
+ :param group_idx: Index of the constraint group
232
+ :param constraints: Full constraints tensor
233
+ :param update_duals: Whether to update dual variables
234
+ :return: Tuple of (duals, group_constraints)
235
+ """
236
+ duals = group["params"][0]
237
+ if constraints.ndim > 0:
238
+ group_constraints = (
239
+ constraints[group_idx * len(duals) : (group_idx + 1) * len(duals)]
240
+ )
241
+ else:
242
+ group_constraints = constraints.unsqueeze(0)
243
+
244
+ lr = group.get("lr")
245
+ momentum = group.get("momentum", 0.0)
246
+ dampening = group.get("dampening", 0.0)
247
+ momentum_buffer = group["momentum_buffer"]
248
+ dual_lb = group.get("lower_bound")
249
+ dual_ub = group.get("upper_bound")
250
+ is_ineq = group.get("is_ineq")
251
+
252
+ with torch.no_grad():
253
+ if momentum > 0:
254
+ _update_c_buffers(group_constraints, momentum, dampening, momentum_buffer)
255
+ if update_duals:
256
+ _update_duals(duals, momentum_buffer if momentum > 0 else group_constraints, lr)
257
+ clamp_(duals, min=dual_lb, max=dual_ub)
258
+
259
+
260
+ return duals, group_constraints
261
+
262
+
263
+ def _init_constraint_group(
264
+ m: int = None,
265
+ lr: float = None,
266
+ momentum: float = None,
267
+ dampening: float = None,
268
+ init_duals: float | Tensor = None,
269
+ dual_range: Tuple[float, float] = None,
270
+ is_ineq: bool = None,
271
+ device = None,
272
+ ):
273
+ ## checks ##
274
+ if init_duals is None and m is None:
275
+ raise ValueError("At least one of m, init_duals must be set")
276
+
277
+ if momentum is not None and (momentum < 0 or momentum > 1):
278
+ raise ValueError(f"momentum must be within [0,1]; got {momentum}")
279
+
280
+ if not isinstance(is_ineq, bool):
281
+ raise ValueError(f"Expected a Boolean value for is_ineq, got {is_ineq}")
282
+
283
+ m = m if m is not None else len(init_duals)
284
+
285
+ if init_duals is None: # initialize duals if not set or set to scalar
286
+ init_duals = torch.zeros(m, requires_grad=False, device=device)
287
+ elif isinstance(init_duals, float):
288
+ init_duals = torch.zeros(m, requires_grad=False, device=device) + init_duals
289
+
290
+ duals = Parameter(init_duals, requires_grad=False)
291
+
292
+ if dual_range is None and not is_ineq:
293
+ dual_range = (None, None)
294
+ elif dual_range is None and is_ineq:
295
+ dual_range = (0, None)
296
+
297
+ settings_dict = {
298
+ "lr": lr,
299
+ "momentum": momentum,
300
+ "dampening": dampening,
301
+ "momentum_buffer": torch.zeros_like(
302
+ init_duals, requires_grad=False, device=device
303
+ ),
304
+ "lower_bound": max(dual_range[0], 0) if is_ineq else dual_range[0],
305
+ "upper_bound": dual_range[1],
306
+ "is_ineq": is_ineq
307
+ }
308
+ settings_dict = {k: v for k, v in settings_dict.items() if v is not None}
309
+
310
+ param_group = ([duals], settings_dict)
311
+ return param_group
312
+
313
+
314
+ def _update_c_buffers(
315
+ constraints: Tensor,
316
+ momentum: float,
317
+ dampening: float,
318
+ buffer: Tensor,
319
+ ) -> None:
320
+ """Update the constraint buffer with momentum."""
321
+ if momentum == 0:
322
+ buffer = constraints
323
+ else:
324
+ buffer.mul_(momentum).add_(constraints, alpha=1 - dampening)
325
+
326
+
327
+ def _update_duals(
328
+ duals: Tensor,
329
+ buffer: Tensor,
330
+ lr: float,
331
+ ) -> None:
332
+ """Update duals using the buffered constraint gradients."""
333
+ duals.add_(buffer, alpha=lr)
334
+
335
+
336
+
337
+ ALM.__doc__ = (
338
+
339
+ # \textbf{input}: \gamma \text{ (lr) }, \pmb{\lambda}_t \text{ (dual variables, created by method) }, \\
340
+ # \mathbf{c}(\theta) \text{ (constraints) }, f(\theta) \text{ (objective) }, \rho \text{ (penalty coefficient) } \\
341
+ r"""
342
+ A Dual Optimizer that works on the dual maximization tasks according to the Augmented Lagrangian rule. Creates and updates dual variables. Reference: https://doi.org/10.48550/arXiv.2504.07607
343
+
344
+ .. math::
345
+
346
+ \pmb{\lambda}_{t+1} & \leftarrow \pmb{\lambda}_t + \gamma \mathbf{c}_t(\theta_{t})
347
+
348
+ \mathcal{L}_{t+1} & \leftarrow f_t(\theta_{t}) + \pmb{\lambda}_{t+1}^T \mathbf{c}_t(\theta_{t}) + \frac{\rho}{2} \| \mathbf{c}_t(\theta_{t}) \|^2_2
349
+
350
+ :param m: Number of constraints (determines the number of dual variables to create)
351
+ :type m: int
352
+ :param lr: Dual variable update rate.
353
+ :type lr: float
354
+ :param init_duals: Initial values for the new dual variables. Defaults to 0 for all.
355
+ :type init_duals: float | Tensor
356
+ :param penalty: Augmented Lagrangian penalty parameter. Defaults to`1.`
357
+ :type penalty: float
358
+ :param dual_range: Safeguarding range for dual variables; they will be`clamp`-ed to this range.
359
+ :type dual_range: Tuple[float, float]
360
+ :param momentum: Momentum/Smoothing factor for dual variables. Equivalent to SGD momentum. Set to `0` to disable.
361
+ :type momentum: float
362
+ :param dampening: Dampening for momentum. Equivalent to SGD dampening. Set to `0` to disable.
363
+ :type dampening: float
364
+ :param is_ineq: Whether to treat the constraints as equality or inequality. If`True`, dual variables will be decreased on strict satisfaction and lower-bounded by `max(dual_range[0], 0)`.
365
+ :type is_ineq: bool
366
+ :param ctol: Constraint tolerance; allows tiny violations of constraints to account for noise.
367
+ :type ctol: float
368
+ """
369
+ )
@@ -8,23 +8,22 @@ https://www.researchgate.net/publication/2775406_PenaltyBarrier_Multiplier_Metho
8
8
 
9
9
  """
10
10
 
11
+
11
12
  def exponential_penalty(t):
12
13
 
13
14
  return torch.exp(t) - 1.0
14
15
 
16
+
15
17
  def modified_log_barrier(t):
16
18
 
17
- return -torch.log(1-t)
19
+ return -torch.log(1 - t)
20
+
18
21
 
19
22
  def augmented_lagrangian(t):
20
23
  """
21
24
  Vectorized version of augmented_lagrangian
22
25
  """
23
- return torch.where(
24
- t >= -1,
25
- t + 0.5 * torch.square(t),
26
- -0.5 * torch.ones_like(t)
27
- )
26
+ return torch.where(t >= -1, t + 0.5 * torch.square(t), -0.5 * torch.ones_like(t))
28
27
 
29
28
 
30
29
  def quad_log(t):
@@ -36,7 +35,7 @@ def quad_log(t):
36
35
 
37
36
  mask = t >= -0.5
38
37
  out[mask] = t[mask] + 0.5 * torch.pow(t[mask], 2)
39
- out[~mask] = -0.25 * torch.log(-2 * t[~mask]) - 3/8
38
+ out[~mask] = -0.25 * torch.log(-2 * t[~mask]) - 3 / 8
40
39
 
41
40
  return out
42
41
 
@@ -48,27 +47,26 @@ def quad_recipr(t):
48
47
 
49
48
  out = torch.empty_like(t)
50
49
 
51
- mask = t >= -1/3
50
+ mask = t >= -1 / 3
52
51
  out[mask] = t[mask] + 0.5 * torch.pow(t[mask], 2)
53
- out[~mask] = (32/27) * (1 / (1 - t[~mask])) - 7/6
52
+ out[~mask] = (32 / 27) * (1 / (1 - t[~mask])) - 7 / 6
53
+
54
+ return out
54
55
 
55
- return out
56
56
 
57
57
  def exponential_penalty_derivative(t):
58
58
 
59
- return torch.exp(t)
59
+ return torch.exp(t)
60
+
60
61
 
61
62
  def modified_log_barrier_derivative(t):
62
63
 
63
- return 1 / (1-t)
64
+ return 1 / (1 - t)
65
+
64
66
 
65
67
  def aug_lagr_der(t):
66
68
 
67
- return torch.where(
68
- t >= -1,
69
- 1 + t,
70
- torch.zeros_like(t)
71
- )
69
+ return torch.where(t >= -1, 1 + t, torch.zeros_like(t))
72
70
 
73
71
 
74
72
  def quad_log_der(t):
@@ -81,12 +79,13 @@ def quad_log_der(t):
81
79
 
82
80
  return out
83
81
 
82
+
84
83
  def quad_recipr_der(t):
85
84
 
86
85
  out = torch.empty_like(t)
87
86
 
88
- mask = t >= -1/3
87
+ mask = t >= -1 / 3
89
88
  out[mask] = 1 + t[mask]
90
- out[~mask] = (32/27) * (1 / torch.square(1 - t[~mask]))
89
+ out[~mask] = (32 / 27) * (1 / torch.square(1 - t[~mask]))
91
90
 
92
- return out
91
+ return out