%% compilado con exporter=pdflatex weaver=sweave-ess
\documentclass{beamer} % símbolos menos ambiguos
\usefonttheme{serif}
\usepackage{neuralnetwork}
\usepackage[spanish]{babel}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{dsfont}               % para \mathds (double stroke)
\usepackage[cal=boondox]{mathalfa}% para "o" manuscrita
\newcommand{\oo}{{\mathcal o}}
\newcommand{\phio}{\phi_{\oo}}
\newcommand{\por}{\,}             % multiplicar
% \renewcommand{\v}[1]{{\vec #1}}
\renewcommand{\v}[1]{{\bf #1}}
\newcommand{\x}{\v x}
\newcommand{\w}{\v w}
\begin{document}
\title{Neuronas artificiales}
\author{Análisis de Datos}

\begin{frame} [fragile]
  \maketitle
\end{frame}
\section{Introducción}
\begin{frame} [fragile]
  \frametitle{Introducción}
  \begin{itemize}
  \item inspirado en las conexiones (sinapsis)\\ entre neuronas cerebrales
  \item aprendizaje supervisado: clasificación o regresión
  \item son modelos de regresión no lineal con muchos parámetros\\
    (caja negra: el ajuste no es constructivo)
  \item permiten extraer patrones de información no estructurada \\(textos, fotos...) pero
    % \url{https://techcrunch.com/2018/01/02/these-psychedelic-stickers-blow-ai-minds/}
    a veces alucinan
  \item tipos
    \begin{itemize}
    \item perceptrón multicapa ({\sc mlp})
    \item base radial ({\sc rbf})
    \item mapas autoorganizados ({\sc som}; no supervisado)
    \item convolucionales ({\sc cnn}) 
    \item recurrentes ({\sc rnn})
    \item adversativas ({\sc gan})
    \item trasformadores (p.ej. {\sc gpt})
    \item ...
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame} [fragile]
  \frametitle{Índice}
  \begin{itemize}
  \item Clasificación
    \begin{itemize}
    \item Perceptrón simple
    \item Perceptrón multicapa (1 oculta)
    \end{itemize}
  \item Regresión
  \item Parámetros
  \item Recomendaciones
  \end{itemize}
\end{frame}

\section{Clasificación}
\begin{frame} [fragile]
  \frametitle{Perceptrón simple}
  \begin{neuralnetwork}[height=5]
    \newcommand{\nodetextx}[2]{$\ifnum0=#2 \alpha \else x_{#2}\fi$}
    \newcommand{\nodetexty}[2]{$y_{#2}$}
    \inputlayer[count=4, bias=false, title=Capa de\\entrada, text=\nodetextx]
    \outputlayer[count=3, title=Capa de\\salida, text=\nodetexty] \linklayers
  \end{neuralnetwork}
\end{frame}

\begin{frame} [fragile]
  \frametitle{Perceptrón simple}
  \begin{neuralnetwork}[height=5]
    \newcommand{\nodetextx}[2]{$\ifnum0=#2 \alpha \else x_{#2}\fi$}
    \newcommand{\nodetexty}[2]{$y_{#2}$}
    \inputlayer[count=4, bias=true, title=Capa de\\entrada, text=\nodetextx]
    \outputlayer[count=3, title=Capa de\\salida, text=\nodetexty] \linklayers
  \end{neuralnetwork}
\end{frame}

\newcommand{\peso}[4]{\ensuremath{w_{#2k}}}

\begin{frame} [fragile]
  \frametitle{Perceptrón simple}
  \begin{neuralnetwork}[height=5]
    \newcommand{\nodetextx}[2]{$\ifnum0=#2 \alpha_k \else x_{#2}\fi$}
    \newcommand{\nodetexty}[2]{$y_{k}$}
    \inputlayer[count=4, bias=true, title=Capa de\\entrada, text=\nodetextx]
    \outputlayer[count=1, title=Capa de\\salida, text=\nodetexty] %\linklayers
    \link[from layer=0, to layer=1, from node=0, to node=1]
    \link[from layer=0, to layer=1, from node=1, to node=1, label=\peso]
    \link[from layer=0, to layer=1, from node=2, to node=1, label=\peso]
    \link[from layer=0, to layer=1, from node=3, to node=1, label=\peso]
    \link[from layer=0, to layer=1, from node=4, to node=1, label=\peso]
  \end{neuralnetwork}
\end{frame}

\begin{frame} [fragile]
  \frametitle{Perceptrón simple}
  \begin{neuralnetwork}[height=5]
    \newcommand{\nodetextx}[2]{$\ifnum0=#2 1 \else x_{#2}\fi$}
    \newcommand{\nodetexty}[2]{$y_{k}$}
    \newcommand{\pesa}[4]{\ensuremath{\alpha_{k}}}
    \inputlayer[count=4, bias=true, title=Capa de\\entrada, text=\nodetextx]
    \outputlayer[count=1, title=Capa de\\salida, text=\nodetexty] %\linklayers
    \link[from layer=0, to layer=1, from node=0, to node=1, label=\pesa]
    \link[from layer=0, to layer=1, from node=1, to node=1, label=\peso]
    \link[from layer=0, to layer=1, from node=2, to node=1, label=\peso]
    \link[from layer=0, to layer=1, from node=3, to node=1, label=\peso]
    \link[from layer=0, to layer=1, from node=4, to node=1, label=\peso]
  \end{neuralnetwork}
\end{frame}

\begin{frame} [fragile]
  \frametitle{Perceptrón simple}
  \begin{neuralnetwork}[height=5]
    \newcommand{\nodetextx}[2]{$x_{#2}$}
    \newcommand{\nodetexty}[2]{$y_{k}$}
    \inputlayer[count=4, bias=true, title=Capa de\\entrada, text=\nodetextx]
    \outputlayer[count=1, title=Capa de\\salida, text=\nodetexty] %\linklayers
    \link[from layer=0, to layer=1, from node=0, to node=1, label=\peso]
    \link[from layer=0, to layer=1, from node=1, to node=1, label=\peso]
    \link[from layer=0, to layer=1, from node=2, to node=1, label=\peso]
    \link[from layer=0, to layer=1, from node=3, to node=1, label=\peso]
    \link[from layer=0, to layer=1, from node=4, to node=1, label=\peso]
  \end{neuralnetwork}
\end{frame}

\begin{frame} [fragile]
  \frametitle{Perceptrón simple}
    \begin{itemize}
  \item \(x_i\) = variable de entrada (\(i=1,\dots,I\))
  \item \(y_k\) = variable de salida (\(k=1,\dots,K\))
  \item \(\phi_\oo\) = función de activación en la capa de salida ({\em output\/})
  \item \(\alpha_k\) = constante, sesgo ({\em bias\/}) para la salida \(k\)
  \item \(w_{ik}\) = peso ({\em weight\/}), coeficiente de sinapsis entre \(x_i\) y \(y_k\)
    \[ y_k = \phio \left( \alpha_k + \sum_{i=1}^I w_{ik}\por x_i \right) = 
    \phio \left( \sum_{i=0}^I w_{ik}\por x_i \right) \]
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Perceptrón simple}

  Sean \(\x=(x_1,\dots,x_I)^\top \in \mathbb{R}^I\) y \(\x_1=(1,x_1,\dots,x_I)^\top\). \\Definimos el modelo como una familia
  de aplicaciones:
  \[
  f_\w : \mathbb{R}^I \to \mathbb{R}^K,
    \quad
  \v y=f_\w(\x)=g\left[\phi_\oo\left( \w_1^\top \x_1 \right),
    \dots,\phi_\oo\left( \w_K^\top \x_1 \right)\right]
\]
donde \(g\in\{\text{identidad},\text{softmax}\}\) \\[2ex]
Sean\quad\(\v t\)=\emph{target} (respuesta) \quad
\(\v y\)=predicción (salida)
\\[2ex]
Error o pérdida
\(  E(\w) = E\left[\v y, \v t\right]= E\left[f_\w(\x),\v t\right] \)
  
  \vspace{2mm}

  \begin{itemize}
  \item \(E\) es diferenciable si \(\phi\) lo es.
    \begin{itemize}
    \item esto permite calcular gradientes respecto a \(\x\) y a \(\w\)
    \item esencial para optimización mediante retropropagación
    \end{itemize}
  % \item La familia \(\{f_\theta\}\) es un subconjunto de
  %   \(C(\mathbb{R}^d)\).
  \item El entrenamiento consiste en resolver:
  \(\displaystyle
  \min_{\w \in \mathbb{R}^{I+1}} E(\w)%\qquad\text{con \(E\) función de error o pérdida}
  \)
  \end{itemize}

  \vspace{2mm}

  Interpretación: modelo no lineal en \(\x\), pero
  lineal en los parámetros antes de la activación.
\end{frame}

\begin{frame} [fragile,t]
   \frametitle{Perceptrón simple}

     \begin{itemize}
     \item lineal \[\phio(x) = x\]
       \only<1>{
<<fig=TRUE,echo=FALSE,width=5,height=4>>=
par(mar=c(6, 4, 2, 2) + 0.1)  # margen inferior grande (10 líneas)
plot(c(-1,1),c(-1,1),type="l",xlab="",ylab="",xlim=c(-2,2))
@ 
         }
     \item<2-> logística 
       \[ \phio (x)=\ell(x) = \frac {\exp(x)} {1+\exp(x)} = \frac {1} {1+\exp(-x)} \]
       \only<2>{
<<fig=TRUE,echo=FALSE,width=5,height=5>>=
par(mar=c(12, 4, 0, 2) + 0.1)  # margen inferior grande (10 líneas)
plot(function(x)1/(1+exp(-x)),-10,10,xlab="",ylab="")
@ 
         }
 \end{itemize}
\end{frame}

\begin{frame} [fragile,t]
  \frametitle{Perceptrón simple}
\begin{itemize}
   \item indicatriz, umbral, característica, Heaviside
       \[ \phio(x)= \mathds1_{[0,\infty)}(x) =
       \begin{cases}
         0&\text{si }x<0\\
         1&\text{si }x\geqslant0
       \end{cases}
     \]
     \only<1>{
<<fig=TRUE,echo=FALSE,width=5,height=3>>=
plot(function(x)pmax(sign(x),0),-10,10,xlab="",ylab="",n=1000,yaxt="n")
axis(2, at=c(0,1))
@
}
%     
% % <<results=tex,echo=FALSE>>=
% % temporal <- "/tmp/temporal.pdf"
% % pdf(temporal,width=5,height=3)
% % par(mar=c(0,4,0,2)+.1)
% % plot(function(x)pmax(sign(x),0),-10,10,xlab="",ylab="",n=1000)
% % invisible(dev.off())
% % cat(paste0("\\includegraphics{",temporal,"}\n\n"))
% % @ 
% }
     \only<2->{
       \begin{itemize}
   \item no es derivable
   \item no es adecuada para optimización por gradiente
   \item se aproxima en la práctica por funciones suaves ; \\p.ej. mediante la logística :
 \[
 \ell_\beta(x)=\frac{1}{1+\exp(-\beta x)},\quad
 \ell_\beta(x)\to \mathds1_{[0,\infty)}(x)\ \text{cuando }\beta\to\infty
 \]
 \end{itemize}
 }
\end{itemize}
\end{frame}

% \begin{frame} [fragile,t]
%   \frametitle{Perceptrón simple}
%     \begin{itemize}
%     \item ReLU
%     \[
%     \phio(x)=\max\{0,x\}
%     \]
%     \begin{itemize}
%     \item continua, no derivable en \(0\)
%     \item muy usada en la práctica
%     \end{itemize}
% \end{itemize}\vspace{5mm}
% <<fig=TRUE,echo=FALSE,width=5,height=5>>=
% par(mar=c(12, 4, 0, 2) + 0.1)  # margen inferior grande (10 líneas)
% plot(function(x)pmax(x,0),-10,10,xlab="",ylab="",n=1000)
% @ 
% \end{frame}

% \begin{frame} [fragile]
%   \frametitle{Perceptrón simple}
% <<fig=TRUE,echo=FALSE>>=
% set.seed (3) # para que quepan las salidas
% data(mtcars) # porque lo modificamos después
% xx <- seq(-4,4,.1)
% plot (xx, xx, type="l", ylim=c(-2,2), lwd=2, xlab="", ylab="")
% lines (xx, 1/(1+exp(-xx)), col=2, lwd=2, lty=2)
% lines (xx, xx>=0, type="s", col=3, lwd=2, lty=1)
% lines (xx, pmax(xx,0), col=4, lwd=4, lty=2)
% legend ("bottomright", legend=c("lineal","logit","indicatriz","ReLU"), 
%         col=1:4, lwd=2, lty=1:2)
% @ 
% \end{frame}


% \begin{frame} [fragile]
%   \frametitle{Perceptrón simple}
% <<fig=TRUE,echo=FALSE>>=
% set.seed (3) # para que quepan las salidas
% data(mtcars) # porque lo modificamos después
% xx <- seq(-4,4,.1)
% plot (xx, xx, type="l", ylim=c(-2,2), lwd=2, xlab="", ylab="")
% lines (xx, 1/(1+exp(-10*xx)), col=2, lwd=2, lty=2)
% lines (xx, xx>=0, type="s", col=3, lwd=2, lty=1)
% lines (xx, pmax(xx,0), col=4, lwd=4, lty=2)
% legend ("bottomright", legend=c("lineal","logit(10x)","indicatriz","ReLU"), 
%         col=1:4, lwd=2, lty=1:2)
% @ 
% \end{frame}

\begin{frame} [fragile]
  \frametitle{Perceptrón simple: ajuste}
  \begin{itemize}
  \item función de activación:
    \begin{itemize}
    \item para respuesta dicótoma, logística: \( \phi_\oo(x)= \frac {\exp(x)} {1+\exp(x)} \)
    \item para tres o más categorías, lineal: \(\phi_\oo(x)=x\) 
    \end{itemize}
  \item criterios de ajuste \\ 
    \(n=\text{instancia}\quad t=\text{respuesta}\in\{0;1\}
    \quad y=\text{predicción}\)
    \begin{itemize}
    \item para respuesta dicótoma: una neurona de salida, \(y\in[0;1]\)
      \[E=\sum_{n=1}^N\left[
        {t^{(n)}}\por\ln\frac{t^{(n)}}{y^{(n)}} +(1-t^{(n)})\por\ln\frac{1-t^{(n)}}{1-y^{(n)}}\right]\]
    \item para respuesta múltiple, \emph{softmax} (\(y\in\mathds R\))
      \[ E = \sum_n\sum_k-t^{(n)}_k\por\ln {\widehat\Pr}[t_n=k]\qquad
        {\widehat\Pr}[t_n=k]=\frac{\exp\bigl({y^{(n)}_k}\bigr)}{\sum_{c=1}^K \exp\bigl({y^{(n)}_c}\bigr)} \]
    \end{itemize}
  \end{itemize}
\end{frame}
\begin{frame}[fragile]
  \frametitle{Entropía, entropía cruzada y divergencia KL}
  
  \textbf{Entropía de Shannon}
  \begin{itemize}
    \item Distribución discreta sobre \(K\) clases:
  \(\displaystyle
  H(\v p) = -\sum_{k=1}^K p_k \ln p_k
  \)
  \item
  Mide la incertidumbre o la cantidad media de información.
\end{itemize}
\vspace{2mm}
  
  \textbf{\(H\) cruzada} entre \(\v p\) (real) y \(\v q\) (modelo):\\
  \hfill\(
  H(\v p,\v q) = -\sum_{k} p_k \ln q_k
  \)
  \begin{itemize}
  \item No es simétrica: \(H(\v p,\v q) \neq H(\v q,\v p)\).
  \item En aprendizaje supervisado, \(\v p\) es la distribución empírica (degenerada o \emph{one‑hot}\/: un 1 y el resto 0).
  \end{itemize}

  \vspace{2mm}
  
  \textbf{Divergencia de Kullback–Leibler} (o entropía relativa):

    \vspace{-2ex}
  \[
  D_{\rm KL}(\v p \| \v q) = \sum_{k} p_k \ln\frac{p_k}{q_k}
      = H(\v p,\v q) - H(\v p)
    \]

  \vspace{-2ex}
  \begin{itemize}
  \item Mide la “distancia” (no simétrica) entre dos distribuciones.
  \item \(D_{\rm KL}(\v p\|\v q)\ge 0\) y es cero si y solo si \(\v p=\v q\) (casi seguro).
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Aplicación a los criterios de ajuste}
    \begin{itemize}
  \item El término \(H(\v t)\) es constante (depende sólo de los datos).
  \item Minimizar \(D_{\rm KL}\) equivale a minimizar \(H(\v t,\v y)\).
  \item \(H(\v t)=0\) si \(\v t\) es degenerada.
  \end{itemize}
\vspace{3ex}
  \textbf{Caso binario} (una salida logística \(y\), objetivo \(t\in\{0,1\}\)) :
  \[
  \begin{gathered}
  D_{\rm KL}\bigl((t,1-t)\,\|\,(y,1-y)\bigr)
  = t\ln\frac{t}{y} + (1-t)\ln\frac{1-t}{1-y} ={}\\
  {}= \underbrace{\bigl[-t\ln y -(1-t)\ln(1-y)\bigr]}_{H(\v t,\v y)} - \underbrace{\bigl[-t\ln t -(1-t)\ln(1-t)\bigr]}_{H(\v t)}
  \end{gathered}
  \]

  \textbf{Caso multiclase} (\(\v p\) = softmax(\(\v y\)), objetivo \(\v t\)):
  \[
  D_{\rm KL}(\mathbf{t}\|\mathbf{p}) = \sum_{k} t_k \ln\frac{t_k}{p_k}
%  = \underbrace{-\sum_{k} t_k \ln y_k}_{\text{entropía cruzada}} - H(\mathbf{t})
  = H(\v t,\v p) - H(\mathbf{t})
  \]\vspace{-2ex}
\end{frame}
\begin{frame} [fragile]
  \frametitle{Perceptrón simple}
<<>>=
## para ahorrar espacio en esta presentación:
options (width = 58)  
names(iris)[1:4] <- c("Lsep","Asep","Lpet","Apet")
library (nnet)   # biblioteca distribuida con R básico
red <- nnet (Species ~ ., iris, size = 0, skip = TRUE)
@   
\end{frame}

\begin{frame} [fragile]
  \frametitle{Perceptrón simple}
<<>>=
red
@   
\end{frame}

\begin{frame} [fragile]
  \frametitle{Perceptrón simple}
<<>>=
summary (red)
@   
\end{frame}

\begin{frame} [fragile]
  \frametitle{Perceptrón simple}
<<>>=
names (red)
@   
\end{frame}

\begin{frame} [fragile]
  \frametitle{Perceptrón simple}
<<>>=
red $ wts
head (red $ fitted.values)
@   
\end{frame}

\begin{frame} [fragile]
  \frametitle{Perceptrón simple}
<<>>=
tail (red $ fitted.values)
summary (apply (red $ fitted.values, 1, sum))
@   
\end{frame}

\begin{frame} [fragile]
  \frametitle{Perceptrón simple}
<<>>=
red $ value
indices.fila    <- 1 : nrow (iris)
indices.columna <- match (iris$Species, 
                          levels(iris$Species))
indices <- cbind (indices.fila, indices.columna)
- sum (log (red$fitted.values [indices]))
@   
\end{frame}

\begin{frame} [fragile]
  \frametitle{Perceptrón simple}
<<>>=
aggregate (iris[,1:4], list(iris$Species), median)
flor <- data.frame(Lsep=6,Asep=2.9,Lpet=5,Apet=1.7)
predict (red, flor)
predict (red, flor, type="class")
@   
\end{frame}

\begin{frame} [fragile]
  \frametitle{Perceptrón simple}
<<>>=
predict (red, flor)
summary (red)
@   
\end{frame}

\begin{frame} [fragile]
  \frametitle{Perceptrón simple}
<<>>=
predict (red, flor)
flor1 <- c (1, as.numeric (flor))
e1 <- exp (as.numeric (flor1 %*% red$wts[1:5]))
e2 <- exp (as.numeric (flor1 %*% red$wts[6:10]))
e3 <- exp (as.numeric (flor1 %*% red$wts[11:15]))
c(e1,e2,e3) / (e1+e2+e3)
@   
\end{frame}

\begin{frame} [fragile]
  \frametitle{Respuesta dicótoma}
<<>>=
red2 <- nnet (factor(am)~mpg, mtcars, 
              size=0, skip=TRUE, trace=FALSE)
predict (red2, data.frame (mpg = 20))
1 / (1 + 1/exp (red2$wts[1] + red2$wts[2] * 20)) #logit
red2 $ value
p <- red2 $ fitted.values             #una sola columna
t <- +(mtcars$am == mtcars$am[1])
n0 <- function (x) ifelse (is.na(x), 0, x)
sum (n0(t*log(t/p)) + n0((1-t)*log((1-t)/(1-p))))
@ 
\end{frame}

\begin{frame} [fragile]
  \frametitle{Perceptrón multicapa (1 oculta)}
  \begin{neuralnetwork}[height=5]
    \newcommand{\nodetextclear}[2]{}
    \newcommand{\nodetextx}[2]{$x_#2$}
    \newcommand{\nodetexty}[2]{$y_#2$}
    \inputlayer[count=4, bias=false, title=Entrada, text=\nodetextx]
    \hiddenlayer[count=2, bias=false, title=Capa\\oculta, text=\nodetextclear] \linklayers
    \outputlayer[count=3, title=Salida, text=\nodetexty] \linklayers
    \renewcommand{\peso}[4]{\ensuremath{w_{ij}}}
    \link[from layer=0, to layer=1, from node=1, to node=1, label=\peso]
    \renewcommand{\peso}[4]{\ensuremath{w_{jk}}}
    \link[from layer=1, to layer=2, from node=1, to node=1, label=\peso]
  \end{neuralnetwork}
\end{frame}

\begin{frame} [fragile]
  \frametitle{Perceptrón multicapa (1 oculta)}
  \begin{neuralnetwork}[height=5]
    \newcommand{\nodetextclear}[2]{}
    \newcommand{\nodetextx}[2]{$x_#2$}
    \newcommand{\nodetexty}[2]{$y_#2$}
    \inputlayer[count=4, bias=true, title=Entrada, text=\nodetextx]
    \hiddenlayer[count=2, bias=true, title=Oculta, text=\nodetextclear] \linklayers
    \outputlayer[count=3, title=Salida, text=\nodetexty] \linklayers
    \renewcommand{\peso}[4]{\ensuremath{\alpha_{j}}}
    \link[from layer=0, to layer=1, from node=0, to node=1, label=\peso]
    \renewcommand{\peso}[4]{\ensuremath{\beta_{k}}}
    \link[from layer=1, to layer=2, from node=0, to node=1, label=\peso]
  \end{neuralnetwork}
\end{frame}

\begin{frame} [fragile]
  \frametitle{Perceptrón multicapa (1 oculta)}
  \begin{itemize}
  \item  \(j\) = índice de neuronas en capa oculta (\emph{hidden})
    \[ y_k = \phi_{\oo} \left( \beta_k + \sum_{j=1}^J w_{jk}\por \phi_h \Biggl( \alpha_j + \sum_{i=1}^I w_{ij}\por x_i  \Biggr) \right) \]
    \[ y_k = \phi_{\oo} \left( \sum_{j=0}^J w_{jk} \por\phi_h \Biggl( \sum_{i=0}^I w_{ij}\por x_i  \Biggr) \right) \]
  \item \(\phi\) casi siempre logística en la oculta
    \[ \phi_h(x)=\ell(x) = \frac {\exp(x)} {1+\exp(x)} \]
  \end{itemize}
\end{frame}

\begin{frame} [fragile]
  \frametitle{Perceptrón multicapa (1 oculta, \texttt{skip=FALSE})}
  \begin{neuralnetwork}[height=5]
    \newcommand{\nodetextclear}[2]{}
    \newcommand{\nodetextx}[2]{$x_#2$}
    \newcommand{\nodetexty}[2]{$y_k$}
    \renewcommand{\peso}[4]{\ensuremath{w_{#2k}}}
    \inputlayer[count=2, bias=true, title=Entrada, text=\nodetextx]
    \hiddenlayer[count=3, bias=true, title=Oculta, text=\nodetextclear, exclude={1,2}]
    \outputlayer[count=1, title=Salida, text=\nodetexty] 
    \link[from layer=0, to layer=1, from node=0, to node=3]
    \link[from layer=0, to layer=1, from node=1, to node=3]
    \link[from layer=0, to layer=1, from node=2, to node=3]
    \link[from layer=1, to layer=2, from node=0, to node=1]
    \link[from layer=1, to layer=2, from node=3, to node=1]
  \end{neuralnetwork}
\end{frame}

\begin{frame} [fragile]
  \frametitle{Perceptrón multicapa (1 oculta, \texttt{skip=TRUE})}
  \begin{neuralnetwork}[height=5]
    \newcommand{\nodetextclear}[2]{}
    \newcommand{\nodetextx}[2]{$x_#2$}
    \newcommand{\nodetexty}[2]{$y_k$}
    \renewcommand{\peso}[4]{\ensuremath{w_{#2k}}}
    \inputlayer[count=2, bias=true, title=Entrada, text=\nodetextx]
    \hiddenlayer[count=3, bias=true, title=Oculta, text=\nodetextclear, exclude={1,2}]
    \outputlayer[count=1, title=Salida, text=\nodetexty] 
    \link[from layer=0, to layer=1, from node=0, to node=3]
    \link[from layer=0, to layer=1, from node=1, to node=3]
    \link[from layer=0, to layer=1, from node=2, to node=3]
    \link[from layer=1, to layer=2, from node=0, to node=1]
    \link[from layer=1, to layer=2, from node=3, to node=1]
%    \link[from layer=0, to layer=2, from node=0, to node=1, label=\peso] % no en nnet
    \link[from layer=0, to layer=2, from node=1, to node=1, label=\peso]
    \link[from layer=0, to layer=2, from node=2, to node=1, label=\peso]
  \end{neuralnetwork}
\end{frame}

\begin{frame} [fragile]
  \frametitle{Perceptrón multicapa (1 oculta)}
  \begin{itemize}
  \item  \texttt{skip=FALSE}
    \[ y_k = \phi_{\oo} \left( \sum_{j} w_{jk} \por\phi_h \Biggl( \sum_{i} w_{ij}\por x_i  \Biggr)  \right) \] 
  \item  \texttt{skip=TRUE}
    \[ y_k = \phi_{\oo} \left( \sum_{j} w_{jk} \por\phi_h \Biggl( \sum_{i} w_{ij}\por x_i  \Biggr)  + \sum_i w_{ik}\por x_i \right) \] 
  \item los atajos o conexiones soslayantes (\emph{skip}) pueden facilitar\\la interpretación de la red neuronal
  \end{itemize}
\end{frame}

\begin{frame} [fragile]
  \frametitle{Perceptrón multicapa (1 oculta)}
<<>>=
red0 <- nnet (Species ~ ., iris, size = 2,
              skip = FALSE, trace = FALSE)
red0
red1 <- nnet (Species ~ ., iris, size = 2,
              skip = TRUE, trace = FALSE)
red1
@   
\end{frame}

\begin{frame} [fragile]
  \frametitle{Perceptrón multicapa (1 oculta)}
<<>>=
summary (red0)
@   
\end{frame}

\begin{frame} [fragile]
  \frametitle{Perceptrón multicapa (1 oculta)}
<<>>=
summary (red1)
@   
\end{frame}
\section{Regresión}
\begin{frame} [fragile]
  \frametitle{Regresión}
  \begin{itemize}
  \item función de activación de salida lineal: \(\phi_\oo(x)=x\)
  \item teorema de aproximación universal (Cybenko, Hornik, etc.)
    \begin{itemize}
    \item sea \(f:(C\text{ compacto})\subset\mathbb R^I\to\mathbb R\) continua
    \item existe perceptrón que aproxima \(f\) uniformemente en \(C\)
    \item basta
      \begin{itemize}
      \item elegir funciones de activación adecuadas
      \item incrementar el número de neuronas en la capa oculta
      \end{itemize}
    \end{itemize}
  \item la aproximación es ``no constructiva''
    \begin{itemize}
    \item el número de neuronas se decide por validación
    \end{itemize}
  \item criterios de ajuste (\(n\)=instancia, \(t\)=objetivo, \(y\)=predicción)
    \begin{itemize}
    \item mínimos cuadrados: \(E = \sum_n\Vert t^{(n)}-y^{(n)}\Vert^2\)
    \end{itemize}
  \end{itemize}
\end{frame}

% \begin{frame}[fragile]
%   \frametitle{Regresión}
%   \begin{itemize}
%   \item Función de activación en la capa de salida: lineal, \(\phi_\oo(x)=x\).
%     \begin{itemize}
%     \item Así la red puede aproximar cualquier valor real (no solo probabilidades).
%     \end{itemize}
%   \item \textbf{Teorema de aproximación universal} (Cybenko, Hornik, etc.):
%     \begin{itemize}
%     \item Sea \(f: \mathbb{R}^I \supset K \to \mathbb{R}\) una función continua sobre un compacto \(K\).
%     \item Existe una red neuronal con una sola capa oculta (con suficientes neuronas) y activación no lineal (p.ej. logística) que aproxima \(f\) uniformemente en \(K\).
%     \item Basta incrementar el número de neuronas en la capa oculta; no se necesitan más capas ocultas para aproximar funciones continuas.
%     \end{itemize}
%   \item La aproximación es \textbf{no constructiva}:
%     \begin{itemize}
%     \item El teorema garantiza la existencia, pero no dice cuántas neuronas ni cómo ajustar los pesos.
%     \item En la práctica, el número de neuronas se elige mediante validación o heurísticas.
%     \end{itemize}
%   \item Criterios de ajuste (para regresión): minimizar el error cuadrático medio.
%     \begin{itemize}
%     \item Dados patrones \(n=1,\dots,N\), con objetivo \(t^{(n)}\in\mathbb{R}^K\) y predicción \(y^{(n)}\in\mathbb{R}^K\):
%     \[
%     E = \sum_{n=1}^N \bigl\| t^{(n)} - y^{(n)} \bigr\|^2
%     \]
%     \item Es la suma de cuadrados de los residuos, igual que en regresión lineal múltiple.
%     \end{itemize}
%   \item \textbf{Relación con regresión lineal}:
%     \begin{itemize}
%     \item Si no hay capa oculta (tamaño 0) y activación lineal, se obtiene exactamente una regresión lineal múltiple.
%     \item La capa oculta con activación no lineal permite modelar relaciones no lineales.
%     \end{itemize}
%   \end{itemize}
% \end{frame}


\begin{frame} [fragile,t]
  \frametitle{Parámetros}
  \begin{itemize}
  \item \texttt{maxit}: límite del número de iteraciones\\antes de alcanzar convergencia
  \item \texttt{rang}: pesos inicializados según
    \(\mathcal U(-\text{rang}, +\text{rang})\)
  \item \texttt{decay}: coeficiente \(\lambda\) de decaimiento de pesos
      \begin{itemize}%\addtolength{\itemsep}{1ex}
  \item pretende evitar óptimos locales al ajustar los pesos \(w\)
  \item minimizar \(\displaystyle E+\lambda\por\sum_{i,j,k} w^2\)
  \item se aconseja \( 0.001 \lessapprox \lambda \lessapprox 0.1\)
  \item recuerda: conviene tipificar las instancias
  \end{itemize}
\end{itemize}
<<>>=
E <- function (l) {
 red <- nnet(Species~., iris,, 2, decay=l, trace=FALSE)
 c(red$value,
  -sum(log(red$fitted[cbind(1:150,rep(1:3,each=50))]))+
  + l * sum(red$wts^2)) }
E (0) ; E (.1)
@   
\end{frame}

\begin{frame} [fragile]
  \frametitle{Regresión}
<<echo=FALSE>>=
grafpred <- function (modelo,d)
{
    plot (mpg ~ wt, d)
    d <- d[order(d$wt),]
    lines (d$wt, 
           predict (modelo,
                    d),
           col=2, lwd=2)
}

print.summary.lm <- 
function (x, digits = max(3L, getOption("digits") - 3L), symbolic.cor = x$symbolic.cor, 
    signif.stars = FALSE, ...) 
{
    resid <- x$residuals
    df <- x$df
    rdf <- df[2L]
    if (rdf > 5L) {
        nam <- c("Min", "1Q", "Median", "3Q", "Max")
        rq <- if (length(dim(resid)) == 2L) 
            structure(apply(t(resid), 1L, quantile), dimnames = list(nam, 
                dimnames(resid)[[2L]]))
        else {
            zz <- zapsmall(quantile(resid), digits + 1L)
            structure(zz, names = nam)
        }
        ##print(rq, digits = digits, ...)
    }
    else if (rdf > 0L) {
        ##print(resid, digits = digits, ...)
    }
    else {
        ##cat("ALL", df[1L], "residuals are 0: no residual degrees of freedom!")
        ##cat("\n")
    }
    cat("[...]\n") # por no sacar los residuos
    if (length(x$aliased) == 0L) {
        cat("\nNo Coefficients\n")
    }
    else {
        if (nsingular <- df[3L] - df[1L]) 
            cat("\nCoefficients: (", nsingular, " not defined because of singularities)\n", 
                sep = "")
        else cat("\nCoefficients:\n")
        coefs <- x$coefficients
        if (any(aliased <- x$aliased)) {
            cn <- names(aliased)
            coefs <- matrix(NA, length(aliased), 4, dimnames = list(cn, 
                colnames(coefs)))
            coefs[!aliased, ] <- x$coefficients
        }
        printCoefmat(coefs, digits = digits, signif.stars = signif.stars, 
            na.print = "NA", ...)
    }
    cat("\nResidual standard error:", format(signif(x$sigma, 
        digits)), "on", rdf, "degrees of freedom")
    cat("\n")
    if (nzchar(mess <- naprint(x$na.action))) 
        cat("  (", mess, ")\n", sep = "")
    if (!is.null(x$fstatistic)) {
        cat("Multiple R-squared:", formatC(x$r.squared, digits = digits))
        cat(", Adjusted R-squared:", formatC(x$adj.r.squared, 
            digits = digits), "\nF-statistic:", formatC(x$fstatistic[1L], 
            digits = digits), "on", x$fstatistic[2L], "and", 
            x$fstatistic[3L], "DF,  p-value:", format.pval(pf(x$fstatistic[1L], 
                x$fstatistic[2L], x$fstatistic[3L], lower.tail = FALSE), 
                digits = digits))
        cat("\n")
    }
    correl <- x$correlation
    if (!is.null(correl)) {
        p <- NCOL(correl)
        if (p > 1L) {
            cat("\nCorrelation of Coefficients:\n")
            if (is.logical(symbolic.cor) && symbolic.cor) {
                print(symnum(correl, abbr.colnames = NULL))
            }
            else {
                correl <- format(round(correl, 2), nsmall = 2, 
                  digits = digits)
                correl[!lower.tri(correl)] <- ""
                print(correl[-1, -p, drop = FALSE], quote = FALSE)
            }
        }
    }
    cat("\n")
    invisible(x)
}
@ 
<<>>=
reg <- lm (mpg ~ wt, mtcars)
print (summary (reg))
@ 
\end{frame}

\begin{frame}[fragile]
  \frametitle{}
<<fig=TRUE,echo=FALSE>>=
grafpred (reg, mtcars)
@ 
\end{frame}

\begin{frame} [fragile]
\frametitle{Regresión}
<<>>=
set.seed(1) # para reproducir ejemplo malo
red <- nnet (mpg ~ wt, mtcars, size = 2, linout = TRUE)
summary (red)
@ 
\end{frame}

\begin{frame} [fragile]
  \frametitle{Regresión}
<<>>=
red $ value
sum (red $ residuals ^ 2)
sum (reg $ residuals ^ 2)
@ 
\end{frame}

\begin{frame}[fragile]
  \frametitle{}
<<fig=TRUE,echo=FALSE>>=
grafpred (red, mtcars)
@ 
\end{frame}

\begin{frame} [fragile]
  \frametitle{Regresión}
<<>>=
set.seed(2) # mucho mejor cambiando la semilla
red <- nnet (mpg ~ wt, mtcars, size = 2, linout = TRUE)
@ 
\end{frame}

\begin{frame}[fragile]
  \frametitle{}
<<fig=TRUE,echo=FALSE>>=
grafpred (red, mtcars)
@ 
\end{frame}


\begin{frame} [fragile]
  \frametitle{Regresión}
<<>>=
set.seed(1) # caso malo; pesos com mayor rango inicial
red <- nnet (mpg ~ wt, mtcars, size = 2, linout = TRUE,
             rang = 5)
@ 
\end{frame}

\begin{frame}[fragile]
  \frametitle{}
<<fig=TRUE,echo=FALSE>>=
grafpred (red, mtcars)
@ 
\end{frame}


\begin{frame} [fragile]
  \frametitle{Regresión}
<<>>=
set.seed(1) # caso malo; tipificando; sobreajuste
red <- nnet (mpg ~ wt, scale(mtcars), size = 2,
             linout = TRUE)
@ 
\end{frame}

\begin{frame}[fragile]
  \frametitle{}
<<fig=TRUE,echo=FALSE>>=
grafpred (red, data.frame(scale(mtcars)))
@ 
\end{frame}

\begin{frame} [fragile]
  \frametitle{Regresión}
<<>>=
set.seed(1) # decay para evitar sobreajuste
red <- nnet (mpg ~ wt, scale(mtcars), size = 2,
             linout = TRUE, decay=.001)
@ 
\end{frame}

\begin{frame}[fragile]
  \frametitle{}
<<fig=TRUE,echo=FALSE>>=
grafpred (red, data.frame(scale(mtcars)))
@ 
\end{frame}

\begin{frame} [fragile]
  \frametitle{Regresión}
<<>>=
set.seed(1) # decay para evitar sobreajuste
red <- nnet (mpg ~ wt, scale(mtcars), size = 2,
             linout = TRUE, decay=.01)
@ 
\end{frame}

\begin{frame}[fragile]
  \frametitle{}
<<fig=TRUE,echo=FALSE>>=
grafpred (red, data.frame(scale(mtcars)))
@ 
\end{frame}

\begin{frame} [fragile]
  \frametitle{Regresión}
<<>>=
set.seed(1) # decay para evitar sobreajuste
red <- nnet (mpg ~ wt, scale(mtcars), size = 2,
             linout = TRUE, decay=.1)
@ 
\end{frame}

\begin{frame}[fragile]
  \frametitle{}
<<fig=TRUE,echo=FALSE>>=
grafpred (red, data.frame(scale(mtcars)))
@ 
\end{frame}

\begin{frame} [fragile]
  \frametitle{Regresión}
<<>>=
set.seed(1) # muchas neuronas ocultas; sobreajuste
red <- nnet (mpg~wt, mtcars, size = 100, linout = TRUE)
@ 
\end{frame}

\begin{frame}[fragile]
  \frametitle{}
<<fig=TRUE,echo=FALSE>>=
grafpred (red, mtcars)
@ 
\end{frame}


\begin{frame} [fragile]
  \frametitle{Regresión}
<<>>=
set.seed(1) # rang no evita sobreajuste
red <- nnet (mpg~wt, mtcars, size = 100, linout = TRUE,
             rang=5)
@ 
\end{frame}

\begin{frame}[fragile]
  \frametitle{}
<<fig=TRUE,echo=FALSE>>=
grafpred (red, mtcars)
@ 
\end{frame}

\begin{frame} [fragile]
  \frametitle{Regresión}
<<>>=
set.seed(1) # decay evita sobreajuste pero no converge
red <- nnet (mpg~wt, mtcars, size = 100, linout = TRUE,
             decay=.1)
@ 
\end{frame}
\begin{frame} [fragile]
  \frametitle{Regresión}
<<>>=
set.seed(1) # decay evita sobreajuste si aumentamos maxit
salida <- capture.output (
  red <- nnet (mpg~wt, mtcars, size = 100, linout = TRUE,
               decay=.1, maxit=1000))
tail (salida)
@ 
\end{frame}

\begin{frame}[fragile]
  \frametitle{}
<<fig=TRUE,echo=FALSE>>=
grafpred (red, mtcars)
@ 
\end{frame}

% \begin{frame} [fragile]
%   \frametitle{Regresión}
% <<>>=
% set.seed(1)
% red <- nnet (mpg ~ wt, mtcars, size = 100, linout = TRUE,
%              trace = FALSE, maxit = 1000)
% red $ value
% set.seed(1)
% red <- nnet (mpg ~ wt, mtcars, size = 100, linout = TRUE,
%              trace = FALSE, maxit = 1e6)
% red $ value
% @ 
% \end{frame}

% \begin{frame}[fragile]
%   \frametitle{}
% <<fig=TRUE,echo=FALSE>>=
% grafpred (red, mtcars)
% @ 
% \end{frame}

\begin{frame} [fragile]
  \frametitle{Regresión}
<<>>=
set.seed(1) # decay no funciona siempre
red <- nnet (mpg ~ wt, mtcars, size = 2, linout = TRUE,
             decay = 0.001)
@ 
\end{frame}

\begin{frame}[fragile]
  \frametitle{}
<<fig=TRUE,echo=FALSE>>=
grafpred (red, mtcars)
@ 
\end{frame}

\begin{frame} [fragile]
  \frametitle{Regresión}
<<>>=
set.seed(1) # decay no funciona siempre
red <- nnet (mpg ~ wt, mtcars, size = 2, linout = TRUE,
             decay = 0.01)
@ 
\end{frame}

\begin{frame}[fragile]
  \frametitle{}
<<fig=TRUE,echo=FALSE>>=
grafpred (red, mtcars)
@ 
\end{frame}

\begin{frame} [fragile]
  \frametitle{Regresión}
<<>>=
set.seed(1) # decay no funciona siempre
red <- nnet (mpg ~ wt, mtcars, size = 2, linout = TRUE,
             decay = 0.1)
@ 
\end{frame}

\begin{frame}[fragile]
  \frametitle{}
<<fig=TRUE,echo=FALSE>>=
grafpred (red, mtcars)
@ 
\end{frame}

\begin{frame} [fragile]
  \frametitle{Recomendaciones}
  \begin{itemize}
  \item tipificar / normalizar / rescalar las variables
  \item ejecutar varias veces (probar distintas semillas)
  \item validación cruzada
  \item promediar las predicciones de varias redes (ensamblar) para
    mejorar la generalización
  \end{itemize}
\end{frame}

\begin{frame} [fragile]
  \frametitle{}
<<>>=
valcruz <- function (numneur, decai, partes=10)
{
    iparte <- sample (rep (1:partes,
                           length.out = nrow(mtcars)))
    mean (sapply (1:partes,
            function (i)
            {
                red <- nnet (mpg ~ wt, 
                             mtcars[iparte!=i,],
                             linout = TRUE,
                             size = numneur, 
                             decay = decai,
                             trace = FALSE)
                mean ((predict (red, 
                                mtcars[iparte==i,]) -
                       mtcars$mpg[iparte==i]) ^ 2)
            }))
}
@ 
\end{frame}

\begin{frame} [fragile]
  \frametitle{}
<<>>=
valcruz (  2, 0.001)
valcruz (  2, 0.001)
valcruz ( 10, 0.001)
valcruz ( 10, 0.001)
valcruz (100, 0.001)
valcruz (100, 0.001)
mean (reg $ residuals ^ 2)
@ 
\end{frame}

\begin{frame} [fragile]
  \frametitle{}
<<>>=
valcruzreg <- function (partes=10)
{
    iparte <- sample (rep (1:partes,
                           length.out = nrow(mtcars)))
    mean (sapply (1:partes,
            function (i)
            {
                reg <- lm (mpg ~ wt, 
                           mtcars[iparte!=i,])
                mean ((predict (reg, 
                                mtcars[iparte==i,]) -
                       mtcars$mpg[iparte==i]) ^ 2)
            }))
}
@ 
\end{frame}
\begin{frame} [fragile]
  \frametitle{}
<<>>=
valcruzreg ()
mean (reg $ residuals ^ 2)
@ 
\end{frame}

\begin{frame} [fragile]
  \frametitle{}
<<>>=
valcruz01 <- function (numneur, decai, partes=10)
{
    iparte <- sample (rep (1:partes,
                           length.out=nrow(mtcars01)))
    mean (sapply (1:partes,
            function (i)
            {
                red <- nnet (mpg ~ wt, 
                             mtcars01[iparte!=i,],
                             linout = TRUE,
                             size = numneur, 
                             decay = decai,
                             trace = FALSE)
                mean ((predict (red, 
                                mtcars01[iparte==i,])
                       - mtcars01$mpg[iparte==i]) ^ 2)
            }))
}
@ 
\end{frame}

\begin{frame}[fragile]
  \frametitle{}
<<>>=
mtcars01 <- data.frame (scale (mtcars))
mean (lm(mpg~wt,mtcars01) $ residuals ^ 2)
valcruz01 (2, 0.001)
valcruz01 (2, 0.001)
valcruz01 (2, 0.001)
valcruz01 (2, 0.001)
@ 
\end{frame}
\begin{frame} [fragile]
  \frametitle{Bibliografía}
  \begin{itemize}
  \item \url{https://cran.r-project.org/view=MachineLearning}
  \item Ripley B.; 1996; Pattern recognition and neural networks; Cambridge University Press
  \item Venables W., Ripley B.; 2002; Modern applied statistics with S; Springer
  \end{itemize}
\end{frame}

\section{Anexo: Retropropagación}

\begin{frame}[plain]
  \title{Anexo: Retropropagación}\author{}\date{}
  \titlepage
\end{frame}

\begin{frame}[fragile]
  \frametitle{Perceptrón simple: retropropagación}

  Para una instancia \(n\in\{1,\dots,N\}\) :

  \[
  y_k^{(n)} =
  \phio\!\left(
  \sum_{i=0}^I w_{ik}\por x_i^{(n)}
  \right)
  \]

 Error (p.ej. divergencia en \(k\) respuestas dicótomas):
   \begin{eqnarray*}
   E &=& \sum_n \sum_k
   \left[
   t_k^{(n)} \por \ln\frac{t_k^{(n)}}{y_k^{(n)}}
   + (1-t_k^{(n)}) \por
   \ln\frac{1-t_k^{(n)}}{1-y_k^{(n)}}
         \right]\\
   &=&\sum_n \sum_k\left[ -t_k^{(n)}\ln y_k^{(n)} - (1-t_k^{(n)})\ln(1-y_k^{(n)})\right] + \text{cte.}
   \end{eqnarray*}
  
  Objetivo: minimizar \(E\) respecto a \(w_{ik}\)
\end{frame}

\begin{frame}[fragile]
  \frametitle{Perceptrón simple: derivada de \(E\) respecto a \(w_{ik}\)}
  \begin{eqnarray*}
  y_k^{(n)} &=& \phio\!\left(\sum_{i=0}^I w_{ik} x_i^{(n)}\right) \qquad
  \phio(z)=\frac{1}{1+e^{-z}} \quad\text{(logística)}
  \\
  E &=& \sum_n \sum_k\left[ -t_k^{(n)}\ln y_k^{(n)} - (1-t_k^{(n)})\ln(1-y_k^{(n)}) \right]
  \\
  \frac{\partial E}{\partial w_{ik}}
  &=& \sum_n \frac{\partial E^{(n)}}{\partial y_k^{(n)}} \;
    \frac{\partial y_k^{(n)}}{\partial a_k^{(n)}} \;
    \frac{\partial a_k^{(n)}}{\partial w_{ik}}
  \qquad
  a_k^{(n)} = \sum_{i} w_{ik} x_i^{(n)}
  \\
    \frac{\partial E^{(n)}}{\partial y_k^{(n)}}
    &=& -\frac{t_k^{(n)}}{y_k^{(n)}} + \frac{1-t_k^{(n)}}{1-y_k^{(n)}}
    = \frac{y_k^{(n)}-t_k^{(n)}}{y_k^{(n)}(1-y_k^{(n)})} \\
    \frac{\partial y_k^{(n)}}{\partial a_k^{(n)}}
    &=& \phio'(a_k^{(n)}) = y_k^{(n)}\bigl(1-y_k^{(n)}\bigr) \qquad\text{(derivada de la logística)} \\
    \frac{\partial a_k^{(n)}}{\partial w_{ik}}
    &=& x_i^{(n)}
  \end{eqnarray*}

\end{frame}

\begin{frame}[fragile]
  \frametitle{Perceptrón simple: derivada de \(E\) respecto a \(w_{ik}\)}
  \vspace{2mm}
  Multiplicando los tres factores:

  \[
  \frac{\partial E^{(n)}}{\partial w_{ik}}
  = \frac{y_k^{(n)}-t_k^{(n)}}{y_k^{(n)}(1-y_k^{(n)})} \;\cdot\;
    y_k^{(n)}\bigl(1-y_k^{(n)}\bigr) \;\cdot\; x_i^{(n)}
  = \bigl(y_k^{(n)}-t_k^{(n)}\bigr)\, x_i^{(n)}
  \]

  Sumando para todas las instancias:

  \[
    \frac{\partial E}{\partial w_{ik}} = \sum_{n=1}^N \bigl(y_k^{(n)}-t_k^{(n)}\bigr)\, x_i^{(n)}
  \]
\end{frame}

\begin{frame}[fragile]
  \frametitle{Perceptrón simple: gradiente}

  Para activación logística:
  \[
  \phio'(z) = y_k(1-y_k)
  \]

  Derivada del error:
  \[
  \frac{\partial E}{\partial w_{ik}}
  =
  \sum_n
  \left(y_k^{(n)} - t_k^{(n)}\right)
  \por x_i^{(n)}
  \]

  Regla de actualización (descenso por gradiente):
  \[
  w_{ik}
  \leftarrow
  w_{ik}
  - \eta
  \sum_n
  \left(y_k^{(n)} - t_k^{(n)}\right)
  \por x_i^{(n)}
  \]

  \(\eta>0\) es la tasa de aprendizaje.
\end{frame}

\begin{frame}[fragile]
  \frametitle{Perceptrón multicapa (1 oculta)}

  Capa oculta:
  \[
  h_j^{(n)} =
  \phi\!\left(
  \sum_{i=0}^I w_{ij}\por x_i^{(n)}
  \right)
  \]

  Capa de salida:
  \[
  y_k^{(n)} =
  \phio\!\left(
  \sum_{j=0}^J v_{jk}\por h_j^{(n)}
  \right)
  \]

  El error \(E\) es el mismo que antes.
\end{frame}

\begin{frame}[fragile]
  \frametitle{Multicapa: retropropagación}

  Definimos el \emph{error local} en salida:

  \[
  \delta_k^{(n)} =
  y_k^{(n)} - t_k^{(n)}
  \]

  Gradiente en la capa de salida:
  \[
  \frac{\partial E}{\partial v_{jk}}
  =
  \sum_n
  \delta_k^{(n)} \por h_j^{(n)}
  \]

  Actualización:
  \[
  v_{jk}
  \leftarrow
  v_{jk}
  - \eta
  \sum_n
  \delta_k^{(n)} \por h_j^{(n)}
  \]
\end{frame}

\begin{frame}[fragile]
  \frametitle{Multicapa: error en capa oculta}

  Error propagado a la neurona oculta:

  \[
  \delta_j^{(n)}
  =
  \phi'\!\left(
  \sum_i w_{ij}\por x_i^{(n)}
  \right)
  \sum_k
  \delta_k^{(n)} \por v_{jk}
  \]

  Gradiente en pesos de entrada:
  \[
  \frac{\partial E}{\partial w_{ij}}
  =
  \sum_n
  \delta_j^{(n)} \por x_i^{(n)}
  \]

  Actualización:
  \[
  w_{ij}
  \leftarrow
  w_{ij}
  - \eta
  \sum_n
  \delta_j^{(n)} \por x_i^{(n)}
  \]
\end{frame}

\begin{frame}[fragile]
  \frametitle{Resumen: algoritmo de retropropagación}

  Para cada instancia \(n\):

  \begin{enumerate}
  \item Propagación hacia delante:
    calcular \(h_j^{(n)}\), luego \(y_k^{(n)}\).
  \item Calcular errores en salida:
    \(\delta_k^{(n)}\).
  \item Propagar errores hacia atrás:
    \(\delta_j^{(n)}\).
  \item Actualizar pesos:
    \(v_{jk}\), luego \(w_{ij}\).
  \end{enumerate}

  Es un descenso por gradiente aplicado \\mediante
  regla de la cadena.
\end{frame}

\begin{frame}[fragile]
  \frametitle{Descenso por gradiente vs BFGS (lo que usa \texttt{nnet})}

  Sean \(E(\mathbf{w})\) la función de error y
  \(\nabla E(\mathbf{w})\) su gradiente.

  Sea \(t\) el índice de iteración.

  \vspace{2mm}

  \textbf{1. Descenso por gradiente clásico}

  \[
  \mathbf{w}^{(t+1)}
  =
  \mathbf{w}^{(t)}
  -
  \eta
  \nabla E\!\left(\mathbf{w}^{(t)}\right)
  \]

  \begin{itemize}
  \item \(\eta>0\) tasa de aprendizaje explícita.
  \item Dirección: gradiente negativo.
  \item Convergencia lineal.
  \item Sensible a la elección de \(\eta\).
  \end{itemize}

\end{frame}

\begin{frame}[fragile]
  \frametitle{Descenso por gradiente vs BFGS (lo que usa \texttt{nnet})}

  \vspace{3mm}

  \textbf{2. BFGS (cuasi-Newton)}

  \[
  \mathbf{w}^{(t+1)}
  =
  \mathbf{w}^{(t)}
  -
  H_t^{-1}
  \nabla E\!\left(\mathbf{w}^{(t)}\right)
  \]

  donde \(H_t^{-1}\) aproxima la inversa del Hessiano.

  \begin{itemize}
  \item No hay parámetro \(\eta\) explícito.
  \item Dirección adaptativa usando curvatura.
  \item Búsqueda en línea interna para el tamaño de paso.
  \item Convergencia superlineal (en condiciones regulares).
  \end{itemize}

\end{frame}

\begin{frame}[fragile]
  \frametitle{¿Qué implementa \texttt{nnet} en R?}

  Paquete: \texttt{nnet}

  \vspace{2mm}

  \begin{itemize}
  \item Optimización mediante algoritmo BFGS.
  \item Minimiza directamente la entropía o la SCE.
  \item El tamaño del paso se determina por búsqueda en línea.
  \item No existe parámetro de tasa de aprendizaje \(\eta\).
  \item El argumento \texttt{decay} implementa regularización:
  \[
  E_{\mathrm{reg}}
  =
  E + \lambda \sum w^2
  \]
  \end{itemize}

  \vspace{3mm}

  Por tanto:

  \[
  \texttt{nnet}
  \quad \neq \quad
  \text{descenso por gradiente con tasa fija}
  \]

  Es un método cuasi-Newton determinista,
  adecuado para redes pequeñas y medianas.
\end{frame}

\begin{frame}[fragile]
  \frametitle{Búsqueda en línea: condición de Armijo}

  Sea \(E(\mathbf{w})\) diferenciable y
  \(\mathbf{d}_t\) una dirección de descenso:

  \[
  \nabla E(\mathbf{w}^{(t)})^{\!\top}\mathbf{d}_t < 0
  \]

  Se actualiza:

  \[
  \mathbf{w}^{(t+1)}
  =
  \mathbf{w}^{(t)}
  +
  \alpha_t \mathbf{d}_t
  \]

  \vspace{2mm}

  \textbf{Condición de Armijo (suficiente descenso)}

  Dado \(c \in (0,1)\), se busca \(\alpha_t>0\) tal que:

  \[
  E(\mathbf{w}^{(t)} + \alpha_t \mathbf{d}_t)
  \le
  E(\mathbf{w}^{(t)})
  +
  c \alpha_t
  \nabla E(\mathbf{w}^{(t)})^{\!\top}\mathbf{d}_t
  \]

  \vspace{2mm}

  Interpretación:
  el descenso real debe ser proporcional
  al descenso lineal predicho por el gradiente.
\end{frame}

\begin{frame}[fragile]
  \frametitle{Búsqueda en línea: \it backtracking}

  Procedimiento típico:

  \begin{enumerate}
  \item Fijar \(\alpha = \alpha_0\) (p.ej. 1).
  \item Mientras no se cumpla Armijo:
    \[
    \alpha \leftarrow \rho \alpha,
    \qquad \rho \in (0,1)
    \]
  \item Tomar \(\alpha_t = \alpha\).
  \end{enumerate}

  \vspace{2mm}

  Propiedades:

  \begin{itemize}
  \item Garantiza descenso.
  \item Evita pasos excesivos.
  \item Compatible con descenso por gradiente y BFGS.
  \end{itemize}
\end{frame}

\section{Anexo: Hiperparámetros}

\begin{frame}[plain]
  \title{Anexo: Hiperparámetros}\author{}\date{}
  \titlepage
\end{frame}

\begin{frame}[fragile]
<<>>=
library(e1071) # para tune
tune(lm, mpg~., data=mtcars, # CV para lm
     tunecontrol=tune.control(cross=32))
library(rpart) # para rpart
tune(rpart, mpg~., data=mtcars,
     ranges=list(minsplit=c(5,10)))
@ 
\end{frame}

\begin{frame}[fragile]
<<>>=
library(nnet) # para nnet
tune(nnet, mpg~., data=mtcars,
     linout=TRUE, trace=FALSE,
     ranges=list(size=c(2,10), decay=.1^(1:2)))
@ 
\end{frame}

\begin{frame}[fragile]
<<>>=
library(caret, quietly=TRUE)
salida <- capture.output(
 res <- train(mpg ~ ., data=mtcars, method="nnet",
         trControl = trainControl("repeatedcv",32),
         tuneGrid = expand.grid(size=c(2,10),
                                decay=c(.1,.01))))
names(res)
@ 
\end{frame}

\begin{frame}[fragile]\footnotesize
<<>>=
res
@ 
\end{frame}

\end{document}

% ## ejemplo de que la expresión suma(p.ln(p)+(1-p).ln(1-p)) no es válida:


% ## R version 4.3.3 (2024-02-29) -- "Angel Food Cake"
% ## Copyright (C) 2024 The R Foundation for Statistical Computing
% ## Platform: x86_64-pc-linux-gnu (64-bit)

% ## R es un software libre y viene sin GARANTIA ALGUNA.
% ## Usted puede redistribuirlo bajo ciertas circunstancias.
% ## Escriba 'license()' o 'licence()' para detalles de distribucion.

% ## R es un proyecto colaborativo con muchos contribuyentes.
% ## Escriba 'contributors()' para obtener más información y
% ## 'citation()' para saber cómo citar R o paquetes de R en publicaciones.

% ## Escriba 'demo()' para demostraciones, 'help()' para el sistema on-line de ayuda,
% ## o 'help.start()' para abrir el sistema de ayuda HTML con su navegador.
% ## Escriba 'q()' para salir de R.

% ## > setwd('/tmp/')
% ## > library(nnet)
% ## > red2 <- nnet (factor(am)~mpg, mtcars, size=0, skip=TRUE, trace=FALSE)
% ## > p <- red2 $ fitted.values
% ## > p
% ##                           [,1]
% ## Mazda RX4           0.46108985
% ## Mazda RX4 Wag       0.46108985
% ## Datsun 710          0.59789043
% ## Hornet 4 Drive      0.49171393
% ## Hornet Sportabout   0.29689962
% ## Valiant             0.25993267
% ## Duster 360          0.09858910
% ## Merc 240D           0.70846021
% ## Merc 230            0.59789043
% ## Merc 280            0.32990942
% ## Merc 280C           0.24260965
% ## Merc 450SE          0.17246527
% ## Merc 450SL          0.21552534
% ## Merc 450SLC         0.12601293
% ## Cadillac Fleetwood  0.03197249
% ## Lincoln Continental 0.03197249
% ## Chrysler Imperial   0.11005378
% ## Fiat 128            0.96591077
% ## Honda Civic         0.93877653
% ## Toyota Corolla      0.97821744
% ## Toyota Corona       0.49938871
% ## Dodge Challenger    0.13651116
% ## AMC Javelin         0.12601293
% ## Camaro Z28          0.07446642
% ## Pontiac Firebird    0.32990942
% ## Fiat X1-9           0.85548435
% ## Porsche 914-2       0.79885476
% ## Lotus Europa        0.93877653
% ## Ford Pantera L      0.14773616
% ## Ferrari Dino        0.36468569
% ## Maserati Bora       0.11940409
% ## Volvo 142E          0.49171393
% ## > predict(red2,type="class")
% ##  [1] "0" "0" "1" "0" "0" "0" "0" "1" "1" "0" "0" "0" "0" "0" "0" "0" "0" "1" "1"
% ## [20] "1" "0" "0" "0" "0" "0" "1" "1" "1" "0" "0" "0" "0"
% ## > mtcars$am
% ##  [1] 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 1 1 1 1 1 1 1
% ## > table(real=mtcars$am, pred=predict(red2,type="class"))
% ##     pred
% ## real  0  1
% ##    0 17  2
% ##    1  6  7
% ## > - sum (p * log(p) + (1-p) * log(1-p))
% ## [1] 14.83771
% ## > red2$value
% ## [1] 14.83758
% ## > t <- +(mtcars$am == mtcars$am[1])
% ## > n0 <- function (x) ifelse (is.na(x), 0, x)
% ## > sum (n0(t*log(t/p)) + n0((1-t)*log((1-t)/(1-p))))
% ## [1] 14.83758
% ## >


% ## - sum (p * log(p) + (1-p) * log(1-p)) #entropía
% ## @ 
% ## \end{frame}

% ## \begin{frame} [fragile]
% ##   \frametitle{Respuesta dicótoma}
% ## <<>>=
% ## p <- red2 $ fitted.values             #una sola columna
% ## - sum (p * log(p) + (1-p) * log(1-p)) #entropía
% ## ## equivale a 
