Skip to content

Commit d3e1ac1

Browse files
authored
Merge pull request #2559 from oneapi-src/release/2025.0_AITools
2025.0 AI Tools Release
2 parents d7a4270 + 606c5b1 commit d3e1ac1

16 files changed

+206
-366
lines changed
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
"cell_type": "markdown",
1818
"metadata": {},
1919
"source": [
20-
"# Genetic Algorithms on GPU using Intel Distribution of Python numba-dpex\n",
20+
"# Genetic Algorithms on GPU using Intel Distribution of Python \n",
2121
"\n",
22-
"This code sample shows how to implement a basic genetic algorithm with Data Parallel Python using numba-dpex.\n",
22+
"This code sample shows how to implement a basic genetic algorithm with Data Parallel Python using Data Parallel Extension of NumPy.\n",
2323
"\n",
2424
"## Genetic algorithms\n",
2525
"\n",
@@ -98,7 +98,7 @@
9898
"\n",
9999
"### Simple evaluation method\n",
100100
"\n",
101-
"We are starting with a simple genome evaluation function. This will be our baseline and comparison for numba-dpex.\n",
101+
"We are starting with a simple genome evaluation function. This will be our baseline and comparison for dpnp.\n",
102102
"In this example, the fitness of an individual is computed by an arbitrary set of algebraic operations on the chromosome."
103103
]
104104
},
@@ -317,9 +317,9 @@
317317
"cell_type": "markdown",
318318
"metadata": {},
319319
"source": [
320-
"## GPU execution using numba-dpex\n",
320+
"## GPU execution using dpnp\n",
321321
"\n",
322-
"We need to start with new population initialization, as we want to perform the same operations but now on GPU using numba-dpex implementation.\n",
322+
"We need to start with new population initialization, as we want to perform the same operations but now on GPU using dpnpx implementation.\n",
323323
"\n",
324324
"We are setting random seed the same as before to reproduce the results. "
325325
]
@@ -344,11 +344,11 @@
344344
"cell_type": "markdown",
345345
"metadata": {},
346346
"source": [
347-
"### Evaluation function using numba-dpex\n",
347+
"### Evaluation function using Data Parallel Extension for NumPy\n",
348348
"\n",
349-
"The only par that differs form the standard implementation is the evaluation function.\n",
349+
"The only part that differs form the standard implementation is the evaluation function.\n",
350350
"\n",
351-
"The most important part is to specify the index of the computation. This is the current index of the computed chromosomes. This serves as a loop function across all chromosomes."
351+
"In this implementation we are taking benefit from vectorized operations. DPNP will automatically vectorize addition, substraction, multiplication operations, making them efficient and suitable for GPU acceleration."
352352
]
353353
},
354354
{
@@ -364,31 +364,28 @@
364364
},
365365
"outputs": [],
366366
"source": [
367-
"import numba_dpex\n",
368-
"from numba_dpex import kernel_api\n",
367+
"import dpnp as dpnp\n",
369368
"\n",
370-
"@numba_dpex.kernel\n",
371-
"def eval_genomes_sycl_kernel(item: kernel_api.Item, chromosomes, fitnesses, chrom_length):\n",
372-
" pos = item.get_id(0)\n",
369+
"def eval_genomes_dpnp(chromosomes_list, fitnesses):\n",
373370
" num_loops = 3000\n",
374-
" for i in range(num_loops):\n",
375-
" fitnesses[pos] += chromosomes[pos*chrom_length + 1]\n",
376-
" for i in range(num_loops):\n",
377-
" fitnesses[pos] -= chromosomes[pos*chrom_length + 2]\n",
378-
" for i in range(num_loops):\n",
379-
" fitnesses[pos] += chromosomes[pos*chrom_length + 3]\n",
380371
"\n",
381-
" if (fitnesses[pos] < 0):\n",
382-
" fitnesses[pos] = 0"
372+
" # Calculate fitnesses using vectorized operations\n",
373+
" fitnesses += chromosomes_list[:, 1] * num_loops\n",
374+
" fitnesses -= chromosomes_list[:, 2] * num_loops\n",
375+
" fitnesses += chromosomes_list[:, 3] * num_loops\n",
376+
"\n",
377+
" # Clip negative fitness values to zero\n",
378+
" fitnesses = np.where(fitnesses < 0, 0, fitnesses)\n",
379+
" return fitnesses"
383380
]
384381
},
385382
{
386383
"cell_type": "markdown",
387384
"metadata": {},
388385
"source": [
389-
"Now, we can measure the time to perform some generations of the Genetic Algorithm with Data Parallel Python Numba dpex. \n",
386+
"Now, we can measure the time to perform some generations of the Genetic Algorithm with Data Parallel Python Extension for NumPy. \n",
390387
"\n",
391-
"Similarly like before, the time of the evaluation, creation of new generation and fitness wipe are measured for GPU execution. But first, we need to send all the chromosomes and fitnesses container to the chosen device. "
388+
"Similarly like before, the time of the evaluation, creation of new generation and fitness wipe are measured for GPU execution. But first, we need to send all the chromosomes and fitnesses container to the chosen device - GPU. "
392389
]
393390
},
394391
{
@@ -399,25 +396,26 @@
399396
},
400397
"outputs": [],
401398
"source": [
402-
"import dpnp\n",
403-
"\n",
404399
"print(\"SYCL:\")\n",
405400
"start = time.time()\n",
406401
"\n",
407402
"# Genetic Algorithm on GPU\n",
408403
"for i in range(num_generations):\n",
409404
" print(\"Gen \" + str(i+1) + \"/\" + str(num_generations))\n",
410-
" chromosomes_flat = chromosomes.flatten()\n",
411-
" chromosomes_flat_dpctl = dpnp.asarray(chromosomes_flat, device=\"gpu\")\n",
412-
" fitnesses_dpctl = dpnp.asarray(fitnesses, device=\"gpu\")\n",
405+
" chromosomes_dpctl = chromosomes\n",
406+
" fitnesses_dpctl = fitnesses\n",
407+
" try:\n",
408+
" chromosomes_dpctl = dpnp.asarray(chromosomes, device=\"gpu\")\n",
409+
" fitnesses_dpctl = dpnp.asarray(fitnesses, device=\"gpu\")\n",
410+
" except Exception:\n",
411+
" print(\"GPU device is not available\")\n",
412+
" \n",
413+
" fitnesses = eval_genomes_dpnp(chromosomes, fitnesses)\n",
413414
" \n",
414-
" exec_range = kernel_api.Range(pop_size)\n",
415-
" numba_dpex.call_kernel(eval_genomes_sycl_kernel, exec_range, chromosomes_flat_dpctl, fitnesses_dpctl, chrom_size)\n",
416415
" fitnesses = dpnp.asnumpy(fitnesses_dpctl)\n",
417416
" chromosomes = next_generation(chromosomes, fitnesses)\n",
418417
" fitnesses = np.zeros(pop_size, dtype=np.float32)\n",
419418
"\n",
420-
"\n",
421419
"end = time.time()\n",
422420
"time_sycl = end-start\n",
423421
"print(\"time elapsed: \" + str((time_sycl)))\n",
@@ -457,7 +455,7 @@
457455
"\n",
458456
"plt.figure()\n",
459457
"plt.title(\"Time comparison\")\n",
460-
"plt.bar([\"Numba_dpex\", \"without optimization\"], [time_sycl, time_cpu])\n",
458+
"plt.bar([\"DPNP\", \"without optimization\"], [time_sycl, time_cpu])\n",
461459
"\n",
462460
"plt.show()"
463461
]
@@ -546,7 +544,7 @@
546544
"\n",
547545
"The evaluate created generation we are calculating the full distance of the given path (chromosome). In this example, the lower the fitness value is, the better the chromosome. That's different from the general GA that we implemented.\n",
548546
"\n",
549-
"As in this example we are also using numba-dpex, we are using an index like before."
547+
"As in the previous example dpnp will vectorize basic mathematical operations to take benefit from optimizations."
550548
]
551549
},
552550
{
@@ -555,11 +553,11 @@
555553
"metadata": {},
556554
"outputs": [],
557555
"source": [
558-
"@numba_dpex.kernel\n",
559-
"def eval_genomes_plain_TSP_SYCL(item: kernel_api.Item, chromosomes, fitnesses, distances, pop_length):\n",
560-
" pos = item.get_id(1)\n",
561-
" for j in range(pop_length-1):\n",
562-
" fitnesses[pos] += distances[int(chromosomes[pos, j]), int(chromosomes[pos, j+1])]\n"
556+
"def eval_genomes_plain_TSP_SYCL(chromosomes, fitnesses, distances, pop_length):\n",
557+
" for pos in range(pop_length):\n",
558+
" for j in range(chromosomes.shape[1]-1):\n",
559+
" fitnesses[pos] += distances[int(chromosomes[pos, j]), int(chromosomes[pos, j+1])]\n",
560+
" return fitnesses\n"
563561
]
564562
},
565563
{
@@ -703,22 +701,26 @@
703701
"source": [
704702
"print(\"Traveling Salesman Problem:\")\n",
705703
"\n",
706-
"distances_dpctl = dpnp.asarray(distances, device=\"gpu\")\n",
704+
"distances_dpnp = distances\n",
705+
"try:\n",
706+
" distances_dpnp = dpnp.asarray(distances, device=\"gpu\")\n",
707+
"except Exception:\n",
708+
" print(\"GPU device is not available\")\n",
709+
"\n",
707710
"# Genetic Algorithm on GPU\n",
708711
"for i in range(num_generations):\n",
709712
" print(\"Gen \" + str(i+1) + \"/\" + str(num_generations))\n",
710-
" chromosomes_flat_dpctl = dpnp.asarray(chromosomes, device=\"gpu\")\n",
711-
" fitnesses_dpctl = dpnp.asarray(fitnesses.copy(), device=\"gpu\")\n",
712713
"\n",
713-
" exec_range = kernel_api.Range(pop_size)\n",
714-
" numba_dpex.call_kernel(eval_genomes_plain_TSP_SYCL, exec_range, chromosomes_flat_dpctl, fitnesses_dpctl, distances_dpctl, pop_size)\n",
715-
" fitnesses = dpnp.asnumpy(fitnesses_dpctl)\n",
716-
" chromosomes = next_generation_TSP(chromosomes, fitnesses)\n",
714+
" chromosomes_dpnp = chromosomes\n",
715+
" try:\n",
716+
" chromosomes_dpnp = dpnp.asarray(chromosomes, device=\"gpu\")\n",
717+
" except Exception:\n",
718+
" print(\"GPU device is not available\")\n",
719+
"\n",
717720
" fitnesses = np.zeros(pop_size, dtype=np.float32)\n",
718721
"\n",
719-
"for i in range(len(chromosomes)):\n",
720-
" for j in range(11):\n",
721-
" fitnesses[i] += distances[int(chromosomes[i][j])][int(chromosomes[i][j+1])]\n",
722+
" fitnesses = eval_genomes_plain_TSP_SYCL(chromosomes_dpnp, fitnesses, distances_dpnp, pop_size)\n",
723+
" chromosomes = next_generation_TSP(chromosomes, fitnesses)\n",
722724
"\n",
723725
"fitness_pairs = []\n",
724726
"\n",
@@ -736,7 +738,7 @@
736738
"cell_type": "markdown",
737739
"metadata": {},
738740
"source": [
739-
"In this code sample, there was a general purpose Genetic Algorithm created and optimized using numba-dpex to run on GPU. Then the same approach was applied to the Traveling Salesman Problem."
741+
"In this code sample, there was a general purpose Genetic Algorithm created and optimized using dpnp to run on GPU. Then the same approach was applied to the Traveling Salesman Problem."
740742
]
741743
},
742744
{
@@ -756,7 +758,7 @@
756758
"provenance": []
757759
},
758760
"kernelspec": {
759-
"display_name": "base",
761+
"display_name": "Base",
760762
"language": "python",
761763
"name": "base"
762764
},
@@ -770,7 +772,7 @@
770772
"name": "python",
771773
"nbconvert_exporter": "python",
772774
"pygments_lexer": "ipython3",
773-
"version": "3.9.18"
775+
"version": "3.9.19"
774776
}
775777
},
776778
"nbformat": 4,

0 commit comments

Comments
 (0)