Bitwa programistów, czyli TDD Randori Session

posted on Czerwiec 29th, 2009 ·

Czy widzieliście walczących programistów? Jeśli nie, to wybierzcie się kiedyś na sesję randori. Na czym to polega? Otóż, dwóch programistów siedzi przed jednym komputerem. Jeden z nich pisze kod, drugi zaś go kontroluje i ewentualnie podpowiada. Zasada jest taka, że jeśli jeden pisze test jednostkowy, to drugi pisze implementację. W myśl TDD (test driven development) test jednostkowy pisany jest jako pierwszy. Potem drugi programista pisze tylko tyle implementacji, by zapalił się zielony kolor - czyli przejść nowy test jednostkowy oraz wszystkie poprzednie. Gdy test zakończy się sukcesem, pierwszy programista refaktoryzuje kod kolegi - obserwator widzi zawsze trochę więcej, niż robotnik. ;-)

W pokoju znajduje się również widownia, która patrzy, czym zajmują się w danym momencie. Nie stoją oczywiście wszyscy za plecami dwóch programistów, ale śledzą wszystko na rzutniku. Dopóki nie pali się zielone światło, widownia nie ma prawa komentować ich działań - może tylko odpowiadać na pytania zadane przez nich. Dopiero, gdy testy jednostkowe zakończą się powodzeniem, widownia może zadawać swoje pytania oraz wyrażać opinie na temat jakości kodu.

Każda para testu i implementacji zostaje zaakceptowana, gdy wszyscy uczestnicy nie będą mieli zastrzeżeń. Wtedy można przejść do pisania kolejnego testu jednostkowego i implementacji. Dodatkowo, co 5-10 minut następuje zmiana par - obecna para udaje się na widownię, a do komputera zasiada inna para.

Po co takie podejście? Po pierwsze, można nauczyć skupiać się na chwilowym celu. Jeśli muszę napisać implementację, która ma przejść test - robię to i tylko to. Nie myślę, czy za chwilę będę musiał rozszerzyć jakąś metodę o nową funkcjonalność. Tym zajmę się, gdy przyjdzie na to czas. Kolejnym plusem jest jakość kodu - zawsze pokryty testami oraz wstępnie refaktoryzowany. Kolega zawsze poprawi jakiś bakcyl albo złą praktykę, bo siedząc obok widzi po prostu więcej.

Poza tym, dobrzy i doświadczeni programiści potwierdzają skuteczność tego podejścia - informacja wyniesiona prosto z COOLuarów. ;-) Ale ostrzegają, że programowanie w parach bardzo szybko obnaża braki w umiejętnościach któregoś z programistów.

P.S. Podziękowania dla Łukasza Lenarta za poprowadzenie sesji TDD randori oraz poprawki merytoryczne.

→ No CommentsTags: Programowanie

COOLuary v.2 i Open Space Technology (Unconference)

posted on Czerwiec 27th, 2009 ·

Dzisiaj uczestniczyłem w pierwszej części konferencji COOLuary v.2. Nim jednak podzielę się wrażeniami, opiszę samą ideę konferencji tego typu.

Najczęściej konferencje są zwykłymi wykładami. Prelegent, nim przejdzie do meritum sprawy, mówi dużo o sobie. Potem zaczyna mówić o swojej firmie. Dopiero po wielu pustych słowach zaczyna się coś rzeczowego. Niewielu też się odważy zadać jakieś pytanie w trakcie trwania wykładu. Nie mówiąc już o wyrażeniu swojej przeciwnej opinii w stosunku do tego, o czym mówi prelegent. W efekcie, wykład jest najmniej interesującym punktem programu. Najważniejsze okazują się przerwy między wykładami - tylko rozmowami prowadzonymi w kuluarach face to face można dowiedzieć się czegoś ciekawego, poznać ciekawych ludzi, czy wymienić poglądy.

Cel, jaki przyświeca „antykonferencjom”, nazywanymi przez Bruce’a Eckela jako Open Space, to prowadzenie rozmów znanych z kuluarów zwykłych konferencji. Uczestnicy sami decydują, na jaki temat chcieliby porozmawiać. Na dzisiejszych COOLuarach były cztery sale i pięć sesji. Na samym początku spotkania proponowane były tematy rozmów, spisywane na żółte karteczki post-it i przyczepiane do którejś sali i sesji. Po ustaleniu agendy rozpoczęła się pierwsza konferencja.

Na konferencji każdy jest równy - nie ma podziału na prelegenta i słuchaczy. Każdy może zadać pytanie, czy też wyrazić swoją opinię. Mówi każdy, kto ma coś do powiedzenia. Nie ma miejsca na opowiadanie o sobie więcej niż potrzeba, jak to w zwykłej rozmowie. Jeśli temat Cię nie interesuje, możesz (a nawet musisz) w każdej chwili opuścić salę i przyłączyć się do innej rozmowy.

