<jupyter_start><jupyter_text>XOR - Perceptrón y Retroprop Vamos a constuir un perceptrón multicapa para entrenarlo a reconocer la tabla del XOR pero esta vez no asumiremos nada de los pesos y dejaremos que el algoritmo de retropropagación lo encuentre.<jupyter_code>from __future__ import absolute_import
from __future__ import print_function
from six.moves import range
from six.moves import zip
from numpy import hstack,exp,dot,ones,tanh,mean,abs,array
import numpy as np
import sys<jupyter_output><empty_output><jupyter_text>Perceptrón multicapa  Aquí definiremos las funciones que vamos a estar ocupando<jupyter_code>def fact(f='sigmoide'):
    if f=='sigmoide':
        return [lambda x: 1./(1+exp(-x)), lambda y: y*(1-y)]
    elif f=='tanh':
        return [tanh, lambda y: 1 - y**2]
    elif f=='ident':
        return [lambda x: x, lambda y: 1]

def creapesos( arq ):
    en,hn,sn = arq
    Wh = 2*np.random.random( (en+1,hn) )-1
    Ws = 2*np.random.random( (hn,sn) )-1
    return [Wh, Ws]


def ff(estimulo,pesos):
    """
    predicción de la red
    Función feed-forward que hace la predicción en el estíumulo 
    en el parámetro con los pesos especificados.
    """    
    Wh, Ws = pesos
    I = hstack((-1*ones((len(estimulo),1)),estimulo))
    H = fh(dot(I,Wh))
    S = fs(dot(H,Ws))
    return S<jupyter_output><empty_output><jupyter_text>Como vamos a usar el descenso del gradiente con retropropagación, requerimos entonces un método que reciba los pesos origniales y que los actualice iteradamente.<jupyter_code>def entrena(X,iters,alfa,pesos,iterr=1000,verbose=False):
    Wh, Ws  = pesos
    for j in range(iters):
        #agregamos nodo sesgo
        I = hstack((-1*ones((len(X[:]),1)), X[:]))
        #feedforward
        H = fh(dot(I,Wh))
        #H = hstack((-1*ones((len(H),1)),H))
        #print("H y Ws shapes\n{} {}".format(H.shape, Ws.shape))
        S = fs(dot(H,Ws))
        #error de la capa de salida
        S_err = S - Y
        #delta capa salida
        S_d = S_err*dfs(S)
        #error capa escondida
        H_err = dot(S_d,Ws.T)
        #delta capa escondida
        H_d = H_err*dfh(H)
        #actualizamos pesos
        Ws    -= alfa * (dot(H.T,S_d))
        Wh    -= alfa * (dot(I.T,H_d))
        if(verbose):
            if((iterr>0) and (j%iterr==0)):
                print(mean(abs(S_err)))
    return [Wh,Ws]<jupyter_output><empty_output><jupyter_text>DatosNuestros datos a usar es simplemente la tabla del XOR.<jupyter_code>xor = array( [[0,0,0],[0,1,1],[1,0,1],[1,1,0]] )
X = xor[:,:-1]
Y = xor[:,-1].reshape(-1,1)
for x, y in zip(X,Y):
    print("{} : {}".format(x,y))<jupyter_output>[0 0] : [0]
[0 1] : [1]
[1 0] : [1]
[1 1] : [0]<jupyter_text>Definición y entrenamiento.<jupyter_code>tipocapa1="sigmoide"
tipocapa2="sigmoide"
f1, f2 = fact(tipocapa1), fact(tipocapa2)
fh, dfh = f1
fs, dfs = f2

#arquitectura
# como recibimos un par ordenado y queremos predecir su
# etiqueta entonces nuestra red empieza siendo
# (2 , h, 1)
# h la especificamos como 5
intermedias = 5
en, hn, sn = ( X.shape[1], intermedias, Y.shape[1] )

cons_aprendizaje = 0.1
iteraciones = 5000
alfa, iters = (cons_aprendizaje, iteraciones)
en, hn, sn = ( X.shape[1], intermedias, Y.shape[1] )
Wh, Ws = creapesos( (en,hn,sn) )
print("alfa: {}".format(alfa))
print("iteraciones: {}".format(iters))
print("arquitectura: {} {} {}".format(en,hn,sn))
print("pesos primera capa: {} {}".format(Wh.shape,tipocapa1))
print("pesos segunda capa: {} {}".format(Ws.shape,tipocapa2))
print("Datos \n{}".format(X))<jupyter_output>alfa: 0.1
iteraciones: 5000
arquitectura: 2 5 1
pesos primera capa: (3, 5) sigmoide
pesos segunda capa: (5, 1) sigmoide
Datos 
[[0 0]
 [0 1]
 [1 0]
 [1 1]]<jupyter_text>Previo al entrenamiento tenemos esto<jupyter_code>err = 0.
for x,y in zip(ff(X,[Wh,Ws]),Y):
    err += (y-x)**2
print("Error {}".format(err.mean(axis=0)))<jupyter_output>Error 1.0508473440379815<jupyter_text>Entrenamos la red<jupyter_code>#entrenamos
pesos_t = entrena(X,iteraciones,alfa,[Wh,Ws])<jupyter_output><empty_output><jupyter_text>La red entrenada ahora computa así cada estímulo<jupyter_code>print("\nRed Entrenada")
err = 0.
for x,y in zip(ff(X,pesos_t),Y):
    err += (y-x)**2
print("Error {}\n".format(err.mean(axis=0)))
for x,y in zip(Y, ff(X,pesos_t)):
    print("x: {} <-> {} : y".format(x,y))<jupyter_output>x: [0] <-> [0.08174302] : y
x: [1] <-> [0.90787719] : y
x: [1] <-> [0.91693318] : y
x: [0] <-> [0.10053767] : y<jupyter_text>Los pesos se ven ahora como:<jupyter_code>print("pesos primera capa \n{0}".format(pesos_t[0]))
print("pesos segunda capa \n{0}".format(pesos_t[1]))<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.16389907267629933, 'fraction_numerical': 0.03515203795557473, 'mean_word_length': 4.030368763557484, 'pattern_counts': {'":': 0, '<': 38, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '9', 'dir': 'jupyter-structured-clean-dedup', 'id': '597673', 'license': 'MIT', 'n_tokens_mistral': 2017, 'n_tokens_neox': 1938, 'n_words': 446, 'path': 'NN/XOR_Backprop.ipynb', 'repo_name': 'mentesniker/Notebooks-Ciencia-de-Datos', 'size': '4637'}