-
Notifications
You must be signed in to change notification settings - Fork 990
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
Add batch support to cirq Engine client #3114
Add batch support to cirq Engine client #3114
Conversation
- Adds a run_batch() call to engine that can handle lists of circuits and lists of programs. - Creates BatchProgram and BatchRunContext objects. - Pipes the objects through engine program and engine job.
cirq/google/engine/engine.py
Outdated
code = qtypes.any_pb2.Any() | ||
batch = v2.batch_pb2.BatchProgram() | ||
for program in programs: | ||
batch.programs.append(gate_set.serialize(program)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One thing you can do here is to instead serialize directly into the existing message:
for program in programs:
gate_set.serialize(program, msg=batch.programs.add())
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I guess this would get rid of the need for a copy. Done.
cirq/google/engine/engine_job.py
Outdated
@@ -285,6 +285,10 @@ def results(self) -> List[study.TrialResult]: | |||
result_type == 'cirq.api.google.v2.Result'): | |||
v2_parsed_result = v2.result_pb2.Result.FromString(result.value) | |||
self._results = self._get_job_results_v2(v2_parsed_result) | |||
elif result_type == 'cirq.google.api.v2.BatchResult': |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could use the built-in Any mechanism for checking types here:
elif result.Is(v2.batch_pb2.BatchResult.DESCRIPTOR):
...
We could change other cases as well though we'd have to leave in code to handle old cirq.api.google
types if we still need that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. I will leave the other cases how they are for now.
for sweep_result in sweep_results: | ||
for trial_result in sweep_result: | ||
trial_results.append(trial_result) | ||
return trial_results |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could use the existing _get_job_results_v2
function here:
@classmethod
def _get_batch_results_v2(cls, ...):
trial_results = []
for result in results.results:
trial_results.extend(cls._get_job_results_v2(result))
return trial_results
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
elif result_type == 'cirq.google.api.v2.BatchResult': | ||
v2_parsed_result = v2.batch_pb2.BatchResult.FromString( | ||
result.value) | ||
self._results = self._get_batch_results_v2(v2_parsed_result) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems rather odd to flatten this down to a single list of results across all programs in the batch. I would think we might want a new API to access batch results in a more structured manner.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, my plan is to have something like that in a future PR that extends the interface. This will fit into the current implementation, and then we can have a new API to grab batch results in a follow-up.
Sound good?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Drive by :)
Do we want to make EngineProgram
and EngineJob
be able to know if they were batch or not? Right now I don't think you won't be able to tell this easily?
cirq/google/engine/engine.py
Outdated
job_id: Optional[str] = None, | ||
params_list: List[study.Sweepable] = None, | ||
repetitions: int = 1, | ||
processor_ids: Sequence[str] = ('xmonsim',), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggest not having a default and yelling if not supplied. this is different from other cases, but there is an issue out to not have this default (it is too dangerous, you could think you were doing an experiment, but actually be running on a simulator).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
to run the program. Only one of these will be scheduled for | ||
execution. | ||
gate_set: The gate set used to serialize the circuit. The gate set | ||
must be supported by the selected processor. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not a fan of the default being xmon here, but we should at least document (yes run doesn't document this too)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed it to raise an error, like the other parameters.
…115/Cirq-1 into add_batch_support_engine
Acknowledged but have not addressed yet. Will fix before submitting. |
I have added batch_mode to the classes. For |
FYI: I gave this a try over the weekend and it worked! Woo woo! After this is submitted, I think we are good to try this out with a limited set of testers. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor comments, then LGTM.
cirq/google/engine/engine_program.py
Outdated
raise ValueError('No parameter list specified') | ||
|
||
# Pack the run contexts into batches | ||
batch_context = qtypes.any_pb2.Any() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer to import any_pb2
directly here, rather than rely on it being "reexported" by the qtypes module, but it looks like this is the pattern we're using throughout this module.
Also, consider creating this below, after populating the batch
message, when it's ready to be packed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved batch below the for loop. Also changed this to import any_pb2 directly.
cirq/google/engine/engine_program.py
Outdated
job_id: Optional[str] = None, | ||
params_list: List[study.Sweepable] = None, | ||
repetitions: int = 1, | ||
processor_ids: Sequence[str] = ('xmonsim',), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use empty tuple for the default value, as in engine.py
above?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
cirq/google/engine/engine.py
Outdated
params_list: List[study.Sweepable] = None, | ||
repetitions: int = 1, | ||
processor_ids: Sequence[str] = (), | ||
gate_set: serializable_gate_set.SerializableGateSet = None, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be Optional[serializable_gate_set.SerializableGateSet]
if None
is allowed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. Fixed in a bunch of places in this file.
cirq/google/engine/engine.py
Outdated
TrialResults, one for each parameter sweep. | ||
""" | ||
if not gate_set: | ||
raise ValueError('Gate set must be specified.') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move this check to create_batch_program
instead (or add a similar check there so that create_batch_program
works the same way).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
cirq/google/engine/engine.py
Outdated
Returns: | ||
A EngineProgram for the newly created program. | ||
""" | ||
gate_set = gate_set or gate_sets.XMON |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this raise an error if gate_set
is not given, as does run_batch
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
cirq/google/engine/engine.py
Outdated
if not program_id: | ||
program_id = _make_random_id('prog-') | ||
|
||
code = qtypes.any_pb2.Any() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: move this down below after batch
is populated and ready to pack.
It might be nice to create a helper function that packs a proto message into an any and can be called in a single expression. Then we could do, for example:
self.context.client.create_program(..., code=pack_any(batch), ...)
We could also consider changing client.create_program
to take google.protobuf.Message
for code and have it do the packing internally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implemented the first suggestion.
I hesitate to mess with the client too much, since it is partially generated by the gapic tools, so, if we regenerate the library, we don't want to mess with any customizations to the greatest extent possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah!
cirq/google/engine/engine.py
Outdated
job_description: Optional[str] = None, | ||
job_labels: Optional[Dict[str, str]] = None, | ||
) -> engine_job.EngineJob: | ||
"""Runs the supplied Circuit via Quantum Engine.Creates |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Circuit -> Circuits
* Add batch support to cirq Engine client - Adds a run_batch() call to engine that can handle lists of circuits and lists of programs. - Creates BatchProgram and BatchRunContext objects. - Pipes the objects through engine program and engine job.
lists of circuits and lists of programs.