Pytanie o warstwy ukryte SSN

0

Witam

To znowu ja, aby zwiększyć efektywność mojej sieci ( mała jednowarstwowa ) chciałbym dla próby dać jedną warstwę ukrytą. Założmy, że zapisuje znak na matrycy 7x7 ( litera pomniejsza do teg rozmiari ), a chcę ich rozpoznać 5 to w 1 warstwie mam 5 neuronów, z czego każdy ma 49 wejść, na wyjściu też mam 5 neuronów ( 5 znaków więć dają odpowiedzi ).

Moje pytanie brzmi do warstwy ukrytej. Wiadomo, że jej neurony też mają jakieś funkcje aktywacji ( właśnie jakie? Bo o ile w pierwszej warstwie można dać ilość "1" dla każdej litery ) o tyle tutaj nie wiem. Druga sprawa to kwestia wag bo z pierwszej warstwy neuron może puścić 1 lub 0 ( czyli, że nie został wzbudzony ).

W necie każdy pięknie pisze sieć 16-4-4, na wykładach w necie też ale każdy kopiuje i nie dodaje nic nowego.

1

Nie ogarniam za bardzo o co pytasz odnośnie efektywności - tzn kodujesz własne neurony w jakimś celu i nie idzie czy pracujesz z jakimś frameworkiem?
Ogólnie zadanie wygląda identycznie jak jedno z pierwszych na przedmiocie "Wstęp do sieci neuronowych" na WMiI UMK, gdzie zazwyczaj prowadzący te zajęcia Piersa odpowiada na podobne pytania od ręki.
Dobra strona ze slajdami od tego przedmiotu: http://www-users.mat.umk.pl/~piersaj/www/teaching.php, gość też odpowiada na maile.

Wagi przed uczeniem nie mają znaczenia - losujesz je sobie dla wejść wszystkich neuronów przed uczeniem, a podczas uczenia modyfikujesz zgodnie z algorytmem uczącym.
Dla pojedynczego neuronu jego wyjście to jest funkcja aktywacji na sumie wejść*wagi, gdzie funkcja aktywacji jest taka jaką sobie zakodowałeś - np sigmoidalna albo progowa. Wejścia sugerowałbym znormalizować aby były w zakresie (-1,1)
Sprecyzuj jakim algorytmem zamierzasz uczyć te neurony.

0

Wejśćia już mam w postaci 1 0, pierwsza warstwa ma 5 neuronów każdy po 100 wejść ( obraz 10x10 ) po prostu nie wiem jaki cel ma jedna ukryta warstwa i połączenia. Nie mogę znaleźć żadnego sensownego przykładu.

0

"Nie mogę znaleźć żadnego sensownego przykładu." - są na slajdach z linku z mojego poprzedniego posta.
Jakie połączenia - między neuronami? Zakładając że tak:
Masz sobie w pierwszej warstwie sieci n neuronów, których wyjścia są n wejściami każdego neuronu 2 warstwy i tak dalej, aż do warstwy ostatniej, zakładając jednokierunkową sieć neuronową. Pytanie po co są Tobie dodatkowe warstwy - bo taki wybrałeś sobie sposób do klasyfikacji, jak to można rozwiązać inaczej - też na slajdach.

Pozwolisz, że powtórzę pytanie: Sprecyzuj jakim algorytmem zamierzasz uczyć te neurony?

0

@Ciekawski z twoich postów wynika jakbyś próbował napisać własną implementację SSN (bo nigdy nie widziałem żeby gdzieś była użyta taka śmieszna funkcja aktywacji na przykład) tylko że totalnie nie rozumiesz jak one działają. Czy faktycznie tak jest?

0

Metoda z Nauczycielem, ale teraz to już mi się totalnie one pomieszały i tu mam pytanie by uściślić.

Mam wektor waga[i], Mam jakiś odpowiedź tego neuronu X i mam jakąś odpowiedź oczekiwaną Y ( błąd Y-X ) i teraz przy współczynniku uczenia N jak modyfikować wagi aby było dobrze. Dotychczas korzystam z pewnego wzoru na anglorytmach org.

Tutaj znalazłęm jakiś kod:

 waga[j][k]+=eta*E_wy[j]*matryca[k]+alfa*(waga[j][k]-waga_pop[j][k]);

