PYTHON AND VECTORISATION
La vectorisation est fondamentalement l’art de débarrasser votre code des boucles for explicites. A
l'ère de l'apprentissage profond et
en particulier dans sa mise en pratique, vous avez souvent à entraîner sur des
ensembles de données relativement importants, parce que c’est là que les algorithmes
d’apprentissage profond ont tendance à briller. Et il est donc important que votre code
s'exécute rapidement parce que sinon, si vous entraînez sur
un grand ensemble de données, votre code peut prendre beaucoup de temps
à calculer, vous vous retrouverez à attendre très longtemps
pour obtenir le résultat. Je pense qu'à l'ère du deep learning la capacité à effectuer la vectorisation
est devenue une compétence clé. Commençons par un exemple. Donc, qu'est-ce que la
vectorisation ? Dans la régression logistique, vous deviez
calculer z égal à transposée de w * x + b, où w est ce vecteur colonne
et x est ce vecteur. ça peux être de très grands vecteurs si vous
avez un grand nombre de caractéristiques. Donc, w et x appartiennent à R nx,
ils sont de dimension nx Pour calculer la transposée de w par x, si vous avez une implémentation non
vectorisée, vous ferez quelque chose comme z = 0, et puis for i in range(nx) : donc pour i de 1 à nx, z
+= w[i] * x[i] Et puis peut-être à la fin z += b Ceci est une implémentation non vectorisée. Vous verrez
que cela va être vraiment lent. En revanche, une implémentation vectorisée
calculerait directement la transposée de w par x. En Python avec numpy, la commande que vous
utilisez pour cela est
z = [Link](w, x) ceci calcule la transposée de w, x. Et vous pouvez y ajouter b directement. Et vous
verrez que c’est beaucoup plus rapide. Nous allons en fait illustrer ceci
avec une petite démo. Voici donc mon notebook Jupyter,
dans lequel je vais écrire du code Python. Alors, tout d’abord, je vais importer
la librairie numpy. import numpy as np Par exemple, je peux créer
un tableau a, comme ceci. Puis print(a) Après avoir écrit ce morceau de code, si j'appuie sur
Maj+Entrée, il exécute le code. Donc il a créé la tableau a et il l'a affiché. Maintenant, nous allons
faire
la démonstration de la vectorisation. Je vais importer la librairie time, puisque nous allons l'utiliser
pour mesurer le temps que prennent
les différentes opérations. Je vais créer un tableau a [Link](1000000) Cela crée une tableau
de taille 1 million
avec des valeurs aléatoires. b = [Link](1000000) Un autre tableau de taille 1 million. Et,
maintenant, tic=[Link](),
donc stockons la date actuelle c = [Link] (a, b). toc = [Link](). Et puis affichons, C’est la version
vectorisée. Donc, version vectorisée. Et affichons le temps écoulé c'est à dire (toc - tic ) * 1000 afin
que ce soit en millisecondes. Ainsi, ms est pour millisecondes. Je vais appuyer sur Maj + Entrée. Ainsi,
ce code a mis environ 3 millisecondes
ou cette fois 1.5, environ entre 1.5 et 3,5 millisecondes
cette fois. ça varie un peu à chaque fois que je l'exécute, mais on dirait qu'en moyenne il met
quelque chose comme 1,5 millisecondes, peut-être deux millisecondes,
quand j'exécute ceci. Très bien. Nous allons continuer ce bloc de code. Nous allons implémenter
la version non vectorisée. Voyons voir, c = 0, puis tic = [Link]() Maintenant, nous allons
implémenter une boucle for. for i in range(1 million) : je vérifie que j'ai le bon nombre de zéros. c +=
a[i] * b[i] et puis toc = [Link](). et enfin afficher, pour la boucle for explicite Le temps qu’il faut est
ceci
1000 *( toc -tic) + " ms " pour montrer que ce sont des millisecondes. Nous allons faire encore une
chose. Nous allons juste afficher
la valeur de c que nous calculons pour nous assurer que
c’est la même valeur dans les deux cas. Je vais appuyer sur Maj + Entrée
pour exécuter et vérifier cela. Dans les deux cas, la version vectorisée et la version non-vectorisée
ont calculé les mêmes valeurs, comme vous le voyez
, 2 5 0 2 8 6 point 99 et ainsi de suite. La version vectorisée a mis 1,5 millisecondes. La version non-
vectorisée avec
la boucle for explicite a mis
environ 400, presque 500 millisecondes. Donc la version non-vectorisée a mis
quelque chose comme 300 fois plus de temps que la version vectorisée. Avec cet exemple, vous
voyez que si
vous prenez la peine de vectoriser votre code, votre code tourne plus de 300 fois plus vite. Nous
allons l'exécuter à nouveau. Et encore. Oui. Version vectorisée : 1,5 millisecondes
et la boucle for 481 millisecondes, encore une fois, c'est environ 300 fois plus lent
de faire la boucle for explicite. Donc, 300 fois plus lent, c’est la différence entre votre code prenant
peut-être une minute pour s'exécuter par rapport à environ 5 heures. Et lorsque vous implémentez
des algorithmes d’apprentissage profond, vous pouvez vraiment obtenir
un résultat plus rapidement. Ce sera beaucoup plus rapide
si vous vectorisez votre code. Certains d'entre vous ont
peut-être entendu dire que beaucoup d'implémentations évolutive
d’apprentissage profond se font sur
un GPU ou une unité de traitement graphique. Mais toutes les démos que j’ai faites tout à l’heure
dans le notebook Jupyter sont faites sur le CPU. Et il s’avère que le GPU et le CPU ont
des instructions de parallélisation, qui sont parfois appelées instructions SIMD. Cela signifie Single
Instruction Multiple Data
(une seule instruction, données multiples) Mais ce que cela signifie est que, Si vous utilisez les
fonctions intégrées comme la fonction [Link] ou d'autres fonctions
qui ne nécessitent pas d'implémenter
explicitement une boucle for, ça permet à numpy de tirer un bien meilleur avantage du parallélisme
pour faire
vos calculs beaucoup plus rapidement. Et cela vaut aussi bien pour les calculs sur les
processeurs que sur les cartes graphiques. C’est juste que les GPU sont
remarquablement bons pour ces calculs SIMD mais
le CPU n'est pas trop mauvais non plus, simplement pas aussi bon que le GPU. Vous avez vu
comment la vectorisation peut
accélérer considérablement votre code. La règle à retenir est, dès que c'est possible, évitez d’utiliser
des boucles for explicites.
MORE VECTORISATION EXAMPLES
Dans la vidéo précédente, vous avez vu
quelques exemples sur comment
la vectorisation, en utilisant des fonctions intégrées et
en évitant les boucles explicites FOR peut permettre d’accélérer
votre code de manière significative Voyons quelques autres exemples. La règle de base à retenir
est lorsque vous programmez votre réseau de neurones
ou votre régression logistique, évitez dans la mesure du possible
les boucles explicites FOR. Et il n'est pas toujours possible de
ne jamais utiliser de boucle FOR mais quand vous pouvez utiliser une
fonction intégrée ou trouver une autre façon de calculer ce
dont vous avez besoin, vous irez souvent plus vite que si vous
utilisiez une boucle explicite FOR. Regardons un autre exemple. Si jamais vous voulez calculer un
vecteur
u comme le produit d’une matrice A, et un autre vecteur, v, alors la définition d’un multiplicateur
de matrice est que votre ui est égal à la somme sur j, Aij, vj En effet. Voila comment vous définissez
ui, et donc l'implémentation non vectorisée,
de ceci serait de fixer u = np. zéros et ça sera n par un et alors FOR i et ainsi de suite FOR j et ainsi de
suite OK? et puis ui plus égal Aij fois vj Alors maintenant, nous avons
deux boucles FOR sur i et j donc ceci est la version non vectorisée. L’implémentation vectorisée
consistera
à dire u = [Link](A, v). L'implémentation sur votre droite, la version vectorisée, élimine maintenant
deux boucles FOR différentes
et sera beaucoup plus rapide. Parcourons un exemple de plus Disons que vous avez déjà un vecteur v
en mémoire et que vous voulez appliquer l’opération exponentielle à
chaque élément de, disons, ce vecteur v, donc vous calculez u
égal au vecteur qui est e de v1 e de v2 et ainsi de suite jusqu'à e de vn Donc ce serait une
implémentation
non vectorisée où dans un premier temps vous initialisez u comme vecteur de zéros
et vous avez ensuite une boucle FOR qui calcule les éléments
un par un Il s’avère que Python et NumPy ont
de nombreuses fonctions intégrées
qui vous permettent de calculer ces vecteurs avec juste
un seul appel à une fonction unique. Donc ce que je ferais pour implémenter
cela est import numpy as np et puis, vous appelez simplement u = [Link](v).
Notez que tandis que précédemment, vous avez la boucle FOR explicite,
avec juste une ligne de code ici avec ce v comme vecteur d’entrée, u comme un vecteur de sortie,
vous vous êtes débarrassés de la
boucle FOR explicite et
la mise en œuvre de droite sera beaucoup plus rapide que
celle ayant besoin de la boucle FOR. En fait, la bibliothèque NumPy contient
beaucoup d'autres fonctions vectorielles. Donc [Link](v) calculera le log
élément par élément [Link] calcule la valeur absolue [Link] calcule les maxima
élément par élément vous pouvez prendre le max de tous
les éléments de v par rapport à zéro. v**2 prend le carré, élément par élément de v 1/v prend
l'inverse élément par
élément et ainsi de suite Ainsi, à chaque fois que vous êtes
tenté d’écrire une boucle FOR, Regardez et vérifiez si il y a
une manière d'appeler une fonction intégrée de NumPy
pour le faire sans cette boucle FOR. Donc tirons les leçons de tout ceci
et appliquons-les à l'implémentation de la descente de gradient
de notre régression logistique et voyons si nous pouvons au moins
nous débarrasser de l’une des deux
boucles FOR que nous avions. Voici donc notre code pour calculer
les dérivées pour la régression logistique. Nous avions deux boucles FOR. Une était celle ci en haut, et
la seconde était celle là. Donc, dans notre exemple, Nous avions n ou nx égal à deux, mais si vous
aviez plus de
caractéristiques que juste deux alors vous auriez
besoin d'une boucle FOR sur dw1 dw2, dw3 et ainsi de suite. Donc c’est comme si il y a
effectivement un FOR j=1 à nx. dwj, vous le savez, est mis à jour, non ? Nous voudrions donc éliminer
cette deuxième boucle FOR C’est ce que nous allons faire
sur cette diapo. Donc, la façon dont nous allons
le faire est qu’au lieu
d’initialiser explicitement dw1, dw2 et ainsi de suite, à zéros, nous allons nous en débarrasser et
plutôt déclarer dw comme un vecteur. Ainsi nous allons définir dw=np.zéros
et définissons, disons, (nx,1) comme dimension du vecteur. Alors ici au lieu de cette boucle FOR sur
les composants individuels Nous utilisons simplement
cette opération vectorielle dw += ... dw += x(i).dz(i) et finalement
au lieu de cela nous avons simplement dw/=m. Donc maintenant nous sommes
passés de deux boucles FOR à une. Nous avons encore cette boucle FOR qui
fait une boucle sur
les exemples d'apprentissage. Donc j’espère que cette vidéo
vous a donné une idée de la vectorisation et en retirant
une boucle FOR votre code s'exécute déjà plus vite. Mais il s’avère que nous
pouvons faire encore mieux. Donc dans la prochaine vidéo, nous verrons comment vectoriser
encore plus la régression logistique et vous verrez le résultat plutôt surprenant
que sans utiliser aucune boucle FOR, sans avoir besoin de boucle FOR
sur les exemples d'apprentissage vous pouvez écrire du code pour traiter
la totalité de l’échantillon d'apprentissage, donc à peu près tout en même temps. Voyons donc cela
dans la prochaine vidéo.
VECTORIZING LOGISTIC REGRESSION
Nous avons vu comment la vectorisation
vous permet d’accélérer votre code
de manière significative. Dans cette vidéo, nous allons parler de
comment vous pouvez vectoriser l'implémentation de la régression logistique, pour pouvoir traiter
un ensemble d'apprentissage complet, c'est à dire implémenter une unique
itération de descente de gradient pour un ensemble d'apprentissage entier
sans utiliser une seule boucle FOR explicite. Je suis très enthousiasmé
par cette technique, et lorsque nous parlerons de
réseaux de neurones plus tard nous n'utiliserons aucune boucle FOR explicite. Allons-y. Examinons
d’abord l'étape de
propagation directe de la régression logistique. Donc, si vous avez m exemples d'apprentissage, pour
faire une prédiction
sur le premier exemple, vous devez calculer ceci, calculer z,
en utilisant cette formule familière, puis calculer les activations, vous calculez ŷ pour le premier
exemple. Puis pour faire une prédiction sur
le deuxième exemple d'apprentissage, vous devez calculer ceci. Puis, pour faire une prédiction
sur le troisième exemple, vous devez calculer ça et ainsi de suite. Et vous devez faire ça m fois, si vous
avez m exemples d'apprentissage. Donc, il s’avère que pour réaliser
l'étape de la propagation directe, c’est-à-dire pour calculer ces prédictions
sur nos m exemples d'apprentissage, il existe un moyen de le faire sans avoir besoin d’une boucle
FOR explicite. Nous allons voir comment
vous pouvez faire ça. Tout d’abord, rappelez vous que nous
avons défini une matrice grand X
constituant vos entrées d'apprentissage rangées en colonnes comme ceci. C’est donc une matrice,
c’est une matrice nx par m. Alors, j’ai écrit ceci comme
une "shape" en Python numpy, Cela signifie simplement que X est
une matrice de dimensions nx par m Je veux premièrement vous montrer
comment vous pouvez calculer z1, z2, z3 et ainsi de suite, en une seule étape, en fait, avec une seule
ligne de code. Donc, je vais construire une matrice 1 par m, c’est-à-dire un vecteur
simple, dans laquelle je vais calculer z1, z2 et ainsi de suite, jusqu'à zm, tous en même temps. Il
s’avère que ceci peut s'écrire Transposée de w fois la matrice grand X
plus ce vecteur [b, b, ..., b] [b, b, ..., b] et ainsi de suite... b b où ceci, ce vecteur [b, b, ..., b] est un
vecteur 1 par m, ou une matrice 1 par m, ou
un vecteur ligne de dimension m. Donc si vous êtes à l'aise avec
la multiplication de matrices, vous pouvez voir que W transpose x1, x2 et ainsi de suite jusqu'à xm,
que la transposée de W peut
être un vecteur ligne. Donc la transposée de W sera
un vecteur ligne comme ça. Et donc ce premier terme sera égal
à W transpose fois x1, W transpose fois x2, et ainsi de suite,
trois petits points, W transpose fois xm,
puis lorsque vous ajoutez ce second terme b, b, b et ainsi de suite vous vous retrouvez à
ajouter b à chaque élément. Si vous vous retrouvez avec
un autre vecteur 1 par m, avec ceci comme premier élément, ceci comme deuxième élément,
et ainsi de suite et ceci est le m-ième élément. Et si vous vous référez
aux définitions ci-dessus, ce premier élément est exactement
la définition de z1, le deuxième élément est exactement
la définition de z2 et ainsi de suite. De la même façon que X était
ce que vous obteniez lorsque vous avez pris
vos exemples d'apprentissage et et les avez empilés l'un près de l'autre,
empilés horizontalement, Je vais définir grand Z égal à ceci, où vous prenez tous les z minuscules
et les empilez horizontalement. Donc, quand vous juxtaposez les x correspondant
aux différents exemples d'apprentissage, vous obtenez cette variable grand X et de la même manière,
lorsque vous prenez
ces variables z minuscule, et que vous les empilez horizontalement, vous obtenez cette variable
grand Z. Et il s’avère que pour implémenter ça, la commande numpy est
grand Z égal à [Link](w.T,X) c'est la transposée w de X, puis + b Maintenant, il y a une subtilité en
Python, qui est que ici, b est un nombre réel ou,
si vous voulez, une matrice 1 x 1, c'est juste un nombre réel normal. Mais, lorsque vous ajoutez
ce vecteur à ce nombre réel, Python prend automatiquement ce nombre réel b
et l'étend pour en faire ce vecteur de 1 par m. Si cette opération vous semble
un peu mystérieuse, cela s'appelle le "broadcasting" en Python, et il ne faut pas
vous en inquiéter pour l’instant, nous allons en parler un peu plus
dans la prochaine vidéo. Mais ce qu'il faut retenir est qu’avec une seule
ligne de code, avec cette ligne de code, vous pouvez calculer grand Z et grand Z sera une matrice 1
par m qui contiendra
tous les z minuscule. De petit z1 jusqu'à petit zm. Donc voilà pour z,
qu'en est il de ces valeurs a ? Ce que nous allons faire ensuite, est de trouver un moyen de calculer
a1, a2 et ainsi de suite jusqu'à am, tous en même temps, et, de même qu'en juxtaposant
les x minuscules, on a obtenu grand X et
grand Z en empilant horizontalement les petits z, l'empilement des a minuscules, va nous donner une
nouvelle variable, que nous allons définir comme grand A. Dans l'exercice de programmation, vous
voyez comment implémenter une
fonction sigmoïde à partir d'un vecteur, pour que la fonction sigmoïde prenne comme variable
d'entrée ce grand Z et
calcule très efficacement la sortie grand A. Donc, vous verrez les détails de cela
dans l’exercice de programmation. Donc juste pour résumer, ce que nous avons vu sur cette
diapositive
est qu’au lieu de devoir boucler sur m exemples d'apprentissage pour
calculer z minuscule et a minuscule, un par un, vous pouvez implémenter
cette seule ligne de code, pour calculer tous les z en même temps. Et puis, cette ligne de code, avec
l’implémentation appropriée de sigma minuscule pour calculer tous
les a minuscules en même temps. Donc, voilà comment implémenter une implémentation vectorisée
de la propagation directe pour tous les m exemples
d'apprentissage en même temps. Donc pour résumer, vous venez de voir
comment vous pouvez utiliser la vectorisation pour calculer très
efficacement toutes les activations, tous les a minuscules en même temps. Ensuite, il s’avère, vous
pouvez également
utiliser la vectorisation pour calculer efficacement la propagation inverse, pour calculer les gradients.
Nous allons voir comment vous pouvez
faire ça dans la prochaine vidéo.
Broadcasting in python
Dans la vidéo précédente,
j’ai mentionné que le broadcasting est une autre technique que vous pouvez
utiliser pour faire tourner
votre code Python plus vite. Dans cette vidéo, nous allons voir
en profondeur comment le broadcasting
en Python fonctionne réellement. Voyons cela avec un exemple. Dans cette matrice, j’ai montré
le nombre de calories de glucides, de protéines et de lipides pour
100 grammes de quatre différents aliments. Ainsi, par exemple,
100 grammes de pommes contiennent 56 calories de glucides et beaucoup moins
de protéines et de lipides. En revanche, 100 grammes de bœuf
contiennent 104 calories provenant
des protéines et 135 calories provenant des lipides. Maintenant, supposons que votre but est
de calculer le pourcentage de calories de glucides, de protéines et de lipides
pour chacun des quatre aliments. Ainsi, par exemple, si vous regardez
cette colonne et additionnez les chiffres de cette colonne,
vous obtenez que 100 grammes de pomme ont 56 plus 1,2 plus 1,8
c’est-à-dire 59 calories. Et donc en pourcentage la proportion de calories des glucides dans une
pomme sera de 56 sur 59, c’est environ 94,9 %. Donc la majorité des calories dans une pomme
viennent des glucides, alors qu’au contraire, la plupart des calories du bœuf proviennent
des protéines et des lipides et ainsi de suite. Donc le calcul que vous voulez faire est
la somme de chacune des quatre colonnes de cette matrice pour obtenir le nombre total
de calories pour 100 grammes de pommes, de bœuf, d'œufs et de pommes de terre. Et ensuite de
diviser
chaque terme de la matrice, afin d’obtenir le pourcentage
de calories de glucides, protéines et lipides pour chacun des quatre aliments. Donc la question est,
pouvez-vous faire
cela sans une boucle FOR explicite ? Nous allons voir comment vous pouvez le faire. Ce que je vais
faire est vous montrer
comment vous pouvez définir, par exemple, cette matrice A,
une matrice de trois par quatre et puis avec une seule ligne de code Python
nous allons faire la somme des colonnes. Donc nous allons obtenir quatre nombres
correspondant au nombre total de calories dans ces quatre différents
types d’aliments, 100 grammes de ces quatre types d’aliments, et je vais utiliser une deuxième ligne
de code Python pour diviser chacune des quatre colonnes par
leur somme correspondante. Si cette description verbale
n’a pas été très claire, J’espère que ce sera plus clair dans une
seconde quand vous verrez le code Python. Nous voici donc dans Jupyter notebook. J’ai déjà écrit
cette première partie
du code pour préremplir la matrice A avec les nombres que nous
avions tout à l’heure, alors nous allons
faire Maj + Entrée et lancer cela, donc voilà la matrice A. Et maintenant, voici les deux lignes
de code Python. Tout d’abord, nous allons calculer
cal = [Link](axis=0) axis = 0 signifie sommer verticalement. Nous en reparlerons un peu plus tard. Et
puis print cal Donc, nous allons faire la somme
verticalement. 59 est le nombre total de calories
dans la pomme, 239 est le nombre total de calories dans le bœuf
puis les œufs et les pommes de terre
et ainsi de suite. Et puis nous allons calculer le pourcentage pourcentage = A/[Link]( 1,4). En
fait, nous voulons des pourcentages,
donc nous allons multiplier par 100 ici. Et puis nous allons imprimer pourcentage. Exécutons ça. Et
donc avec cette commande
nous avons pris la matrice A et nous l'avons divisée
par cette matrice un par quatre. Et cela nous donne
la matrice des pourcentages. Comme quand nous avons fait les calculs
à la main tout à l’heure, pour la pomme dans la première colonne,
94,9 % des calories proviennent des glucides. Revenons sur les diapositives. Alors juste pour répéter
les deux lignes de code que nous avons, voici ce qu’on a écrit dans Jupyter notebook. Pour ajouter un
peu de détails, ce paramètre, (axis = 0), signifie que vous voulez que
Python calcule la somme verticalement. Donc, si c'est axis = 0 cela signifie
calculer la somme verticalement, alors que l’axe horizontal est l’axe 1. Donc on écrirait axis = 1 pour
faire la somme
horizontalement au lieu de verticalement. Et puis cette commande ici, c'est l'exemple du
broadcasting de Python,
où vous prenez une matrice A, c’est une matrice de trois par quatre et vous
la divisez par une matrice un par quatre. Et techniquement,
après cette première ligne de code, cal, la variable cal
est déjà une matrice un par quatre. Donc, techniquement, il n'y a pas besoin
d'appeler reshape ici encore une fois, donc c’est en fait un peu redondant. Mais quand j’écris du
code Python, si je
ne suis pas entièrement sûr de la matrice, des dimensions d’une matrice j’appelle
souvent une commande reshape juste pour être sûr que c'est bien
un vecteur colonne ou lun vecteur ligne ou ce que vous voulez qu’il soit. La commande reshape est
exécutée en temps constant. C’est une un opération d'ordre 1 qui
ne coute presque rien en temps de calcul. Alors n'hésitez pas à utiliser la commande
reshape pour vous assurer que vos matrices sont de la taille qu'il faut qu’elles soient. Maintenant,
nous allons expliquer plus en
détail comment fonctionne ce type d’opération. Nous avons une matrice 3 x 4 et
nous la divisons par une matrice 1 x 4. Alors, comment peut-on diviser une
matrice 3 x 4 par une matrice 1 x 4, c'est à dire par un vecteur 1 x 4 ? Examinons quelques autres
exemples de broadcasting. Si vous prenez un vecteur 4 x 1 et
que vous lui ajoutez un nombre, ce que Python va faire est de prendre
ce nombre et automatiquement l'étendre pour en faire un vecteur 4 x 1 comme ceci. Et donc le
vecteur [1, 2, 3, 4] plus le nombre 100 donne
ce vecteur sur la droite. Vous ajoutez 100 à chaque élément.
En fait, nous avons utilisé cette forme de broadcasting où cette constante était
le paramètre b dans une vidéo précédente. Et ce type de broadcasting fonctionne avec
des vecteurs colonnes et des vecteurs lignes, et en fait nous avons utilisé plus tôt une
forme similaire de broadcasting en ajoutant à un vecteur une constante qui était
le paramètre b dans la régression logistique. Voici un autre exemple : Imaginons que vous ayez une
matrice 2 x 3 et et que vous l’ajoutez à cette matrice 1 x n. Le cas général serait d'avoir une matrice
(m, n) ici et vous y ajoutez à une matrice (1, n) . Ce que fera Python, c’est copier la matrice m fois
pour la transformer en
une matrice (m, n), au lieu de cette matrice (1, 3), il la va copier une fois
dans cet exemple, pour qu’elle devienne ceci, qui est aussi une matrix (2, 3) et
nous ajouterons ces deux matrices pour obtenir la somme sur la droite, OK ? Donc, vous avez ajouté
100
à la première colonne, 200 à la deuxième colonne et
300 à la troisième colonne. Et c’est essentiellement ce que nous
avons fait sur la diapositive précédente, sauf que nous avons utilisé une opération
de division au lieu d’une opération d’addition. Un dernier exemple,
si vous avez une matrice (m, n) et que vous l'ajoutez à
un vector (m, 1), une matrice (m, 1) alors ça va le copier n fois horizontalement, pour que vous vous
retrouviez
avec une matrice (m, n). Donc, comme vous pouvez imaginer,
on copie horizontalement trois fois. Et vous les ajoutez. Donc lorsque vous les ajoutez
vous vous retrouvez avec ceci. Nous avons ajouté 100 à la première ligne
et ajouté 200 à la deuxième ligne. Voici le principe plus général
du broadcasting en Python. Si vous avez une matrice (m, n)
et que vous y ajoutez ou soustrayez, multipliez ou divisez par une matrice (1, n), alors ceci la copiera
n fois dans une matrice (m, n). Puis l’addition, la soustraction, la multiplication ou la division seront
appliquées
élément par élément. Si à l’inverse, vous aviez une matrice (m, n)
et que vous ajoutez, soustrayez, multipliez, divisez par une matrice (m, 1),
de la même manière, elle serait copiée n fois et transformée en une matrice (m, n) et
l'opération serait ensuite appliquée
élément par élément. Une autre forme de broadcasting est que,
si vous avez une matrice (m,1), donc c’est en fait un vecteur colonne
comme [1,2,3], et que vous ajoutez, soustrayez, multipliez ou divisez
par un nombre réel, peut-être une matrice (1,1), par exemple plus 100, alors le nombre réel est copié
m fois jusqu'à ce que vous ayez
une autre matrice (m,1). Et puis vous effectuez l’opération,
l’addition dans cet exemple,
élément par élément. Et quelque chose de similaire fonctionne
également pour les vecteurs lignes. La version entièrement généralisée
du broadcasting peut faire
même un peu plus que cela. Si vous êtes intéressé,
vous pouvez lire la documentation de NumPy et jeter un œil au broadcasting
dans cette documentation. Cela donne une définition légèrement
plus générale du broadcasting. Mais les cas de la diapositive sont
les principales formes de broadcasting dont vous aurez besoin lorsque
vous implémenterez un réseau de neurones. Avant de conclure,
juste une dernière remarque, qui est pour ceux d'entre vous qui
savent programmer en MATLAB ou en Octave, si vous avez déjà utilisé
la fonction MATLAB ou Octave bsxfun pour programmer un réseau neuronal,
bsxfun fait quelque chose de semblable,
pas tout à fait la même chose. Mais il est souvent utilisé pour le même
résultat que lorsque nous utilisons
le broadcasting en Python. Mais c’est vraiment seulement pour
les utilisateurs avancés en MATLAB et Octave, si vous ne connaissez
pas cela, ne vous inquiétez pas à ce sujet. Vous n’avez pas besoin de le savoir
lorsque vous implémentez
des réseaux neuronaux en Python. Alors, c'était le broadcasting en Python. J’espère que lorsque vous
ferez l'exercice
de programmation, le broadcasting
vous permettra d'avoir un code qui s’exécute plus vite, mais aussi de faire ce que vous voulez
faire avec moins de lignes de code. Avant de vous plonger dans l’exercice de
programmation, je veux partager avec vous quelques idées de plus, quelques conseils et astuces qui
m'ont permis de réduire le nombre
de bogues dans mon code Python et J’espère que cela vous aidera aussi. Donc, nous allons parler de
cela
dans la prochaine vidéo.