# importamos Librerías
import numpy as np
import scipy as sc
import matplotlib.pyplot as plt
from sklearn.datasets import make_circles
# Creamos el DataSet
# Usaremos la función make_circles
# Definimos variables
n = 500 # Número de registros que queremos de los datos
p = 2 # Cuántas características tenemos de nuestros datos. Por efectos de visualización, se usa 2 para graficar en un eje de coordenadas bidimensional
X,Y = make_circles(n_samples=n, factor= 0.5,noise=0.05) # "factor" hacer referencia a el factor de escala entre el circulo interior y el exterior
# 'noise' hace referencia a la desviación estándar Gaussiana agregada a los datos
Y = Y[:,np.newaxis]
plt.scatter(X[:,0],X[:,1]);
#Sim embargo vamos a graficarlo de forma más "bonita":
# Puntos de la circunferencia
# Notemos que al imprimir Y, nos dan 0 y 1
print(Y)
# Por lo tanto solo graficamos cuando y = 0
plt.scatter(X[Y[:,0]==0,0],X[Y[:,0]==0,1],c="skyblue");
plt.scatter(X[Y[:,0]==1,0],X[Y[:,0]==1,1],c="salmon");
plt.axis("equal");
#CLASE DE LA CAPA DE LA RED
# Creamos una clase:
# Esto es una estructura de datos que contiene los parámetros e información de nuestra red neuronal
# Esto ayuda a crear capas
# Se llamará "neural_layer":
class neural_layer():
def __init__(self,n_conn,n_neur,act_f):
self.act_f = act_f
self.b = np.random.rand(1,n_neur) * 2 - 1
self.W = np.random.rand(n_conn,n_neur) * 2 - 1
# Funciones de Activación
# La sigmoide y su derivada se saca para mayor facilidad de una vez a la hora de calcular el error
sigm = (lambda x: 1 / (1+np.e**(-x)),
lambda x: x * ( 1 - x ))
relu = lambda x: np.maximum(0,x)
#Ejemplo
_x = np.linspace(-5,5,100)
plt.plot(_x,sigm[0](_x))
# Empezamos a diseñar capas
# l0 => Layer #0
l0 = neural_layer(p,4,sigm)
l1 = neural_layer(4,8,sigm)
#----
#Definimos la función que cree la red neural
def create_nn(topology,act_f):
nn = []
for l, layer in enumerate(topology[:-1]):
nn.append(neural_layer(topology[l],topology[l+1],act_f))
return nn
topology = [2,4,8,16,8,4,1] #Las capas que tendrá la red
create_nn(topology,sigm)
# Vamos a definir el entrenamiento de la red neuronal
topology = [p,4,8,1] # Lo ajustamos
neural_net = create_nn(topology,sigm)
l2_cost = (lambda Yp,Yr: np.mean((Yp - Yr) ** 2),
lambda Yp,Yr: (Yp - Yr))
def train(neural_net,X,Y,l2_cost,lr=0.5,train=True):
out = [(None,X)]
# Forward Pass
# @ es multiplicación matricial
for l,layer in enumerate(neural_net):
z = out[-1][1] @ neural_net[l].W + neural_net[l].b
a = neural_net[l].act_f[0](z)
out.append((z,a))
# print(out[-1][1].shape)
# print(l2_cost[0](out[-1][1],Y))
if train:
# Backward pass
deltas = []
for l in reversed(range(0,len(neural_net))):
z = out[l+1][0]
a = out[l+1][1]
if l == len(neural_net) - 1:
deltas.insert(0,l2_cost[1](a,Y)*neural_net[l].act_f[1](a))
#Calcular Delta última capa
else:
deltas.insert(0,deltas[0] @ _W.T * neural_net[l].act_f[1](a))
_W = neural_net[l].W
# Gradient Descent
neural_net[l].b = neural_net[l].b - np.mean(deltas[0],axis=0,keepdims=True) * lr
neural_net[l].W = neural_net[l].W - out[l][1].T @ deltas[0] * lr
return out[-1][1]
train(neural_net,X,Y,l2_cost,0.5)
print('')
#Vamos a ver cómo queda nuestro proceso
import time
from IPython.display import clear_output
neural_net = create_nn(topology,sigm)
loss = []
for i in range (10000):
# Entrenemos a la red:
pY = train(neural_net,X,Y,l2_cost,lr=0.03)
if i % 25 == 0:
# print(pY)
loss.append(l2_cost[0](pY,Y))
res = 50
_x0 = np.linspace(-1.5,1.5,res)
_x1 = np.linspace(-1.5,1.5,res)
_Y = np.zeros((res,res))
for i0, x0 in enumerate(_x0):
for i1, x1 in enumerate(_x1):
_Y[i0,i1] = train(neural_net, np.array([[x0,x1]]),Y,l2_cost,train=False)[0][0]
plt.pcolormesh(_x0,_x1,_Y,cmap="coolwarm")
plt.axis('equal')
plt.scatter(X[Y[:,0] == 0,0],X[Y[:,0] == 0,1], c="skyblue")
plt.scatter(X[Y[:,0] == 1,0],X[Y[:,0] == 1,1], c="salmon")
clear_output(wait=True)
plt.show()
plt.plot(range(len(loss)),loss)
plt.show()
time.sleep(0.2)
#print('iteración #', i)
import session_info
session_info.show()