-
Notifications
You must be signed in to change notification settings - Fork 139
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* small fixes * split * toc * update * update * update * executable * 2019.1->2019.2
- Loading branch information
Showing
13 changed files
with
276 additions
and
139 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,3 +6,4 @@ _build | |
model_1 | ||
model_2 | ||
model_3 | ||
.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
#!/bin/bash | ||
# Copyright (c) Jupyter Development Team. | ||
# Distributed under the terms of the Modified BSD License. | ||
|
||
set -e | ||
|
||
# setup vivado 2019.2 | ||
source /opt/Xilinx/Vivado/2019.2/settings64.sh | ||
|
||
# The Jupyter command to launch | ||
# JupyterLab by default | ||
DOCKER_STACKS_JUPYTER_CMD="${DOCKER_STACKS_JUPYTER_CMD:=lab}" | ||
|
||
if [[ -n "${JUPYTERHUB_API_TOKEN}" ]]; then | ||
echo "WARNING: using start-singleuser.sh instead of start-notebook.sh to start a server associated with JupyterHub." | ||
exec /usr/local/bin/start-singleuser.sh "$@" | ||
fi | ||
|
||
wrapper="" | ||
if [[ "${RESTARTABLE}" == "yes" ]]; then | ||
wrapper="run-one-constantly" | ||
fi | ||
|
||
# shellcheck disable=SC1091,SC2086 | ||
exec /usr/local/bin/start.sh ${wrapper} jupyter ${DOCKER_STACKS_JUPYTER_CMD} ${NOTEBOOK_ARGS} "$@" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,7 +5,7 @@ | |
"id": "6ee8630c", | ||
"metadata": {}, | ||
"source": [ | ||
"# Part 7: Deployment\n", | ||
"# Part 7a: Bitstream Generation\n", | ||
"\n", | ||
"In the previous sections we've seen how to train a Neural Network with a small resource footprint using QKeras, then to convert it to `hls4ml` and create an IP. That IP can be interfaced into a larger design to deploy on an FPGA device. In this section, we introduce the `VivadoAccelerator` backend of `hls4ml`, where we can easily target some supported devices to get up and running quickly. Specifically, we'll deploy the model on a [pynq-z2 board](http://www.pynq.io/)." | ||
] | ||
|
@@ -26,7 +26,7 @@ | |
"_add_supported_quantized_objects(co)\n", | ||
"import os\n", | ||
"\n", | ||
"os.environ['PATH'] = '/opt/Xilinx/Vivado/2019.2/bin:' + os.environ['PATH']" | ||
"os.environ['PATH'] = os.environ['XILINX_VIVADO'] + '/bin:' + os.environ['PATH']" | ||
] | ||
}, | ||
{ | ||
|
@@ -136,27 +136,6 @@ | |
"np.save('model_3/y_hls.npy', y_hls)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"id": "9ca4f0e2", | ||
"metadata": {}, | ||
"source": [ | ||
"## Synthesize\n", | ||
"Now synthesize the model, and also export the IP." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"id": "ef6c817f", | ||
"metadata": { | ||
"tags": [] | ||
}, | ||
"outputs": [], | ||
"source": [ | ||
"hls_model.build(csim=False, export=True)" | ||
] | ||
}, | ||
{ | ||
"attachments": { | ||
"part7_block_design.png": { | ||
|
@@ -167,8 +146,9 @@ | |
"id": "3412fa7c", | ||
"metadata": {}, | ||
"source": [ | ||
"## Make bitfile\n", | ||
"Now we've exported the NN IP, let's create a bitfile! The `VivadoAccelerator` backend design scripts create a Block Design in Vivado IPI containing our Neural Network IP, as well as the other necessary IPs to create a complete system.\n", | ||
"## Synthesize and make bitfile\n", | ||
"\n", | ||
"Now we will synthesize the model, export the IP, and create a bitfile! The `VivadoAccelerator` backend design scripts create a Block Design in Vivado IPI containing our Neural Network IP, as well as the other necessary IPs to create a complete system.\n", | ||
"\n", | ||
"In the case of our `pynq-z2`, we add a DMA IP to transfer data between the PS and PL containg the Neural Network. If you want to create a different design, for example to connect your NN to a sensor, you can use our block designs as a starting point and add in relevant IP for your use case.\n", | ||
"\n", | ||
|
@@ -184,7 +164,7 @@ | |
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"hls4ml.templates.VivadoAcceleratorBackend.make_bitfile(hls_model)" | ||
"hls_model.build(csim=False, export=True, bitfile=True)" | ||
] | ||
}, | ||
{ | ||
|
@@ -222,148 +202,68 @@ | |
}, | ||
{ | ||
"cell_type": "markdown", | ||
"id": "033cc4d9", | ||
"id": "aac3541d", | ||
"metadata": {}, | ||
"source": [ | ||
"## Part 7b: running on a pynq-z2\n", | ||
"The following section is the code to execute in the pynq-z2 jupyter notebook to execute NN inference. \n", | ||
"## Preparations for deployment\n", | ||
"First, you'll need to follow the [setup instructions for the pynq-z2 board](https://pynq.readthedocs.io/en/latest/getting_started/pynq_z2_setup.html).\n", | ||
"Typically, this includes connecting the board to your host via ethernet and setting up a static IP address for your host (192.168.2.1). \n", | ||
"The IP address for the pynq-z2 is 192.168.2.99.\n", | ||
"The default username and password is xilinx.\n", | ||
"\n", | ||
"First, you'll need to follow the setup instructions for the pynq-z2 board, then transfer the following files from the earlier part of this notebook into a directory on the pynq-z2:\n", | ||
"Next you'll transfer the following files from the earlier part of this notebook into a directory on the pynq-z2:\n", | ||
"- bitfile: `model_3/hls4ml_prj_pynq/myproject_vivado_accelerator/project_1.runs/impl_1/design_1_wrapper.bit` -> `hls4ml_nn.bit`\n", | ||
"- hardware handoff: `model_3/hls4ml_prj_pynq/myproject_vivado_accelerator/project_1.srcs/sources_1/bd/design_1/hw_handoff/design_1.hwh` -> `hls4ml_nn.hwh`\n", | ||
"- driver: `model_3/hls4ml_prj_pynq/axi_stream_driver.py` -> `axi_stream_driver.py`\n", | ||
"- data: `X_test.npy`, `y_test.npy`\n", | ||
"- notebook: `part7b_deployment.ipynb`\n", | ||
"\n", | ||
"The following commands archive these files into `model_3/hls4ml_prj_pynq/package.tar.gz` that can be copied over to the pynq-z2 and extracted." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"id": "22892f4b", | ||
"id": "3ca20d05", | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"!mkdir model_3/hls4ml_prj_pynq/package/\n", | ||
"!mkdir -p model_3/hls4ml_prj_pynq/package\n", | ||
"!cp model_3/hls4ml_prj_pynq/myproject_vivado_accelerator/project_1.runs/impl_1/design_1_wrapper.bit model_3/hls4ml_prj_pynq/package/hls4ml_nn.bit\n", | ||
"!cp model_3/hls4ml_prj_pynq/myproject_vivado_accelerator/project_1.srcs/sources_1/bd/design_1/hw_handoff/design_1.hwh model_3/hls4ml_prj_pynq/package/hls4ml_nn.hwh\n", | ||
"!cp model_3/hls4ml_prj_pynq/axi_stream_driver.py model_3/hls4ml_prj_pynq/package/\n", | ||
"!cp X_test.npy y_test.npy model_3/hls4ml_prj_pynq/package\n", | ||
"!cp part7b_deployment.ipynb model_3/hls4ml_prj_pynq/package\n", | ||
"!tar -czvf model_3/hls4ml_prj_pynq/package.tar.gz -C model_3/hls4ml_prj_pynq/package/ ." | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"id": "a9a52cfb", | ||
"id": "06d6bd96", | ||
"metadata": {}, | ||
"source": [ | ||
"The following cells are intended to run on a pynq-z2, they will not run on the server used to train and synthesize models!\n", | ||
"To copy it to the pynq-z2 with the default settings, the command would be:\n", | ||
"\n", | ||
"First, import our driver `Overlay` class. We'll also load the test data." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"id": "89c67e4f", | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"from axi_stream_driver import NeuralNetworkOverlay\n", | ||
"import numpy as np\n", | ||
"```bash\n", | ||
"scp model_3/hls4ml_prj_pynq/package.tar.gz [email protected]:~/jupyter_notebooks\n", | ||
"```\n", | ||
"\n", | ||
"X_test = np.load('X_test.npy')\n", | ||
"y_test = np.load('y_test.npy')" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"id": "551c5cd6", | ||
"metadata": {}, | ||
"source": [ | ||
"Create a `NeuralNetworkOverlay` object. This will download the `Overlay` (bitfile) onto the PL of the pynq-z2. We provide the `X_test.shape` and `y_test.shape` to allocate some buffers for the data transfer." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"id": "cfb786f3", | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"nn = NeuralNetworkOverlay('hls4ml_nn.bit', X_test.shape, y_test.shape)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"id": "5fde9b2d", | ||
"metadata": {}, | ||
"source": [ | ||
"Now run the prediction! When we set `profile=True` the function times the inference, and prints out a summary as well as returning the profiling information. We also save the output to a file so we can do some validation." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"id": "1fd6dee7", | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"y_hw, latency, throughput = nn.predict(X_test, profile=True)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"id": "1983e7d7", | ||
"metadata": {}, | ||
"source": [ | ||
"An example print out looks like:\n", | ||
"Then you can navigate your web browser to http://192.168.2.99.\n", | ||
"You will see the JupyterHub running on the pynq-z2. Open a terminal and extract the tarball.\n", | ||
"\n", | ||
"```bash\n", | ||
"cd ~/jupyter_notebooks\n", | ||
"tar xvzf package.tar.gz\n", | ||
"```\n", | ||
"\n", | ||
"Classified 166000 samples in 0.402568 seconds (412352.6956936468 inferences / s)" | ||
"Now open the notebook `part7b_deployment.ipynb` on the pynq-z2 JupyterHub" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"id": "005ae126", | ||
"metadata": {}, | ||
"source": [ | ||
"## Part 7c: final validation\n", | ||
"We executed NN inference on the pynq-z2! Now we can copy the `y_hw.npy` back to the host we've been using for the training and synthesis, and make a final plot to check that the output we took on the board is as expected." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"id": "fee790be", | ||
"id": "f876eff5", | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"import matplotlib.pyplot as plt\n", | ||
"\n", | ||
"%matplotlib inline\n", | ||
"from sklearn.metrics import accuracy_score\n", | ||
"\n", | ||
"y_hw = np.load('y_hw.npy')\n", | ||
"y_test = np.load('y_test.npy')\n", | ||
"classes = np.load('classes.npy', allow_pickle=True)\n", | ||
"y_qkeras = model.predict(X_test)\n", | ||
"\n", | ||
"print(\"Accuracy QKeras, CPU: {}\".format(accuracy_score(np.argmax(y_test, axis=1), np.argmax(y_qkeras, axis=1))))\n", | ||
"print(\"Accuracy hls4ml, pynq-z2: {}\".format(accuracy_score(np.argmax(y_test, axis=1), np.argmax(y_hw, axis=1))))\n", | ||
"\n", | ||
"fig, ax = plt.subplots(figsize=(9, 9))\n", | ||
"_ = plotting.makeRoc(y_test, y_qkeras, classes, linestyle='-')\n", | ||
"plt.gca().set_prop_cycle(None) # reset the colors\n", | ||
"_ = plotting.makeRoc(y_test, y_hw, classes, linestyle='--')\n", | ||
"\n", | ||
"from matplotlib.lines import Line2D\n", | ||
"\n", | ||
"lines = [Line2D([0], [0], ls='-'), Line2D([0], [0], ls='--')]\n", | ||
"from matplotlib.legend import Legend\n", | ||
"\n", | ||
"leg = Legend(ax, lines, labels=['QKeras, CPU', 'hls4ml, pynq-z2'], loc='lower right', frameon=False)\n", | ||
"ax.add_artist(leg)" | ||
] | ||
"source": [] | ||
} | ||
], | ||
"metadata": { | ||
|
Oops, something went wrong.