lato 2014,, Wydział Elektroniki i Technik Informacyjnych
erówka Projekt Egzamin
OpenMP (czyli Open Multiprocessing) umożliwia tworzenie aplikacji wielowątkowych bez konieczności jawnego tworzenia wątków i przypisywania im zadań. Standard tworzony m.in. Przez: AMD Intel HP NVIDIA HP Fujitsu i inne... Wprowadza szereg komend preprocesora (#pragma) i standardowych funkcji. Wprowadza nowe zmienne środowiskowe.
W miejscu gdzie wpiszemy określoną instrukcję, proces zostaje zrównoleglony na kilka wątków, np.:
omp_set_num_threads określa liczbę uruchomionych wątków #pragma omp parallel umieszczone przed pętlą określa, że właśnie ta pętla powinna zostać zrównoleglona aby umożliwić działanie wszystkich opcji OpenMP musimy dołączyć plik <omp.h> i ustawić opcję kompilacji /openmp (VS Properties- >C/C++->Language->OpenMP support).
W trakcie działania możemy (podobnie jak w programowaniu kart graficznych) pobrać numer wątka który wykonuje daną operację: Proszę zauważyć co wyświetliła konsola, nastąpił wyścig dostępu do konsoli. Należałoby wprowadzić sekcję krytyczną.
Sekcję krytyczną definiujemy poprzez #pragma omp critical Mamy też możliwość wprowadzenia operacji atomowych (#pragma omp atomic) do operacji odczytu/zapisu zmiennych. Operacje atomowe także wykonają się zawsze w całości, są szybsze, ale przewidziane tylko do niektórych typów operacji: (bez #pragma omp atomic cnt wynosił ok. 120000)
Większość poleceń wykonuje się poprzez #pragma omp parallell... Można także w prosty sposób zlecić równoległe wykonanie pętli: Jacek Naruniec
Można także ręcznie określić ile wątków ma być wykorzystanych w pętli poprzez omp_set_num_threads(). Jeśli nie określimy liczby wątków, dobrana zostanie liczba automatycznie. W OpenMP można także definiować rodzaj zmiennej jako: prywatną każdy wątek ma swoją własną kopię zmiennej dzieloną każdy wątek operuje na tej samej kopii zmiennej Dlaczego numer wątka się nie zgadza?
Domyślnie wszystkie zmienne które były zadeklarowane wcześniej w bloku są dzielone (shared) na wszystkie wątki. mienne wewnętrzne wątku są prywatne. Indeksy pętli są domyślnie prywatne dla każdego wątka. mienne, które chcemy jawnie zadeklarować jako prywatne (każdy wątek ma swoją kopię) definiujemy poprzez słowo kluczowe private: Jacek Naruniec
Należy pamiętać, że wartość zmiennych prywatnych nie jest kopiowana do zmiennych poszczególnych wątków. Prywatność oznacza jedynie, że w wątku tworzona jest zmienna o tej samej nazwie i tym samym typie, ale niezainicjalizowanej zawartości. Aby wartość zmiennej została skopiowana do zmiennej wątka należy wykorzystać klauzulę firstprivate. Jacek Naruniec
miany zmiennej prywatnej wewnątrz wątków nie powodują zmiany oryginalnej zmiennej. achowanie to zmienić poprzez klauzulę lastprivate która sprawia, że wartość zmiennej oryginalnej ustawia się na wartość wpisaną w ostatnim wątku pętli. Jacek Naruniec
Możemy także określić barierę, na której wszystkie wątki będą oczekiwały na zakończenie pracy przez pozostałe wątki. Działanie jest analogiczne do funkcji syncthreads z CUDA.
Blok for może być także oddzielony od bloku parallel. Każdy blok for wewnątrz bloku parallel będzie wykonywany sekwencyjnie tak jakby pomiędzy nimi była bariera: Jacek Naruniec
OpenMP umożliwia bardzo łatwe zrównoleglenie programu w ramach wielu wątków. Visual Studio obługuje OpenMP w wersji specyfikacji 2.0 (większość użytecznych opcji) Nowsze kompilatory GCC i LLVM obsługują OpenMP 3.1 Najnowsza wersja OpenMP to 4.0 (z 2013 roku). Więcej informacji, także na temat różnic pomiędzy specyfikacjami openmp.org Jacek Naruniec
Istnieje kilka klasycznych metod dekompozycji algorytmów tak, aby można było je efektywniej zrealizować. dekompozycja rekursywna dekompozycje danych dekompozycja eksploracyjna dekompozycja spekulatywna dekompozycja hybrydowa (łącząca cechy powyższych).
Rekursywna (recursive) metody typu dziel i zwyciężaj rozdzielamy dany problem na pewne podproblemy proces ten powtarzamy aż uzyskamy żądaną ziarnistość zadań Klasyczny przykład dekompozycji rekursywnej (quicksort):
Inny przykład dekompozycji rekursywnej znajdywanie minimum/maksimum danego zbioru: Min(1, 1) Min(3, 1) Min(1, 9) Min(4, 3) Min(1, 3) Min(8, 1) Min(9, 10)
Dekompozycja danych wyjściowych. Jako przykład mnożenie dwóch macierzy prostokątnych: C AB C C 1,1 2,1 C C 1,2 2,2 A A 1,1 2,1 A A 1,2 2,2 B B 1,1 2,1 B B 1,2 2,2 Co znowu może być zdekomponowane na: C C C C 1,1 1,2 2,1 2,2 A A A 1,1 A 1,1 2,1 2,1 B B B 1,1 B 1,2 1,1 1,2 A 1,2 A A 1,2 A 2,2 B 2,2 B 2,1 B 2,2 B 2,1 2,2
Dalsza dekompozycja mogłaby przebiegać np. tak: C C C C C C C C 1,1 1,1 1,2 1,2 2,1 2,1 2,2 2,2 C C C apewnia nam to podział algorytmu na 8 osobnych zadań z pewnymi zależnościami. A A A 1,1 A C 1,1 1,1 1,2 2,1 2,1 2,1 B 2,2 B B 1,1 B 1,2 A 1,1 1,2 1,2 A A 1,2 A 2,2 B 2,2 B 2,1 B 2,2 B 2,1 2,2
Inny przykład: ałóżmy że rekonstruujemy twarz z kombinacji liniowej wielu twarzy własnych. Oznacza to dodanie do obrazu średniego szeregu obrazów, każdego pomnożonego przez odpowiedni współczynnik: 0.12 0.08 0.01
Dekompozycja danych wyjściowych mogłaby oznaczać, że obraz wyjściowy podzielimy na kilka fragmentów, z których każdy będzie realizowany jako osobne zadanie: 0.12 adanie 1 adanie 2 0.08 adanie 3 adanie 4 0.01
Jeszcze inny przykład: dekompozycja algorytmu obliczania wystąpień danego ciągu symboli w bazie danych: Baza danych Szukane sekwencje 4434 11 4 1252 43 1 1123 22 1 11242 33 0 1342 1111124 42223 Liczba wystąpień w całej bazie
Dekompozycja na 2 zadania względem danych wyjściowych Baza danych Szukane sekwencje Liczba wystąpień w całej bazie 4434 11 4 1252 43 1 1123 11242 1342 1111124 42223 Baza danych Szukane sekwencje Liczba wystąpień w całej bazie 4434 22 1 1252 33 0 1123 11242 1342 1111124 42223
Dekompozycja danych wejściowych przebiega analogicznie do danych wyjściowych. Dla przykładu z twarzą: adanie 1 0.12 0.08 0.01 adanie n
Dekompozycja według danych wejściowych przykładu z bazą danych: Baza danych Szukane sekwencje 4434 11 1 1252 43 1 1123 22 0 Baza danych 33 0 Szukane sekwencje 11242 11 3 1342 43 0 1111124 22 1 42223 33 0 Liczba wystąpień w całej bazie Liczba wystąpień w całej bazie
Dekompozycja może być także przeprowadzona jednocześnie dla danych wejściowych jak i wyjściowych. 0.12 0.08 0.01
Dekompozycja eksploracyjna Etapy dekompozycji są dostosowywane w trakcie wykonywania się algorytmu. Najłatwiej określić to np. w problemie optymalizacji eksplorujemy rozwiązania w celu znalezienia najlepszego Jako przykład weźmy grę TRON z Google AI Challenge z roku 2010. adanie polegało na stworzeniu najlepszego bota gry. [źródło: https://www.youtube.com/watch?v=jyys22xowdi]
Podstawowym algorytmem prowadzącym do zwycięstwa był algorytm min-maks, czyli algorytm minimalizowania maksymalnych strat. Weźmy pod uwagę następującą sytuację: Mamy do dyspozycji zielonego bota (czerwony to przeciwnik) i musimy podjąć decyzję w którą stronę się poruszyć w górę, w dół czy w lewo aby zminimalizować maksymalne straty. akładamy, że przewidujemy jedynie 3 kroki do przodu. [obrazki z kursu konkursu: http://www.sifflez.org/misc/tronbot/index.html]
Strategia będzie zależała od faktu czy jesteśmy odcięci od przeciwnika czy nie. Jeśli jesteśmy odcięci, to lepszy będzie taki kierunek, który zapewni nam więcej wolnego miejsca. Jeśli nie jesteśmy odcięci to naszym celem jest zbliżenie się do przeciwnika (bo wtedy będzie dobrze działał nasz algorytm min-maks bo mamy ograniczenie na głębokość drzewa). Dodatkowo przyjmujemy (żeby mieć obraz skali ), że np.: zwycięstwo: 100 punktów przegrana: -100 punktów remis: -50 punktów [obrazki z kursu konkursu: http://www.sifflez.org/misc/tronbot/index.html]
W N E S N N S E akładamy, że my zawsze podejmiemy najlepszą dla nas decyzję a przeciwnik podejmie zawsze decyzję najgorszą dla nas. Po prawej mamy wynik w zależności od oceny sytuacji. SEW będzie kiepską decyzją praktycznie na pewno przegramy (-75,2) WNS byłoby znacznie lepsze przeciwnik jest zamknięty w mniejszej przestrzeni (47,0). Każdą decyzję można traktować jako oddzielne zadanie. S N N E W W E Decyzje: E wschód N północ W zachód S - południe [obrazki z kursu konkursu: http://www.sifflez.org/misc/tronbot/index.html]
W N E S N N S Naturalnie algorytm można przyspieszyć poprzez przycinanie niekorzystnych ścieżek. Decyzja o głębokości drzewa może być podejmowana dynamicznie, np. w zależności od czasu wykonania. Algorytm taki jest bardzo podatny na zrównoleglenie. Odnalezienie rozwiązania idealnego powoduje zatrzymanie pozostałych procesów. E S N W N E W E [obrazki z kursu konkursu: http://www.sifflez.org/misc/tronbot/index.html]
Ciekawostka zwycięzca konkursu jako miarę jakości ruchu wybrał miarę opartą na diagramie Voronoi, czyli mapie mówiącej do którego piksela szybciej może dojść który waż. Jako miarę jakości początkowo przyjął różnicę liczby pikseli do której pierwszy może dojść gracz od liczby do której może pierwszy dojść przeciwnik. [obrazki z kursu konkursu: http://www.sifflez.org/misc/tronbot/index.html]
Inny przykład Dynamic Time Warping ( marszczenie czasu ) Jest to metoda pozwalająca porównać dwa wzorce, które mogą być różnej długości. W tym przypadku prosta odległość euklidesowa nie może być zastosowana. Może być wykorzystana np. przy rozpoznawaniu gestów jak porównać gest SSEEWW z SSWSEEEW? Weźmy przykład rozpoznawania słów: zakładamy, że mamy pewien opis (tutaj spektrogram) wypowiedzianego słowa z podziałem na ramki, np. po 15ms (po prawej). [źródło: J. Holmes, Speech Synthesis and Recognition ]
Stwórzmy obraz, którego jeden punkt odpowiada odległości dwóch opisów w danych chwilach czasu (różnych dla pierwszego i drugiego słowa). Większy okrąg oznacza większe podobieństwo opisów (deskryptorów). Jedno słowo wypowiedziane dwukrotnie: [źródło: J. Holmes, Speech Synthesis and Recognition ]
Dwa inne wypowiedziane słowa: [źródło: J. Holmes, Speech Synthesis and Recognition ]
Algorytm DTW polega na znalezieniu takiej ścieżki od dolnego lewego do górnego prawego rogu, która da najmniejszy sumaryczny koszt. m3 m2 m1 4 3 5 3 5 2 1 4 2 4 7 5 v1 v2 v3 v4 [źródło: J. Holmes, Speech Synthesis and Recognition ]
Poszukiwanie najlepszej ścieżki może przebiegać w różny sposób. Można zastosować algorytm zachłanny za każdym razem podejmowana będzie decyzja najlepsza w tym kroku zakładając, że możemy poruszać się w kierunku w górę, w prawo i po skosie. Preferowanym kierunkiem zawsze jest diagonalny. Można wprowadzać dodatkowe wagi dla przejść poziomych/pionowych. Aby uniezależnić wynik od długości słowa, wszystkie sumy można podzielić przez ilość przebytych elementów Generalnie należy sprawdzić wszystkie możliwe drogi i wyszukać tę o najmniejszej wadze łącznej awsze musimy dojść do końcowego elementu modelu części ścieżek można zrezygnować wcześniej jeśli sumaryczna waga jest zbyt duża
Przycinanie gałęzi wyboru (score pruning) - jeśli jej waga znacznie przekracza wagę ścieżki o minimalnej wadze w tej samej kolumnie [źródło: J. Holmes, Speech Synthesis and Recognition ]
Dekompozycja spekulatywna Może np. oznaczać przetestowanie N opcji i usunięcie N-1 opcji w przypadku znalezienia tej najlepszej. Przy braku informacji o przebiegu algorytmu przy złożonym systemie obarczonym zależnościami możemy przyjąć algorytm: konserwatywny tzn. uruchamiamy równolegle tylko te gałęzie, dla których mamy pewność, że nie ma między nimi powiązań. optymistyczny tzn. nie mamy zapewnionego braku zależności między gałęziami. Przy napotkaniu sprzecznych warunkach, niekiedy musimy cofnąć się w analizie drzewa. W pewnych przypadkach bardzo podobna do eksploracyjnej.
Przy dekompozycji algorytmów można brać także pod uwagę możliwość przetwarzania heteregenicznego. Jako przykład weźmy obliczenia zderzenia cząstek. Jacek Naruniec
Kolizje między cząsteczkami są podzielone na trzy rodzaje: SS (Small-Small) czyli małe cząstki z małymi LS (Large-Small) duże cząstki z małymi LL (Large-Large) duże cząstki z dużymi akładamy, że granularność problemu SS jest znana i stała, więc będzie on pasował do GPU. akładamy, że granularność problemów LS i LL jest zmienna, więc będą one pasować do CPU.
Algorytm będzie złożony z trzech kroków: konstrukcji struktur danych wyznaczania kolizji integracji działających sił. adania muszą być odpowiednio zsynchronizowane aby zapewnić poprawne działanie algorytmu.
Jako strukturę, będziemy mieli do dyspozycji siatkę, gdzie do każdej siatki należy odpowiednia liczba cząstek. W przypadku wyznaczania kolizji małych cząstek sprawa jest prosta analizujemy sąsiedztwo 3x3 elementowe (w przypadku 3W 3x3x3) Wyznaczamy działające siły na podstawie prędkości i pozycji cząstek. CPU wykorzystuje siatkę stworzoną dla GPU i rozszerza ją o duże cząstki. Na GPU powodowałoby to przestoje niektórych wątków Jacek Naruniec
Integracja polega na wyznaczeniu aktualnych pozycji i prędkości cząstek. Dla małych cząstek będzie to połączenie siły wyznaczonych dla SS i LS. Jacek Naruniec
Równoważenie obciążenia