3. diel - Neurónové siete - Krokovanie, bias a viac dimenzií
V minulej lekcii, Neurónové siete - Perceptron , sme spomenuli Perceptron a ukázali si niektoré druhy algoritmov vhodných na generovanie a triedenie dát.
V dnešnej lekcii kurzu Neurónovej siete - Krok za krokom si ukážeme krokovanie algoritmu, povieme si niečo o biase a lekciu zakončíme prípadom s 10-timi dimenziami.
Krokovanie algoritmu
Teraz, keď máme algoritmus, môžeme sa naň pozrieť bližšie. Pretože som vám sľúbil množstvo grafov, poďme si každú aktualizáciu vykresliť. Najprv vytvoríme dátovú sadu. Znížil som počet dátových bodov, aby bol príklad jasnejší:
data, classes = sklearn.datasets.make_blobs( n_samples=10, n_features=2, centers=[[-1,0.4],[1,0.6]], cluster_std=0.8, random_state=82 ) plt.scatter(data[:,0], data[:,1], c=classes) plt.show()Teraz si vykreslíme všetky zmeny. Na nižšie uvedených grafoch je červená priamka oddeľujúca nadrovinou a čierna priamka jej normála. Zle klasifikovaná inštancia (pri ktorej aktualizujeme váhy) je označená zeleno. Zelená priamka predstavuje inštančný vektor, tj vektor, ktorý chceme pripočítať (alebo odpočítať) od váh. Napokon, svetlo červené a modré priamky sú novou deliacou nadrovinou (po aktualizácii) a zodpovedajúce normála:
# Tréning perceptrónu # Inicializácia váh weights = np.random.RandomState(42).uniform(size=2) # Opakovanie až do konvergencie weights_changed = True while weights_changed: weights_changed = False # pre každú inštanciu v dátach for instance, target in zip(data, classes): # predikcia výstupu perceptrónu prediction = sign(instance @ weights) # aktualizácia váh weights_new = weights + (target - prediction) * instance # vykreslenie zmeny if (weights != weights_new).any(): slope = - weights[0] / weights[1] # vypočítanie sklonu plt.figure(figsize=(8, 5)) plt.plot( [data.min(axis=0)[0], data.max(0)[0]], [slope * data.min(axis=0)[0], slope * data.max(axis=0)[0]], c='r') # vykreslenie deliacej nardoviny plt.plot([0, weights[0]],[0, weights[1]], c='black') # vykreslenie normály plt.scatter(data[:,0], data[:,1], c=classes) # vykreslenie dát plt.scatter(instance[0], instance[1], c='g') # vykreslenie chybne klasifikovanej inštancie plt.plot([0, instance[0]], [0, instance[1]], c='g', alpha=0.4) # vykreslenie inštančného vektora plt.plot( [weights[0], weights[0] + (target - prediction) * instance[0]], [weights[1], weights[1] + (target - prediction) * instance[1]], c='g', alpha=0.4) # vykreslenie inštančného vektora z normály plt.plot( [0, weights[0] + (target - prediction) * instance[0]], [0, weights[1] + (target - prediction) * instance[1]], c='c', alpha=0.4) # vykreslenie novej normály slope_new = - weights_new[0] / weights_new[1] # výpočet sklonu novej priamky plt.plot( [data.min(axis=0)[0], data.max(0)[0]], [slope_new * data.min(axis=0)[0], slope_new * data.max(axis=0)[0]], c='r', alpha=0.2) # vykreslenie deliacej nadroviny plt.axis('equal') plt.ylim(-2,4) plt.show() weights_changed = weights_changed or (weights != weights_new).any() weights = weights_new # VYKRESLENIE KONEČNÝCH VÁH slope = - weights[0] / weights[1] plt.figure(figsize=(8, 5)) plt.scatter(data[:,0], data[:,1], c=classes) plt.plot( [data.min(axis=0)[0], data.max(0)[0]], [slope * data.min(axis=0)[0], slope * data.max(axis=0)[0]], c='r') plt.show()
Bias
Zatiaľ sme nepoužili bias. Ak si pamätáte všeobecné rovnice priamky ?? + ?? + ? = 0, nastavili sme ? na nulu. Z tohto dôvodu prechádza priamka vždy súradnicou [0, 0]. Ale čo ak máme dáta, ktoré nemožno takto oddeliť? Radi by sme zaviedli posun ? (anglicky bias) a umožnili algoritmu posunúť deliacu nadrovinu z nulovej súradnice. Najprv si vygenerujeme novú dátovú sadu:
data, classes = sklearn.datasets.make_blobs( n_features=2, centers=2, random_state=44 ) plt.scatter(data[:,0], data[:,1], c=classes) plt.show()Túto dátovú sadu nemožno oddeliť pomocou nášho perceptrónového algoritmu, pretože ju nemôže oddeliť žiadna priamka prechádzajúca [0, 0]. Pre bias pridáme term ? do lineárnej kombinácie vstupov: ?=?(?? ? +?)
Bias sa učí rovnakým spôsobom ako váhy. Keď algoritmus nesprávne klasifikuje pozitívnu inštanciu, zvýši bias o 1. Keď je chybne klasifikovaná negatívna inštancia, zníži ho o 1:
# Tréning perceptrónu # Inicializácia váh weights = np.random.RandomState(42).uniform(-2, 2, 2) bias = 0 # Opakovanie až do konvergencie old_weights = None old_bias = None while (weights != old_weights).any() or bias != old_bias: old_weights = weights old_bias = bias # pre každú inštanciu v dátach for instance, target in zip(data, classes): # predikcia výstupu perceptrónu prediction = sign(instance @ weights + bias) # aktualizácia váh weights = weights + (target - prediction) * instance bias = bias + (target - prediction) # vykreslenie slope = - weights[0] / weights[1] plt.scatter(data[:,0], data[:,1], c=classes) plt.plot( [data.min(axis=0)[0], data.max(0)[0]], [slope * data.min(axis=0)[0] - bias / weights[1], slope * data.max(axis=0)[0] - bias / weights[1]], c='r') plt.show()Ako vidíme, priamka sa posunula dole a už neprechádza cez [0, 0]. Niekedy je zbytočné riešiť bias samostatne. Môžeme ho zahrnúť do váh a doplniť dátové body jednotkami. Je to rovnaké, ako by sme presunuli dáta do novej dimenzie. Ukážme si to na jednorozmerných dátach. Máme pozitívne dáta {1, 2, 3} a negatívne dáta {4, 5, 6}. Radi by sme ich oddelili nadrovinou (to je v tomto prípade bodom), ktorá prechádza 0. To nie je možné, pretože oddeľujúcou nadrovinou môže byť iba bod 0:
data = np.array([[1],[2],[3],[4],[5],[6]]) classes = np.array([0,0,0,1,1,1]) plt.scatter(data, np.zeros((6,)), c=classes) plt.scatter(0,0,c='r') plt.show()Ak by sme však presunuli dáta do novej dimenzie (tie by bolo v tomto prípade 2D), oddeľujúcou nadrovinou je priamka a dáta sú lineárne separované:
data = np.array([[1],[2],[3],[4],[5],[6]]) classes = np.array([0,0,0,1,1,1]) plt.scatter(data, np.ones((6,)), c=classes) plt.scatter(0,0,c='r') plt.plot([0, 6],[0, 1.75], c='r') plt.show()S biasom sa môžeme vysporiadať rovnakým spôsobom. Pridáme novú dimenziu s jednotkami av algoritme perceptróne použijeme 3 váhy:
# GENEROVANIE DÁT data, classes = sklearn.datasets.make_blobs( n_features=2, centers=2, random_state=44 ) data = np.hstack([data, np.ones((data.shape[0],1))]) # Tréning perceptrónu # Inicializácia váh weights = np.random.RandomState(42).uniform(-2, 2, 3) # Opakovanie až do konvergencie old_weights = None while (weights != old_weights).any(): old_weights = weights # pre každú inštanciu v dátach for instance, target in zip(data, classes): # predikcia výstupu perceptrónu prediction = sign(instance @ weights) # aktualizácia váh weights = weights + (target - prediction) * instance # vykreslenie slope = - weights[0] / weights[1] bias = weights[2] / weights[1] plt.scatter(data[:,0], data[:,1], c=classes) plt.plot( [data.min(axis=0)[0], data.max(0)[0]], [slope * data.min(axis=0)[0] - bias, slope * data.max(axis=0)[0] - bias], c='r') plt.show()
Viacdimenzionálny prípad
Zatiaľ sme si ukázali iba dvojrozmerné prípady. Nie je nič, čo by bránilo použitiu viacerých dimenzionálnych dát, okrem toho, že ich nebudeme môcť vykresliť. Skúsme napríklad 10 dimenzií, ale bez vykresľovania, pretože vizualizáciu 10D dát by nebolo ľahké urobiť:
# GENEROVANIE DÁT data, classes = sklearn.datasets.make_blobs( n_samples=1000, n_features=10, centers=2, random_state=42 ) data = np.hstack([data, np.ones((data.shape[0],1))]) train_data, test_data, train_classes, test_classes = sklearn.model_selection.train_test_split(data, classes, test_size=0.15) # Tréning perceptrónu weights = np.random.RandomState(42).uniform(-2, 2, 11) old_weights = None while (weights != old_weights).any(): old_weights = weights for instance, target in zip(train_data, train_classes): prediction = sign(instance @ weights) weights = weights + (target - prediction) * instance # TEST predictions = [sign(instance @ weights) for instance in test_data] print(f'Presnosť: {sklearn.metrics.accuracy_score(test_classes, predictions)}')
Výstup
Presnosť: 1.0
Ako vidíme, algoritmus dosiahol 100% presnosť. Správne oddelil dáta, pretože sú lineárne separované.
V budúcej lekcii, Neurónové siete - Normalizácia , sa zameriame na normalizáciu alebo štandardizáciu dátových bodov.