Idea jest świetna, a co z wykonaniem? Otóż, również było świetne. ;-) Naprawdę nie żałuję wydanych pieniędzy. Dowiedziałem się naprawdę ciekawych rzeczy, których nie znalazłbym w żadnej książce i na żadnym blogu. Poznałem też ludzi, którzy bardzo chętnie dzielili się ze mną swoją wiedzą.

W sumie była to moja pierwsza konferencja dla programistów Javy. Większość osób uczestniczących w spotkaniu to fachowcy z branży. Część problemów, o jakich rozmawiali nigdy nie dotknąłem. Pomimo, że dzieliła nas ogromna przepaść w posiadanej wiedzy, czułem się swobodnie za sprawą miłej atmosfery i bycia ze wszystkimi na równi. A w temacie analizy potrzeb klienta powiedziałem nawet trochę od siebie.

Na zakończenie dziesiejszej części COOLuarów odbyło się losowanie. Pierwszy raz w życiu coś wygrałem - wejściówkę na tegoroczny Java Developers’ Day. Dobrze, że nie było tam Zala, bo wtedy nie miałbym szans na wygraną ;-) Pięć osób wyszło z książkami Helionu, m.in. kolega z mojej przyszłej pracy Wojtek Seliga. Otrzymaliśmy też kupony rabatowe 20% na książki Helionu oraz koszulki. Jutro kolejna część COOLuarów, tym razem warsztatowa.

P.S. Pozdrowienia dla wszystkich uczestników.

→ No CommentsTags: Programowanie

Sztuczne sieci neuronowe w Matlabie - zrozum net.IW, LW i b

posted on Maj 26th, 2009 ·

W ramach projektu ze Sztucznej Inteligencji mieliśmy stworzyć sieć neuronową, która będzie odpowiadała, czy punkt S = [x, y] należy do kwadratu spełniającego układ nierówności:

  • x > 2
  • x < 6
  • y > 3
  • y < 7

Sieć neuronowa powinna być utworzona na dwa sposoby.

  1. Poprzez nauczenie sieci neuronowej przykładowymi danymi.
  2. Poprzez ręczne ustawienie wag oraz współczynników poszczególnym neuronom.

Wykonanie punktu pierwszego nie jest zbyt trudne, ponieważ w sieci dostępnych jest bardzo dużo przykładów. Kłopoty rozpoczynają się przy drugim zadaniu. Dokumentacja Neural Toolbox w Matlabie co prawda jest bardzo dobra, ale akurat kwestię ręcznego przypisywania wag opisuje słabo. Stąd też tylko metodą prób i błędów można próbować zrozumieć sposób tworzenia sztucznych sieci neuronowych w Matlabie. Dwa dni prób mam za sobą i teraz mogę się podzielić swoją wiedzą.

Najpierw należy rozpocząć od analizy problemu. Mamy zwrócić wartość 1 dla punktów, które spełniają pewien układ nierówności. Każdy jeden neuron w sieci neuronowej potrafi zrealizować jedną prostą oddzielającą klasy. W związku z tym w warstwie ukrytej sieci neuronowej potrzebujemy czterech neuronów. Wejścia są dwa - x oraz y, a wyjście jest jedno i zwraca wartość 0 lub 1. Szkic pożądanej sieci neuronowej przedstawia się następująco:

Sztuczna sieć neuronowa - klasyfikacja

Sztuczna sieć neuronowa - klasyfikacja

net = newff([-10 10; -10 10], [4 1], {'hardlim', 'hardlim'});
% pierwszy parametr - zakresy kolejnych wejść
% drugi parametr - ilość neuronów w każdej kolejnej warstwie
% trzeci parametr - funkcje przynależności, np. hardlim, tansig, logsig, purelin, satlin

% Obejrzyj na wykresie, jak się zachowują poszczególne funkcje przynależności:
% plot(-10: 0.1 : 10, tansig(-10: 0.1 : 10))

Jak widać, każdy neuron realizuje pewną funkcję. Żeby jednak pierwsze dwa neurony działały poprawnie, należy na ich wejście doprowadzić tylko wartość x. W tym celu ustawiamy wagę wejścia y na 0 dla tych neuronów. Analogicznie czynimy dla neuronów trzeciego i czwartego, ustawiając wagi dla wejść x na 0. Takim zabiegiem sieć neuronowa działa, jak gdyby nie było połączeń pomiędzy wejściem x i dolnymi neuronami oraz wejściem y i górnymi neuronami.

% Tak mniej więcej powinny wyglądać wagi.
% Jedynki mogą się zmienić później, jednak zera zostaną.

