Skip to content

Commit 3d3dcea

Browse files
authored
Merge pull request #12 from khalil-research/NCE
Docs
2 parents db070e0 + b5738b9 commit 3d3dcea

File tree

6 files changed

+66
-48
lines changed

6 files changed

+66
-48
lines changed

notebooks/03 Training and Testing.ipynb

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@
413413
"id": "eebb2ef2",
414414
"metadata": {},
415415
"source": [
416-
"The core capability of PyEPO is to build optimization models with GurobiPy, Pyomo, or any other solvers and algorithms, then embed the optimization model into an artificial neural network for the end-to-end training. For this purpose, PyEPO implements **SPO+ loss** and **differentiable Black-Box optimizer**, **differentiable perturbed optimizer**, and **Fenchel-Young loss with Perturbation** as PyTorch autograd modules.\n",
416+
"The core capability of PyEPO is to build optimization models with GurobiPy, Pyomo, or any other solvers and algorithms, then embed the optimization model into an artificial neural network for the end-to-end training. For this purpose, PyEPO implements **SPO+ loss** and **differentiable Black-Box optimizer**, **differentiable perturbed optimizer**, **Fenchel-Young loss with Perturbation**, **Noise Contrastive Estimation**, and **Learning to Rank** as PyTorch autograd modules.\n",
417417
"\n",
418418
"We will train and test the above aproaches."
419419
]
@@ -1436,7 +1436,7 @@
14361436
"id": "7eaab10b",
14371437
"metadata": {},
14381438
"source": [
1439-
"it uses a Noise Contrastive approach to motivate a family of surrogate loss functions, based on viewing non-optimal solutions as negative examples."
1439+
"It uses a noise contrastive approach to motivate a family of surrogate loss functions, based on viewing non-optimal solutions as negative examples. For the NCE, the cost vector needs to be predicted from contextual data and maximizes the separation of the probability of the optimal solution."
14401440
]
14411441
},
14421442
{
@@ -1473,8 +1473,8 @@
14731473
"``pyepo.func.NCE`` allows us to use a noise contrastive estimiation loss for training, which requires parameters:\n",
14741474
"- ``optmodel``: an PyEPO optimization model\n",
14751475
"- ``processes``: number of processors for multi-thread, 1 for single-core, 0 for all of cores\n",
1476-
"- ``solve-ratio``: a ratio between 0 and 1 that denotes for what proportion of cost vectors predicted during training the instantiated optimization problem should be solved. Whenever the optimization problem is solved, the obtained solution is added to the solution pool which is ranked over.\n",
1477-
"- ``dataset``: a dataset to initialize the solution pool with. Usually this is simply the training set."
1476+
"- ``solve_ratio``: the ratio of new solutions computed during training\n",
1477+
"- ``dataset``: a dataset to initialize the solution pool with. Usually this is simply the training set"
14781478
]
14791479
},
14801480
{
@@ -1661,7 +1661,7 @@
16611661
"id": "2327a93b",
16621662
"metadata": {},
16631663
"source": [
1664-
"The listwise learning to rank loss measures the difference in how the predicted cost vector and the true cost vector rank a pool of feasible solutions, where listwise ranking measures the scores of the whole ranked lists."
1664+
"A autograd module for listwise learning to rank, where the goal is to learn an objective function that ranks a pool of feasible solutions correctly. For the listwise LTR, the cost vector needs to be predicted from contextual data, and the loss measures the scores of the whole ranked lists."
16651665
]
16661666
},
16671667
{
@@ -1703,8 +1703,8 @@
17031703
"``pyepo.func.listwiseLTR`` allows us to use a listwise learning to rank loss for training, which requires parameters:\n",
17041704
"- ``optmodel``: an PyEPO optimization model\n",
17051705
"- ``processes``: number of processors for multi-thread, 1 for single-core, 0 for all of cores\n",
1706-
"- ``solve-ratio``: a ratio between 0 and 1 that denotes for what proportion of cost vectors predicted during training the instantiated optimization problem should be solved. Whenever the optimization problem is solved, the obtained solution is added to the solution pool which is ranked over.\n",
1707-
"- ``dataset``: a dataset to initialize the solution pool with. Usually this is simply the training set."
1706+
"- ``solve_ratio``: the ratio of new solutions computed during training\n",
1707+
"- ``dataset``: a dataset to initialize the solution pool with. Usually this is simply the training set"
17081708
]
17091709
},
17101710
{
@@ -1911,7 +1911,7 @@
19111911
"id": "7477432c",
19121912
"metadata": {},
19131913
"source": [
1914-
"The pairwise learning to rank loss measures the difference in how the predicted cost vector and the true cost vector rank a pool of feasible solutions, where pairwise ranking aim to learn the relative ordering of pairs of items."
1914+
"An autograd module for pairwise learning to rank, where the goal is to learn an objective function that ranks a pool of feasible solutions correctly. For the pairwise LTR, the cost vector needs to be predicted from contextual data, and the loss learns the relative ordering of pairs of items."
19151915
]
19161916
},
19171917
{
@@ -1950,10 +1950,10 @@
19501950
"id": "27d7caf5",
19511951
"metadata": {},
19521952
"source": [
1953-
"``pyepo.func.listwiseLTR`` allows us to use a listwise learning to rank loss for training, which requires parameters:\n",
1953+
"``pyepo.func.pairwiseLTR`` allows us to use a listwise learning to rank loss for training, which requires parameters:\n",
19541954
"- ``optmodel``: an PyEPO optimization model\n",
19551955
"- ``processes``: number of processors for multi-thread, 1 for single-core, 0 for all of cores\n",
1956-
"- ``solve-ratio``: a ratio between 0 and 1 that denotes for what proportion of cost vectors predicted during training the instantiated optimization problem should be solved. Whenever the optimization problem is solved, the obtained solution is added to the solution pool which is ranked over.\n",
1956+
"- ``solve_ratio``: the ratio of new solutions computed during training\n",
19571957
"- ``dataset``: a dataset to initialize the solution pool with. Usually this is simply the training set."
19581958
]
19591959
},
@@ -2162,7 +2162,7 @@
21622162
"id": "ab4fef25",
21632163
"metadata": {},
21642164
"source": [
2165-
"The pointwise learning to rank loss measures the difference in how the predicted cost vector and the true cost vector rank a pool of feasible solutions, where pointwise ranking calculates the ranking scores of the items."
2165+
"An autograd module for pointwise learning to rank, where the goal is to learn an objective function that ranks a pool of feasible solutions correctly. For the pointwise LTR, the cost vector needs to be predicted from contextual data, and calculates the ranking scores of the items."
21662166
]
21672167
},
21682168
{
@@ -2201,11 +2201,11 @@
22012201
"id": "05dea9c7",
22022202
"metadata": {},
22032203
"source": [
2204-
"``pyepo.func.listwiseLTR`` allows us to use a listwise learning to rank loss for training, which requires parameters:\n",
2204+
"``pyepo.func.pointwiseLTR`` allows us to use a listwise learning to rank loss for training, which requires parameters:\n",
22052205
"- ``optmodel``: an PyEPO optimization model\n",
22062206
"- ``processes``: number of processors for multi-thread, 1 for single-core, 0 for all of cores\n",
2207-
"- ``solve-ratio``: a ratio between 0 and 1 that denotes for what proportion of cost vectors predicted during training the instantiated optimization problem should be solved. Whenever the optimization problem is solved, the obtained solution is added to the solution pool which is ranked over.\n",
2208-
"- ``dataset``: a dataset to initialize the solution pool with. Usually this is simply the training set."
2207+
"- ``solve_ratio``: the ratio of new solutions computed during training\n",
2208+
"- ``dataset``: a dataset to initialize the solution pool with. Usually this is simply the training set"
22092209
]
22102210
},
22112211
{

pkg/pyepo/func/blackbox.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
class blackboxOpt(optModule):
1717
"""
18-
A autograd module for differentiable black-box optimizer, which yield
18+
An autograd module for differentiable black-box optimizer, which yield
1919
optimal a solution and derive a gradient.
2020
2121
For differentiable block-box, the objective function is linear and

pkg/pyepo/func/contrastive.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/env python
22
# coding: utf-8
33
"""
4-
Noise Contrastive Estimation Loss function
4+
Noise contrastive estimation loss function
55
"""
66

77
import numpy as np
@@ -15,9 +15,13 @@
1515

1616
class NCE(optModule):
1717
"""
18-
An autograd module for the noise contrastive estimation loss.
19-
For the noise contrastive loss, the constraints are known and fixed,
20-
but the cost vector needs to be predicted from contextual data.
18+
An autograd module for noise contrastive estimation as surrogate loss
19+
functions, based on viewing non-optimal solutions as negative examples.
20+
21+
For the NCE, the cost vector needs to be predicted from contextual data and
22+
maximizes the separation of the probability of the optimal solution.
23+
24+
Thus, allows us to design an algorithm based on stochastic gradient descent.
2125
"""
2226

2327
def __init__(self, optmodel, processes=1, solve_ratio=1, dataset=None):
@@ -26,7 +30,7 @@ def __init__(self, optmodel, processes=1, solve_ratio=1, dataset=None):
2630
optmodel (optModel): an PyEPO optimization model
2731
processes (int): number of processors, 1 for single-core, 0 for all of cores
2832
solve_ratio (float): the ratio of new solutions computed during training
29-
dataset (None/optDataset): the training data
33+
dataset (None/optDataset): the training data, usually this is simply the training set
3034
"""
3135
super().__init__(optmodel, processes, solve_ratio, dataset)
3236
# solution pool

pkg/pyepo/func/perturbed.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
class perturbedOpt(optModule):
1717
"""
18-
A autograd module for differentiable perturbed optimizer, in which random
18+
An autograd module for differentiable perturbed optimizer, in which random
1919
perturbed costs are sampled to optimize.
2020
2121
For the perturbed optimizer, the cost vector need to be predicted from
@@ -133,7 +133,7 @@ def backward(ctx, grad_output):
133133

134134
class perturbedFenchelYoung(optModule):
135135
"""
136-
A autograd module for Fenchel-Young loss using perturbation techniques. The
136+
An autograd module for Fenchel-Young loss using perturbation techniques. The
137137
use of the loss improves the algorithmic by the specific expression of the
138138
gradients of the loss.
139139

pkg/pyepo/func/rank.py

Lines changed: 39 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/env python
22
# coding: utf-8
33
"""
4-
Learning To Rank Loss functions
4+
Learning to rank Losses
55
"""
66

77
import numpy as np
@@ -17,9 +17,13 @@
1717

1818
class listwiseLTR(optModule):
1919
"""
20-
An autograd module for the listwise learning to rank loss.
21-
For the listwise learning to rank loss, the constraints are known and fixed,
22-
but the cost vector needs to be predicted from contextual data.
20+
An autograd module for listwise learning to rank, where the goal is to learn
21+
an objective function that ranks a pool of feasible solutions correctly.
22+
23+
For the listwise LTR, the cost vector needs to be predicted from contextual
24+
data, and the loss measures the scores of the whole ranked lists.
25+
26+
Thus, allows us to design an algorithm based on stochastic gradient descent.
2327
"""
2428

2529
def __init__(self, optmodel, processes=1, solve_ratio=1, dataset=None):
@@ -28,7 +32,7 @@ def __init__(self, optmodel, processes=1, solve_ratio=1, dataset=None):
2832
optmodel (optModel): an PyEPO optimization model
2933
processes (int): number of processors, 1 for single-core, 0 for all of cores
3034
solve_ratio (float): the ratio of new solutions computed during training
31-
dataset (optDataset): the training data
35+
dataset (optDataset): the training data, usually this is simply the training set
3236
"""
3337
super().__init__(optmodel, processes, solve_ratio, dataset)
3438
# solution pool
@@ -51,11 +55,12 @@ def forward(self, pred_cost, true_cost, reduction="mean"):
5155
self.solpool = np.concatenate((self.solpool, sol))
5256
# remove duplicate
5357
self.solpool = np.unique(self.solpool, axis=0)
58+
# convert tensor
5459
solpool = torch.from_numpy(self.solpool.astype(np.float32)).to(device)
55-
# get obj for solpool
56-
objpool_c = true_cost @ solpool.T
57-
objpool_cp = pred_cost @ solpool.T
58-
# get cross entropy loss
60+
# obj for solpool
61+
objpool_c = true_cost @ solpool.T # true cost
62+
objpool_cp = pred_cost @ solpool.T # pred cost
63+
# cross entropy loss
5964
if self.optmodel.modelSense == EPO.MINIMIZE:
6065
loss = - (F.log_softmax(objpool_cp, dim=1) *
6166
F.softmax(objpool_c, dim=1))
@@ -76,9 +81,13 @@ def forward(self, pred_cost, true_cost, reduction="mean"):
7681

7782
class pairwiseLTR(optModule):
7883
"""
79-
An autograd module for the pairwise learning to rank loss.
80-
For the pairwise learning to rank loss, the constraints are known and fixed,
81-
but the cost vector needs to be predicted from contextual data.
84+
An autograd module for pairwise learning to rank, where the goal is to learn
85+
an objective function that ranks a pool of feasible solutions correctly.
86+
87+
For the pairwise LTR, the cost vector needs to be predicted from contextual
88+
data, and the loss learns the relative ordering of pairs of items.
89+
90+
Thus, allows us to design an algorithm based on stochastic gradient descent.
8291
"""
8392

8493
def __init__(self, optmodel, processes=1, solve_ratio=1, dataset=None):
@@ -112,24 +121,24 @@ def forward(self, pred_cost, true_cost, reduction="mean"):
112121
self.solpool = np.unique(self.solpool, axis=0)
113122
# convert tensor
114123
solpool = torch.from_numpy(self.solpool.astype(np.float32)).to(device)
115-
# get obj for solpool
116-
objpool_c = torch.einsum("bd,nd->bn", true_cost, solpool)
117-
objpool_cp = torch.einsum("bd,nd->bn", pred_cost, solpool)
124+
# obj for solpool
125+
objpool_c = torch.einsum("bd,nd->bn", true_cost, solpool) # true cost
126+
objpool_cp = torch.einsum("bd,nd->bn", pred_cost, solpool) # pred cost
118127
# init relu as max(0,x)
119128
relu = nn.ReLU()
120129
# init loss
121130
loss = []
122131
for i in range(len(pred_cost)):
123-
# get best
132+
# best sol
124133
if self.optmodel.modelSense == EPO.MINIMIZE:
125134
best_ind = torch.argmin(objpool_c[i])
126135
if self.optmodel.modelSense == EPO.MAXIMIZE:
127136
best_ind = torch.argmax(objpool_c[i])
128137
objpool_cp_best = objpool_cp[i, best_ind]
129-
# get rest
138+
# rest sol
130139
rest_ind = [j for j in range(len(objpool_cp[i])) if j != best_ind]
131140
objpool_cp_rest = objpool_cp[i, rest_ind]
132-
# get loss
141+
# best vs rest loss
133142
if self.optmodel.modelSense == EPO.MINIMIZE:
134143
loss.append(relu(objpool_cp_best - objpool_cp_rest).mean())
135144
if self.optmodel.modelSense == EPO.MAXIMIZE:
@@ -149,9 +158,14 @@ def forward(self, pred_cost, true_cost, reduction="mean"):
149158

150159
class pointwiseLTR(optModule):
151160
"""
152-
An autograd module for the pointwise learning to rank loss.
153-
For the pointwise learning to rank loss, the constraints are known and fixed,
154-
but the cost vector needs to be predicted from contextual data.
161+
An autograd module for pointwise learning to rank, where the goal is to
162+
learn an objective function that ranks a pool of feasible solutions
163+
correctly.
164+
165+
For the pointwise LTR, the cost vector needs to be predicted from contextual
166+
data, and calculates the ranking scores of the items.
167+
168+
Thus, allows us to design an algorithm based on stochastic gradient descent.
155169
"""
156170

157171
def __init__(self, optmodel, processes=1, solve_ratio=1, dataset=None):
@@ -185,10 +199,10 @@ def forward(self, pred_cost, true_cost, reduction="mean"):
185199
self.solpool = np.unique(self.solpool, axis=0)
186200
# convert tensor
187201
solpool = torch.from_numpy(self.solpool.astype(np.float32)).to(device)
188-
# get obj for solpool as score
189-
objpool_c = true_cost @ solpool.T
190-
objpool_cp = pred_cost @ solpool.T
191-
# get squared loss
202+
# obj for solpool as score
203+
objpool_c = true_cost @ solpool.T # true cost
204+
objpool_cp = pred_cost @ solpool.T # pred cost
205+
# squared loss
192206
loss = (objpool_c - objpool_cp).square()
193207
# reduction
194208
if reduction == "mean":

pkg/pyepo/func/spoplus.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
class SPOPlus(optModule):
1616
"""
17-
A autograd module for SPO+ Loss, as a surrogate loss function of SPO Loss,
17+
An autograd module for SPO+ Loss, as a surrogate loss function of SPO Loss,
1818
which measures the decision error of optimization problem.
1919
2020
For SPO/SPO+ Loss, the objective function is linear and constraints are

0 commit comments

Comments
 (0)