704 lines
364 KiB
Plaintext
704 lines
364 KiB
Plaintext
{
|
||
"cells": [
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "d8uIS7qdD2Y3"
|
||
},
|
||
"source": [
|
||
"# Tarea 4 — Inferencia (Forward Propagation) en Redes Neuronales\n",
|
||
"\n",
|
||
"En esta tarea vas a implementar la **inferencia** (*forward propagation*) de **tres redes neuronales distintas** usando **NumPy** y **multiplicación matricial**.\n",
|
||
"\n",
|
||
"Las tres son clasificadores **binarios**: tienen una **única neurona de salida con activación sigmoide** y usan **sigmoide** también en las capas ocultas.\n",
|
||
"\n",
|
||
"**Los pesos ya están entrenados y te los entregamos dibujados en el diagrama de cada red**: cada peso está anotado sobre su conexión (en amarillo) y cada *bias* junto a su neurona (`b=...`). Tu trabajo es **leer** esos valores del diagrama y programar el forward propagation.\n",
|
||
"\n",
|
||
"## Qué debes hacer en cada red\n",
|
||
"\n",
|
||
"1. **Transcribir** los pesos y biases del diagrama a arreglos de NumPy.\n",
|
||
"2. **Contar** el número total de parámetros de la red.\n",
|
||
"3. **Implementar** el forward propagation con multiplicación matricial.\n",
|
||
"4. **Probar** tu red con las entradas dadas y compararlas con el resultado esperado.\n",
|
||
"\n",
|
||
"> 💡 Aquí solo hacemos **inferencia**: los pesos ya están dados, **no** hay entrenamiento."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "JsBA_RlXD2Y8"
|
||
},
|
||
"source": [
|
||
"## Repaso: producto punto y multiplicación matricial\n",
|
||
"\n",
|
||
"Una neurona toma un vector de entrada $\\vec{a}_{in}$, lo combina con su vector de pesos $\\vec{w}_j$ y su bias $b_j$, y aplica la activación $g$ (aquí, la sigmoide):\n",
|
||
"\n",
|
||
"$$a_j = g\\!\\left(\\vec{w}_j \\cdot \\vec{a}_{in} + b_j\\right)$$\n",
|
||
"\n",
|
||
"donde $\\vec{w}_j \\cdot \\vec{a}_{in} = \\sum_i w_{ij}\\,a_i$ es el **producto punto**.\n",
|
||
"\n",
|
||
"💡 **Relación clave (multiplicación matricial ↔ producto punto).** Calcular **todas** las neuronas de una capa a la vez es una **multiplicación matricial**:\n",
|
||
"\n",
|
||
"$$\\vec{z} = \\vec{a}_{in}\\,W + \\vec{b}, \\qquad \\vec{a} = g(\\vec{z})$$\n",
|
||
"\n",
|
||
"Cada elemento del resultado es **exactamente un producto punto**: la entrada $\\vec{a}_{in}$ por una **columna** de $W$ (los pesos de una neurona). Es decir, **una multiplicación matricial es muchos productos punto calculados de una sola vez**. Por eso en NumPy `a_in @ W` (o np.matmul) calcula toda la capa con una sola operación.\n",
|
||
"\n",
|
||
"**Convención de formas** (importante para transcribir):\n",
|
||
"\n",
|
||
"- $W$ tiene forma `(n_entradas, n_neuronas)` → la **columna $j$** son los pesos de la neurona $j$.\n",
|
||
"- $\\vec{b}$ tiene forma `(n_neuronas,)`.\n",
|
||
"\n",
|
||
"Forward propagation = aplicar esto **capa por capa**: $\\vec{a}_{in} \\to \\vec{a}^{[1]} \\to \\vec{a}^{[2]} \\to \\cdots \\to \\hat{y}$.\n",
|
||
"\n",
|
||
"**Cómo leer el diagrama:** el número amarillo sobre cada conexión es $w_{ij}$ (de la entrada/neurona $i$ hacia la neurona $j$); el valor `b=...` debajo de cada neurona es su bias. Para una misma neurona de origen, las etiquetas van ordenadas de la neurona destino más cercana ($j=1$) a la más lejana."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 15,
|
||
"metadata": {
|
||
"id": "yR6x7yT3D2Y9"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Listo. sigmoid(0) = 0.5\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"import numpy as np\n",
|
||
"\n",
|
||
"# La funcion de activacion sigmoide ya esta implementada (NO la modifiques).\n",
|
||
"def sigmoid(z):\n",
|
||
" z = np.clip(z, -500, 500) # estabilidad numerica\n",
|
||
" return 1 / (1 + np.exp(-z))\n",
|
||
"\n",
|
||
"print(\"Listo. sigmoid(0) =\", sigmoid(0.0))"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "0ubNbYhhD2ZA"
|
||
},
|
||
"source": [
|
||
"## Ejercicio 0 — La función `dense` (una capa)\n",
|
||
"\n",
|
||
"Implementa **una sola vez** la función `dense`, que calcula **una capa completa** con multiplicación matricial y activación sigmoide. La reutilizarás en las tres redes.\n",
|
||
"\n",
|
||
"$$\\vec{a}_{out} = g\\!\\left(\\vec{a}_{in}\\,W + \\vec{b}\\right)$$\n",
|
||
"\n",
|
||
"Recuerda: `a_in @ W` es la multiplicación matricial; cada elemento de su resultado es el producto punto de `a_in` con una columna de `W`."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 16,
|
||
"metadata": {
|
||
"id": "WcXI0Mt2D2ZB"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"[0.73105858 0.88079708 0.95257413]\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"def dense(a_in, W, b):\n",
|
||
" \"\"\"Calcula UNA capa: a_in (n_in,) -> a_out (n_neuronas,).\n",
|
||
" Debe usar multiplicacion matricial: sigmoid(a_in @ W + b).\"\"\"\n",
|
||
" # a_out = None\n",
|
||
" # YOUR CODE HERE\n",
|
||
" a_out = sigmoid(a_in @ W + b) # a_in @ W = un producto punto por cada neurona (columna de W)\n",
|
||
" #\n",
|
||
" return a_out\n",
|
||
"\n",
|
||
"# Prueba rapida (NO la cambies): una capa de 2 entradas -> 3 neuronas\n",
|
||
"W_test = np.array([[1.0, 0.0, -1.0],\n",
|
||
" [0.0, 1.0, 2.0]])\n",
|
||
"b_test = np.array([0.0, 0.0, 0.0])\n",
|
||
"print(dense(np.array([1.0, 2.0]), W_test, b_test))\n",
|
||
"# Deberias obtener aprox: [0.731 0.881 0.953]"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "-cicgOk9D2ZB"
|
||
},
|
||
"source": [
|
||
"---\n",
|
||
"\n",
|
||
"## Red A — ¿Aprueba el examen? (2 → 2 → 1)\n",
|
||
"\n",
|
||
"Predice si un estudiante **aprueba** un examen a partir de:\n",
|
||
"\n",
|
||
"- $x_1$: horas de **estudio**\n",
|
||
"- $x_2$: horas de **sueño**\n",
|
||
"\n",
|
||
"Arquitectura: **2 entradas → 1 capa oculta de 2 neuronas → 1 salida**. Los pesos están en el diagrama:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "QuZLxur6D2ZC"
|
||
},
|
||
"source": [
|
||
""
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "cXOBWGZYD2ZE"
|
||
},
|
||
"source": [
|
||
"### A.1 — Transcribe los pesos\n",
|
||
"\n",
|
||
"Lee el diagrama y crea los arreglos. `A_W1` tiene forma `(2, 2)`; `A_W2` tiene forma `(2, 1)`."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 17,
|
||
"metadata": {
|
||
"id": "ETBJ8ytuD2ZF"
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"# Capa oculta: 2 entradas -> 2 neuronas\n",
|
||
"# A_W1 = None # forma (2, 2) # YOUR CODE HERE\n",
|
||
"A_W1 = np.array([[ 1.0, -1.5], # fila = entrada x1: x1->a1=+1.0 , x1->a2=-1.5\n",
|
||
" [ 0.5, 2.0]]) # fila = entrada x2: x2->a1=+0.5 , x2->a2=+2.0\n",
|
||
"# A_b1 = None # forma (2,)\n",
|
||
"A_b1 = np.array([-1.0, -2.0]) # bias de a1 y a2\n",
|
||
"# Capa de salida: 2 -> 1\n",
|
||
"# A_W2 = None # forma (2, 1) # YOUR CODE HERE\n",
|
||
"A_W2 = np.array([[ 2.0], # a1 -> y = +2.0\n",
|
||
" [-1.5]]) # a2 -> y = -1.5\n",
|
||
"# A_b2 = None # forma (1,)\n",
|
||
"A_b2 = np.array([-1.0]) # bias de la salida"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "KbJOlRACD2ZG"
|
||
},
|
||
"source": [
|
||
"### A.2 — Número de parámetros\n",
|
||
"\n",
|
||
"Calcula el total de parámetros = (todos los pesos) + (todos los biases). Pista: `W.size` te da cuántos números tiene una matriz."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 18,
|
||
"metadata": {
|
||
"id": "Z1jm22PGD2ZG"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Parametros Red A: 9\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"# A_n_params = None # YOUR CODE HERE\n",
|
||
"A_n_params = A_W1.size + A_b1.size + A_W2.size + A_b2.size\n",
|
||
"print(\"Parametros Red A:\", A_n_params)\n",
|
||
"# Deberias obtener: 9"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "7G_RimX_D2ZH"
|
||
},
|
||
"source": [
|
||
"### A.3 — Forward propagation\n",
|
||
"\n",
|
||
"Encadena `dense` capa por capa. La Red A tiene **2 capas**: $\\vec{a}^{[1]} \\to \\hat{y}$."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 19,
|
||
"metadata": {
|
||
"id": "vdTChhgbD2ZH"
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"def forward_A(x):\n",
|
||
" \"\"\"x: arreglo (2,) -> probabilidad de aprobar.\"\"\"\n",
|
||
" # YOUR CODE HERE: usa dense con (A_W1, A_b1) y luego con (A_W2, A_b2)\n",
|
||
" # y = None\n",
|
||
" a1 = dense(x, A_W1, A_b1) # capa oculta: (2,) -> (2,)\n",
|
||
" y = dense(a1, A_W2, A_b2) # capa salida: (2,) -> (1,)\n",
|
||
" return y"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "XKY-nFj0D2ZH"
|
||
},
|
||
"source": [
|
||
"### A.4 — Prueba tu red"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 20,
|
||
"metadata": {
|
||
"id": "uRgEIspsD2ZJ"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"estudio=2 sueno=6 -> p=0.3694\n",
|
||
"estudio=5 sueno=5 -> p=0.5158\n",
|
||
"estudio=8 sueno=1 -> p=0.7308\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"/tmp/ipykernel_102539/2121402088.py:3: DeprecationWarning: Conversion of an array with ndim > 0 to a scalar is deprecated, and will error in future. Ensure you extract a single element from your array before performing this operation. (Deprecated NumPy 1.25.)\n",
|
||
" print(f\"estudio={x[0]} sueno={x[1]} -> p={float(p):.4f}\")\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"for x in [[2, 6], [5, 5], [8, 1]]:\n",
|
||
" p = forward_A(np.array(x, dtype=float))\n",
|
||
" print(f\"estudio={x[0]} sueno={x[1]} -> p={float(p):.4f}\")\n",
|
||
"\n",
|
||
"# Deberias obtener aprox:\n",
|
||
"# estudio=2 sueno=6 -> p=0.3694 (no aprueba)\n",
|
||
"# estudio=5 sueno=5 -> p=0.5158 (apenas aprueba)\n",
|
||
"# estudio=8 sueno=1 -> p=0.7308 (aprueba)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "zyR0m35KD2ZK"
|
||
},
|
||
"source": [
|
||
"---\n",
|
||
"\n",
|
||
"## Red B — ¿El correo es spam? (3 → 4 → 2 → 1)\n",
|
||
"\n",
|
||
"Clasifica un correo como **spam** (1) o no (0) a partir de:\n",
|
||
"\n",
|
||
"- $x_1$: número de **enlaces**\n",
|
||
"- $x_2$: número de palabras en **MAYÚSCULAS**\n",
|
||
"- $x_3$: menciones de **dinero/premios**\n",
|
||
"\n",
|
||
"Arquitectura: **3 entradas → oculta de 4 → oculta de 2 → 1 salida**. Lee los pesos:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "zA-RPF_KD2ZK"
|
||
},
|
||
"source": [
|
||
""
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "Ott8ugrKD2ZN"
|
||
},
|
||
"source": [
|
||
"### B.1 — Transcribe los pesos\n",
|
||
"\n",
|
||
"Formas: `B_W1` `(3, 4)`, `B_b1` `(4,)`, `B_W2` `(4, 2)`, `B_b2` `(2,)`, `B_W3` `(2, 1)`, `B_b3` `(1,)`."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 21,
|
||
"metadata": {
|
||
"id": "s0-Ly5aID2ZN"
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"# Capa oculta 1: 3 entradas -> 4 neuronas\n",
|
||
"# B_W1 = None # forma (3, 4) # YOUR CODE HERE\n",
|
||
"B_W1 = np.array([[ 0.5, -1.0, 2.0, 0.3], # x1 -> a1,a2,a3,a4\n",
|
||
" [-1.5, 0.8, -0.5, 1.0], # x2 -> a1,a2,a3,a4\n",
|
||
" [ 1.0, 0.4, -2.0, -0.6]]) # x3 -> a1,a2,a3,a4\n",
|
||
"# B_b1 = None # forma (4,)\n",
|
||
"B_b1 = np.array([-0.5, 1.0, 0.2, -1.0])\n",
|
||
"# Capa oculta 2: 4 -> 2\n",
|
||
"# B_W2 = None # forma (4, 2) # YOUR CODE HERE\n",
|
||
"B_W2 = np.array([[ 1.0, -0.5], # a1 -> A1,A2\n",
|
||
" [-2.0, 1.5], # a2 -> A1,A2\n",
|
||
" [ 0.6, 0.9], # a3 -> A1,A2\n",
|
||
" [-1.0, -0.4]]) # a4 -> A1,A2\n",
|
||
"# B_b2 = None # forma (2,)\n",
|
||
"B_b2 = np.array([0.3, -0.7])\n",
|
||
"# Capa de salida: 2 -> 1\n",
|
||
"# B_W3 = None # forma (2, 1) # YOUR CODE HERE\n",
|
||
"B_W3 = np.array([[ 2.0], # A1 -> y\n",
|
||
" [-1.8]]) # A2 -> y\n",
|
||
"# B_b3 = None # forma (1,)\n",
|
||
"B_b3 = np.array([-0.2])"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "qwoABh6fD2ZN"
|
||
},
|
||
"source": [
|
||
"### B.2 — Número de parámetros"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 22,
|
||
"metadata": {
|
||
"id": "2SflR0JmD2ZN"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Parametros Red B: 29\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"# B_n_params = None # YOUR CODE HERE\n",
|
||
"B_n_params = B_W1.size + B_b1.size + B_W2.size + B_b2.size + B_W3.size + B_b3.size\n",
|
||
"print(\"Parametros Red B:\", B_n_params)\n",
|
||
"# Deberias obtener: 29"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "yq6uljKVD2ZN"
|
||
},
|
||
"source": [
|
||
"### B.3 — Forward propagation\n",
|
||
"\n",
|
||
"La Red B tiene **3 capas**: $\\vec{a}^{[1]} \\to \\vec{a}^{[2]} \\to \\hat{y}$."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 23,
|
||
"metadata": {
|
||
"id": "3bWYYk5HD2ZN"
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"def forward_B(x):\n",
|
||
" \"\"\"x: arreglo (3,) -> probabilidad de spam.\"\"\"\n",
|
||
" # YOUR CODE HERE: encadena dense tres veces\n",
|
||
" # y = None\n",
|
||
" a1 = dense(x, B_W1, B_b1) # (3,) -> (4,)\n",
|
||
" a2 = dense(a1, B_W2, B_b2) # (4,) -> (2,)\n",
|
||
" y = dense(a2, B_W3, B_b3) # (2,) -> (1,)\n",
|
||
" return y"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "aYJbOwjTD2ZN"
|
||
},
|
||
"source": [
|
||
"### B.4 — Prueba tu red"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 24,
|
||
"metadata": {
|
||
"id": "szqEdHdID2ZN"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"enlaces=1 mayus=3 dinero=0 -> p=0.2226\n",
|
||
"enlaces=2 mayus=1 dinero=1 -> p=0.3922\n",
|
||
"enlaces=3 mayus=0 dinero=2 -> p=0.6114\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"/tmp/ipykernel_102539/2199352188.py:3: DeprecationWarning: Conversion of an array with ndim > 0 to a scalar is deprecated, and will error in future. Ensure you extract a single element from your array before performing this operation. (Deprecated NumPy 1.25.)\n",
|
||
" print(f\"enlaces={x[0]} mayus={x[1]} dinero={x[2]} -> p={float(p):.4f}\")\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"for x in [[1, 3, 0], [2, 1, 1], [3, 0, 2]]:\n",
|
||
" p = forward_B(np.array(x, dtype=float))\n",
|
||
" print(f\"enlaces={x[0]} mayus={x[1]} dinero={x[2]} -> p={float(p):.4f}\")\n",
|
||
"\n",
|
||
"# Deberias obtener aprox:\n",
|
||
"# enlaces=1 mayus=3 dinero=0 -> p=0.2226 (no spam)\n",
|
||
"# enlaces=2 mayus=1 dinero=1 -> p=0.3922 (no spam)\n",
|
||
"# enlaces=3 mayus=0 dinero=2 -> p=0.6114 (spam)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "GQ21r6ZRD2ZN"
|
||
},
|
||
"source": [
|
||
"---\n",
|
||
"\n",
|
||
"## Red C — ¿Transacción fraudulenta? (4 → 3 → 3 → 2 → 1)\n",
|
||
"\n",
|
||
"Detecta si una transacción con tarjeta es **fraude** (1) o no (0) a partir de:\n",
|
||
"\n",
|
||
"- $x_1$: **monto** (en miles)\n",
|
||
"- $x_2$: **hora** del día (0–3, codificada)\n",
|
||
"- $x_3$: número de **transacciones recientes**\n",
|
||
"- $x_4$: **distancia** al domicilio\n",
|
||
"\n",
|
||
"Arquitectura: **4 entradas → oculta de 3 → oculta de 3 → oculta de 2 → 1 salida**. Lee los pesos:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "J4KlbSo5D2ZN"
|
||
},
|
||
"source": [
|
||
""
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "LmAlxqXJD2ZP"
|
||
},
|
||
"source": [
|
||
"### C.1 — Transcribe los pesos\n",
|
||
"\n",
|
||
"Formas: `C_W1` `(4, 3)`, `C_b1` `(3,)`, `C_W2` `(3, 3)`, `C_b2` `(3,)`, `C_W3` `(3, 2)`, `C_b3` `(2,)`, `C_W4` `(2, 1)`, `C_b4` `(1,)`."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 25,
|
||
"metadata": {
|
||
"id": "ovXNmsTLD2ZQ"
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"# Capa oculta 1: 4 entradas -> 3 neuronas\n",
|
||
"# C_W1 = None # forma (4, 3) # YOUR CODE HERE\n",
|
||
"C_W1 = np.array([[ 0.8, -1.0, 0.5], # x1 -> a1,a2,a3\n",
|
||
" [-0.6, 1.2, 0.3], # x2 -> a1,a2,a3\n",
|
||
" [ 1.0, -0.4, -1.5], # x3 -> a1,a2,a3\n",
|
||
" [ 0.2, 0.7, 1.0]]) # x4 -> a1,a2,a3\n",
|
||
"# C_b1 = None # forma (3,)\n",
|
||
"C_b1 = np.array([-0.5, 0.4, 1.0])\n",
|
||
"# Capa oculta 2: 3 -> 3\n",
|
||
"# C_W2 = None # forma (3, 3) # YOUR CODE HERE\n",
|
||
"C_W2 = np.array([[ 1.5, -0.8, 0.6], # a1 -> b1,b2,b3\n",
|
||
" [-1.0, 1.0, -0.5], # a2 -> b1,b2,b3\n",
|
||
" [ 0.4, 1.2, -1.4]]) # a3 -> b1,b2,b3\n",
|
||
"# C_b2 = None # forma (3,)\n",
|
||
"C_b2 = np.array([0.2, -1.0, 0.5])\n",
|
||
"# Capa oculta 3: 3 -> 2\n",
|
||
"# C_W3 = None # forma (3, 2) # YOUR CODE HERE\n",
|
||
"C_W3 = np.array([[ 1.0, -1.2], # b1 -> c1,c2\n",
|
||
" [-0.7, 0.9], # b2 -> c1,c2\n",
|
||
" [ 1.4, 0.5]]) # b3 -> c1,c2\n",
|
||
"# C_b3 = None # forma (2,)\n",
|
||
"C_b3 = np.array([-0.3, 0.6])\n",
|
||
"# Capa de salida: 2 -> 1\n",
|
||
"# C_W4 = None # forma (2, 1) # YOUR CODE HERE\n",
|
||
"C_W4 = np.array([[ 1.8], # c1 -> y\n",
|
||
" [-2.0]]) # c2 -> y\n",
|
||
"# C_b4 = None # forma (1,)\n",
|
||
"C_b4 = np.array([0.1])"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "CWvJkM_RD2ZQ"
|
||
},
|
||
"source": [
|
||
"### C.2 — Número de parámetros"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 26,
|
||
"metadata": {
|
||
"id": "w0YU6Gv6D2ZQ"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Parametros Red C: 38\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"# C_n_params = None # YOUR CODE HERE\n",
|
||
"C_n_params = (C_W1.size + C_b1.size + C_W2.size + C_b2.size +\n",
|
||
" C_W3.size + C_b3.size + C_W4.size + C_b4.size)\n",
|
||
"print(\"Parametros Red C:\", C_n_params)\n",
|
||
"# Deberias obtener: 38"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "AHnYVtRLD2ZQ"
|
||
},
|
||
"source": [
|
||
"### C.3 — Forward propagation\n",
|
||
"\n",
|
||
"La Red C tiene **4 capas**: $\\vec{a}^{[1]} \\to \\vec{a}^{[2]} \\to \\vec{a}^{[3]} \\to \\hat{y}$."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 27,
|
||
"metadata": {
|
||
"id": "ab9Qwn3HD2ZQ"
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"def forward_C(x):\n",
|
||
" \"\"\"x: arreglo (4,) -> probabilidad de fraude.\"\"\"\n",
|
||
" # YOUR CODE HERE: encadena dense cuatro veces\n",
|
||
" # y = None\n",
|
||
" a1 = dense(x, C_W1, C_b1) # (4,) -> (3,)\n",
|
||
" a2 = dense(a1, C_W2, C_b2) # (3,) -> (3,)\n",
|
||
" a3 = dense(a2, C_W3, C_b3) # (3,) -> (2,)\n",
|
||
" y = dense(a3, C_W4, C_b4) # (2,) -> (1,)\n",
|
||
" return y"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "VxHdwgSwD2ZQ"
|
||
},
|
||
"source": [
|
||
"### C.4 — Prueba tu red"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 28,
|
||
"metadata": {
|
||
"id": "OGn-edBED2ZQ"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"x=[0, 3, 0, 1] -> p=0.3936\n",
|
||
"x=[1, 1, 1, 1] -> p=0.5109\n",
|
||
"x=[3, 0, 3, 0] -> p=0.6247\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"/tmp/ipykernel_102539/2859525198.py:3: DeprecationWarning: Conversion of an array with ndim > 0 to a scalar is deprecated, and will error in future. Ensure you extract a single element from your array before performing this operation. (Deprecated NumPy 1.25.)\n",
|
||
" print(f\"x={x} -> p={float(p):.4f}\")\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"for x in [[0, 3, 0, 1], [1, 1, 1, 1], [3, 0, 3, 0]]:\n",
|
||
" p = forward_C(np.array(x, dtype=float))\n",
|
||
" print(f\"x={x} -> p={float(p):.4f}\")\n",
|
||
"\n",
|
||
"# Deberias obtener aprox:\n",
|
||
"# x=[0, 3, 0, 1] -> p=0.3936 (no fraude)\n",
|
||
"# x=[1, 1, 1, 1] -> p=0.5109 (frontera)\n",
|
||
"# x=[3, 0, 3, 0] -> p=0.6247 (fraude)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "vgKGwLR_D2ZQ"
|
||
},
|
||
"source": [
|
||
"---\n",
|
||
"\n",
|
||
"## ¡Felicidades! 🎉\n",
|
||
"\n",
|
||
"Implementaste la **inferencia** (forward propagation) de tres redes neuronales de distinto tamaño, usando solo **NumPy** y **multiplicación matricial**:\n",
|
||
"\n",
|
||
"- Leíste los pesos directamente del **diagrama** de cada red.\n",
|
||
"- Contaste sus **parámetros** (9, 29 y 38).\n",
|
||
"- Encadenaste la función `dense` **capa por capa**.\n",
|
||
"\n",
|
||
"**Idea clave:** sin importar cuántas entradas, capas o neuronas tenga la red, la inferencia es siempre lo mismo — propagar la entrada hacia adelante con una **multiplicación matricial por capa** (que no es más que muchos **productos punto** a la vez) seguida de la activación. El **entrenamiento** —encontrar esos pesos— es el tema de la siguiente unidad.\n",
|
||
"\n",
|
||
"*Material de Universidad Galileo / adaptado de DeepLearning.AI (CC BY-SA 2.0).*"
|
||
]
|
||
}
|
||
],
|
||
"metadata": {
|
||
"colab": {
|
||
"provenance": []
|
||
},
|
||
"kernelspec": {
|
||
"display_name": "Python 3",
|
||
"language": "python",
|
||
"name": "python3"
|
||
},
|
||
"language_info": {
|
||
"codemirror_mode": {
|
||
"name": "ipython",
|
||
"version": 3
|
||
},
|
||
"file_extension": ".py",
|
||
"mimetype": "text/x-python",
|
||
"name": "python",
|
||
"nbconvert_exporter": "python",
|
||
"pygments_lexer": "ipython3",
|
||
"version": "3.10.12"
|
||
}
|
||
},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 0
|
||
}
|