% Waga X dla kolejnych neuronów
net.IW{1}(:,1) = [1; 1; 0; 0];
% Waga Y dla kolejnych neuronów
net.IW{2}(:,2) = [0; 0; 1; 1];

Teraz przyjrzymy się pierwszemu neuronowi, mającemu realizować zadanie x > 2. Każdy neuron realizuje pewną matematyczną funkcję. W tym przykładzie funkcję hardlim. Wartość na wyjściu neurona liczona jest wg wzoru: a = hardlim(w * x + b). Zatem, aby funkcja zwracała wartość 1 dla x > 2, współczynnik wagowy w powinien wynosić 1, zaś b -2.

net.IW{1}(1,1) = 1;
net.b{1}(1) = -2;

% Skorzystaj z polecenia nnd2n1, aby wspomóc sobie dobieranie wag graficznie.

Prostą x < 6 zrealizujemy w podobny sposób. Trzeba tylko zmienić stronę - funkcja hardlim ma zwracać wartość 1 nie na prawo, lecz na lewo od szóstki. W tym celu wagę ustawimy na -1, a współczynnik b na 6. Podobne działania wykonujemy dla neuronów dolnych.

Teraz każdy neuron realizuje swoją pożądaną funkcję. Przejdźmy więc do neurona wyjściowego. Neuron wyjściowy powinien zwracać 1 wtedy i tylko wtedy, gdy każdy z neuronów poprzedzających zwrócił wartość 1. Należy wiedzieć, że jeśli do dowolnego neurona podłączone są dwa wejścia i na jednym wejściu wchodzi wartość 2, a na drugim 3, to neuron otrzymuje sumę tych wartości, czyli 5. Z tego wynika, że neuron końcowy powinien zwracać wartość 1 tylko, jeśli na wejściu otrzymał sumę równą 4. W tym celu wagi wszystkich wejść ustawiamy na 1, a współczynnik b na -4.

% Kompletny kod:

% Utworzenie sieci neuronowej o dwóch wejściach i jednym wyjściu
net = newff([-10 10; -10 10], [4 1], {'hardlim', 'hardlim'});

% Ustalenie współczynników b
net.b{1} = [-2; 6; -3; 7];

% Wejście X - wagi wejściowe dla kolejnych neuronów
net.IW{1}(:,1) = [1; -1; 0; 0];
% Wejście Y - wagi wejściowe dla kolejnych neuronów
net.IW{1}(:,2) = [0; 0; 1; -1];

% Ustawienie wag dla neuronów
net.LW{2,1}(1,:) = [1 1 1 1];
net.b{2} = -4;

Zwracam uwagę na nieszczęsne IW oraz LW. net.IW to wagi wejściowe dla pierwszej warstwy neuronów, zaś net.LW to wagi wyjściowe z pierwszej warstwy neuronów.

Wygenerujmy teraz jakieś losowe punkty i sprawdźmy, czy nasza sieć neuronowa działa.

% Wygenerowanie punktów
x1 = rand(1, 80) * 8;
x2 = rand(1, 80) * 8;
obrazy = [x1; x2];
klasy = (obrazy(1,:) > 2) .* (obrazy(1,:) < 6) .* (obrazy(2,:) > 3) .* (obrazy(2,:) < 7 );
ind1 = find(klasy == 0);
ind2 = find(klasy == 1);

% Utworzenie sieci neuronowej o dwóch wejściach i jednym wyjściu
net = newff([-10 10; -10 10], [4 1], {'hardlim', 'hardlim'});

% Ustalenie współczynników b
net.b{1} = [-2; 6; -3; 7];

% Wejście X - wagi wejściowe dla kolejnych neuronów
net.IW{1}(:,1) = [1; -1; 0; 0];
% Wejście Y - wagi wejściowe dla kolejnych neuronów
net.IW{1}(:,2) = [0; 0; 1; -1];

% Ustawienie wag dla neuronów
net.LW{2,1}(1,:) = [1 1 1 1];
net.b{2} = -4;

% Narysowanie wykresu
[X,Y] = meshgrid(0 : 0.1 : 8);
Z = X;
Z(:) = sim(net, [X(:) Y(:)]');
contour(X,Y,Z,[0.499 0.5 0.501]);
hold on
plot(x1(ind1),x2(ind1),'bo',x1(ind2),x2(ind2),'rs')
hold off

Mam nadzieję, że mój artykuł pomógł zrozumieć, w jaki sposób tworzyć sztuczne sieci neuronowe przy pomocy Matlaba. Kluczowym do zrozumienia zagadnienia jest opanowanie właściwości net.IW, net.LW oraz net.b, które są bardzo nieintuicyjne i słabo udokumentowane.

→ No CommentsTags: Programowanie