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

Feature gst checkpointing #347

Merged
merged 22 commits into from
Sep 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ jupyter_notebooks/Tutorials/tutorial_files/exampleMultiDataSetReport
jupyter_notebooks/Tutorials/tutorial_files/exampleBriefReport
jupyter_notebooks/Tutorials/tutorial_files/*.ipynb
jupyter_notebooks/Tutorials/tutorial_files/tempTest
jupyter_notebooks/Tutorials/tutorial_files/*checkpoints



# Compiled source #
Expand Down
4 changes: 2 additions & 2 deletions jupyter_notebooks/Examples/BootstrappedErrorBars.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@
"\n",
"\n",
"results = pygsti.run_stdpractice_gst(ds, target_model, prep_fiducials, meas_fiducials,\n",
" germs, maxLengths, modes=\"TP\")\n",
"estimated_model = results.estimates['TP'].models['stdgaugeopt']"
" germs, maxLengths, modes=\"full TP\")\n",
"estimated_model = results.estimates['full TP'].models['stdgaugeopt']"
]
},
{
Expand Down
4 changes: 2 additions & 2 deletions jupyter_notebooks/Examples/CirqIntegration.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,7 @@
}
],
"source": [
"gst_results = pygsti.run_stdpractice_gst(dataset, target_model, preps, effects, germs, max_lengths, modes=\"TP,Target\", verbosity=1)"
"gst_results = pygsti.run_stdpractice_gst(dataset, target_model, preps, effects, germs, max_lengths, modes=[\"full TP\",\"Target\"], verbosity=1)"
]
},
{
Expand All @@ -503,7 +503,7 @@
}
],
"source": [
"mdl_estimate = gst_results.estimates['TP'].models['stdgaugeopt']\n",
"mdl_estimate = gst_results.estimates['full TP'].models['stdgaugeopt']\n",
"print(\"2DeltaLogL(estimate, data): \", pygsti.tools.two_delta_logl(mdl_estimate, dataset))\n",
"print(\"2DeltaLogL(ideal, data): \", pygsti.tools.two_delta_logl(target_model, dataset))"
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"ds = pygsti.data.simulate_data(mdl_datagen, exp_design.all_circuits_needing_data, num_samples=1000, seed=1234)\n",
"data = pygsti.protocols.ProtocolData(exp_design, ds)\n",
"\n",
"gst = pygsti.protocols.StandardGST(\"TP\", gaugeopt_suite={'go0': {'item_weights': {'gates': 1, 'spam': 1}}})\n",
"gst = pygsti.protocols.StandardGST(\"full TP\", gaugeopt_suite={'go0': {'item_weights': {'gates': 1, 'spam': 1}}})\n",
"results = gst.run(data) \n",
"results.write(\"example_files/regaugeopt_example\")"
]
Expand All @@ -59,7 +59,7 @@
"metadata": {},
"outputs": [],
"source": [
"estimate = my_results.estimates['TP']\n",
"estimate = my_results.estimates['full TP']\n",
"estimate.add_gaugeoptimized( {'item_weights': {'gates': 1, 'spam': 0.001}}, label=\"Spam 1e-3\" )\n",
"mdl_gaugeopt = estimate.models['Spam 1e-3']\n",
"\n",
Expand Down
12 changes: 6 additions & 6 deletions jupyter_notebooks/Examples/GOpt-NonIdealTargets.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@
"outputs": [],
"source": [
"# GST with standard \"ideal target\" gauge optimization\n",
"results1 = pygsti.protocols.StandardGST(\"TP\").run(data)"
"results1 = pygsti.protocols.StandardGST(\"full TP\").run(data)"
]
},
{
Expand All @@ -84,7 +84,7 @@
"# GST with our guess as the gauge optimization target\n",
"gaugeopt_suite = pygsti.protocols.GSTGaugeOptSuite(gaugeopt_suite_names=['stdgaugeopt'],\n",
" gaugeopt_target=mdl_guess)\n",
"results2 = pygsti.protocols.StandardGST(\"TP\", gaugeopt_suite).run(data)"
"results2 = pygsti.protocols.StandardGST(\"full TP\", gaugeopt_suite).run(data)"
]
},
{
Expand All @@ -104,8 +104,8 @@
"outputs": [],
"source": [
"target_model = smq1Q_XYI.target_model()\n",
"mdl_1 = results1.estimates['TP'].models['stdgaugeopt']\n",
"mdl_2 = results2.estimates['TP'].models['stdgaugeopt']\n",
"mdl_1 = results1.estimates['full TP'].models['stdgaugeopt']\n",
"mdl_2 = results2.estimates['full TP'].models['stdgaugeopt']\n",
"print(\"Diff between ideal and ideal-target-gauge-opt = \", mdl_1.frobeniusdist(target_model))\n",
"print(\"Diff between ideal and mdl_guess-gauge-opt = \", mdl_2.frobeniusdist(target_model))\n",
"print(\"Diff between data-gen and ideal-target-gauge-opt = \", mdl_1.frobeniusdist(mdl_datagen))\n",
Expand Down Expand Up @@ -133,7 +133,7 @@
"metadata": {},
"outputs": [],
"source": [
"results1.estimates['TP'].add_gaugeoptimized(results2.estimates['TP'].goparameters['stdgaugeopt'],\n",
"results1.estimates['full TP'].add_gaugeoptimized(results2.estimates['full TP'].goparameters['stdgaugeopt'],\n",
" label=\"using mdl_guess\")"
]
},
Expand All @@ -143,7 +143,7 @@
"metadata": {},
"outputs": [],
"source": [
"mdl_1b = results1.estimates['TP'].models['using mdl_guess']\n",
"mdl_1b = results1.estimates['full TP'].models['using mdl_guess']\n",
"print(mdl_1b.frobeniusdist(mdl_2)) # gs1b is the same as gs2"
]
},
Expand Down
2 changes: 1 addition & 1 deletion jupyter_notebooks/Examples/MPI-RunningGST.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
"memLim = 2.1*(1024)**3 # 2.1 GB\n",
"\n",
"#Perform TP-constrained GST\n",
"protocol = pygsti.protocols.StandardGST(\"TP\")\n",
"protocol = pygsti.protocols.StandardGST(\"full TP\")\n",
"start = time.time()\n",
"results = protocol.run(data, memlimit=memLim, comm=comm)\n",
"end = time.time()\n",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@
"outputs": [],
"source": [
"#run the GST protocol and create a report \n",
"gst_protocol = pygsti.protocols.StandardGST('full TP,CPTP,Target')\n",
"gst_protocol = pygsti.protocols.StandardGST(['full TP','CPTPLND','Target'])\n",
"results = gst_protocol.run(data)\n",
"\n",
"report = pygsti.report.construct_standard_report(\n",
Expand Down
170 changes: 163 additions & 7 deletions jupyter_notebooks/Tutorials/algorithms/GST-Protocols.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
"metadata": {},
"outputs": [],
"source": [
"from __future__ import print_function\n",
"import pygsti"
]
},
Expand Down Expand Up @@ -63,7 +62,7 @@
"## `GateSetTomography`\n",
"This protocol performs a single model optimization, and so computes a **single GST estimate** given a `DataSet`, a target `Model`, and other parameters. (The returned `ModelEstimateResults` object may sometimes contain multiple related estimates in certain cases, but in these cases all the estimates are closely related.) The experiment design provides all of the information about the GST circuits, in this case a *standard* (*prep_fiducial + germ^power + meas_fiducial*) set, so the only thing needed by the protocol is an initial `Model` to optimize. Thus, the `GateSetTomography` protocol is essentially just a model optimizer that you give an initial point. Importantly, this initial point (a `Model`) also specifies the *parameterization*, i.e. the space of parameters that are optimized over.\n",
"\n",
"Minimally, when using `GateSetTomography` you should set the parameterization of the initial model. This can be viewed as setting the constraints on the optimization. For instance, when the gates in the model are parameterized as trace-preserving (TP) maps, the optimization will be constrained to trying gate sets with TP gates (because every set of parameters corresponds to a set of TP gates). In the cell below, we constrain the optimization to TP gate sets by using `.target_model(\"TP\")`, which returns a version of the target model where all the gates are TP-parameterized, the state preparation has trace = 1, and the POVM effects always add to the identity. This could also be done by calling `set_all_parameterizations(\"TP\")` on the fully-parameterized target model returned by `.target_model()`. See the [tutorial on explicit models](../objects/ExplicitModel.ipynb) for more information on setting a model's parameterization."
"Minimally, when using `GateSetTomography` you should set the parameterization of the initial model. This can be viewed as setting the constraints on the optimization. For instance, when the gates in the model are parameterized as trace-preserving (TP) maps, the optimization will be constrained to trying gate sets with TP gates (because every set of parameters corresponds to a set of TP gates). In the cell below, we constrain the optimization to TP gate sets by using `.target_model(\"full TP\")`, which returns a version of the target model where all the gates are TP-parameterized, the state preparation has trace = 1, and the POVM effects always add to the identity. This could also be done by calling `set_all_parameterizations(\"TP\")` on the fully-parameterized target model returned by `.target_model()`. See the [tutorial on explicit models](../objects/ExplicitModel.ipynb) for more information on setting a model's parameterization."
]
},
{
Expand Down Expand Up @@ -126,7 +125,7 @@
" target_model_TP2, name=\"GSTwithMyGO\",\n",
" gaugeopt_suite={'my_gauge_opt': {'item_weights': {'gates': 1.0, 'spam': 0.001}}}\n",
" )\n",
"results_TP2 = proto.run(data)"
"results_TP2 = proto.run(data, disable_checkpointing=True)"
]
},
{
Expand Down Expand Up @@ -168,7 +167,7 @@
"\n",
"\n",
"proto = pygsti.protocols.GateSetTomography(target_model_TP2, name=\"GSTwithReducedData\")\n",
"results_reduced = proto.run(reduced_data)"
"results_reduced = proto.run(reduced_data, disable_checkpointing=True)"
]
},
{
Expand All @@ -183,7 +182,7 @@
"metadata": {},
"source": [
"## `StandardGST`\n",
"The protocol embodies a standard *set* of GST protocols to be run on a set of data. It essentially runs multiple `GateSetTomography` protocols on the given data which use different parameterizations of an `ExplicitOpModel` (the `StandardGST` protocol doesn't work with other types of `Model` objects, e.g. *implicit* models, which don't implement `set_all_parameterizations`). The `modes` argument is a comma-separated list of the parameterization types that should be run (e.g. `\"TP,CPTP\"` will compute a Trace-Preserving estimate *and* a Completely-Positive & Trace-Preserving estimate). The currently available modes are:\n",
"The protocol embodies a standard *set* of GST protocols to be run on a set of data. It essentially runs multiple `GateSetTomography` protocols on the given data which use different parameterizations of an `ExplicitOpModel` (the `StandardGST` protocol doesn't work with other types of `Model` objects, e.g. *implicit* models, which don't implement `set_all_parameterizations`). The `modes` argument is a list strings corresponding to the parameterization types that should be run (e.g. `[\"full TP\",\"CPTPLND\"]` will compute a Trace-Preserving estimate *and* a Completely-Positive & Trace-Preserving estimate). The currently available modes are:\n",
" - \"full\" : unconstrained gates (fully parameterized) \n",
" - \"TP\" : TP-constrained gates and state preparations\n",
" - \"CPTP\" : CPTP-constrained gates and TP-constrained state preparations \n",
Expand Down Expand Up @@ -321,6 +320,163 @@
"# pickle.dump(results_stdprac, open('../tutorial_files/exampleResults_stdprac.pkl',\"wb\"))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Checkpointing/Warmstarting\n",
"\n",
"The `GateSetTomography` and `StandardGST` protocols both support checkpointing to enable resuming GST analysis after an unexpected failure, such as an out-of-memory error, or an unexpected timeout in resource limited compute environments (clusters etc.), or for whatever other reason. Checkpointing is enabled by default, so no additional changes are needed in order to have these generated. \n",
"\n",
"Each protocol has a corresponding checkpoint object, `GateSetTomographyCheckpoint` and `StandardGSTCheckpoint`, which are saved to disk over the course of an iterative fit in serialized json format. By default checkpoint files associated with a `GateSetTomographyCheckpoint` object are saved to a new directory located in whichever current working directory the protocol is being run from named 'gst_checkpoints'. A new file is written to disk after each iteration with default naming of the form `GateSetTomography_iteration_{i}.json` where i is the index of the completed GST iteration associated with that checkpoint. Similarly, for a `StandardGSTCheckpoint` object the checkpoints are by default saved to a directory named 'standard_gst_checkpoints' with default file names of the form `StandardGST_{mode}_iteration_{i}` where mode corresponds to the current parameterized fit or model test associated with that file (including checkpoint information for all previously completed modes prior to the currently running one) and i is the index of the completed iteration within that current mode.\n",
"\n",
"Below we repeat our first example of the notebook, but this time with checkpointing enabled (as is the default)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from pygsti.modelpacks import smq1Q_XYI\n",
"target_model_TP = smq1Q_XYI.target_model(\"full TP\")\n",
"proto = pygsti.protocols.GateSetTomography(target_model_TP)\n",
"results_TP = proto.run(data, checkpoint_path = '../tutorial_files/gst_checkpoints/GateSetTomography')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Note that in the example above we have specified a value for an additional kwarg called `checkpoint_path`. This allows for overriding the default behavior for the save location and naming of checkpoint files. The expected format is `{path}/{name}` where path is the directory to save the checkpoint files to (with that directory being created is required) and where name is the stem of the checkpoint file names `{name}_iteration_{i}.json`. Inspecting the contents of the directory we just specified, we can see that it is now populated by 8 new checkpoint files."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"os.listdir('../tutorial_files/gst_checkpoints/')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Suppose hypothetically that a GST fit had failed at iteration 5 and we wanted to restart from that point without redoing all of the previous iterations from scratch again. We'll call this warmstarting. We can do so by reading in the appropriate serialized checkpoint object using the `read` class method of `GateSetTomographyCheckpoint` and passing that now loaded checkpoint object in for the `checkpoint` kwarg of `run`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from pygsti.protocols import GateSetTomographyCheckpoint\n",
"gst_iter_5_checkpoint = GateSetTomographyCheckpoint.read('../tutorial_files/gst_checkpoints/GateSetTomography_iteration_5.json')\n",
"results_TP_from_iter_5= proto.run(data, checkpoint= gst_iter_5_checkpoint, checkpoint_path = '../tutorial_files/gst_checkpoints/GateSetTomography')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can see from the output that we indeed started from iteration 6 (note the output log indexes from 1 instead of 0). Moreover we can see that we've indeed produced the same output as before without warmstarting, as we would expect/hope:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"all(results_TP.estimates['GateSetTomography'].models['final iteration estimate'].to_vector() == \\\n",
"results_TP_from_iter_5.estimates['GateSetTomography'].models['final iteration estimate'].to_vector())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The checkpoint object itself contains information that could be useful for diagnostics or debugging, including the current list of models associated each iterative fit, the last completed iteration it is associated with, and the list of circuits for the last completed iteration it is associated with."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Checkpointing with the StandardGST protocol works similarly:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"proto_standard_gst = pygsti.protocols.StandardGST(modes=['full TP', 'CPTPLND', 'Target'], verbosity=3)\n",
"results_stdprac = proto_standard_gst.run(data, checkpoint_path = '../tutorial_files/standard_gst_checkpoints/StandardGST')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Except this time we have significantly more files saved, as during the course of the StandardGST protocol we're actually running three subprotocols:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"os.listdir('../tutorial_files/standard_gst_checkpoints/')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Note that the StandardGST protocol runs the subprotocols in the order listed in the `modes` argument, and checkpoint objects labeled with a given model label additionally contain the checkpointing information for the final iterations of any preceding modes which have been completed. i.e. the CPTPLND checkpoint objects contain the information required for full TP. Likewise, checkpoints for Target contain the information required for the full TP and CPTPLND modes. As before, imagine that our fitting failed for whatever reason during iteration 5 of CPTPLND, we can warmstart the protocol by loading in the checkpoint object associated with iteration 4 as below:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"from pygsti.protocols import StandardGSTCheckpoint\n",
"standard_gst_checkpoint = StandardGSTCheckpoint.read('../tutorial_files/standard_gst_checkpoints/StandardGST_CPTPLND_iteration_4.json')\n",
"results_stdprac_warmstart= proto_standard_gst.run(data, checkpoint= standard_gst_checkpoint, checkpoint_path = '../tutorial_files/standard_gst_checkpoints/StandardGST')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Notice that we've indeed skipped past the previously completed full TP mode and jumped straight to the 6th iteration of the CPTPLND fit as expected. \n",
"\n",
"As for the GateSetTomographyCheckpoint object described above, the `StandardGSTCheckpoint` can often be useful to inspect as a debugging/diagnostic tool. `StandardGSTCheckpoints` are essentially structured as container object that hold a set of child `GateSetTomographyCheckpoint` and `ModelTestCheckpoint` (more on these in the ModelTest tutorial) objects for each of the modes being run (and potentially more types of chile checkpoints in the future as we add additional functionality). These children can be accessed using the `children` attribute of a `StandardGSTCheckpoint` instance which is a dictionary with keys given by the mode names contained therein."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print(standard_gst_checkpoint.children['CPTPLND'])"
]
},
{
"cell_type": "code",
"execution_count": null,
Expand All @@ -331,9 +487,9 @@
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"display_name": "gst_checkpointing",
"language": "python",
"name": "python3"
"name": "gst_checkpointing"
},
"language_info": {
"codemirror_mode": {
Expand Down
Loading
Loading