Roumiem, że waga_pop to co to jest? poprzednie wartości wag?

0

Shalom wiem jak działa jednowarstwowa sieć neuronowa ( piszę sam ) i rozumiem dychotomizatory punktów. Już Zastosowałem odpowiednią funkcję aktywacji ( bipolarną ), ale jakoś ciężko mi sobie to uświadomić, że dla dowolnego ustalonego progu ( wartości tej funkcji ) sieć będzie modyfikowała wagi. Bo w próg aktywacji mogę ustalić byle co, i tyle byle co mnie gubi trochę.

0

Tak właśnie myślałem że próbujesz to napisac sam, ale z tego co tu piszesz to nie wróżę ci dobrze...
Metod nauki sieci z nauczycielem jest więcej niż jedna. Zapewnie wygooglałeś jakieś backpropagation.
Czego nie rozumiesz w kontekście progu? Przecież nawet jak ustawisz dowolnie duży próg to siec w trakcie nauki po prostu dostanie bardzo wysokie wagi połączeń i tyle.
Skoro ax + by + c*z ma być większe od pewnej wartości (progu) D i x,y,z są stałe (to jest nasze wejscie sieci) to logiczne że możemy sobie tak ustawić a,b,c żeby to działało.
Dla 10 razy większego D możemy ustawić 10 razy większe a,b,c i nadal wszystko będzie działać.

0

Tak rozumiem to co napisałeś. Korzystam z tego wzoru na wyliczenie nowych wag: http://www.algorytm.org/sztuczna-inteligencja/uczenie-pojedynczego-neuronu-z-nauczycielem.html, może być?

Druga sprawa: o BP ( backpropagation ) najczęściej czytam w momencie kiedy mamy do czynienia z sieciami wielowarstowymi, czy ta metoda jest zarezerwowana dla nich?

0

Nie jest dla nich zarezerwowana, ale jak masz jedną warstwę to nie za bardzo jest gdzie wykonać tą "propagację" ;]

0

Dokładnie

Mam jeszcze pytanie odnośnie uczenia. Jak już mam sieć i chcę uczyć sieć rozpoznającą moje wybrane litery to uczę ją dobierając wagi przy każdym wzorcu liczby A? Np. piszę A i wciskam ucz ( sieć się nauczyła rozpoznawać ten charakter ), ale jeszcze inny styl chcę dodać więc piszę A i wciskam Ucz, na tej zasadzie to działa?

0

Ty sobie robisz jaja? Przecież proces nauki sieci trwa często dziesiątki tysięcy kroków! Chodzi o to że puszczasz na wejście sieci zestaw danych uczących i uczysz sieć algorytmem, zwykle aż do czasu kiedy błąd odpowiedzi sieci spadnie odpowiednio nisko. To nie jest tak że pokazujesz sieci jedną literkę a sieć już jest nauczona. Tzn oczywiscie, mógłbyś tak zrobić gdyby ta sieć miała rozpoznawać tylko tą jedną literkę i nie miałaby mieć własnosci generalizacji, ale to wtedy jest g**no a nie SSN. POMYŚL! Przecież wagi w sieci masz jedne i one muszą być tak ustawione żeby wykrywać wszystkie możliwe klasy równoważności danych wejściowych. Logiczne więc że ustalenie tych wag wymaga bardzo dużej ilości prób!

Błagam cię, przeczytaj ze zrozumieniem jakieś "SSN for dummies"...

0

@Ciekawski
Zacznij może od jakiś prostszych modeli matematycznych jak np. modele liniowe (AR). Zasada działania SSN jest identyczna, tylko one są nieco bardziej złożonym wzorem matematycznym. Natomiast metoda BP to zwykły algorytm gradientowy najszybszego spadku.
Ty ewidentnie albo nie wiesz co robisz albo nie wiesz co piszesz (albo co gorsza jedno i drugie), bo te Twoje posty to jakiś bełkot, z którego ciężko cokolwiek wywnioskować.
Pokaż może co już zrobiłeś.

0

To znaczy ja dużo czytam o SSN i nie jest mi to potrzebne na zaliczenia tylko tak dla siebie. Wychodzi to lepiej, gorzej, ale zawsze coś innego człowiek robi przy tym komputerze.

