Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modify gRPC API with Current Request Number #1728

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions docs/new-algorithm-service.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ class HyperoptService(
trials = Trial.convert(request.trials)
#--------------------------------------------------------------
# Your code here
# Implement the logic to generate new assignments for the given request number.
# For example, if request.request_number is 2, you should return:
# Implement the logic to generate new assignments for the given current request number.
# For example, if request.current_request_number is 2, you should return:
# [
# [Assignment(name=param-1, value=3),
# Assignment(name=param-2, value=cat2),
Expand All @@ -73,7 +73,7 @@ class HyperoptService(
# Assignment(name=param-4, value=4.32)
# ],
# ]
list_of_assignments = your_logic(search_space, trials, request.request_number)
list_of_assignments = your_logic(search_space, trials, request.current_request_number)
#--------------------------------------------------------------
# Convert list_of_assignments to
return api_pb2.GetSuggestionsReply(
Expand Down
241 changes: 121 additions & 120 deletions pkg/apis/manager/v1beta1/api.pb.go

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions pkg/apis/manager/v1beta1/api.proto
Original file line number Diff line number Diff line change
Expand Up @@ -288,9 +288,9 @@ message DeleteObservationLogReply {

message GetSuggestionsRequest {
Experiment experiment = 1;
repeated Trial trials = 2; // all completed trials owned by the experiment.
int32 request_number = 3; ///The number of Suggestion you request at one time. When you set 3 to request_number, you can get three Suggestions at one time.
int32 total_request_number = 4;//The number of Suggestions requested till now
repeated Trial trials = 2; // All completed trials owned by the experiment.
int32 current_request_number = 3; // The number of Suggestions requested at one time. When you set 3 to current_request_number, you get three Suggestions at one time.
int32 total_request_number = 4; // The number of Suggestions requested till now.
}

message GetSuggestionsReply {
Expand Down
6 changes: 3 additions & 3 deletions pkg/apis/manager/v1beta1/gen-doc/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -352,9 +352,9 @@ Discrete and Categorical type use List.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| experiment | [Experiment](#api.v1.beta1.Experiment) | | |
| trials | [Trial](#api.v1.beta1.Trial) | repeated | all completed trials owned by the experiment. |
| request_number | [int32](#int32) | | The number of Suggestion you request at one time. When you set 3 to request_number, you can get three Suggestions at one time. |
| total_request_number | [int32](#int32) | | The number of Suggestions requested till now |
| trials | [Trial](#api.v1.beta1.Trial) | repeated | All completed trials owned by the experiment. |
| current_request_number | [int32](#int32) | | The number of Suggestions requested at one time. When you set 3 to current_request_number, you get three Suggestions at one time. |
| total_request_number | [int32](#int32) | | The number of Suggestions requested till now. |



Expand Down
8 changes: 4 additions & 4 deletions pkg/apis/manager/v1beta1/gen-doc/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -965,21 +965,21 @@ <h3 id="api.v1.beta1.GetSuggestionsRequest">GetSuggestionsRequest</h3>
<td>trials</td>
<td><a href="#api.v1.beta1.Trial">Trial</a></td>
<td>repeated</td>
<td><p>all completed trials owned by the experiment. </p></td>
<td><p>All completed trials owned by the experiment. </p></td>
</tr>

<tr>
<td>request_number</td>
<td>current_request_number</td>
<td><a href="#int32">int32</a></td>
<td></td>
<td><p>The number of Suggestion you request at one time. When you set 3 to request_number, you can get three Suggestions at one time. </p></td>
<td><p>The number of Suggestions requested at one time. When you set 3 to current_request_number, you get three Suggestions at one time. </p></td>
</tr>

<tr>
<td>total_request_number</td>
<td><a href="#int32">int32</a></td>
<td></td>
<td><p>The number of Suggestions requested till now </p></td>
<td><p>The number of Suggestions requested till now. </p></td>
</tr>

</tbody>
Expand Down
62 changes: 31 additions & 31 deletions pkg/apis/manager/v1beta1/python/api_pb2.py

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ func (g *General) SyncAssignments(
e *experimentsv1beta1.Experiment,
ts []trialsv1beta1.Trial) error {
logger := log.WithValues("Suggestion", types.NamespacedName{Name: instance.GetName(), Namespace: instance.GetNamespace()})
requestNum := int(instance.Spec.Requests) - int(instance.Status.SuggestionCount)
if requestNum <= 0 {
currentRequestNum := int(instance.Spec.Requests) - int(instance.Status.SuggestionCount)
if currentRequestNum <= 0 {
return nil
}

Expand All @@ -102,19 +102,19 @@ func (g *General) SyncAssignments(
instance.Status.AlgorithmSettings)

requestSuggestion := &suggestionapi.GetSuggestionsRequest{
Experiment: g.ConvertExperiment(filledE),
Trials: g.ConvertTrials(ts),
RequestNumber: int32(requestNum),
TotalRequestNumber: int32(instance.Spec.Requests),
Experiment: g.ConvertExperiment(filledE),
Trials: g.ConvertTrials(ts),
CurrentRequestNumber: int32(currentRequestNum),
TotalRequestNumber: int32(instance.Spec.Requests),
}

// Get new suggestions
responseSuggestion, err := rpcClientSuggestion.GetSuggestions(ctx, requestSuggestion)
if err != nil {
return err
}
logger.Info("Getting suggestions", "endpoint", endpoint, "Number of request parameters", requestNum, "Number of response parameters", len(responseSuggestion.ParameterAssignments))
if len(responseSuggestion.ParameterAssignments) != requestNum {
logger.Info("Getting suggestions", "endpoint", endpoint, "Number of request parameters", currentRequestNum, "Number of response parameters", len(responseSuggestion.ParameterAssignments))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Number of request parameters -> Number of current request parameters

if len(responseSuggestion.ParameterAssignments) != currentRequestNum {
err := fmt.Errorf("The response contains unexpected trials")
logger.Error(err, "The response contains unexpected trials")
return err
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -909,7 +909,7 @@ func newFakeRequest() *suggestionapi.GetSuggestionsRequest {
},
},
},
RequestNumber: 2,
TotalRequestNumber: 6,
CurrentRequestNumber: 2,
TotalRequestNumber: 6,
}
}
29 changes: 17 additions & 12 deletions pkg/suggestion/v1beta1/chocolate/base_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,11 @@ def __init__(self, algorithm_name, search_space):
self.chocolate_optimizer = None
self.create_optimizer(algorithm_name)
# created_trials is the list of dicts with all created trials assignments, loss and trial name
# _chocolate_id is the ID of the trial, Assignment names are encoded, _loss is the target metric, _trial_name is the Trial name
# _chocolate_id is the ID of the trial, Assignment names are encoded,
# _loss is the target metric, _trial_name is the Trial name
# One row example:
# {'_chocolate_id': 0, 'LS1scg==': 0.001, 'LS1udW0tZXBvY2hz': 1, 'LS1udW0tbGF5ZXJz': 2, "_loss": "0.97", "_trial_name": "grid-hsdvfdwl"}
# {'_chocolate_id': 0, 'LS1scg==': 0.001, 'LS1udW0tZXBvY2hz': 1, 'LS1udW0tbGF5ZXJz': 2,
# "_loss": "0.97", "_trial_name": "grid-hsdvfdwl"}
self.created_trials = []
self.recorded_trials_names = []

Expand Down Expand Up @@ -103,13 +105,13 @@ def create_optimizer(self, algorithm_name):
raise Exception(
'"Failed to create Chocolate optimizer for the algorithm: {}'.format(algorithm_name))

def getSuggestions(self, trials, request_number, total_request_number):
def getSuggestions(self, trials, current_request_number, total_request_number):
"""
Get the new suggested trials with chocolate algorithm.
"""
logger.info("-" * 100 + "\n")
logger.info("New GetSuggestions call with total requested {} and currently requesting {} \n".format(
total_request_number, request_number))
total_request_number, current_request_number))
for _, trial in enumerate(trials):
if trial.name not in self.recorded_trials_names:
loss_for_choco = float(trial.target_metric.value)
Expand Down Expand Up @@ -137,8 +139,10 @@ def getSuggestions(self, trials, request_number, total_request_number):
i = 0
while new_trial_loss_idx == -1 and i < len(self.created_trials):
# Created Trial must not include loss and must have the same param assignment
if ((DB_FIELD_LOSS not in self.created_trials[i] or self.created_trials[i][DB_FIELD_LOSS] is None) and
len(trial_assignments_dict.items() & self.created_trials[i].items()) == len(self.search_space.params)):
if ((DB_FIELD_LOSS not in self.created_trials[i] or
self.created_trials[i][DB_FIELD_LOSS] is None) and
len(trial_assignments_dict.items() & self.created_trials[i].items()) ==
len(self.search_space.params)):
new_trial_loss_idx = i
i += 1

Expand All @@ -161,12 +165,13 @@ def getSuggestions(self, trials, request_number, total_request_number):
# Assuming that created_trials are already populated
# TODO: Handle Restart of algorithm pod
logger.info("{} Trials created in DB".format(len(self.created_trials)))
if total_request_number != len(self.created_trials) + request_number:
if total_request_number != len(self.created_trials) + current_request_number:
logger.info("Mismatch in generated trials with k8s suggestions trials")
new_actual_requested_no = total_request_number - len(self.created_trials)
prev_generated_no = request_number - new_actual_requested_no
logger.info("In this call, New {} Trials will be generated, {} Trials will be reused from previously generated".format(
new_actual_requested_no, prev_generated_no))
prev_generated_no = current_request_number - new_actual_requested_no
logger.info(
"In this call, New {} Trials will be generated, {} Trials will be reused from previously generated".format(
new_actual_requested_no, prev_generated_no))

list_of_assignments = []
if prev_generated_no > 0:
Expand Down Expand Up @@ -199,8 +204,8 @@ def getSuggestions(self, trials, request_number, total_request_number):
"Chocolate db is exhausted, increase Search Space or decrease maxTrialCount!")

if len(list_of_assignments) > 0:
logger.info(
"GetSuggestions returns {} Trials from requested {} Trials\n\n".format(len(list_of_assignments), request_number))
logger.info("GetSuggestions returns {} Trials from requested {} Trials\n\n".format(
len(list_of_assignments), current_request_number))

return list_of_assignments

Expand Down
2 changes: 1 addition & 1 deletion pkg/suggestion/v1beta1/chocolate/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def GetSuggestions(self, request, context):

trials = Trial.convert(request.trials)
new_assignments = self.base_service.getSuggestions(
trials, request.request_number, request.total_request_number)
trials, request.current_request_number, request.total_request_number)
return api_pb2.GetSuggestionsReply(
parameter_assignments=Assignment.generate(new_assignments)
)
Expand Down
6 changes: 3 additions & 3 deletions pkg/suggestion/v1beta1/goptuna/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,9 @@ func (s *SuggestionService) GetSuggestions(
return nil, status.Error(codes.Internal, err.Error())
}

requestNumber := int(req.GetRequestNumber())
parameterAssignments := make([]*api_v1_beta1.GetSuggestionsReply_ParameterAssignments, requestNumber)
for i := 0; i < requestNumber; i++ {
currentRequestNumber := int(req.GetCurrentRequestNumber())
parameterAssignments := make([]*api_v1_beta1.GetSuggestionsReply_ParameterAssignments, currentRequestNumber)
for i := 0; i < currentRequestNumber; i++ {
trialID, assignments, err := sampleNextParam(s.study, s.searchSpace)
if err != nil {
klog.Errorf("Failed to sample next param: trialID=%d, err=%s", trialID, err)
Expand Down
10 changes: 5 additions & 5 deletions pkg/suggestion/v1beta1/goptuna/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ func TestSuggestionService_GetSuggestions(t *testing.T) {
ParameterSpecs: parameterSpecs,
},
},
RequestNumber: 2,
CurrentRequestNumber: 2,
},
expectedCode: codes.OK,
},
Expand Down Expand Up @@ -122,7 +122,7 @@ func TestSuggestionService_GetSuggestions(t *testing.T) {
ParameterSpecs: parameterSpecs,
},
},
RequestNumber: 2,
CurrentRequestNumber: 2,
},
},
{
Expand All @@ -149,7 +149,7 @@ func TestSuggestionService_GetSuggestions(t *testing.T) {
ParameterSpecs: parameterSpecs,
},
},
RequestNumber: 2,
CurrentRequestNumber: 2,
},
},
} {
Expand All @@ -169,8 +169,8 @@ func TestSuggestionService_GetSuggestions(t *testing.T) {
return
}

if len(reply.ParameterAssignments) != int(tt.req.RequestNumber) {
t.Errorf("GetSuggestions() should return %d suggestions, but got %#v", tt.req.RequestNumber, reply.ParameterAssignments)
if len(reply.ParameterAssignments) != int(tt.req.CurrentRequestNumber) {
t.Errorf("GetSuggestions() should return %d suggestions, but got %#v", tt.req.CurrentRequestNumber, reply.ParameterAssignments)
return
}

Expand Down
4 changes: 2 additions & 2 deletions pkg/suggestion/v1beta1/hyperband/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def GetSuggestions(self, request, context):
# Hyperband outlerloop has finished
return reply
# This is a hack to get request number.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: how about change this comment to add the word current ?

param.n = request.request_number
param.n = request.current_request_number

trials = self._make_bracket(experiment, param)
for trial in trials:
Expand Down Expand Up @@ -212,7 +212,7 @@ def ValidateAlgorithmSettings(self, request, context):
return self._set_validate_context_error(context, "r_l and resource_name must be set.")
try:
rl = float(setting_dict["r_l"])
except:
except Exception:
return self._set_validate_context_error(context, "r_l must be a positive float number.")
else:
if rl < 0:
Expand Down
14 changes: 7 additions & 7 deletions pkg/suggestion/v1beta1/hyperopt/base_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def create_fmin(self):

self.fmin.catch_eval_exceptions = False

def getSuggestions(self, trials, request_number):
def getSuggestions(self, trials, current_request_number):
"""
Get the new suggested trials with the given algorithm.
"""
Expand Down Expand Up @@ -192,8 +192,8 @@ def getSuggestions(self, trials, request_number):
self.fmin.trials.insert_trial_docs(hyperopt_trials)
self.fmin.trials.refresh()

# Produce new request_number ids to make new Suggestion
hyperopt_trial_new_ids = self.fmin.trials.new_trial_ids(request_number)
# Produce new current_request_number ids to make new Suggestion
hyperopt_trial_new_ids = self.fmin.trials.new_trial_ids(current_request_number)
random_state = self.fmin.rstate.randint(2**31 - 1)

# Trial list that must be deployed
Expand All @@ -206,7 +206,7 @@ def getSuggestions(self, trials, request_number):
seed=random_state)
elif self.algorithm_name == TPE_ALGORITHM_NAME:
# n_startup_jobs indicates for how many Trials we run random suggestion
# This must be request_number value
# This must be current_request_number value
# After this tpe suggestion starts analyse Trial info.
# On the first run we can run suggest just once with n_startup_jobs
# Next suggest runs must be for each new Trial generation
Expand All @@ -216,18 +216,18 @@ def getSuggestions(self, trials, request_number):
domain=self.fmin.domain,
trials=self.fmin.trials,
seed=random_state,
n_startup_jobs=request_number,
n_startup_jobs=current_request_number,
**self.algorithm_conf)
self.is_first_run = False
else:
for i in range(request_number):
for i in range(current_request_number):
# hyperopt_algorithm always returns one new Trial
new_trials.append(self.hyperopt_algorithm(
new_ids=[hyperopt_trial_new_ids[i]],
domain=self.fmin.domain,
trials=self.fmin.trials,
seed=random_state,
n_startup_jobs=request_number,
n_startup_jobs=current_request_number,
**self.algorithm_conf)[0])

# Construct return advisor Trials from new hyperopt Trials
Expand Down
2 changes: 1 addition & 1 deletion pkg/suggestion/v1beta1/hyperopt/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def GetSuggestions(self, request, context):
self.is_first_run = False

trials = Trial.convert(request.trials)
new_assignments = self.base_service.getSuggestions(trials, request.request_number)
new_assignments = self.base_service.getSuggestions(trials, request.current_request_number)
return api_pb2.GetSuggestionsReply(
parameter_assignments=Assignment.generate(new_assignments)
)
Expand Down
2 changes: 1 addition & 1 deletion pkg/suggestion/v1beta1/nas/darts/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def GetSuggestions(self, request, context):
self.is_first_run = False

parameter_assignments = []
for i in range(request.request_number):
for i in range(request.current_request_number):

self.logger.info(">>> Generate new Darts Trial Job")

Expand Down
Loading