Skip to content

Commit 1b70595

Browse files
authored
tests(manual): add tensorflow-test.ipynb (#1975)
This is a basic TensorFlow smoke test created by @daniellutz Coderabbit wished it to be enhanced in the following areas * #2491
1 parent 405159d commit 1b70595

File tree

1 file changed

+347
-0
lines changed

1 file changed

+347
-0
lines changed

tests/manual/tensorflow-test.ipynb

Lines changed: 347 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,347 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"id": "06fb33f2-64d3-4555-97ae-1fbd4d35bcf3",
6+
"metadata": {},
7+
"source": [
8+
"# Tensorflow test notebook\n",
9+
"\n",
10+
"This notebook aims to provide a very basic testing perspective on Jupyter notebooks with GPU support, in such way that:\n",
11+
"\n",
12+
"1. Verify the installed Python version\n",
13+
"2. Find the GPU on the devices list\n",
14+
"3. Check if nvidia-smi loads properly\n",
15+
"4. CUDA/ROCm drivers are installed\n",
16+
"5. TensorFlow quickstart for beginners\n",
17+
"6. TensorFlow tests (basic operations on GPU)\n",
18+
"7. TensorBoard spins up properly"
19+
]
20+
},
21+
{
22+
"cell_type": "markdown",
23+
"id": "9c5d228b-1e87-4dde-a469-7e89ac27e0f3",
24+
"metadata": {},
25+
"source": [
26+
"## 1. Verify the installed Python version\n",
27+
"Multiple notebooks are available, and it can happen of system upgrades, notebooks built with different Python versions, across other possible changes.\n",
28+
"\n",
29+
"The following test will only print out the Python version installed on this notebook, so it can be verified that the expected Python is really running.\n",
30+
"\n",
31+
"> Note: this is yet a manual test, you need to know what version is supposed to run here and match with the output below."
32+
]
33+
},
34+
{
35+
"cell_type": "code",
36+
"execution_count": 2,
37+
"id": "5964db1a-5a7c-4988-a3ee-2b7794cdfc38",
38+
"metadata": {},
39+
"outputs": [
40+
{
41+
"name": "stdout",
42+
"output_type": "stream",
43+
"text": [
44+
"3.12.9 (main, Jun 20 2025, 00:00:00) [GCC 11.5.0 20240719 (Red Hat 11.5.0-5)]\n"
45+
]
46+
}
47+
],
48+
"source": [
49+
"import sys\n",
50+
"print(sys.version)"
51+
]
52+
},
53+
{
54+
"cell_type": "markdown",
55+
"id": "14291502-9d3b-40dc-b1a3-0721ab26e12d",
56+
"metadata": {},
57+
"source": [
58+
"## 2. Find the GPU on the devices list\n",
59+
"To understand if the GPUs are present in the current setup, we wil rely on TensorFlow Python client, which refers to the official Python API for interacting with the system's properties and devices.\n",
60+
"\n",
61+
"- If the following code returns a list with items inside, this means that there are GPUs running on this server;\n",
62+
"- If the following code returns an empty list, this means that there are no GPUs available;"
63+
]
64+
},
65+
{
66+
"cell_type": "code",
67+
"execution_count": null,
68+
"id": "612058a9-cbfe-4e4b-a5cc-bc08e31df830",
69+
"metadata": {},
70+
"outputs": [],
71+
"source": [
72+
"from tensorflow.python.client import device_lib\n",
73+
"\n",
74+
"def get_available_gpus():\n",
75+
" \"\"\"\n",
76+
" Get all devices connected to this server and return only\n",
77+
" the devices that contain the keyword \"GPU\"\n",
78+
" \"\"\"\n",
79+
" local_device_protos = device_lib.list_local_devices()\n",
80+
" return ([x.name for x in local_device_protos if x.device_type == 'GPU'])\n",
81+
"\n",
82+
"get_available_gpus()"
83+
]
84+
},
85+
{
86+
"cell_type": "markdown",
87+
"id": "40f07595-a51e-4b17-b537-53d2c21ea83f",
88+
"metadata": {},
89+
"source": [
90+
"## 3. Check if nvidia-smi loads properly\n",
91+
"The NVIDIA System Management Interface (nvidia-smi) is a command line utility, based on top of the NVIDIA Management Library (NVML), intended to aid in the management and monitoring of NVIDIA GPU devices.\n",
92+
"\n",
93+
"The following command only spins up the `nvidia-smi` utility:"
94+
]
95+
},
96+
{
97+
"cell_type": "code",
98+
"execution_count": null,
99+
"id": "e4307f74-b172-4a4e-8d35-c8f6b98421f6",
100+
"metadata": {},
101+
"outputs": [],
102+
"source": [
103+
"!nvidia-smi"
104+
]
105+
},
106+
{
107+
"cell_type": "markdown",
108+
"id": "86ed7b78-1171-4347-a99a-cedc5e513415",
109+
"metadata": {},
110+
"source": [
111+
"## 4. CUDA/ROCm drivers are installed;\n",
112+
"This test aims to simply check if CUDA/ROCm drivers are properly installed. To test this, the `nvcc` command will be executed for NVIDIA GPUs and `hipcc` for ROCm GPUs.\n",
113+
"\n",
114+
"> Note: the code is as simple as possible, run the ones that makes sense for the tests you are doing (there are no extended programming to check automatically, etc, this is done this way on purpose to simplify the code as much as possible"
115+
]
116+
},
117+
{
118+
"cell_type": "code",
119+
"execution_count": null,
120+
"id": "98a7a87d-c814-458a-b47a-36681c384223",
121+
"metadata": {},
122+
"outputs": [],
123+
"source": [
124+
"# Run the following for NVIDIA GPUs\n",
125+
"!nvcc --version"
126+
]
127+
},
128+
{
129+
"cell_type": "code",
130+
"execution_count": null,
131+
"id": "58878971-ddde-4310-bee3-992cb60e6444",
132+
"metadata": {},
133+
"outputs": [],
134+
"source": [
135+
"# Run the following for ROCm GPUs\n",
136+
"!hipcc --version"
137+
]
138+
},
139+
{
140+
"cell_type": "markdown",
141+
"id": "3d3fbdc6-fafb-48a7-bfdb-4bf8f00ea414",
142+
"metadata": {},
143+
"source": [
144+
"## 5. TensorFlow quickstart for beginners\n",
145+
"This test aims to use the basic Getting Started tutorial on TensorFlow website to check if this installation is working properly:\n",
146+
"\n",
147+
"- Load a prebuilt dataset;\n",
148+
"- Build a neural network machine learning model that classifies images;\n",
149+
"- Train this neural network;\n",
150+
"- Evaluate the accuracy of the model;\n",
151+
"\n",
152+
"The expected output here is a matrix of probabilities, i.e.:\n",
153+
"\n",
154+
"```\n",
155+
"<tf.Tensor: shape=(5, 10), dtype=float32, numpy=\n",
156+
"array([[1.6603454e-07, 1.1202768e-09, 3.5647324e-06, 2.7514023e-05,\n",
157+
" 1.0256378e-10, 1.7054673e-07...\n",
158+
"```"
159+
]
160+
},
161+
{
162+
"cell_type": "code",
163+
"execution_count": null,
164+
"id": "9a84a9ec-f867-44aa-b078-61156f71e132",
165+
"metadata": {},
166+
"outputs": [],
167+
"source": [
168+
"import tensorflow as tf\n",
169+
"\n",
170+
"# 1. Load a dataset\n",
171+
"# ----------------------------------------------------------------------------------------------\n",
172+
"# Load and prepare the MNIST dataset. The pixel values of the images range from 0 through 255.\n",
173+
"# Scale these values to a range of 0 to 1 by dividing the values by 255.0.\n",
174+
"# This also converts the sample data from integers to floating-point numbers:\n",
175+
"mnist = tf.keras.datasets.mnist\n",
176+
"\n",
177+
"(x_train, y_train), (x_test, y_test) = mnist.load_data()\n",
178+
"x_train, x_test = x_train / 255.0, x_test / 255.0\n",
179+
"\n",
180+
"\n",
181+
"# 2. Build a machine learning model\n",
182+
"# ----------------------------------------------------------------------------------------------\n",
183+
"# Build a tf.keras.Sequential model:\n",
184+
"model = tf.keras.models.Sequential([\n",
185+
" tf.keras.layers.Flatten(input_shape=(28, 28)),\n",
186+
" tf.keras.layers.Dense(128, activation='relu'),\n",
187+
" tf.keras.layers.Dropout(0.2),\n",
188+
" tf.keras.layers.Dense(10)\n",
189+
"])\n",
190+
"\n",
191+
"# Sequential is useful for stacking layers where each layer has one input tensor and one output tensor.\n",
192+
"# Layers are functions with a known mathematical structure that can be reused and have trainable variables.\n",
193+
"# Most TensorFlow models are composed of layers. This model uses the Flatten, Dense, and Dropout layers.\n",
194+
"#\n",
195+
"# For each example, the model returns a vector of logits or log-odds scores, one for each class.\n",
196+
"predictions = model(x_train[:1]).numpy()\n",
197+
"predictions\n",
198+
"\n",
199+
"# The tf.nn.softmax function converts these logits to probabilities for each class:\n",
200+
"tf.nn.softmax(predictions).numpy()\n",
201+
"\n",
202+
"# Define a loss function for training using losses.SparseCategoricalCrossentropy:\n",
203+
"loss_fn = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)\n",
204+
"\n",
205+
"# The loss function takes a vector of ground truth values and a vector of logits and returns a scalar loss for each example.\n",
206+
"# This loss is equal to the negative log probability of the true class: The loss is zero if the model is sure of the correct class.\n",
207+
"#\n",
208+
"# This untrained model gives probabilities close to random (1/10 for each class), so the initial loss should be close to -tf.math.log(1/10) ~= 2.3.\n",
209+
"loss_fn(y_train[:1], predictions).numpy()\n",
210+
"\n",
211+
"# Before you start training, configure and compile the model using Keras Model.compile.Set the optimizer class to adam, set the loss to the loss_fn\n",
212+
"# function you defined earlier, and specify a metric to be evaluated for the model by setting the metrics parameter to accuracy.\n",
213+
"model.compile(optimizer='adam',\n",
214+
" loss=loss_fn,\n",
215+
" metrics=['accuracy'])\n",
216+
"\n",
217+
"\n",
218+
"# 3. Train and evaluate your model\n",
219+
"# ----------------------------------------------------------------------------------------------\n",
220+
"# Use the Model.fit method to adjust your model parameters and minimize the loss:\n",
221+
"model.fit(x_train, y_train, epochs=5)\n",
222+
"\n",
223+
"# The Model.evaluate method checks the model's performance, usually on a validation set or test set.\n",
224+
"model.evaluate(x_test, y_test, verbose=2)\n",
225+
"\n",
226+
"# The image classifier is now trained to ~98% accuracy on this dataset. To learn more, read the TensorFlow tutorials.\n",
227+
"#\n",
228+
"# If you want your model to return a probability, you can wrap the trained model, and attach the softmax to it:\n",
229+
"probability_model = tf.keras.Sequential([\n",
230+
" model,\n",
231+
" tf.keras.layers.Softmax()\n",
232+
"])\n",
233+
"probability_model(x_test[:5])"
234+
]
235+
},
236+
{
237+
"cell_type": "markdown",
238+
"id": "c1a0ed9e-7372-4b3b-b6c0-0d252ee88c01",
239+
"metadata": {},
240+
"source": [
241+
"## 6. TensorFlow tests (basic operations on GPU)\n",
242+
"This test aims to try out the GPU basic commands, like `add`, `multiply`, `matmul`, `reduce_sum` and `reduce_mean` just to be sure that TensorFlow is really running well.\n",
243+
"\n",
244+
"For more information of the methods that will be tested here:\n",
245+
"- [tf.add](https://www.tensorflow.org/api_docs/python/tf/math/add)\n",
246+
"- [tf.multiply](https://www.tensorflow.org/api_docs/python/tf/math/multiply)\n",
247+
"- [tf.matmul](https://www.tensorflow.org/api_docs/python/tf/linalg/matmul)\n",
248+
"- [tf.reduce_sum](https://www.tensorflow.org/api_docs/python/tf/math/reduce_sum)\n",
249+
"- [tf.reduce_mean](https://www.tensorflow.org/api_docs/python/tf/math/reduce_mean)"
250+
]
251+
},
252+
{
253+
"cell_type": "code",
254+
"execution_count": null,
255+
"id": "e2e44f63-6c50-493b-9742-125e2f09073b",
256+
"metadata": {},
257+
"outputs": [],
258+
"source": [
259+
"import tensorflow as tf\n",
260+
"import numpy as np\n",
261+
"\n",
262+
"# Basic arithmetic\n",
263+
"a = tf.constant([1.0, 2.0, 3.0, 4.0])\n",
264+
"b = tf.constant([4.0, 3.0, 2.0, 1.0])\n",
265+
"\n",
266+
"# Addition\n",
267+
"add_result = tf.add(a, b)\n",
268+
"print(f\"Addition: {a.numpy()} + {b.numpy()} = {add_result.numpy()}\")\n",
269+
"\n",
270+
"# Multiplication\n",
271+
"mul_result = tf.multiply(a, b)\n",
272+
"print(f\"Multiplication: {mul_result.numpy()}\")\n",
273+
"\n",
274+
"# Matrix operations\n",
275+
"matrix_a = tf.constant([[1.0, 2.0], [3.0, 4.0]])\n",
276+
"matrix_b = tf.constant([[2.0, 1.0], [1.0, 3.0]])\n",
277+
"matmul_result = tf.matmul(matrix_a, matrix_b)\n",
278+
"print(f\"Matrix multiplication result: \\n{matmul_result.numpy()}\")\n",
279+
"\n",
280+
"# Reduction operations\n",
281+
"reduce_sum = tf.reduce_sum(a)\n",
282+
"reduce_mean = tf.reduce_mean(a)\n",
283+
"print(f\"Sum: {reduce_sum.numpy()}, Mean: {reduce_mean.numpy()}\")"
284+
]
285+
},
286+
{
287+
"cell_type": "markdown",
288+
"id": "988e8953-6957-44da-ab2e-3a7272d5815d",
289+
"metadata": {},
290+
"source": [
291+
"## 7. TensorBoard spins up properly\n",
292+
"[TensorBoard](https://www.tensorflow.org/tensorboard) provides the visualization and tooling needed for machine learning experimentation:\n",
293+
"\n",
294+
"- Tracking and visualizing metrics such as loss and accuracy\n",
295+
"- Visualizing the model graph (ops and layers)\n",
296+
"- Viewing histograms of weights, biases, or other tensors as they change over time\n",
297+
"- Projecting embeddings to a lower dimensional space\n",
298+
"- Displaying images, text, and audio data\n",
299+
"- Profiling TensorFlow programs\n",
300+
"- and more...\n",
301+
"\n",
302+
"This basic test aims to check if the TensorBoard UI spins up properly and that there are no major issues (see [RHOAIENG-20553](https://issues.redhat.com/browse/RHOAIENG-20553))"
303+
]
304+
},
305+
{
306+
"cell_type": "code",
307+
"execution_count": null,
308+
"id": "9361e574-2e50-46b3-852c-c5b9d06c6f7b",
309+
"metadata": {},
310+
"outputs": [],
311+
"source": [
312+
"import os\n",
313+
"\n",
314+
"# Tensorboard needs to run through a proxy as the Jupyter Notebook is running with a proxy / internal connection\n",
315+
"# More information: https://medium.com/@adrian.punga_29809/how-to-use-tensorboard-inline-in-jupyter-lab-or-colab-d28519619d28\n",
316+
"os.environ[\"TENSORBOARD_PROXY_URL\"] = os.environ[\"NB_PREFIX\"]+\"/proxy/6006/\"\n",
317+
"\n",
318+
"# Load TensorBoard extension\n",
319+
"%load_ext tensorboard\n",
320+
"\n",
321+
"# Show TensorBoard in the Jupyter Notebook\n",
322+
"%tensorboard --logdir /opt/app-root/src/shared"
323+
]
324+
}
325+
],
326+
"metadata": {
327+
"kernelspec": {
328+
"display_name": "Python 3.12",
329+
"language": "python",
330+
"name": "python3"
331+
},
332+
"language_info": {
333+
"codemirror_mode": {
334+
"name": "ipython",
335+
"version": 3
336+
},
337+
"file_extension": ".py",
338+
"mimetype": "text/x-python",
339+
"name": "python",
340+
"nbconvert_exporter": "python",
341+
"pygments_lexer": "ipython3",
342+
"version": "3.12.9"
343+
}
344+
},
345+
"nbformat": 4,
346+
"nbformat_minor": 5
347+
}

0 commit comments

Comments
 (0)