Standardowo stworzyłem sobie klasę "Neuron", która ma funkcje/metody odpowiedzialne za obliczenie błędy, aktualnego wyjścia neuronu, funkcję aktywacji( od jakiegoś argumentu ) i taka co zajmuje się poprawianiem wag.

Mam macierz 1 i 0 ( to się chyba nazywa macierz rzadka, ale to mało istotne tu ) - a bardzij jest to lista 1 i 0 powstała przy obróbce obrazu do rozmiaru 6x6 no i te sygnały są wysyłane na poszczególne wejścia neuronu obliczany jest potencjał membranowy (w1s1+w2s2....=Y') gdzie Y' to obecne wyjście neuronu. On je porównuje z oczekiwanym wyjściem ( np. funkcja_aktywacji(8) ), jeżeli lipton to koryguje wagi do momentu kiedy będą one odpowiednie dla tego wzorca i kolejny wzorzec i kolejna koretka wag. I tak można trenować kolejne neuronu dla innych klas równoważności.

Tak to widzę i tak to u mnie działa na razie.

0

Dam ci moja siec wielowarstwową zaimplementowana w C++, jest opartą o algorytm wstecznej propagacji, możesz w niej ustawić tyle wejść i wyjść ile ci się podoba. Mam nadzieje ze dzięki niej coś ci się wyjaśni, bo ciężko wywnioskować z czym konkretnie masz problem.

Napisane na podstawie - http://kik.pcz.pl/~mg/pcz/si/Lab_3.pdf
x0 - to jest bias.

main.cpp

 
#include <iostream>
#include <vector>
#include <cmath>
#include <ctime>
#include <fstream>
using namespace std;

void WczytajZPlikuUstawieniaIZestawTestowy();
void WczytajUstawienia(ifstream &ustawienia);
void WczytajDane(ifstream &dane, vector< vector<double> > &kontener);
void UtworzUniwersalnaSiec();
void UtworzDodatkoweTablice();
void WypelnijWagiPoczatkowe();
double Losuj();
void NauczSiec();
void Nauczaj(const vector<double> &probka);
void LiczY(const vector<double> &probka);
double Aktywacja(double s);
void LiczE(const vector<double> &probka);
double PochodnaAktywacji(double y);
double ObliczBladSredniokwadratowy();
void PrzeprowadzSprawdzenieSieci();
vector<double> Oblicz(const vector<double> &wejsciaX);
void PobierzIOblicz();
double Round(double fValue);
void WyswietlOstatnieWyjsciaY();
void WyswietlWynikiOstatnichAktywacji();
void WyswietlWagi();
void WyswietlBledy();

vector< vector< vector<double> > > siecNeuronowa;
vector<int> szkieletSieci;
vector< vector<double> > bledy;
vector< vector<double> > bledyPrzedPochodna;
vector< vector<double> > wynikiOstatnichAktywacji;
vector< vector<double> > zestawUczacy;
vector< vector<double> > zestawTestujacy;
double wspolczynikUczenia;
double x0;
double bladKonczacyNauczanie;
unsigned int indeksOstatniejWarstwy;
unsigned int iloscWejscX;
unsigned int iloscWyjscY;
unsigned int liczbaEpok = 0;

int main()
{
    srand(static_cast<unsigned int>(time(NULL)));
   
    WczytajZPlikuUstawieniaIZestawTestowy();
    WypelnijWagiPoczatkowe();
    NauczSiec();

    cout << "Blad Sredniokwadratowy: " << ObliczBladSredniokwadratowy() << endl;
    cout << "Liczba Epok: " << liczbaEpok << endl;
    PrzeprowadzSprawdzenieSieci();
    cout << "\n----------\n\n";

    PobierzIOblicz();

    system("Pause");
}

void WczytajZPlikuUstawieniaIZestawTestowy()
{
    ifstream ustawienia("ustawienia.set");
    ifstream daneUczace("daneUczace.lrn");
    ifstream daneTestujace("daneTestujace.tst");


    if(ustawienia.good() && daneUczace.good() && daneTestujace.good())
    {
       
        WczytajUstawienia(ustawienia);
        WczytajDane(daneUczace, zestawUczacy);
        WczytajDane(daneTestujace, zestawTestujacy);   
    }
    UtworzUniwersalnaSiec();
}

void WczytajUstawienia(ifstream &ustawienia)
{
    unsigned int iloscWarstw, iloscNeuronow;
    ustawienia >> wspolczynikUczenia >> x0 >> bladKonczacyNauczanie >> iloscWejscX >> iloscWarstw;
    for(unsigned int i = 0; i < iloscWarstw; i++)
    {
        ustawienia >> iloscNeuronow;
        szkieletSieci.push_back(iloscNeuronow);
    }
}

void WczytajDane(ifstream &dane, vector< vector<double> > &kontener)
{
    unsigned int iloscProbek, iloscElementowProbki;
    double elementProbki;
    dane >> iloscProbek >> iloscElementowProbki;
    for(unsigned int i = 0; i < iloscProbek; i++)
    {
        vector<double> probka(1, x0);
        for(unsigned int j = 0; j < iloscElementowProbki; j++)
        {
            dane >> elementProbki;
            probka.push_back(elementProbki);
        }
        kontener.push_back(probka);
    }
}

void UtworzUniwersalnaSiec()
{
    siecNeuronowa.resize(szkieletSieci.size());
    for(unsigned int k = 0; k < siecNeuronowa.size(); k++)
    {
        siecNeuronowa[k].resize(szkieletSieci[k]);
    }
    
    for(unsigned int k = 0; k < siecNeuronowa.size(); k++)
    {
        for(unsigned int i = 0; i < siecNeuronowa[k].size(); i++)
        {
            if(k == 0)
            {
                siecNeuronowa[k][i].resize(iloscWejscX + 1); //tyle wag ile wejsc (x1, x2, ..., xn)
            }
            else
            {
                siecNeuronowa[k][i].resize(siecNeuronowa[k-1].size() + 1); //tyle wag ile neuronow w poprzedniej warstwie
            }
        }
    }
    UtworzDodatkoweTablice();
    indeksOstatniejWarstwy = siecNeuronowa.size() - 1;
    iloscWyjscY = siecNeuronowa[indeksOstatniejWarstwy].size();
}

void UtworzDodatkoweTablice()
{
    bledy.resize(siecNeuronowa.size());
    bledyPrzedPochodna.resize(siecNeuronowa.size());
    wynikiOstatnichAktywacji.resize(siecNeuronowa.size());
    for(unsigned int k = 0; k < siecNeuronowa.size(); k++)
    {
        bledy[k].resize(siecNeuronowa[k].size());
        bledyPrzedPochodna[k].resize(siecNeuronowa[k].size());
        wynikiOstatnichAktywacji[k].resize(siecNeuronowa[k].size());
    }
}

void WypelnijWagiPoczatkowe()
{
    for(unsigned int k = 0; k < siecNeuronowa.size(); k++)
    {
        for(unsigned int i = 0; i < siecNeuronowa[k].size(); i++)
        {
            for(unsigned int j = 0; j < siecNeuronowa[k][i].size(); j++)
            {
                siecNeuronowa[k][i][j] = Losuj();
            }
        }
    }
}

double Losuj()
{
    double fMin = 0,
           fMax = 1,
           f = (double)rand() / RAND_MAX;
    return (fMin + f * (fMax - fMin));
}

void NauczSiec()
{
    do
    {
        for(unsigned int i = 0; i < zestawUczacy.size(); i++)
        {
            Nauczaj(zestawUczacy[i]);
        }
        liczbaEpok++;
    }while(ObliczBladSredniokwadratowy() > bladKonczacyNauczanie);
}

void Nauczaj(const vector<double> &probka)
{
    LiczY(probka);
    LiczE(probka);

    for(unsigned int k = 0; k < siecNeuronowa.size(); k++)
    {
        for(unsigned int i = 0; i < siecNeuronowa[k].size(); i++)
        {
            for(unsigned int j = 0; j < siecNeuronowa[k][i].size(); j++)
            {
                if(k == 0)
                {
                    siecNeuronowa[k][i][j] += 2 * wspolczynikUczenia * bledy[k][i] * probka[j];
                }
                else
                {
                    if(j == 0)
                    {
                        siecNeuronowa[k][i][j] += 2 * wspolczynikUczenia * bledy[k][i] * x0;
                    }
                    else
                    {
                        siecNeuronowa[k][i][j] += 2 * wspolczynikUczenia * bledy[k][i] * 
                                                  wynikiOstatnichAktywacji[k-1][j-1];
                    }
                }
            }
        }
    }
}

void LiczY(const vector<double> &probka)
{
    for(unsigned int k = 0; k < siecNeuronowa.size(); k++)
    {
        for(unsigned int i = 0; i < siecNeuronowa[k].size(); i++)
        {
            wynikiOstatnichAktywacji[k][i] = 0;
            for(unsigned int j = 0; j < siecNeuronowa[k][i].size(); j++)
            {   
                if(k == 0)
                {
                    wynikiOstatnichAktywacji[k][i] += siecNeuronowa[k][i][j] * probka[j];
                }
                else
                {
                    if(j == 0)
                    {
                        wynikiOstatnichAktywacji[k][i] += siecNeuronowa[k][i][j] * x0;
                    }
                    else
                    {
                        wynikiOstatnichAktywacji[k][i] += siecNeuronowa[k][i][j] * wynikiOstatnichAktywacji[k-1][j-1];
                    }
                }
            }
            wynikiOstatnichAktywacji[k][i] = Aktywacja(wynikiOstatnichAktywacji[k][i]);
        }
    }
}

double Aktywacja(double s)
{
    return 1 / (1 + exp(-s));
}

void LiczE(const vector<double> &probka)
{
    int indeksWyniku = iloscWyjscY;
    for(int k = indeksOstatniejWarstwy; k >= 0; k--)
    {
        for(unsigned int i = 0; i < siecNeuronowa[k].size(); i++)
        {
            if(k == indeksOstatniejWarstwy)
            {
                bledy[k][i] = probka[probka.size()-indeksWyniku] - wynikiOstatnichAktywacji[k][i];
                bledyPrzedPochodna[k][i] = bledy[k][i];
                bledy[k][i] = PochodnaAktywacji(wynikiOstatnichAktywacji[k][i]) * bledy[k][i];
                indeksWyniku--;
            }
            else
            {
                bledy[k][i] = 0;
                for(unsigned int j = 0; j < siecNeuronowa[k+1].size(); j++)
                {
                    bledy[k][i] += bledy[k+1][j] * siecNeuronowa[k+1][j][i+1];
                }
                bledyPrzedPochodna[k][i] = bledy[k][i];
                bledy[k][i] = PochodnaAktywacji(wynikiOstatnichAktywacji[k][i]) * bledy[k][i];
            }
        }
    }
}

double PochodnaAktywacji(double y)
{
    return y * (1 - y);
}

double ObliczBladSredniokwadratowy()
{
    double suma = 0;
    for(unsigned int i = 0; i < bledy[indeksOstatniejWarstwy].size(); i++)
    {
        suma += pow(bledyPrzedPochodna[indeksOstatniejWarstwy][i], 2);
    }
    return sqrt(suma);
}

void PrzeprowadzSprawdzenieSieci()
{
    for(unsigned int i = 0; i < zestawTestujacy.size(); i++)
    {
        cout << "\nProbka Testujaca[" << i+1 << "]" << endl;
        Oblicz(zestawTestujacy[i]);
        WyswietlOstatnieWyjsciaY();
    }
}

vector<double> Oblicz(const vector<double> &wejsciaX)
{
    vector<double> wyjsciaY;
    LiczY(wejsciaX);
    for(unsigned int i = 0; i < wynikiOstatnichAktywacji[indeksOstatniejWarstwy].size(); i++)
    {
        wyjsciaY.push_back(wynikiOstatnichAktywacji[indeksOstatniejWarstwy][i]);
    }
    return wyjsciaY;
}

void PobierzIOblicz()
{
    double x;
    while(true)
    {
        vector<double> wejsciaX(1, x0);
        for(unsigned int i = 0; i < iloscWejscX; i++)
        {
            cout << "x" << i+1 << ": ";
            cin >> x;
            wejsciaX.push_back(x);
        }
        Oblicz(wejsciaX);
        WyswietlOstatnieWyjsciaY();
        cout << endl;
    }
}

double Round(double fValue)
{
    return fValue < 0 ? ceil( fValue - 0.5 )
        : floor( fValue + 0.5 );
}

//------------------------------------

void WyswietlOstatnieWyjsciaY()
{
    for(unsigned int i = 0; i < wynikiOstatnichAktywacji[indeksOstatniejWarstwy].size(); i++)
    {
        cout << "y" << i << ": ";
        cout << Round(wynikiOstatnichAktywacji[indeksOstatniejWarstwy][i]) << endl;
    }
}

void WyswietlWynikiOstatnichAktywacji()
{
    for(unsigned int k = 0; k < wynikiOstatnichAktywacji.size(); k++)
    {
        for(unsigned int i = 0; i < wynikiOstatnichAktywacji[k].size(); i++)
        {
            cout << "[" << k << "]" << "[" << i << "]:" << wynikiOstatnichAktywacji[k][i] << " ";
        }
        cout << endl;
    }
}

void WyswietlWagi()
{
    for(unsigned int i = 0; i < siecNeuronowa.size(); i++)
    {
        for(unsigned int j = 0; j < siecNeuronowa[i].size(); j++)
        {
            cout << "W" << i << "N" << j << " ";
            for(unsigned int k = 0; k < siecNeuronowa[i][j].size(); k++)
            {
                cout << "W" << k << ": " << siecNeuronowa[i][j][k] << " ";
            }
            cout << endl;
        }
    }
}

void WyswietlBledy()
{
    for(unsigned int k = 0; k < bledy.size(); k++)
    {
        for(unsigned int i = 0; i < bledy[k].size(); i++)
        {
            cout << "[" << k << "]" << "[" << i << "]:" << bledy[k][i] << " ";
        }
        cout << endl;
    }
}

daneUczace.lrn

6 6
5	3.2	1.2	0.2	0.9 0.1
5.5	3.5	1.3	0.2	0.9 0.1
4.9	3.1	1.5	0.1	0.9 0.1
4.4	3	1.3	0.2	0.9 0.1
5.1	3.4	1.5	0.2	0.9 0.1
5	3.5	1.3	0.3	0.9 0.1
 

daneTestujace.tst

 
7 6
5.1	3.5	1.4	0.2	0.9 0.1
4.9	3	1.4	0.2	0.9 0.1
4.7	3.2	1.3	0.2	0.9 0.1
4.6	3.1	1.5	0.2	0.9 0.1
5	3.6	1.4	0.2	0.9 0.1
5.4	3.9	1.7	0.4	0.9 0.1
4.6	3.4	1.4	0.3	0.9 0.1

ustawienia.set

 
0.1  1   0.01   4


4 8 15 8 2

-------------------------
wU  x0  bKN  lW


lW  lNWW1  lNWW2  lNWW3  lNWW4  ...

-------------------------
wspolczynikUczenia  x0  bladKonczacyNauke  liczbaWejsc


liczbaWarst  liczbaNeuronowWWarstwie1  liczbaNeuronowWWarstwie2  liczbaNeuronowWWarstwie3  liczbaNeuronowWWarstwie4  ...
0

@Ciekawski jeśli to miałoby mieć jakikolwiek sens do Neuron powinien mieć dostarczoną funkcje aktywacji i funkcje potencjału (tak żeby można było łatwo je zmienić) oraz podpięte wejścia (ale weź pod uwagę że wejściem neuronu może być wyjście innego neuronu! i to nie muszą być same 0 i 1 wtedy, tylko to mogą być pewne double).
Co do twojej implementacji to chyba nie rozumiesz po co jest funkcja aktywacji. Otóż mając obliczony potencjał powinieneś policzyć funkcję aktywacji od tego potencjału a następnie sprawdzić czy wynik jest < czy > od progu aktywacji i na tej podstawie zwrócic wynik neuronu.
Twój sposób nauki jest totalnie bez sensu i zajmie ci milion lat zanim czegokolwiek tą sieć nauczysz. Czemu? Bo uczenie sie drugiego wzorca "popsuje" ci pierwszy wzorzec. Musisz się uczyć wszystkich wozrców na raz, tzn wrzucać je na wejscie sieci po kolei!

0

Shalom zgadza się oczywiście. Z tą funkcją aktywacji tak uczyniłem lecz nie ująłem tego w stosowny sposób. Rozumiem, że jeżeli wyślemy jakieś sygnały do neuronów to bierzemy odpowiedź ( nie zawsze zapewne poprawną ) tego neuronu, który został najbardziej pobudzony przez zestaw sygnałów - OK.

Stoję w momencie nauki. Założmy, że neuron ma 4 wejścia ( Tablica 4 elementowa ).

ZESTAW A

  1. [1000]
  2. [1001]
  3. [1010]

Ten mały zestawik ( tylko dla idei ) ma posłużyć wykreowaniu odpowiednich wag ( uczenie ) - to też oczywiście rozumiem.

Jednak napisałeś , że neuronowi trzeba podać WSZYSTKIE klasy równoważności jakie ma rozpoznawać ( oczywiście jest pewne ograniczenie z powodu 1 neuronu - ok ), nie pojmuje jak mam mu podać zestaw uczący ( to znaczy potrafię mu wysłać odpowiednie sygnały ), ale Ty piszesz po kolei więc skoro wyślę mu (1) to musi go przetworzyć i skorygować wagi - ale to mówisz jest marne więc w sumie nie kapuje zdeka. Jak najlepiej mu podać dane uczące.

0

Szkoda słów. Podajesz neuronowi na wejście pierwszą próbkę danych, korygujesz wagi. Podajesz neuronowi drugą próbkę, korygujesz wagi,... Podajesz neuronowi n-tą próbkę danych i korygujesz wagi.
I to jest "jedna epoka uczenia". Takich epok będziesz musiał wykonać tysiące, żeby błąd odpowiedzi neuronu spadł do sensownego poziomu.
Z tym "marnym uczeniem" chodziło mi o to co opisałes wyżej, czyli uczenie neuronu najpierw pierwszej klasy równoważności, potem drugiej, potem trzeciej itd. Takie coś nie zadziała.

0

Skorygujcie mnie jeżeli się mylę:
Powinieneś stworzyć sobie do tego zadania zaliczeniowego zestaw takich śmiesznych macierzy jako zestaw uczący wraz z klasyfikacją każdej:
Jedna macierz - jak rozumiem taki asci art tego co rozpoznajesz:
[0,0,0,1,0]
[0,0,1,1,0]
[0,1,0,1,0] -> klasyfikacja 4
[1,1,1,1,0]
[0,0,0,1,0]

Robisz ich więcej trochę zaciemnionych - czyli z zepsutymi niektórymi wejściami np

[1,0,0,1,0]
[0,0,1,1,0]
[0,1,0,1,0] -> klasyfikacja 4
[1,1,1,1,0]
[0,0,0,1,1]

Dla następnej cyfry/asci artu tego co rozpoznajesz tak samo, aż będziesz miał ich kilka na każdy przypadek który Twoje zadanie zaliczeniowe ma rozpoznawać - np rozpoznawać cyferki: 4 i 3 i literkę A.
Potem uczysz na tym neurony przez wiele iteracji (na macierzach gdzieś zadekowanych w programie/wczytanych z Wielkiej Przedwiecznej Trzymarki Macierzy(TM), a nie na tym co wyklinałeś sobie na interfejsie do Twojego zadania zaliczeniowego)
Iteracja uczenia tak jak Shalom napisał. Iteracji dużo.
Jak neurony skończą się uczyć to klikasz sobie na interfejsie, i sprawdzasz czy wyszkolone neurony klasyfikują jak powinno.

A info o tym co to jest funkcja aktywująca oraz wzory jak powinieneś z niej liczyć wyjście neuronu, oraz jak zmieniać wagi w propagacji wstecznej - na slajdach z pierwszego mojego posta, naprawdę pasują pod to zadanie.

0

@Stygimoloch dodałbym tylko że warto podzielić dane którymi dysponujemy na 2 grupy -> dane którymi uczymy sieć i dane którymi będziemy ją potem na koniec testować. Dzięki temu unikniemy błędów typu "nauczenie sieci na pamięć".

0

Z tym że ja pisząc na matrycy literę A i wciskając UCZ wysyłam do neuronu sygnały.

0

Wszyscy cieszymy się z twojego nowatorskiego podejścia do SSN, ale niestety w ten sposób to ty tej sieci nie nauczysz i już. Albo zrobisz to jak człowiek, ale nie zrobisz w ogóle. Jak chcesz popatrzeć na przykładową implemenatację to np. tu:
https://github.com/Pharisaeus/Neural
ale jeszcze nie jest skończona (i akurat backpropagation pojawi się dopiero w przeciągu najblizszych 2 tygodni)
do działania wymaga pythona 2.7, numpy i pyqt

0
Shalom napisał(a):

@Stygimoloch dodałbym tylko że warto podzielić dane którymi dysponujemy na 2 grupy -> dane którymi uczymy sieć i dane którymi będziemy ją potem na koniec testować. Dzięki temu unikniemy błędów typu "nauczenie sieci na pamięć".

à propos podzielenia na zestaw uczący i testujący, to dobrym pomysłem jest dzielenie randomowe (tzn stała jest proporcja wielkości jednego zestawu do drugiego, ale za każdym razem inne przypadki w obu)

A teraz wybrane fragmęty które mnie zaciekawiły:

Ciekawski napisał(a):

Mam macierz 1 i 0 ( to się chyba nazywa macierz rzadka, ale to mało istotne tu ) - a bardzij jest to lista 1 i 0 powstała przy obróbce obrazu do rozmiaru 6x6 no i te sygnały są wysyłane na poszczególne wejścia neuronu obliczany jest potencjał membranowy (w1s1+w2s2....=Y') gdzie Y' to obecne wyjście neuronu. On je porównuje z oczekiwanym wyjściem ( np. funkcja_aktywacji(8) ), jeżeli lipton to koryguje wagi do momentu kiedy będą one odpowiednie dla tego wzorca i kolejny wzorzec i kolejna koretka wag. I tak można trenować kolejne neuronu dla innych klas równoważności.

Uwagi do podkreśleń:
Co to jest "lipton" - lipny neuron czy co ?
"Potencjał membranowy" - no kurczę modelujesz zachowanie neuronu, czyli robisz model zachowania a nie komórki.
Implementacja nie pójdzie dobrze jeśli zagrzebiesz się publikacjach biologicznych, bo tylko w takich występuje wyżej wymieniony potencjał.
Nie porównujesz wyjścia z fukcją aktywacji, bo funkcji aktywacji używasz do obliczenia wyjścia. Argumentem dla niej jest suma wag*wejścia (z tym się już powtarzam).

Ciekawski napisał(a):

Z tym że ja pisząc na matrycy literę A i wciskając UCZ wysyłam do neuronu sygnały.

No i otrzymasz wynik tego co tam się sieci akurat roi, bo będzie nie wyszkolona. Skąd ma mieć dobre klasyfikacje?

0

No dobra teraz to już chyba rozumiem i moja dedukcja była zdecydowanie błędna.

Skoro mam zestaw uczący:

znak[4][3]={{1,0,0},
{1,1,0},
{1,0,1},
{1,1,1}}

i mając do dyspozycji 3 neurony

To np. progi neuronów mogą być na ten zestaw aby poprawnie rozpoznawać ( daną próbkę z tego zestawu ) w klamrach neurony

1 próbka - {0,0,0}
2 próbka - {0,1,0}
3 próbka - {0,0,1}
4 próbka - {1,1,0}

?? :)

0

Czy ty jesteś nienormalny? Ty chcesz tą sieć uczyć ręcznie czy co? Już ci mówiłem że progi NIE MAJĄ ZNACZENIA, to jest tylko taka kosmetyka i już. Zresztą twój przykład jest idiotyczny bo jak sobie ustawisz wszędzie wagi = 0 to i tak ci wszystkie neurony odpowiedzą 0. I co? Będziesz ustawiał ujemny próg wtedy?
Zrozum że sieć uczy sie poprzez modyfikacje wag a nie ustawianie progu potencjału. I nie robi się tego ręcznie. I nie robi się tego za pomocą jednej próby i jednego przypadku testowego. Jeśli nie stać cię na książkę o SSN to ja ci ją zafunduję bo tracę wiarę w ludzkość jak czytam twoje kolejne wynudzenia. Jesteś pewien że nie jesteś bratem kolegi @maszynaz? Bo jeśli chodzi o kunszt programistczny powoli się do niego zbliższasz. Ten temat jak dla mnie powiniene dostać nominację na perelkę.

0

http://tomaszewicz.zpt.tele.pw.edu.pl/files2/ucyf/2004l/7/index.html

Czerpię z tej strony, a konkretnie ze źródła pliku c.

No ja wiem, że się nie robi tego ręcznie, ale przedstawiłem tylko błędną idee.

1 użytkowników online, w tym zalogowanych: 0, gości: 1