Python: Numpy: Broadcasting na przykładach

15-Sty-2020

W uczeniu maszynowym często wykonujemy operacje na macierzach (wektor to też przykład macierzy, tylko że jeden z wymiarów wynosi 1). Cchcemy takie operacje wykonywać, gdzie tylko się da przy pomocy funkcji z modułu numpy, bo tak jest efektywniej!

Matematyka jest bezlitosna. Istnieją pewne określone reguły, określające warunki kiedy na macierzach można wykonywać operacje:

  • aby dodać do siebie macierze/wektory, muszą one mieć takie same wymiary
  • aby pomnożyć przez siebie dwie macierze, pierwsza z nich musi  mieć tyle kolumn, co druga wierszy

Tymczasem u nas te warunki nie zawsze będą spełnione. Można się jednak „umówić”, co do tego jak wykonywać operacje, których, matematycznie rzecz ujmując, nie można wykonywać. Taki mechanizm w numpy nosi nazwę broadcasting, bo określa on, jak należy powiększyć mniejszą macierz do rozmiarów pasujących do większej macierzy, aby w intuicyjny sposób wykonać operację na macierzach.

Żeby uniknąć matematycznego hejtu, na usprawiedliwienie należy dodać, że broadcasting-u można by uniknąć. W takim przypadku programista musiałby po prostu samodzielnie dbać o to, żeby macierze miały właściwe rozmiary. Taka praca, nie dość że nudna, to jeszcze spowoduje znaczne użycie pamięci. Dlatego tak się palimy do zautomatyzowanego i zoptymalizowanego procesu broadcastu.

Zadanie:

Zacznijmy od czegoś prostego. Oto dwa wektory:

Dodaj do siebie te dwa wektory. Nim to zrobisz, zastanów się:

  • czy takie działanie jest poprawne matematycznie?
  • jak najwygodniej zapisać dodawanie takich dwóch wektorów?

Rozwiązanie:

To jest poprawne działanie matematyczne.

Operacja dodawania może wyglądać tak:

Zadanie:

A co wydarzyłoby się, gdyby b był po prostu liczbą? Jak dodać do siebie wektor a i liczbę b?

Zastanów się

  • czy takie działanie jest poprawne matematycznie?
  • jak najwygodniej zapisać dodawanie takich dwóch wektorów?

Rozwiązanie:

To nie jest poprawne matematycznie… do wektora nie można dodawać liczby… ale na intuicję by się dało! Wystarczyło by powtórzyć wartość 100 trzy razy i zrobić z b wektor [100, 100, 100]

Operacja dodawania może wyglądać tak:

Tu właśnie po raz pierwszy skorzystaliśmy z broadcastingu. Jeśli masz do wykonania operację na dwóch tablicach (wektorach) i jeden z nich jest dłuższy od drugiego, to ten drugi „poszerzamy” powtarzając jego wartość.

Zadanie:

A co wydarzyłoby się, gdyby b był po prostu krótszym wektorem, ale nie liczbą?  Jak dodać do siebie dwa wektory o różnej długości?

Zastanów się

  • czy takie działanie jest poprawne matematycznie?
  • jak najwygodniej zapisać dodawanie takich dwóch wektorów?

Rozwiązanie:

To nie jest poprawne matematycznie… aby do wektora dodać wektor, oba wektory musza mieć ten sam wymiar. Chwyt z powieleniem jednej liczby tu się nie uda, bo wektor b składa się z 2 wartości…

Operacja dodawania w poniższej postaci skończy się błędem:

Broadcasting działa tylko w przypadku gdy podczas powiększania mniejszego wektora miał on wymiar 1 – czyli tu musiał być liczbą.

Zadanie:

No to przejdźmy to macierzy 2-wymiarowych. Poniżej definiujemy dwie macierze o takich samych wymiarach. Jak je do siebie dodać?

Zastanów się

  • czy takie działanie jest poprawne matematycznie?
  • jak najwygodniej zapisać dodawanie takich dwóch wektorów?

