<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Regularização
Como vimos, redes neurais podem ser impactadas pelo fenômeno do sobre-ajuste. Nesta interação, abordaremos uma técnica, a regularização, que busca forçar redes neurais a criarem mapeamentos mais suaves.
Objetivos
Ao fim desta lição, o aluno será capaz de
Step1:  ## Resultados da regularização
A seguir, aplicaremos a regularização no mesmo problema de regressão de uma parábola abordado anteriormente
<ASSISTANT_TASK:>
Python Code:
# Inicializacao
%matplotlib inline
import numpy as np
from matplotlib import pyplot as plt
def nova_mlp(entradas, saidas, camadas):
    lista_de_camadas = [entradas] + camadas + [saidas]
    pesos = []
    for i in xrange(len(lista_de_camadas)-1):
        pesos.append(np.random.random((lista_de_camadas[i+1], lista_de_camadas[i])))
    return pesos
def ff_mlp(entradas, pesos):
    s = entradas
    for i in xrange(len(pesos)-1):
        s = np.tanh(np.dot(pesos[i],s))
    s = np.dot(pesos[-1],s)
    return s
def backpropagation_step(entradas, saidas, pesos, regular=0.01, passo=0.01):
    derivadas = []
    resultados_intermediarios = [entradas]
    s = entradas
    for i in xrange(len(pesos)-1):
        s = np.tanh(np.dot(pesos[i],s))
        resultados_intermediarios.append(s)
    s = np.dot(pesos[-1],s)
    resultados_intermediarios.append(s)
  
    # Derivada do erro em relacao a saida estimada
    dedye = (resultados_intermediarios[-1] - saidas)
    
    # Derivada em relacao a camada de saida linear
    dedb = np.dot(dedye, resultados_intermediarios[-2].T)
    
    # Para cada camada nao-linear, calcula a nova derivada na forma:
    deda = dedye
    for i in range(len(pesos)-2, -1, -1):
        linear = np.dot(pesos[i], resultados_intermediarios[i])
        flz = (1-np.tanh(linear)**2) 
        deda = np.dot(pesos[i+1].T, deda) # deriv_front
        derivada = np.dot(deda * flz, resultados_intermediarios[i].T)
        derivadas.insert (0, derivada)
    derivadas.append(dedb)
    
    # Executa um passo na direcao contraria da derivada e adiciona minimizacao da
    # norma L1 ponderada por lambda
    for i in xrange(len(derivadas)):
        n = np.linalg.norm(derivadas[i])
        pesos[i] -= passo * (derivadas[i]/n + (regular * np.sign(pesos[i])))
    
    return pesos
def erro(y, y_e):    
    return np.sum((y-y_e)**2)
Explanation: Regularização
Como vimos, redes neurais podem ser impactadas pelo fenômeno do sobre-ajuste. Nesta interação, abordaremos uma técnica, a regularização, que busca forçar redes neurais a criarem mapeamentos mais suaves.
Objetivos
Ao fim desta lição, o aluno será capaz de:
Entender o conceito de regularização
Aplicar regularização em um problema de aprendizado
Regularização
A regularização é um processo que busca penalizar determinadas configurações de sistemas que são claramente inadequados a um problema. Assim, além de minimizar o erro ($E = ||\boldsymbol y_e - \boldsymbol y||^2.$), o processo de treinamento também buscará minimizar uma determinada função do conjunto de parâmetros $\theta$ da rede. É comum que essa função seja a norma L1 ou L2 dos pesos da rede.
Numa rede regularizada, a função-objetivo, que deve ser minimizada, é dada por:
$$E + \lambda f(\theta),$$
onde $\lambda$ é um parâmetro que determina o quão regular a rede deverá ser. Se definirmos $f(\theta) = ||\theta||_1$, então a função de retro-propagação poderá ser re-definida, na forma:
End of explanation
# Usando 30 amostras aleatoriamente escolhidas (30% do total) para o aprendizado
# e bias nas entradas
import random
x = np.linspace(-3, 3, num=100)
y_ = x**2
y = y_ + np.random.normal(0, 0.5, 100) # Criando uma parabola com ruido
x.shape = (1, x.size)
y.shape = (1, y.size)
x_treino = x[:,0:30]
x_teste = x[:,30:100]
y_treino = y[:,0:30]
y_teste = y[:,30:100]
x.shape = (x.size)
y.shape = (y.size)
train_array = np.zeros((x.size)).astype(bool)
test_array = np.ones((x.size)).astype(bool)
while np.sum(train_array) < 30:
    n = int(random.random() * x.size)
    test_array[n] = False
    train_array[n] = True
x_treino = x[train_array]
x_teste = x[test_array]
y_treino = y[train_array]
y_teste = y[test_array]
x_treino.shape = (1,x_treino.size)
y_treino.shape = (1,y_treino.size)
x_teste.shape = (1,x_teste.size)
y_teste.shape = (1,y_teste.size)
x_treino2 = np.vstack((x_treino, np.ones(x_treino.size)))
x_teste2 = np.vstack((x_teste, np.ones(x_teste.size)))
mlp0 = nova_mlp(entradas=2, saidas=1, camadas=[10])
# Processo de treinamento
n_passos = 2000
eqm_treino = np.zeros((n_passos+1))
eqm_treino[0] = erro(y_treino, ff_mlp(x_treino2, mlp0))
eqm_teste = np.zeros((n_passos+1))
eqm_teste[0] = erro(y_teste, ff_mlp(x_teste2, mlp0))
for i in xrange(n_passos):
    mlp0 = backpropagation_step(x_treino2, y_treino, mlp0, regular=0.3)
    eqm_treino[i+1] = erro(y_treino, ff_mlp(x_treino2, mlp0))
    eqm_teste[i+1] = erro(y_teste, ff_mlp(x_teste2, mlp0))
print "EQM final:", eqm_teste[-1]
    
plt.figure();
plt.plot(range(n_passos+1), eqm_treino);
plt.plot(range(n_passos+1), eqm_teste);
plt.ylabel('EQM');
plt.xlabel('Passos');
plt.title('EQM nos conjuntos de treino e teste');
plt.figure();
plt.plot(x.T, y.T);
plt.plot(x_treino.T, ff_mlp(x_treino2, mlp0).T);
plt.plot(x_teste.T, ff_mlp(x_teste2, mlp0).T);
plt.ylabel('Y');
plt.xlabel('X');
plt.title('Aproximacao nos conjuntos de teste e treino');
Explanation: ## Resultados da regularização
A seguir, aplicaremos a regularização no mesmo problema de regressão de uma parábola abordado anteriormente:
End of explanation
<END_TASK>