Rozwiązanie:

Ponieważ wymiary macierzy są zgodne, to takie dodawanie jest poprawne matematycznie i najłatwiej zapisać je w postaci:

c = a + b

Zadanie:

A co wydarzyłoby się, gdyby b był po prostu liczbą? Jak dodać do siebie dwuwymiarową macierz a i liczbę b?

Zastanów się

  • czy takie działanie jest poprawne matematycznie?
  • jak najwygodniej zapisać dodawanie takich dwóch wektorów?

Rozwiązanie:

To nie jest poprawne matematycznie… do macierzy nie można dodawać liczby… ale na intuicję by się dało! Wystarczyło by powtórzyć wartość 100 w pomocniczej macierzy, o takich samych wymiarach jak a

Operacja dodawania może wyglądać tak:

Tu znowu skorzystaliśmy z broadcastingu. Jeśli masz do wykonania operację na macierzy i liczbie to liczba została powielona tyle razy, aby utworzyć macierz pasującą wymiarami do oryginalnej macierzy, a następnie zostało wykonane dodawanie

Zadanie:

A co wydarzyłoby się, gdyby b był wektorem? Jak dodać do siebie dwuwymiarową macierz a i wektor b? Można tu rozważyć, co najmniej dwa wypadki. Raz b będzie „poziomym wektorem” o długości 3, co pasuje do 3 kolumn macierzy a, a raz b będzie „pionowym wektorem” o długości 2, co pasuje do liczby wierszy w macierzy a

Zastanów się

  • czy takie działanie jest poprawne matematycznie?
  • jak najwygodniej zapisać dodawanie takich dwóch wektorów?

Rozwiązanie:

To nie jest poprawne matematycznie… można do siebie dodawać tylko macierze o takich samych wymiarach, … ale na intuicję by się dało! Wystarczyło by powtórzyć

  • w pierwszym przypadku kilka razy wiersz b
  • a w drugim przypadku kilka razy kolumnę b

i wykonać dodawanie takich poszerzonych macierzy!

Operacja dodawania może wyglądać tak:

Tu znowu skorzystaliśmy z broadcastingu. Jeśli masz do wykonania operację na macierzy i wektorze to ten wektor zostanie powielony tyle razy ile trzeba, aby wykonać obliczenia.

Zadanie:

A co wydarzyłoby się, gdyby b był macierzą 2×2? Jak dodać do siebie dwuwymiarową macierz a i wektor b o różnych wymiarach?

Zastanów się

  • czy takie działanie jest poprawne matematycznie?
  • jak najwygodniej zapisać dodawanie takich dwóch wektorów?

Rozwiązanie:

To nie jest poprawne matematycznie… można do siebie dodawać tylko macierze o takich samych wymiarach, … na dodatek, tutaj broadcasting nie zadziała, bo broadcasting może powielać tylko wektory jednowymiarowe

Poniższe polecenie zakończy się błędem

Podsumowanie:

W tym LAB poznaliśmy zasadę broadcastingu. Pozwala ona w wygodny sposób wykonywać obliczenia na macierzach i wektorach.

Więcej o broadcastingu można przeczytać w artykule dokumentacji modułu numpy:

https://docs.scipy.org/doc/numpy/user/basics.broadcasting.html

Komentarze:

  1. Mateusz Hyla napisał,

    Hej Rafał,

    Bardzo fajny artykuł. Teraz uczę się trochę o macierzach z kursów eTrapez.pl i ten artykuł trochę mi pomógł w zrozumieniu zagadnienia.

    Na razie jestem początkujący w programowaniu w Python i materiał tego artykułu wydaje mi się trochę za bardzo zaawansowany dla mnie, jednak i tak warto było przeczytać.

    Dziękuję za dzielenie się swoją wiedzą i pozdrawiam :-).

Dodaj komentarz:

Autor: Rafał Kraik