grx-tensor 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.es.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  **Ruby habla. C calcula.**
4
4
 
5
- Un framework de tensores para Ruby con diferenciacion automatica (autograd), un nucleo de computo en C con instrucciones vectoriales SIMD, y primitivas completas para redes neuronales, todo respaldado por una API de Ruby limpia y expresiva.
5
+ Un framework de computacion cientifica, procesamiento tensorial multidimensional y Deep Learning de alto rendimiento para Ruby. Cuenta con diferenciacion automatica (Autograd), aceleracion de hardware multi-target SIMD dinamica (AVX2+FMA, SSE y escalar C portable), y primitivas completas para redes neuronales, todo respaldado por una API de Ruby limpia, intuitiva y expresiva.
6
6
 
7
7
  [![Ruby](https://img.shields.io/badge/ruby-%3E%3D%203.0-CC342D?logo=ruby)](https://www.ruby-lang.org)
8
8
  [![Licencia: MIT](https://img.shields.io/badge/license-MIT-blue)](LICENSE.txt)
@@ -10,261 +10,1190 @@ Un framework de tensores para Ruby con diferenciacion automatica (autograd), un
10
10
 
11
11
  ---
12
12
 
13
- ## Que es GRX?
13
+ ## Flujo Arquitectonico del Sistema
14
14
 
15
- GRX es una biblioteca de computacion tensorial de alto rendimiento para Ruby. Su nucleo numerico esta implementado en C y compilado con extensiones **AVX2 + FMA** SIMD — procesando 4 numeros de punto flotante de doble precision (doubles) por ciclo de reloj con multiplicacion-suma fusionada.
15
+ ```mermaid
16
+ flowchart TD
17
+ subgraph AppUsuario["Aplicacion del Usuario"]
18
+ A["require 'grx'"] --> B["GRX.tensor(datos, shape)"]
19
+ B --> C["Computacion Cientifica / Modelos de Machine Learning"]
20
+ C --> D["Bucles de Entrenamiento, Simulaciones e Inferencia"]
21
+ end
22
+
23
+ subgraph CapaRuby["Motor de Alto Nivel en Ruby"]
24
+ E["GRX::Tensor (Shape Multidimensional, Strides, Nodos del Grafo DAG)"]
25
+ F["GRX::NN (Linear, Embedding, LayerNorm, Dropout, BatchNorm1d)"]
26
+ G["GRX::Loss (CrossEntropy, MSE, BCE, Huber, MAE)"]
27
+ H["GRX::Optim (Adam con FMA, SGD con Momento)"]
28
+ I["GRX::Data (TensorDataset, DataLoader)"]
29
+ J["GRX::Serialization (Motor Binario .grx de Alta Velocidad)"]
30
+ end
31
+
32
+ subgraph SubsistemaFFI["Puente FFI y Memoria (Fiddle)"]
33
+ K["GRX::Storage (Punteros de Memoria Alineada / Finalizador GC)"]
34
+ L["GRX::CAPI (Despacho Dinamico de Simbolos Multi-Biblioteca)"]
35
+ end
36
+
37
+ subgraph NucleoNativo["Nucleo Nativo C (ext/grx/grx_core.c)"]
38
+ M{"grx_simd_level() Deteccion de Hardware"}
39
+ N["Motor AVX2 + FMA (4 doubles/ciclo, Multiply-Add Fusionado)"]
40
+ O["Motor SSE (2 doubles/ciclo, Math Vectorizado)"]
41
+ P["C Escalar Universal (Matematica IEEE 754 Portable)"]
42
+ end
43
+
44
+ subgraph Hardware["Capa de Hardware"]
45
+ Q["Memoria Heap Alineada a 32 Bytes"]
46
+ R["Cache Tiling L1/L2 (Bloques de Lineas de Cache de 64 Bytes)"]
47
+ end
16
48
 
17
- Ruby gestiona la interfaz de usuario de alto nivel: validacion de formas dimensionales (shapes), construccion del grafo de computacion y orquestacion. C maneja la memoria nativa y las operaciones aritmeticas pesadas.
49
+ AppUsuario --> CapaRuby
50
+ CapaRuby --> SubsistemaFFI
51
+ SubsistemaFFI --> NucleoNativo
52
+ M -- "CPU con AVX2+FMA" --> N
53
+ M -- "CPU con SSE2/SSE4" --> O
54
+ M -- "Generico / ARM / VM" --> P
55
+ N --> Hardware
56
+ O --> Hardware
57
+ P --> Hardware
58
+ ```
59
+
60
+ ---
18
61
 
19
- ### Caracteristicas clave
62
+ ## Compilacion Universal y Despacho Dinamico de Hardware
63
+
64
+ ```mermaid
65
+ flowchart TD
66
+ A["gem install grx-tensor"] --> B["Gestor de Paquetes RubyGems"]
67
+ B --> C["ext/grx/extconf.rb (mkmf)"]
68
+
69
+ C --> D1["Linux (GCC / Clang)"]
70
+ C --> D2["macOS (Clang / Apple LLVM)"]
71
+ C --> D3["Windows (RubyInstaller DevKit / MinGW-w64)"]
72
+
73
+ D1 --> E1["libgrx_core.so"]
74
+ D2 --> E2["libgrx_core.dylib"]
75
+ D3 --> E3["grx_core.dll"]
76
+
77
+ E1 --> F["Binario Multi-Target Universal"]
78
+ E2 --> F
79
+ E3 --> F
80
+
81
+ F --> G{"Deteccion de Instrucciones de CPU en Ejecucion"}
82
+ G -- "AVX2 + FMA Detectado" --> H["Ejecuta SIMD AVX2+FMA (Maxima Velocidad)"]
83
+ G -- "SSE2 Detectado" --> I["Ejecuta Kernels Vectorizados SSE"]
84
+ G -- "ARM / VM / CPU Antigua" --> J["Ejecuta C Escalar Seguro (Cero Fallos de Hardware)"]
85
+ ```
86
+
87
+ ---
88
+
89
+ ## Tabla de Contenido
90
+
91
+ 1. [Caracteristicas Principales](#caracteristicas-principales)
92
+ 2. [Instalacion](#instalacion)
93
+ 3. [Tutoriales Basicos de Inicio Rapido](#tutoriales-basicos-de-inicio-rapido)
94
+ - [1. Conversor de Grados Celsius a Fahrenheit](#1-conversor-de-grados-celsius-a-fahrenheit-1-neurona-aprende-f--18c--32)
95
+ - [2. Compuertas Logicas (AND y XOR)](#2-compuertas-logicas-and-lineal-vs-xor-no-lineal-con-relu-y-sigmoide)
96
+ - [3. Matematicas Tensoriales Cotidianas](#3-matematicas-tensoriales-cotidianas-en-4-lineas)
97
+ 4. [Manual de Referencia del API de Tensores](#manual-de-referencia-del-api-de-tensores)
98
+ 5. [Autograd y Motor de Diferenciacion](#autograd-y-motor-de-diferenciacion)
99
+ 6. [Computacion Cientifica y Numerica (Mas Alla del Deep Learning)](#computacion-cientifica-y-numerica-mas-alla-del-deep-learning)
100
+ - [A. Vision por Computadora y Filtrado de Imagenes (Convolucion Sobel)](#a-vision-por-computadora-y-filtrado-de-imagenes-convolucion-sobel)
101
+ - [B. Finanzas Cuantitativas y Matriz de Covarianza](#b-finanzas-cuantitativas-y-matriz-de-covarianza)
102
+ - [C. Fisica de Particulas y Simulacion N-Cuerpos](#c-fisica-de-particulas-y-simulacion-n-cuerpos)
103
+ - [D. Optimizacion Matematica Pura con Autograd (Funcion Rosenbrock)](#d-optimizacion-matematica-pura-con-autograd-funcion-rosenbrock)
104
+ 7. [Recetario de Deep Learning (10 Arquitecturas de Redes Neuronales)](#recetario-de-deep-learning-10-arquitecturas-de-redes-neuronales)
105
+ - [Arquitectura 1: Clasificador de Vision y Caracteres (BatchNorm + Dropout)](#arquitectura-1-clasificador-de-vision-y-caracteres-batchnorm--dropout)
106
+ - [Arquitectura 2: NLP y Chatbot de Intenciones (Embedding + LayerNorm)](#arquitectura-2-nlp-y-chatbot-de-intenciones-embedding--layernorm)
107
+ - [Arquitectura 3: Aprendizaje por Refuerzo (Agente Deep Q-Network DQN)](#arquitectura-3-aprendizaje-por-refuerzo-agente-deep-q-network-dqn)
108
+ - [Arquitectura 4: Pronostico No Lineal de Series Temporales Multivariables](#arquitectura-4-pronostico-no-lineal-de-series-temporales-multivariables)
109
+ - [Arquitectura 5: Autoencoder Profundo para Reduccion Dimensional y Deteccion de Anomalias](#arquitectura-5-autoencoder-profundo-para-reduccion-dimensional-y-deteccion-de-anomalias)
110
+ - [Arquitectura 6: Modelo Generador de Lenguaje y Siguiente Caracter Autoregresivo](#arquitectura-6-modelo-generador-de-lenguaje-y-siguiente-caracter-autoregresivo)
111
+ - [Arquitectura 7: Analisis de Sentimiento y Clasificacion de Resenas (BCELoss)](#arquitectura-7-analisis-de-sentimiento-y-clasificacion-de-resenas-bceloss)
112
+ - [Arquitectura 8: Red Neuronal Siamesa para Verificacion de Similitud y Firmas](#arquitectura-8-red-neuronal-siamesa-para-verificacion-de-similitud-y-firmas)
113
+ - [Arquitectura 9: Red Residual Profunda (Bloque ResNet MLP con Conexion Skip)](#arquitectura-9-red-residual-profunda-bloque-resnet-mlp-con-conexion-skip)
114
+ - [Arquitectura 10: Filtrado Colaborativo Neuronal y Sistema de Recomendacion](#arquitectura-10-filtrado-colaborativo-neuronal-y-sistema-de-recomendacion)
115
+ 8. [Funciones de Perdida (GRX::Loss)](#funciones-de-perdida-grxloss)
116
+ 9. [Guia de Notacion Cientifica y Parametros](#guia-de-notacion-cientifica-y-parametros)
117
+ - [1. Que significa la Notacion Cientifica en Machine Learning (1e-1 a 1e-8)?](#1-que-significa-la-notacion-cientifica-en-machine-learning-1e-1-a-1e-8)
118
+ - [2. Parametros de Capas Neuronales (GRX::NN)](#2-parametros-de-capas-neuronales-grxnn)
119
+ 10. [Catalogo de Optimizadores e Hiperparametros (GRX::Optim)](#catalogo-de-optimizadores-e-hiperparametros-grxoptim)
120
+ 11. [Pipelines de Datos y DataLoader (GRX::Data)](#pipelines-de-datos-y-dataloader-grxdata)
121
+ 12. [Persistencia de Modelos y Cerebros (Formato .grx)](#persistencia-de-modelos-y-cerebros-formato-grx)
122
+ - [Especificacion del Formato Binario GRX1](#especificacion-del-formato-binario-grx1)
123
+ - [Flujo de Despliegue de Inferencia en Produccion](#flujo-de-despliegue-de-inferencia-en-produccion)
124
+ 13. [Gestion de Gradientes y Utilidades (GRX::Utils)](#gestion-de-gradientes-y-utilidades-grxutils)
125
+ 14. [Guia de Soporte y Herramientas para Windows](#guia-de-soporte-y-herramientas-para-windows)
126
+ 15. [Licencia](#licencia)
127
+
128
+ ---
20
129
 
21
- | Caracteristica | Detalle |
130
+ ## Caracteristicas Principales
131
+
132
+ | Caracteristica | Especificacion |
22
133
  |---|---|
23
- | **Nucleo C+SIMD** | AVX2+FMA, soporte SSE2 y fallback escalar autodetectado al compilar |
24
- | **Memoria Alineada** | Asignacion en el heap de C alineada a 32 bytes (`posix_memalign` / `_aligned_malloc`) |
25
- | **Autograd** | Diferenciacion automatica con funciones de perdida 100% diferenciables |
26
- | **Optimizadores** | SGD (con momento y weight decay) y Adam (vectorizado en C con FMA) |
27
- | **Capas de Redes Neuronales** | Linear, Sequential, Embedding, LayerNorm, Dropout, BatchNorm1d |
28
- | **Funciones de Activacion** | ReLU, Leaky ReLU, Tanh, Sigmoid, Softmax (todas diferenciables) |
29
- | **Funciones de Perdida** | MSE, MAE, BCE, CrossEntropy, Huber (totalmente diferenciables) |
30
- | **Persistencia de Modelos** | Formato binario nativo de alta velocidad `.grx` (`save_weights` / `load_weights`) |
31
- | **Pipelines de Datos** | `TensorDataset` y `DataLoader` para procesamiento por lotes (*batching*) y barajado (*shuffle*) |
32
- | **Inicializacion de Pesos** | Xavier uniforme, He normal (Box-Muller en C) |
33
- | **Multiplataforma** | Linux (`.so`), macOS (`.dylib`), Windows (`.dll`) |
34
- | **Fallback Ruby Puro** | Funciona sin compilador de C en caso de que los binarios no esten disponibles |
134
+ | **Motor SIMD Multi-Target** | Deteccion dinamica en ejecucion: AVX2+FMA, SSE o escalar C portable |
135
+ | **Memoria Heap Alineada** | Asignacion en heap alineada a 32 bytes (`posix_memalign` / `_aligned_malloc`) |
136
+ | **Vistas Zero-Copy** | Transformaciones geometricas por zancadas (`reshape`, `transpose`, `flatten`, `t`) |
137
+ | **Motor Autograd** | Diferenciacion automatica en modo inverso con retropropagacion dinamica de DAG |
138
+ | **Capas Neuronales** | `Linear`, `Sequential`, `Embedding`, `LayerNorm`, `BatchNorm1d`, `Dropout` |
139
+ | **Funciones de Activacion** | `ReLU`, `LeakyReLU`, `Sigmoid`, `Tanh`, `Softmax` (totalmente diferenciables) |
140
+ | **Funciones de Perdida** | `MSELoss`, `MAELoss`, `BCELoss`, `CrossEntropyLoss`, `HuberLoss` |
141
+ | **Optimizadores** | `Adam` (vectorizado en C con FMA y correccion de sesgo), `SGD` (con momento y decay) |
142
+ | **Persistencia Binaria** | Formato `.grx` ultrarrapido para guardar y cargar pesos al instante |
143
+ | **Pipelines de Datos** | `TensorDataset` y `DataLoader` con division en lotes (*batching*) y barajado (*shuffle*) |
144
+ | **Inicializadores de Pesos** | Xavier uniforme y He normal (xorshift64* y Box-Muller en C) |
145
+ | **Multiplataforma** | Linux (`.so`), macOS (`.dylib`), Windows (`.dll` mediante DevKit) |
146
+ | **Fallback en Ruby Puro** | Ejecuta fluidamente en Ruby puro si el compilador de C no esta presente |
35
147
 
36
148
  ---
37
149
 
38
150
  ## Instalacion
39
151
 
40
- ### Mediante RubyGems
152
+ ### Instalacion Estandar con RubyGems
41
153
 
42
154
  ```bash
43
155
  gem install grx-tensor
44
156
  ```
45
157
 
46
- O agregalo a tu `Gemfile`:
158
+ O agregalo al `Gemfile` de tu proyecto:
47
159
 
48
160
  ```ruby
49
161
  gem "grx-tensor"
50
162
  ```
51
163
 
52
- ### Compilacion Manual desde el Codigo Fuente
164
+ La extension nativa en C se compila y enlaza de forma automatica y transparente durante la instalacion.
53
165
 
54
- Si clonas el repositorio directamente, compila la extension nativa:
166
+ ---
55
167
 
56
- **Linux / macOS:**
57
- ```bash
58
- make -C ext/unix
59
- ```
168
+ ## Tutoriales Basicos de Inicio Rapido
60
169
 
61
- **Windows (MinGW-w64):**
62
- ```bash
63
- make -C ext/windows -f Makefile.mingw
170
+ ### 1. Conversor de Grados Celsius a Fahrenheit (1 Neurona Aprende $F = 1.8C + 32$)
171
+
172
+ El "Hello World" por excelencia del Machine Learning. Una sola neurona lineal ($y = w \cdot x + b$) aprende la relacion termica por si sola:
173
+
174
+ ```ruby
175
+ require "grx"
176
+
177
+ # 1. Datos de entrenamiento (Pares reales de Celsius y Fahrenheit)
178
+ celsius = GRX.tensor([18.0, 25.0, 14.0, 21.0, 9.0, 16.0, 4.0, 32.0], [8, 1])
179
+ fahrenheit = GRX.tensor([64.4, 77.0, 57.2, 69.8, 48.2, 60.8, 39.2, 89.6], [8, 1])
180
+
181
+ # 2. Modelo de 1 neurona
182
+ modelo = GRX::NN::Sequential.new(GRX::NN::Linear.new(1, 1))
183
+ optimizador = GRX::Optim::Adam.new(modelo.parameters, lr: 0.8)
184
+ funcion_error = GRX::Loss::MSELoss.new
185
+
186
+ # 3. Entrenamiento en 5 lineas
187
+ 1500.times do
188
+ optimizador.zero_grad
189
+ prediccion = modelo.call(celsius)
190
+ error = funcion_error.call(prediccion, fahrenheit)
191
+ error.backward
192
+ optimizador.step
193
+ end
194
+
195
+ # 4. Prediccion de temperaturas nunca antes vistas
196
+ temperaturas_test = GRX.tensor([[100.0], [0.0], [37.0]], [3, 1])
197
+ predicciones = modelo.call(temperaturas_test).to_a
198
+
199
+ puts "100.0 C -> #{predicciones[0].round(1)} F (Esperado: 212.0 F)"
200
+ puts " 0.0 C -> #{predicciones[1].round(1)} F (Esperado: 32.0 F)"
201
+ puts " 37.0 C -> #{predicciones[2].round(1)} F (Esperado: 98.6 F)"
64
202
  ```
65
203
 
66
204
  ---
67
205
 
68
- ## Inicio Rapido
206
+ ### 2. Compuertas Logicas (AND Lineal vs XOR No Lineal con ReLU y Sigmoide)
207
+
208
+ Resolucion del clasico problema no lineal XOR mediante una red neuronal de 2 capas:
69
209
 
70
210
  ```ruby
71
211
  require "grx"
72
212
 
73
- # 1. Crear tensores con seguimiento de gradientes
74
- a = GRX.tensor([1.0, 2.0, 3.0], [3], requires_grad: true)
75
- b = GRX.tensor([4.0, 5.0, 6.0], [3], requires_grad: true)
213
+ # Tabla de verdad XOR: (0,0)->0, (0,1)->1, (1,0)->1, (1,1)->0
214
+ x = GRX.tensor([[0.0, 0.0], [0.0, 1.0], [1.0, 0.0], [1.0, 1.0]], [4, 2])
215
+ y = GRX.tensor([[0.0], [1.0], [1.0], [0.0]], [4, 1])
76
216
 
77
- # 2. Realizar operaciones aritmeticas (ejecutadas en C con SIMD)
78
- c = (a * b) + 2.0
217
+ # Red neuronal: 2 entradas -> 4 ocultas (ReLU) -> 1 salida (Sigmoide)
218
+ red_xor = GRX::NN::Sequential.new(
219
+ GRX::NN::Linear.new(2, 4),
220
+ GRX::NN::ReLU.new,
221
+ GRX::NN::Linear.new(4, 1),
222
+ GRX::NN::Sigmoid.new
223
+ )
79
224
 
80
- # 3. Calcular gradientes mediante retropropagacion (backpropagation)
81
- c.sum.backward
225
+ opt = GRX::Optim::Adam.new(red_xor.parameters, lr: 0.05)
226
+ loss_fn = GRX::Loss::BCELoss.new
82
227
 
83
- # 4. Inspeccionar los gradientes calculados
84
- puts a.grad.to_a # [4.0, 5.0, 6.0]
85
- puts b.grad.to_a # [1.0, 2.0, 3.0]
228
+ 400.times do
229
+ opt.zero_grad
230
+ pred = red_xor.call(x)
231
+ loss = loss_fn.call(pred, y)
232
+ loss.backward
233
+ opt.step
234
+ end
235
+
236
+ puts "Predicciones XOR: #{red_xor.call(x).to_a.map { |v| v.round(3) }}"
86
237
  ```
87
238
 
88
239
  ---
89
240
 
90
- ## Arquitecturas Avanzadas: NLP y Tablas de Incrustacion
241
+ ### 3. Matematicas Tensoriales Cotidianas en 4 Lineas
91
242
 
92
243
  ```ruby
93
244
  require "grx"
94
245
 
95
- # 1. Vocabulario de 1000 palabras mapeadas a vectores de 32 dimensiones
96
- vocabulario_size = 1000
97
- embedding_dim = 32
98
- emb = GRX::NN::Embedding.new(vocabulario_size, embedding_dim)
246
+ precios = GRX.tensor([19.99, 45.50, 120.00, 5.25], [4])
247
+ con_descuento = precios * 0.85 # 15% de descuento directo en C con SIMD
248
+
249
+ puts "Ingreso total: #{precios.sum.item.round(2)}"
250
+ puts "Precio promedio: #{precios.mean.item.round(2)}"
251
+ puts "Indice del articulo mas costoso: #{precios.argmax}"
252
+ ```
253
+
254
+ ---
255
+
256
+ ## Manual de Referencia del API de Tensores
257
+
258
+ Los tensores en GRX representan arreglos multidimensionales de numeros de punto flotante de doble precision (IEEE 754 de 64 bits) alojados en buffers contiguos de memoria nativa.
259
+
260
+ ### 1. Creacion y Metodos de Fabrica
261
+
262
+ ```ruby
263
+ require "grx"
264
+
265
+ # 1. Desde arreglos planos o anidados de Ruby (enteros o flotantes)
266
+ t1 = GRX.tensor([1.0, 2.0, 3.0, 4.0], [2, 2])
267
+ t2 = GRX.tensor([[1.0, 2.0], [3.0, 4.0]], [2, 2], requires_grad: true)
268
+
269
+ # 2. Tensores de Ceros y Unos
270
+ ceros = GRX.zeros([3, 4])
271
+ unos = GRX.ones([2, 5], requires_grad: true)
272
+
273
+ # 3. Inicializacion Aleatoria
274
+ aleatorio_u = GRX.rand([4, 4]) # Distribucion uniforme U[0, 1)
275
+ aleatorio_n = GRX.randn([4, 4]) # Distribucion normal estandar N(0, 1)
276
+
277
+ # 4. Inicializacion de Pesos para Redes Neuronales
278
+ xavier = GRX::Tensor.xavier_uniform([64, 32], requires_grad: true)
279
+ he = GRX::Tensor.he_normal([64, 32], requires_grad: true)
280
+
281
+ # 5. Fabricas basadas en otro tensor
282
+ z_like = GRX::Tensor.zeros_like(t1)
283
+ o_like = GRX::Tensor.ones_like(t1)
284
+ ```
285
+
286
+ ### 2. Inspeccion y Acceso a Elementos
287
+
288
+ ```ruby
289
+ t = GRX.tensor([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], [2, 3])
290
+
291
+ puts t.shape # [2, 3] (Dimensiones)
292
+ puts t.strides # [3, 1] (Saltos en memoria)
293
+ puts t.numel # 6 (Numero total de elementos)
294
+ puts t.rank # 2 (Rango / Numero de dimensiones)
295
+ puts t.item # Retorna el float escalar si numel == 1
296
+ puts t.to_a # [1.0, 2.0, 3.0, 4.0, 5.0, 6.0]
297
+ puts t.get(1, 2) # 6.0 (Elemento en fila 1, columna 2)
298
+ t.set(1, 2, 9.9) # Modifica el elemento en (1, 2)
299
+ ```
300
+
301
+ ### 3. Operaciones Aritmeticas (Aceleradas por SIMD)
302
+
303
+ ```ruby
304
+ a = GRX.tensor([1.0, 2.0, 3.0], [3])
305
+ b = GRX.tensor([4.0, 5.0, 6.0], [3])
306
+
307
+ c_suma = a + b # [5.0, 7.0, 9.0]
308
+ c_resta = a - b # [-3.0, -3.0, -3.0]
309
+ c_mult = a * b # [4.0, 10.0, 18.0]
310
+ c_div = b / a # [4.0, 2.5, 2.0]
311
+ c_neg = -a # [-1.0, -2.0, -3.0]
312
+
313
+ # Aritmetica con escalares
314
+ s_suma = a + 10.0 # [11.0, 12.0, 13.0]
315
+ s_mult = a * 2.0 # [2.0, 4.0, 6.0]
316
+ s_div = a / 2.0 # [0.5, 1.0, 1.5]
317
+ ```
318
+
319
+ ### 4. Funciones Matematicas Element-Wise
320
+
321
+ ```ruby
322
+ t = GRX.tensor([1.0, 4.0, 9.0, 16.0], [4])
323
+
324
+ puts t.sqrt.to_a # [1.0, 2.0, 3.0, 4.0] (Raiz cuadrada)
325
+ puts t.square.to_a # [1.0, 16.0, 81.0, 256.0] (Cuadrado)
326
+ puts t.abs.to_a # [1.0, 4.0, 9.0, 16.0] (Valor absoluto)
327
+ puts t.pow(3.0).to_a # [1.0, 64.0, 729.0, 4096.0] (Potencia)
328
+ puts t.log.to_a # Logaritmo natural ln(x)
329
+ puts t.exp.to_a # Exponencial e^x
330
+ puts t.clip(2.0, 10.0) # Limita los valores al rango [2.0, 10.0]
331
+ ```
332
+
333
+ ### 5. Multiplicacion de Matrices y Algebra Lineal
334
+
335
+ ```ruby
336
+ # Multiplicacion matricial (SIMD con Cache Tiling en L1)
337
+ m1 = GRX.tensor([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], [2, 3])
338
+ m2 = GRX.tensor([7.0, 8.0, 9.0, 10.0, 11.0, 12.0], [3, 2])
339
+
340
+ resultado = m1 @ m2 # Equivalente a m1.matmul(m2), retorna Shape [2, 2]
341
+
342
+ # Producto punto (vectores 1D)
343
+ v1 = GRX.tensor([1.0, 2.0, 3.0], [3])
344
+ v2 = GRX.tensor([4.0, 5.0, 6.0], [3])
345
+ punto = v1.dot(v2) # 32.0 (Escalar double)
346
+ ```
347
+
348
+ ### 6. Transformaciones Geometricas (Vistas Zero-Copy)
349
+
350
+ ```ruby
351
+ matriz = GRX.tensor([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], [2, 3])
352
+
353
+ # Reshape y Aplanado
354
+ reestructurado = matriz.reshape([3, 2]) # Shape [3, 2]
355
+ plano = matriz.flatten # Shape [6]
356
+
357
+ # Transposicion
358
+ transpuesta = matriz.transpose(0, 1) # Shape [3, 2]
359
+ t_rapida = matriz.t # Alias para transposicion 2D
360
+ ```
361
+
362
+ ### 7. Reducciones y Estadisticas
363
+
364
+ ```ruby
365
+ t = GRX.tensor([2.0, 4.0, 6.0, 8.0], [4], requires_grad: true)
366
+
367
+ s = t.sum # Tensor escalar [20.0], nodo autograd
368
+ m = t.mean # Tensor escalar [5.0], nodo autograd
369
+ max_v = t.max # 8.0 (Float escalar)
370
+ min_v = t.min # 2.0 (Float escalar)
371
+ max_idx = t.argmax # 3 (Indice del valor maximo)
372
+ min_idx = t.argmin # 0 (Indice del valor minimo)
373
+ ```
374
+
375
+ ---
376
+
377
+ ## Autograd y Motor de Diferenciacion
378
+
379
+ GRX incorpora un motor dinamico de diferenciacion automatica en modo inverso basado en un Grafo Aciclico Dirigido (DAG). Al invocar `backward` sobre un tensor escalar, las derivadas parciales se propagan hacia atras en todas las ramas computacionales.
380
+
381
+ ```mermaid
382
+ flowchart LR
383
+ A["Tensor a (requires_grad: true)"] --> C["Multiplicacion (a * b)"]
384
+ B["Tensor b (requires_grad: true)"] --> C
385
+ C --> D["Suma (+ 2.0)"]
386
+ D --> E["Reduccion (.sum)"]
387
+ E --> F["Perdida Escalar"]
388
+ F -. "loss.backward" .-> E
389
+ E -. "dLoss/dD" .-> D
390
+ D -. "dLoss/dC" .-> C
391
+ C -. "a.grad = dLoss/da" .-> A
392
+ C -. "b.grad = dLoss/db" .-> B
393
+ ```
394
+
395
+ ```ruby
396
+ require "grx"
99
397
 
100
- # 2. Tokens de entrada
101
- tokens = GRX.tensor([42, 108, 999], [3])
398
+ x = GRX.tensor([2.0, 3.0], [2], requires_grad: true)
399
+ w = GRX.tensor([4.0, 5.0], [2], requires_grad: true)
400
+ b = GRX.tensor([1.0, 1.0], [2], requires_grad: true)
102
401
 
103
- # 3. Obtener vectores densos
104
- vectores = emb.call(tokens)
105
- puts vectores.shape # [3, 32]
402
+ y = (x * w) + b
403
+ loss = y.sum
404
+ loss.backward
106
405
 
107
- # 4. Normalizacion por capa (LayerNorm)
108
- ln = GRX::NN::LayerNorm.new(32)
109
- normalizado = ln.call(vectores)
110
- puts normalizado.shape # [3, 32]
406
+ puts "x.grad: #{x.grad.to_a}" # [4.0, 5.0]
407
+ puts "w.grad: #{w.grad.to_a}" # [2.0, 3.0]
408
+ puts "b.grad: #{b.grad.to_a}" # [1.0, 1.0]
111
409
  ```
112
410
 
113
411
  ---
114
412
 
115
- ## Ejemplos Completos y Funcionales
413
+ ## Computacion Cientifica y Numerica (Mas Alla del Deep Learning)
116
414
 
117
- ### Ejemplo 1: Clasificador de Texto y Sentimiento con NLP (CrossEntropyLoss)
415
+ Los tensores son motores matematicos multidimensionales de proposito general ideales para procesamiento de senales, finanzas cuantitativas, fisica computacional y optimizacion matematica.
118
416
 
119
- Clasifica consultas de usuarios en 3 categorias: Queja (0), Elogio (1) y Consulta (2):
417
+ ### A. Vision por Computadora y Filtrado de Imagenes (Convolucion Sobel)
418
+
419
+ Aplica filtrado espacial y deteccion de bordes directamente sobre matrices de pixeles:
120
420
 
121
421
  ```ruby
122
422
  require "grx"
123
423
 
124
- data = [
125
- ["el servicio es pesimo y muy malo", 0],
126
- ["la atencion fue horrible nunca vuelvo", 0],
127
- ["no me gusto para nada es lento", 0],
128
- ["excelente servicio muy rapido y bueno", 1],
129
- ["me encanto la atencion fantastica gracias", 1],
130
- ["todo perfecto muy feliz con la compra", 1],
131
- ["como puedo hacer una devolucion de compra", 2],
132
- ["cual es el horario de atencion hoy", 2],
133
- ["donde puedo consultar el estado del pedido", 2]
134
- ]
135
-
136
- vocab = data.flat_map { |text, _| text.split }.uniq
137
- token_to_id = vocab.each_with_index.to_h
138
- vocab_size = vocab.size
139
- embedding_dim = 16
140
- num_classes = 3
141
- seq_len = 7
142
-
143
- batch_size = data.size
144
- x_indices = data.map { |text, _| (text.split.map { |w| token_to_id[w] } + [0]*seq_len).first(seq_len) }
145
- train_x = GRX.tensor(x_indices.flatten.map(&:to_f), [batch_size, seq_len])
146
-
147
- onehot = Array.new(batch_size * num_classes, 0.0)
148
- data.each_with_index { |(_, label), i| onehot[i * num_classes + label] = 1.0 }
149
- train_y = GRX.tensor(onehot, [batch_size, num_classes])
150
-
151
- emb = GRX::NN::Embedding.new(vocab_size, embedding_dim)
152
- ln = GRX::NN::LayerNorm.new(embedding_dim)
153
- fc1 = GRX::NN::Linear.new(embedding_dim, 16)
154
- act = GRX::NN::ReLU.new
155
- fc2 = GRX::NN::Linear.new(16, num_classes)
156
-
157
- params = emb.parameters + ln.parameters + fc1.parameters + fc2.parameters
158
- opt = GRX::Optim::Adam.new(params, lr: 0.05)
159
- loss_fn = GRX::Loss::CrossEntropyLoss.new
160
-
161
- 120.times do
162
- opt.zero_grad
163
- flat_tokens = train_x.flatten
164
- embedded = emb.call(flat_tokens)
165
-
166
- emb_data = embedded.to_a
167
- pooled_data = Array.new(batch_size * embedding_dim, 0.0)
168
- batch_size.times do |b|
169
- embedding_dim.times do |d|
170
- sum_v = 0.0
171
- seq_len.times { |t| sum_v += emb_data[(b * seq_len + t) * embedding_dim + d] }
172
- pooled_data[b * embedding_dim + d] = sum_v / seq_len.to_f
173
- end
424
+ imagen = GRX.tensor([
425
+ 0.0, 0.0, 0.0, 255.0, 255.0, 255.0,
426
+ 0.0, 0.0, 0.0, 255.0, 255.0, 255.0,
427
+ 0.0, 0.0, 0.0, 255.0, 255.0, 255.0,
428
+ 0.0, 0.0, 0.0, 255.0, 255.0, 255.0,
429
+ 0.0, 0.0, 0.0, 255.0, 255.0, 255.0,
430
+ 0.0, 0.0, 0.0, 255.0, 255.0, 255.0
431
+ ], [6, 6])
432
+
433
+ sobel_h = GRX.tensor([
434
+ -1.0, 0.0, 1.0,
435
+ -2.0, 0.0, 2.0,
436
+ -1.0, 0.0, 1.0
437
+ ], [3, 3])
438
+
439
+ filas_out = imagen.shape[0] - sobel_h.shape[0] + 1
440
+ cols_out = imagen.shape[1] - sobel_h.shape[1] + 1
441
+ mapa_bordes = []
442
+
443
+ filas_out.times do |r|
444
+ cols_out.times do |c|
445
+ parche = []
446
+ 3.times { |kr| 3.times { |kc| parche << imagen.get(r + kr, c + kc) } }
447
+ tensor_parche = GRX.tensor(parche, [3, 3])
448
+ conv_val = (tensor_parche * sobel_h).sum.item
449
+ mapa_bordes << conv_val.abs
174
450
  end
175
- pooled = GRX.tensor(pooled_data, [batch_size, embedding_dim], requires_grad: true)
451
+ end
176
452
 
177
- logits = fc2.call(act.call(fc1.call(ln.call(pooled))))
178
- loss = loss_fn.call(logits, train_y)
179
- loss.backward
453
+ bordes = GRX.tensor(mapa_bordes, [filas_out, cols_out])
454
+ puts "Dimension del Mapa de Bordes: #{bordes.shape}"
455
+ ```
180
456
 
181
- if pooled.grad
182
- grad_emb = Array.new(batch_size * seq_len * embedding_dim, 0.0)
183
- p_grad = pooled.grad.to_a
184
- batch_size.times do |b|
185
- embedding_dim.times do |d|
186
- val = p_grad[b * embedding_dim + d] / seq_len.to_f
187
- seq_len.times { |t| grad_emb[(b * seq_len + t) * embedding_dim + d] = val }
188
- end
189
- end
190
- embedded.backward(GRX.tensor(grad_emb, embedded.shape))
457
+ ---
458
+
459
+ ### B. Finanzas Cuantitativas y Matriz de Covarianza
460
+
461
+ Calcula retornos diarios, volatilidad anualizada y riesgo de portafolios de inversion:
462
+
463
+ ```ruby
464
+ require "grx"
465
+
466
+ precios = GRX.tensor([
467
+ 100.0, 50.0, 200.0,
468
+ 102.0, 49.0, 205.0,
469
+ 101.0, 51.0, 210.0,
470
+ 105.0, 52.0, 208.0,
471
+ 108.0, 53.0, 215.0
472
+ ], [5, 3])
473
+
474
+ retornos_data = []
475
+ 4.times do |t|
476
+ 3.times do |activo|
477
+ p_prev = precios.get(t, activo)
478
+ p_curr = precios.get(t + 1, activo)
479
+ retornos_data << ((p_curr - p_prev) / p_prev)
191
480
  end
481
+ end
482
+ retornos = GRX.tensor(retornos_data, [4, 3])
192
483
 
193
- opt.step
484
+ medias = Array.new(3) do |activo|
485
+ col = 4.times.map { |d| retornos.get(d, activo) }
486
+ col.sum / 4.0
194
487
  end
195
488
 
196
- puts "Entrenamiento NLP completado con perdida CrossEntropy < 0.0001"
489
+ centrado = []
490
+ 4.times do |d|
491
+ 3.times do |activo|
492
+ centrado << (retornos.get(d, activo) - medias[activo])
493
+ end
494
+ end
495
+ retornos_centrados = GRX.tensor(centrado, [4, 3])
496
+
497
+ covarianza = (retornos_centrados.t @ retornos_centrados) / 3.0
498
+
499
+ pesos = GRX.tensor([[0.4, 0.3, 0.3]], [1, 3])
500
+ var_portafolio = (pesos @ covarianza @ pesos.t).item
501
+ volatilidad = Math.sqrt(var_portafolio)
502
+
503
+ puts "Volatilidad Diaria del Portafolio: #{(volatilidad * 100).round(4)}%"
504
+ ```
505
+
506
+ ---
507
+
508
+ ### C. Fisica de Particulas y Simulacion N-Cuerpos
509
+
510
+ Simula posiciones, velocidades y distancias euclidianas matriciales en 3D:
511
+
512
+ ```ruby
513
+ require "grx"
514
+
515
+ n_particulas = 4
516
+ dt = 0.01
517
+
518
+ posiciones = GRX.tensor([
519
+ 0.0, 0.0, 0.0,
520
+ 1.0, 0.0, 0.0,
521
+ 0.0, 1.0, 0.0,
522
+ 0.0, 0.0, 1.0
523
+ ], [n_particulas, 3])
524
+
525
+ velocidades = GRX.tensor([
526
+ 0.1, 0.0, 0.0,
527
+ 0.0, 0.2, 0.0,
528
+ 0.0, 0.0, 0.1,
529
+ -0.1, 0.0, 0.0
530
+ ], [n_particulas, 3])
531
+
532
+ gravedad = GRX.tensor(Array.new(n_particulas * 3) { |i| (i % 3 == 1) ? -9.81 : 0.0 }, [n_particulas, 3])
533
+
534
+ velocidades = velocidades + (gravedad * dt)
535
+ posiciones = posiciones + (velocidades * dt)
536
+
537
+ distancias_data = []
538
+ n_particulas.times do |i|
539
+ n_particulas.times do |j|
540
+ dx = posiciones.get(i, 0) - posiciones.get(j, 0)
541
+ dy = posiciones.get(i, 1) - posiciones.get(j, 1)
542
+ dz = posiciones.get(i, 2) - posiciones.get(j, 2)
543
+ distancias_data << Math.sqrt(dx*dx + dy*dy + dz*dz)
544
+ end
545
+ end
546
+
547
+ distancias = GRX.tensor(distancias_data, [n_particulas, n_particulas])
548
+ puts "Distancia entre Particulas P0 y P1: #{distancias.get(0, 1).round(4)}"
197
549
  ```
198
550
 
199
551
  ---
200
552
 
201
- ### Ejemplo 2: Entrenamiento con Datasets Masivos (5,000 Muestras con DataLoader)
553
+ ### D. Optimizacion Matematica Pura con Autograd (Funcion Rosenbrock)
554
+
555
+ Encuentra el minimo global de la funcion no convexa de Rosenbrock:
556
+ $$f(x, y) = (a - x)^2 + b(y - x^2)^2 \quad \text{con } a=1, b=100$$
202
557
 
203
558
  ```ruby
204
559
  require "grx"
205
560
 
206
- num_samples = 5000
207
- num_features = 4
561
+ punto = GRX.tensor([-1.5, 2.0], [2], requires_grad: true)
562
+ lr = 0.002
208
563
 
209
- # Funcion subyacente: y = 2*x1 - 3*x2 + 1.5*x3 - 0.5*x4 + 4.0
210
- raw_x = Array.new(num_samples * num_features) { rand * 2.0 - 1.0 }
211
- raw_y = Array.new(num_samples) do |i|
212
- x1, x2, x3, x4 = raw_x.slice(i * 4, 4)
213
- 2.0 * x1 - 3.0 * x2 + 1.5 * x3 - 0.5 * x4 + 4.0 + (rand - 0.5) * 0.02
564
+ 500.times do |paso|
565
+ x = punto.get(0)
566
+ y = punto.get(1)
567
+
568
+ tx = GRX.tensor([x], [1], requires_grad: true)
569
+ ty = GRX.tensor([y], [1], requires_grad: true)
570
+
571
+ t1 = (GRX.tensor([1.0], [1]) - tx).square
572
+ t2 = (ty - tx.square).square * 100.0
573
+ perdida = t1 + t2
574
+ perdida.backward
575
+
576
+ nuevo_x = x - lr * tx.grad.item
577
+ nuevo_y = y - lr * ty.grad.item
578
+ punto = GRX.tensor([nuevo_x, nuevo_y], [2])
214
579
  end
215
580
 
216
- train_dataset = GRX::Data::TensorDataset.new(
217
- GRX.tensor(raw_x[0...(4000*4)], [4000, 4]),
218
- GRX.tensor(raw_y[0...4000], [4000, 1])
581
+ puts "Minimo Convergido: x = #{punto.get(0).round(3)}, y = #{punto.get(1).round(3)}"
582
+ ```
583
+
584
+ ---
585
+
586
+ ## Recetario de Deep Learning (10 Arquitecturas de Redes Neuronales)
587
+
588
+ ### Arquitectura 1: Clasificador de Vision y Caracteres (BatchNorm + Dropout)
589
+
590
+ ```ruby
591
+ require "grx"
592
+
593
+ modelo_vision = GRX::NN::Sequential.new(
594
+ GRX::NN::Linear.new(784, 256),
595
+ GRX::NN::BatchNorm1d.new(256),
596
+ GRX::NN::ReLU.new,
597
+ GRX::NN::Dropout.new(0.25),
598
+ GRX::NN::Linear.new(256, 64),
599
+ GRX::NN::LayerNorm.new(64),
600
+ GRX::NN::LeakyReLU.new(alpha: 0.01),
601
+ GRX::NN::Linear.new(64, 10),
602
+ GRX::NN::Softmax.new
603
+ )
604
+
605
+ lote_imagenes = GRX.randn([16, 784])
606
+ predicciones = modelo_vision.forward(lote_imagenes) # Shape [16, 10]
607
+ puts "Predicciones de Vision Shape: #{predicciones.shape}"
608
+ ```
609
+
610
+ ---
611
+
612
+ ### Arquitectura 2: NLP y Chatbot de Intenciones (Embedding + LayerNorm)
613
+
614
+ ```ruby
615
+ require "grx"
616
+
617
+ vocab_size = 500
618
+ embedding_dim = 32
619
+ num_classes = 4
620
+
621
+ embedding = GRX::NN::Embedding.new(vocab_size, embedding_dim)
622
+ clasificador = GRX::NN::Sequential.new(
623
+ GRX::NN::LayerNorm.new(embedding_dim),
624
+ GRX::NN::Linear.new(embedding_dim, 16),
625
+ GRX::NN::Tanh.new,
626
+ GRX::NN::Linear.new(16, num_classes)
627
+ )
628
+
629
+ tokens = GRX.tensor([14, 2, 88, 412], [4])
630
+ palabras = embedding.forward(tokens)
631
+
632
+ vector_oracion = Array.new(embedding_dim) do |d|
633
+ 4.times.sum { |t| palabras.get(t, d) } / 4.0
634
+ end
635
+ tensor_oracion = GRX.tensor(vector_oracion, [1, embedding_dim])
636
+
637
+ logits = clasificador.forward(tensor_oracion)
638
+ puts "Intencion Predicha: #{logits.argmax}"
639
+ ```
640
+
641
+ ---
642
+
643
+ ### Arquitectura 3: Aprendizaje por Refuerzo (Agente Deep Q-Network DQN)
644
+
645
+ ```ruby
646
+ require "grx"
647
+
648
+ dim_estado = 8
649
+ dim_accion = 4
650
+
651
+ q_net = GRX::NN::Sequential.new(
652
+ GRX::NN::Linear.new(dim_estado, 64),
653
+ GRX::NN::ReLU.new,
654
+ GRX::NN::Linear.new(64, 64),
655
+ GRX::NN::ReLU.new,
656
+ GRX::NN::Linear.new(64, dim_accion)
657
+ )
658
+
659
+ optimizador = GRX::Optim::Adam.new(q_net.parameters, lr: 0.001)
660
+ perdida_huber = GRX::Loss::HuberLoss.new(delta: 1.0)
661
+
662
+ estado_actual = GRX.randn([1, dim_estado])
663
+ q_objetivos = GRX.tensor([[1.2, 0.5, -0.8, 3.4]], [1, 4])
664
+
665
+ optimizador.zero_grad
666
+ q_predichos = q_net.forward(estado_actual)
667
+ loss = perdida_huber.call(q_predichos, q_objetivos)
668
+ loss.backward
669
+ optimizador.step
670
+
671
+ puts "Perdida Q: #{loss.item.round(6)}"
672
+ ```
673
+
674
+ ---
675
+
676
+ ### Arquitectura 4: Pronostico No Lineal de Series Temporales Multivariables
677
+
678
+ ```ruby
679
+ require "grx"
680
+
681
+ pronosticador = GRX::NN::Sequential.new(
682
+ GRX::NN::Linear.new(5, 32),
683
+ GRX::NN::Sigmoid.new,
684
+ GRX::NN::Linear.new(32, 16),
685
+ GRX::NN::ReLU.new,
686
+ GRX::NN::Linear.new(16, 1)
219
687
  )
220
- val_x = GRX.tensor(raw_x[(4000*4)..], [1000, 4])
221
- val_y = GRX.tensor(raw_y[4000..], [1000, 1])
222
688
 
223
- train_loader = GRX::Data::DataLoader.new(train_dataset, batch_size: 64, shuffle: true)
689
+ optimizador = GRX::Optim::Adam.new(pronosticador.parameters, lr: 0.01, weight_decay: 1e-4)
690
+ criterio = GRX::Loss::MSELoss.new
691
+
692
+ sensores = GRX.tensor([[22.5, 60.1, 1013.2, 5.4, 0.8]], [1, 5])
693
+ temp_esperada = GRX.tensor([[23.1]], [1, 1])
694
+
695
+ optimizador.zero_grad
696
+ pred = pronosticador.forward(sensores)
697
+ loss = criterio.call(pred, temp_esperada)
698
+ loss.backward
699
+ optimizador.step
700
+
701
+ puts "Error de Pronostico: #{loss.item.round(6)}"
702
+ ```
703
+
704
+ ---
705
+
706
+ ### Arquitectura 5: Autoencoder Profundo para Reduccion Dimensional y Deteccion de Anomalias
707
+
708
+ Comprime vectores de alta dimension en un cuello de botella latente y reconstruye la entrada:
224
709
 
225
- model = GRX::NN::Sequential.new(
710
+ ```ruby
711
+ require "grx"
712
+
713
+ # 1. Red Codificadora (Encoder): 64 entradas -> 16 ocultas -> 4 codigo latente
714
+ encoder = GRX::NN::Sequential.new(
715
+ GRX::NN::Linear.new(64, 16),
716
+ GRX::NN::LayerNorm.new(16),
717
+ GRX::NN::ReLU.new,
718
+ GRX::NN::Linear.new(16, 4)
719
+ )
720
+
721
+ # 2. Red Decodificadora (Decoder): 4 codigo latente -> 16 ocultas -> 64 salidas
722
+ decoder = GRX::NN::Sequential.new(
226
723
  GRX::NN::Linear.new(4, 16),
227
724
  GRX::NN::LayerNorm.new(16),
725
+ GRX::NN::ReLU.new,
726
+ GRX::NN::Linear.new(16, 64),
727
+ GRX::NN::Sigmoid.new
728
+ )
729
+
730
+ optimizador = GRX::Optim::Adam.new(encoder.parameters + decoder.parameters, lr: 0.01)
731
+ perdida_recon = GRX::Loss::MSELoss.new
732
+
733
+ lote = GRX.rand([8, 64])
734
+
735
+ optimizador.zero_grad
736
+ codigo_latente = encoder.forward(lote) # Shape [8, 4]
737
+ reconstruccion = decoder.forward(codigo_latente) # Shape [8, 64]
738
+ loss = perdida_recon.call(reconstruccion, lote)
739
+ loss.backward
740
+ optimizador.step
741
+
742
+ puts "Perdida de Reconstruccion del Autoencoder: #{loss.item.round(6)}"
743
+ ```
744
+
745
+ ---
746
+
747
+ ### Arquitectura 6: Modelo Generador de Lenguaje y Siguiente Caracter Autoregresivo
748
+
749
+ Genera texto caracter a caracter mediante capas de incrustacion densa y cabezas lineales:
750
+
751
+ ```ruby
752
+ require "grx"
753
+
754
+ tamano_vocabulario = 256 # Caracteres ASCII
755
+ dim_embedding = 16
756
+ longitud_contexto = 4 # Ventana de 4 caracteres
757
+
758
+ char_embedding = GRX::NN::Embedding.new(tamano_vocabulario, dim_embedding)
759
+ cabeza_idioma = GRX::NN::Sequential.new(
760
+ GRX::NN::Linear.new(dim_embedding * longitud_contexto, 64),
761
+ GRX::NN::LayerNorm.new(64),
228
762
  GRX::NN::Tanh.new,
229
- GRX::NN::Linear.new(16, 1)
763
+ GRX::NN::Linear.new(64, tamano_vocabulario)
230
764
  )
231
765
 
232
- opt = GRX::Optim::Adam.new(model.parameters, lr: 0.03)
233
- loss_fn = GRX::Loss::MSELoss.new
766
+ # Predecir siguiente caracter para contexto "hola" -> tokens [104, 111, 108, 97]
767
+ contexto_ids = GRX.tensor([104, 111, 108, 97], [4])
768
+ embebido = char_embedding.forward(contexto_ids) # Shape [4, 16]
769
+ contexto_plano = embebido.flatten.reshape([1, dim_embedding * longitud_contexto])
234
770
 
235
- 20.times do |epoch|
236
- train_loader.each do |bx, by|
237
- opt.zero_grad
238
- pred = model.call(bx)
239
- loss = loss_fn.call(pred, by)
240
- loss.backward
241
- opt.step
771
+ logits = cabeza_idioma.forward(contexto_plano) # Shape [1, 256]
772
+ siguiente_char_ascii = logits.argmax
773
+
774
+ puts "Contexto: 'hola' -> Siguiente Caracter Predicho: '#{siguiente_char_ascii.chr}' (ASCII #{siguiente_char_ascii})"
775
+ ```
776
+
777
+ ---
778
+
779
+ ### Arquitectura 7: Analisis de Sentimiento y Clasificacion de Resenas (BCELoss)
780
+
781
+ Clasifica la polaridad de texto (Positivo / Negativo) a partir de secuencias de tokens:
782
+
783
+ ```ruby
784
+ require "grx"
785
+
786
+ tamano_vocabulario = 1000
787
+ dim_embedding = 32
788
+
789
+ embedding_sentimiento = GRX::NN::Embedding.new(tamano_vocabulario, dim_embedding)
790
+ clasificador_sentimiento = GRX::NN::Sequential.new(
791
+ GRX::NN::LayerNorm.new(dim_embedding),
792
+ GRX::NN::Linear.new(dim_embedding, 16),
793
+ GRX::NN::ReLU.new,
794
+ GRX::NN::Dropout.new(0.2),
795
+ GRX::NN::Linear.new(16, 1),
796
+ GRX::NN::Sigmoid.new
797
+ )
798
+
799
+ # Resena tokenizada: "excelente producto entrega muy rapida" -> [42, 189, 7, 85, 301]
800
+ tokens_resena = GRX.tensor([42, 189, 7, 85, 301], [5])
801
+ vectores = embedding_sentimiento.forward(tokens_resena) # Shape [5, 32]
802
+
803
+ # Agregacion por promedio global de palabras
804
+ vector_resena = Array.new(dim_embedding) do |d|
805
+ 5.times.sum { |t| vectores.get(t, d) } / 5.0
806
+ end
807
+ tensor_resena = GRX.tensor(vector_resena, [1, dim_embedding])
808
+
809
+ probabilidad_positiva = clasificador_sentimiento.forward(tensor_resena).item
810
+ etiqueta = probabilidad_positiva >= 0.5 ? "POSITIVO" : "NEGATIVO"
811
+
812
+ puts "Puntuacion de Sentimiento: #{(probabilidad_positiva * 100).round(2)}% -> #{etiqueta}"
813
+ ```
814
+
815
+ ---
816
+
817
+ ### Arquitectura 8: Red Neuronal Siamesa para Verificacion de Similitud y Firmas
818
+
819
+ Ramas gemelas con pesos compartidos para verificacion biometrica o similitud semantica:
820
+
821
+ ```ruby
822
+ require "grx"
823
+
824
+ extractor_caracteristicas = GRX::NN::Sequential.new(
825
+ GRX::NN::Linear.new(32, 16),
826
+ GRX::NN::LayerNorm.new(16),
827
+ GRX::NN::Tanh.new,
828
+ GRX::NN::Linear.new(16, 8)
829
+ )
830
+
831
+ # Dos firmas o imagenes de muestra
832
+ muestra_a = GRX.randn([1, 32])
833
+ muestra_b = GRX.randn([1, 32])
834
+
835
+ # Extraccion de vectores latentes con los mismos pesos compartidos
836
+ vector_a = extractor_caracteristicas.forward(muestra_a) # Shape [1, 8]
837
+ vector_b = extractor_caracteristicas.forward(muestra_b) # Shape [1, 8]
838
+
839
+ # Distancia euclidiana entre representaciones
840
+ diferencia = vector_a - vector_b
841
+ distancia = diferencia.square.sum.sqrt.item
842
+
843
+ resultado = distancia < 1.0 ? "COINCIDENCIA (Misma Entidad)" : "NO COINCIDEN (Distinta Entidad)"
844
+ puts "Distancia Latente: #{distancia.round(4)} -> #{resultado}"
845
+ ```
846
+
847
+ ---
848
+
849
+ ### Arquitectura 9: Red Residual Profunda (Bloque ResNet MLP con Conexion Skip)
850
+
851
+ Permite entrenar redes ultra-profundas evitando el desvanecimiento del gradiente ($y = x + F(x)$):
852
+
853
+ ```ruby
854
+ require "grx"
855
+
856
+ class BloqueResidual < GRX::NN::Module
857
+ def initialize(dim)
858
+ @fc1 = GRX::NN::Linear.new(dim, dim)
859
+ @bn1 = GRX::NN::BatchNorm1d.new(dim)
860
+ @act = GRX::NN::ReLU.new
861
+ @fc2 = GRX::NN::Linear.new(dim, dim)
862
+ @bn2 = GRX::NN::BatchNorm1d.new(dim)
863
+ end
864
+
865
+ def forward(x)
866
+ residual = x
867
+ out = @fc1.forward(x)
868
+ out = @bn1.forward(out)
869
+ out = @act.forward(out)
870
+ out = @fc2.forward(out)
871
+ out = @bn2.forward(out)
872
+ out + residual # Conexion de salto (Skip Connection)
242
873
  end
243
874
  end
244
875
 
245
- val_pred = model.call(val_x)
246
- val_loss = loss_fn.call(val_pred, val_y).item
247
- puts "Error de Validacion MSE: #{val_loss.round(6)}"
876
+ bloque = BloqueResidual.new(16)
877
+ entrada = GRX.randn([4, 16])
878
+ salida_res = bloque.forward(entrada)
879
+
880
+ puts "Dimension de Salida del Bloque Residual: #{salida_res.shape}"
881
+ ```
882
+
883
+ ---
884
+
885
+ ### Arquitectura 10: Filtrado Colaborativo Neuronal y Sistema de Recomendacion
886
+
887
+ Combina vectores de Usuarios e Items con capas densas para predecir afinidad de recomendacion:
888
+
889
+ ```ruby
890
+ require "grx"
891
+
892
+ num_usuarios = 100
893
+ num_articulos = 50
894
+ dim_latente = 16
895
+
896
+ emb_usuario = GRX::NN::Embedding.new(num_usuarios, dim_latente)
897
+ emb_articulo = GRX::NN::Embedding.new(num_articulos, dim_latente)
898
+
899
+ red_afinidad = GRX::NN::Sequential.new(
900
+ GRX::NN::Linear.new(dim_latente * 2, 16),
901
+ GRX::NN::ReLU.new,
902
+ GRX::NN::Linear.new(16, 1),
903
+ GRX::NN::Sigmoid.new
904
+ )
905
+
906
+ # Predecir afinidad entre Usuario #7 y Pelicula #23
907
+ u_idx = GRX.tensor([7], [1])
908
+ i_idx = GRX.tensor([23], [1])
909
+
910
+ u_vec = emb_usuario.forward(u_idx) # Shape [1, 16]
911
+ i_vec = emb_articulo.forward(i_idx) # Shape [1, 16]
248
912
 
249
- # Guardar pesos a disco en formato binario .grx
250
- model.save_weights("modelo_5000_muestras.grx")
913
+ # Concatenar vectores -> Shape [1, 32]
914
+ interaccion = GRX.tensor(u_vec.to_a + i_vec.to_a, [1, dim_latente * 2])
915
+ puntuacion_predicha = red_afinidad.forward(interaccion).item
916
+
917
+ puts "Calificacion Estimada: #{(puntuacion_predicha * 5.0).round(2)} / 5.0 Estrellas"
251
918
  ```
252
919
 
253
920
  ---
254
921
 
255
- ## Pruebas de Rendimiento (Benchmark)
922
+ ## Funciones de Perdida (`GRX::Loss`)
256
923
 
257
- Medido en Ruby 3.3, Linux x86_64 con extensiones AVX2+FMA activadas:
924
+ Todas las funciones de perdida retornan un tensor escalar diferenciable listo para `loss.backward`.
258
925
 
259
- | Operacion | Tamano (n) | Tiempo por iteracion | Rendimiento SIMD |
926
+ | Clase de Perdida | Constructor y Parametros | Por Defecto | Explicacion Matematica y Uso |
260
927
  |---|---|---|---|
261
- | `add` | 1,000,000 | ~4 ms | ~250M doubles/segundo |
262
- | `dot` | 1,000,000 | ~2 ms | ~500M doubles/segundo |
263
- | `relu` | 1,000,000 | ~4 ms | ~250M doubles/segundo |
264
- | `matmul` (256x256) | 65,536 | ~6 ms | Reutilizacion de cache por bloques (tiling) |
928
+ | `GRX::Loss::MSELoss` | `new(reduction: :mean)` | `reduction: :mean` | Error Cuadratico Medio: $\frac{1}{N}\sum(y_{pred} - y_{true})^2$. Estandar en regresion continua. |
929
+ | `GRX::Loss::MAELoss` | `new(reduction: :mean)` | `reduction: :mean` | Error Absoluto Medio: $\frac{1}{N}\sum \|y_{pred} - y_{true}\|$. Robusto ante valores atipicos (*outliers*). |
930
+ | `GRX::Loss::BCELoss` | `new(reduction: :mean, eps: 1e-7)` | `eps: 1e-7` | Entropia Cruzada Binaria: $-[y \log(p) + (1-y) \log(1-p)]$. Protegido con `eps` para evitar $\log(0)$. |
931
+ | `GRX::Loss::CrossEntropyLoss` | `new(reduction: :mean)` | `reduction: :mean` | Entropia Cruzada Multiclase. Combina Softmax con Log-Sum-Exp y log-likelihood negativo. |
932
+ | `GRX::Loss::HuberLoss` | `new(delta: 1.0, reduction: :mean)` | `delta: 1.0` | Perdida Huber / Smooth L1: Cuadratica para error $< \delta$, lineal para error $\ge \delta$. |
933
+
934
+ * Opciones de `reduction`: `:mean` (divide la perdida total entre el tamano del lote; recomendado) o `:sum` (acumula la suma directa sin promediar).
935
+
936
+ ---
937
+
938
+ ## Guia de Notacion Cientifica y Parametros
939
+
940
+ ### 1. Que significa la Notacion Cientifica en Machine Learning (`1e-1` a `1e-8`)?
941
+
942
+ En Ruby y en Inteligencia Artificial, los numeros muy pequenos se escriben en **notacion cientifica exponencial** (`1e-X` que equivale a $1.0 \times 10^{-X}$). Esto evita errores tipograficos al contar ceros decimales:
943
+
944
+ | Notacion Ruby | Valor Decimal Exacto | Fraccion | Nombre Comun | Uso Tipico en GRTensor |
945
+ |---|---|---|---|---|
946
+ | `1e-1` | `0.1` | $1/10$ | Una decima | Momentum de actualizacion en `BatchNorm1d`, learning rate rapido. |
947
+ | `1e-2` | `0.01` | $1/100$ | Una centesima | Learning rate estandar para `SGD`, pendiente `alpha` en `LeakyReLU`. |
948
+ | `1e-3` | `0.001` | $1/1,000$ | Una milesima | Learning rate estandar de oro para `Adam` en redes profundas. |
949
+ | `1e-4` | `0.0001` | $1/10,000$ | Una diezmilesima | Penalizacion de regularizacion L2 (`weight_decay`) para evitar sobreajuste. |
950
+ | `1e-5` | `0.00001` | $1/100,000$ | Una cienmilesima | Epsilon (`eps`) de varianza en `LayerNorm` y `BatchNorm1d`. |
951
+ | `1e-7` | `0.0000001` | $1/10,000,000$ | Una diezmillonesima | Epsilon de corte en `BCELoss` para evitar $\log(0) \to -\infty$. |
952
+ | `1e-8` | `0.00000001` | $1/100,000,000$ | Una cienmillonesima | Epsilon de estabilidad numerica en el denominador de `Adam`. |
953
+
954
+ ---
955
+
956
+ ### 2. Parametros de Capas Neuronales (`GRX::NN`)
957
+
958
+ | Capa / Modulo | Parametro | Tipo | Por Defecto | Rango Valido | Explicacion Didactica |
959
+ |---|---|---|---|---|---|
960
+ | `Linear` | `in_features` | Integer | (Requerido) | $\ge 1$ | Cantidad de numeros de entrada que recibe la capa. |
961
+ | `Linear` | `out_features` | Integer | (Requerido) | $\ge 1$ | Cantidad de neuronas o caracteristicas que produce de salida. |
962
+ | `Linear` | `bias` | Boolean | `true` | `true` / `false` | Si es `true`, agrega el termino de sesgo $b$ ($y = Wx + b$). |
963
+ | `Embedding`| `num_embeddings` | Integer | (Requerido) | $\ge 1$ | Tamano del vocabulario o numero total de entidades unicas. |
964
+ | `Embedding`| `embedding_dim` | Integer | (Requerido) | $\ge 1$ | Dimension del vector denso continuo para representar cada palabra. |
965
+ | `Dropout` | `p` | Float | `0.5` | `0.0` a `0.99` | Probabilidad de desactivar aleatoriamente una neurona durante el entrenamiento (0.2 = 20%, 0.5 = 50%) para evitar que la red se vuelva dependiente de una sola neurona. |
966
+ | `LeakyReLU`| `alpha` | Float | `0.01` | `0.001` a `0.3` | Pendiente para numeros negativos. Evita que las neuronas "mueran" permitiendo pasar un 1% de gradiente cuando $x < 0$. |
967
+ | `LayerNorm`| `normalized_shape`| Integer/Array | (Requerido) | Dimensiones | Dimension sobre la que se calcula la media y varianza unitaria. |
968
+ | `LayerNorm`| `eps` / `epsilon` | Float | `1e-5` | `1e-8` a `1e-4` | Termino sumado a la varianza para evitar division entre 0. |
969
+ | `BatchNorm1d`| `num_features` | Integer | (Requerido) | $\ge 1$ | Cantidad de canales a normalizar a lo largo del lote (*batch*). |
970
+ | `BatchNorm1d`| `eps` / `epsilon` | Float | `1e-5` | `1e-8` a `1e-4` | Termino de estabilidad sumado a la varianza por lote. |
971
+ | `BatchNorm1d`| `momentum` | Float | `0.1` | `0.01` a `0.5` | Factor de actualizacion de medias y varianzas moviles para inferencia. |
972
+
973
+ ---
974
+
975
+ ### 3. Parametros de Creacion y Operaciones de Tensores (`GRX::Tensor`)
976
+
977
+ | Factory / Metodo | Parametro | Tipo | Por Defecto | Descripcion |
978
+ |---|---|---|---|---|
979
+ | `GRX.tensor` | `data` | Array / Storage | (Requerido) | Arreglo plano o anidado de numeros Ruby (`[1.0, 2.0]` o `[[1, 2], [3, 4]]`). |
980
+ | `GRX.tensor` | `shape` | Array[Integer] | `nil` (Auto) | Dimensiones explicitas (ej. `[2, 3]`). Se infiere automaticamente si se omite. |
981
+ | `GRX.tensor` | `requires_grad`| Boolean | `false` | Habilita el rastreo de diferenciacion automatica (Autograd) en el DAG. |
982
+ | `GRX.zeros` / `GRX.ones` | `shape` | Array[Integer] | (Requerido) | Dimensiones del tensor a inicializar con `0.0` o `1.0`. |
983
+ | `GRX.rand` | `shape` | Array[Integer] | (Requerido) | Tensor aleatorio con distribucion uniforme $U[0, 1)$. |
984
+ | `GRX.randn` | `shape` | Array[Integer] | (Requerido) | Tensor aleatorio normal estandar $N(0, 1)$ mediante Box-Muller. |
985
+ | `Tensor.xavier_uniform`| `shape` | Array[Integer] | (Requerido) | Inicializacion Xavier/Glorot ($U[-\sqrt{6/(f_{in}+f_{out})}, \sqrt{6/(f_{in}+f_{out})}]$). |
986
+ | `Tensor.he_normal` | `shape` | Array[Integer] | (Requerido) | Inicializacion He/Kaiming normal ($N(0, \sqrt{2/f_{in}})$). Optima para capas ReLU. |
987
+ | `Tensor.zeros_like` | `other` | Tensor | (Requerido) | Crea un tensor de ceros con la misma forma que `other`. |
988
+ | `Tensor.ones_like` | `other` | Tensor | (Requerido) | Crea un tensor de unos con la misma forma que `other`. |
989
+ | `tensor.clip` | `lo`, `hi` | Numeric | (Requeridos) | Fija todos los elementos dentro del intervalo $[lo, hi]$. |
990
+ | `tensor.pow` | `exponent` | Numeric | (Requerido) | Eleva cada elemento a la potencia $x^e$. Totalmente diferenciable. |
991
+ | `tensor.reshape` | `new_shape` | Array[Integer] | (Requerido) | Cambia la forma manteniendo el conteo de elementos. Vista zero-copy. |
992
+ | `tensor.transpose` | (sin args) | - | - | Intercambia ejes de matrices 2D por zancadas. Vista zero-copy. |
993
+ | `tensor.flatten` | (sin args) | - | - | Aplana el tensor a 1 dimension `[numel]`. Vista zero-copy. |
994
+ | `tensor.contiguous`| (sin args) | - | - | Re-empaqueta vistas no contiguas en un buffer contiguo nuevo. |
995
+ | `tensor.get` | `*coords` | Integers | (Requerido) | Retorna el float escalar en las coordenadas indicadas. |
996
+ | `tensor.set` | `*coords, val` | Integers, Float | (Requeridos) | Modifica directamente el valor en las coordenadas indicadas. |
997
+ | `tensor.item` | (sin args) | - | - | Extrae el valor Float de un tensor escalar de 1 elemento. |
998
+ | `tensor.argmax` | (sin args) | - | - | Retorna el indice del elemento con el valor maximo. |
999
+ | `tensor.argmin` | (sin args) | - | - | Retorna el indice del elemento con el valor minimo. |
1000
+ | `tensor.backward` | `gradient` | Tensor | `nil` | Ejecuta la retropropagacion inversa a traves del grafo computacional DAG. |
1001
+
1002
+ ---
1003
+
1004
+ ### 4. Pipelines de Datos, Persistencia y Utilidades (`GRX::Data`, `GRX::Serialization`, `GRX::Utils`)
1005
+
1006
+ * `TensorDataset.new(*tensors)`:
1007
+ * `*tensors` (Requeridos): Tensores paralelos de caracteristicas y etiquetas que comparten el tamano de lote en dimension 0.
1008
+ * `DataLoader.new(dataset, batch_size: 32, shuffle: true)`:
1009
+ * `dataset` (`GRX::Data::Dataset`): Dataset envuelto.
1010
+ * `batch_size` (Integer, por defecto: `32`): Cantidad de muestras por lote.
1011
+ * `shuffle` (Boolean, por defecto: `true`): Permuta aleatoriamente los indices al inicio de cada epoca.
1012
+ * `GRX::Serialization.save(model, path)` / `model.save_weights(path)`:
1013
+ * `model` (`GRX::NN::Module`): Instancia del modelo neuronal.
1014
+ * `path` (String): Ruta del archivo `.grx` binario de salida. Vuelca directamente los doubles IEEE 754 de 64 bits.
1015
+ * `GRX::Serialization.load(model, path)` / `model.load_weights(path)`:
1016
+ * `model` (`GRX::NN::Module`): Modelo instanciado con la misma arquitectura.
1017
+ * `path` (String): Archivo `.grx` origen a cargar.
1018
+ * `model.train!` y `model.eval!`:
1019
+ * `train!`: Activa modo entrenamiento (habilita `Dropout` y calcula medias por lote en `BatchNorm1d`).
1020
+ * `eval!`: Activa modo inferencia (desactiva `Dropout` y congela medias fijas en `BatchNorm1d`).
1021
+ * `GRX::Utils.clip_grad_norm!(parameters, max_norm: 1.0)`:
1022
+ * `parameters` (Array[Tensor]): Coleccion de parametros con gradientes.
1023
+ * `max_norm` (Float, por defecto: `1.0`): Norma L2 maxima permitida para evitar explosiones.
1024
+ * `GRX::Utils.one_hot(indices, num_classes: nil, requires_grad: false)`:
1025
+ * `indices` (Array[Integer] o Tensor): Etiquetas de clase enteras (ej. `[0, 2, 1]`).
1026
+ * `num_classes` (Integer, opcional): Total de clases. Se calcula como `max + 1` si se omite.
1027
+ * `GRX.simd_mode`:
1028
+ * Consulta el nivel de vectorizacion nativa: `:avx2` (4 doubles/ciclo con FMA), `:sse` (2 doubles/ciclo), `:scalar` (C portable) o `:ruby`.
1029
+
1030
+ ---
1031
+
1032
+ ### 5. Jerarquia de Excepciones de GRTensor
1033
+
1034
+ | Excepcion | Hereda de | Causa Principal |
1035
+ |---|---|---|
1036
+ | `GRX::Error` | `StandardError` | Clase base para todas las excepciones del framework. |
1037
+ | `GRX::ShapeError` | `GRX::Error` | Dimensiones incompatibles en operaciones algebraicas o multiplicaciones de matrices. |
1038
+ | `GRX::DimensionError` | `GRX::Error` | Rango de dimensiones invalido (ej. ejecutar `transpose` o `matmul` en tensores 1D). |
1039
+ | `GRX::StorageError` | `GRX::Error` | Fallo de asignacion de memoria heap en C (OOM) o archivo binario `.grx` corrupto. |
1040
+
1041
+ ---
1042
+
1043
+ ## Catalogo de Optimizadores e Hiperparametros (`GRX::Optim`)
1044
+
1045
+ ### 1. `GRX::Optim::Adam`
1046
+ Optimizador Adam (Adaptive Moment Estimation) vectorizado en C con instrucciones FMA y correccion de sesgo:
1047
+
1048
+ ```ruby
1049
+ optimizer = GRX::Optim::Adam.new(
1050
+ modelo.parameters,
1051
+ lr: 0.001, # Tasa de aprendizaje (alpha). Recomendado: 1e-3 (0.001) para redes profundas
1052
+ betas: [0.9, 0.999], # [beta1, beta2] decaimiento exponencial para momentos de 1er/2do orden
1053
+ eps: 1e-8, # Epsilon para estabilidad numerica en el denominador (evita division entre 0)
1054
+ weight_decay: 1e-4 # Regularizacion L2 (penalizacion para encoger pesos y evitar sobreajuste)
1055
+ )
1056
+ ```
1057
+
1058
+ | Parametro | Tipo | Por Defecto | Rango Recomendado | Descripcion |
1059
+ |---|---|---|---|---|
1060
+ | `lr` | Float | `0.001` | `1e-4` a `1e-2` | Factor de escala del paso en la direccion opuesta al gradiente. |
1061
+ | `betas` / `beta1, beta2` | Array / Floats | `[0.9, 0.999]` | `[0.9, 0.999]` | $\beta_1$ conserva inercia de direccion; $\beta_2$ rastrea la varianza del gradiente al cuadrado. |
1062
+ | `eps` / `epsilon` | Float | `1e-8` | `1e-8` a `1e-6` | Constante diminuta sumada al denominador para prevenir `NaN`. |
1063
+ | `weight_decay` | Float | `0.0` | `1e-5` a `1e-3` | Penalizacion L2 ($\lambda$) que previene la memorizacion de datos (*overfitting*). |
1064
+
1065
+ ### 2. `GRX::Optim::SGD`
1066
+ Descenso por Gradiente Estocastico con momento e inercia:
1067
+
1068
+ ```ruby
1069
+ optimizer = GRX::Optim::SGD.new(
1070
+ modelo.parameters,
1071
+ lr: 0.01, # Tasa de aprendizaje. Recomendado: 0.01 a 0.1
1072
+ momentum: 0.9, # Coeficiente del buffer de momento (mu). Recomendado: 0.9
1073
+ weight_decay: 1e-4 # Factor de regularizacion L2
1074
+ )
1075
+ ```
1076
+
1077
+ | Parametro | Tipo | Por Defecto | Rango Recomendado | Descripcion |
1078
+ |---|---|---|---|---|
1079
+ | `lr` | Float | `0.01` | `0.001` a `0.1` | Tamano del paso de descenso por gradiente. |
1080
+ | `momentum` | Float | `0.0` | `0.8` a `0.99` | Inercia acumulada para acelerar el descenso y filtrar oscilaciones caoticas. |
1081
+ | `weight_decay` | Float | `0.0` | `1e-5` a `1e-3` | Penalizacion L2 para regularizar pesos. |
1082
+
1083
+ ---
1084
+
1085
+ ## Pipelines de Datos y DataLoader (`GRX::Data`)
1086
+
1087
+ ### 1. `GRX::Data::TensorDataset`
1088
+ Encapsula tensores de caracteristicas y etiquetas en un dataset indexable:
1089
+
1090
+ ```ruby
1091
+ x_data = GRX.randn([1000, 20])
1092
+ y_data = GRX.tensor(Array.new(1000) { rand(0..2) }, [1000])
1093
+
1094
+ dataset = GRX::Data::TensorDataset.new(x_data, y_data)
1095
+ puts dataset.size # 1000 muestras
1096
+ ```
1097
+
1098
+ ### 2. `GRX::Data::DataLoader`
1099
+ Generador de lotes (*batches*) con barajado automatico e iteracion eficiente:
1100
+
1101
+ ```ruby
1102
+ loader = GRX::Data::DataLoader.new(dataset, batch_size: 32, shuffle: true)
1103
+
1104
+ loader.each_with_index do |(batch_x, batch_y), idx|
1105
+ optimizer.zero_grad
1106
+ preds = modelo.forward(batch_x)
1107
+ loss = criterio.call(preds, batch_y)
1108
+ loss.backward
1109
+ optimizer.step
1110
+ end
1111
+ ```
1112
+
1113
+ ---
1114
+
1115
+ ## Persistencia de Modelos y Cerebros (Formato `.grx`)
1116
+
1117
+ ### Especificacion del Formato Binario `GRX1`
1118
+
1119
+ GRX incorpora un motor de serializacion binaria de alta velocidad que vuelca los parametros flotantes directamente desde la memoria nativa en C:
1120
+
1121
+ ```text
1122
+ +-------------------+--------------------+---------------------------------------------+
1123
+ | Campo | Tamano | Contenido |
1124
+ +-------------------+--------------------+---------------------------------------------+
1125
+ | Cabecera Magica | 8 bytes | "GRX1\0\0\0\0" (ASCII con relleno nulo) |
1126
+ | Total Parametros | 4 bytes | uint32 big-endian |
1127
+ +-------------------+--------------------+---------------------------------------------+
1128
+ | Para cada tensor de parametros: |
1129
+ | - Rango | 2 bytes | uint16 big-endian |
1130
+ | - Dimensiones | Rango * 4 bytes | Arreglo uint32 big-endian |
1131
+ | - Numel | 8 bytes | uint64 big-endian |
1132
+ | - Carga de Datos | Numel * 8 bytes | Doubles IEEE 754 de 64 bits (Copia directa) |
1133
+ +-------------------+--------------------+---------------------------------------------+
1134
+ ```
1135
+
1136
+ ### Flujo de Despliegue de Inferencia en Produccion
1137
+
1138
+ #### Paso 1: Entrenar y Guardar el Cerebro (`entrenar.rb`)
1139
+ ```ruby
1140
+ require "grx"
1141
+
1142
+ modelo = GRX::NN::Sequential.new(
1143
+ GRX::NN::Linear.new(4, 16),
1144
+ GRX::NN::ReLU.new,
1145
+ GRX::NN::Linear.new(16, 2)
1146
+ )
1147
+
1148
+ # ... (bucle de entrenamiento) ...
1149
+
1150
+ modelo.save_weights("cerebro_campeon.grx")
1151
+ puts "Pesos guardados exitosamente en cerebro_campeon.grx"
1152
+ ```
1153
+
1154
+ #### Paso 2: Cargar e Inyectar en API de Produccion (`servidor_api.rb`)
1155
+ ```ruby
1156
+ require "grx"
1157
+
1158
+ cerebro = GRX::NN::Sequential.new(
1159
+ GRX::NN::Linear.new(4, 16),
1160
+ GRX::NN::ReLU.new,
1161
+ GRX::NN::Linear.new(16, 2)
1162
+ )
1163
+
1164
+ # Cargar los pesos binarios al instante sin re-entrenar
1165
+ cerebro.load_weights("cerebro_campeon.grx")
1166
+ cerebro.eval!
1167
+
1168
+ peticion = GRX.tensor([[0.5, -1.2, 3.4, 0.1]], [1, 4])
1169
+ probabilidades = cerebro.forward(peticion).softmax.to_a
1170
+
1171
+ puts "Probabilidades de Decision en Produccion: #{probabilidades.map { |d| d.round(4) }}"
1172
+ ```
1173
+
1174
+ ---
1175
+
1176
+ ## Gestion de Gradientes y Utilidades (`GRX::Utils`)
1177
+
1178
+ ```ruby
1179
+ # 1. Recorte de norma de gradiente (Gradient Clipping) para estabilizar redes profundas
1180
+ norma_total = GRX::Utils.clip_grad_norm!(modelo.parameters, max_norm: 1.0)
1181
+
1182
+ # 2. Conversion de etiquetas a One-Hot
1183
+ one_hot_matriz = GRX::Utils.one_hot([0, 2, 1], num_classes: 3)
1184
+ ```
1185
+
1186
+ ---
1187
+
1188
+ ## Guia de Soporte y Herramientas para Windows
1189
+
1190
+ En el sistema operativo Windows:
1191
+ * **Aceleracion C Nativa (Recomendado):** Se activa automaticamente al instalar con **RubyInstaller con DevKit (MSYS2 / MinGW-w64)**. La extension nativa se compila de manera transparente durante `gem install grx-tensor`.
1192
+ * **Fallback en Ruby Puro:** Si DevKit no esta instalado en el sistema, GRX conmuta de forma segura al modo de calculo en Ruby puro sin producir errores.
1193
+ * **Binarios Pre-compilados Independientes:** Las gemas fat-binary con archivos `.dll` pre-empaquetados se encuentran en desarrollo activo.
265
1194
 
266
1195
  ---
267
1196
 
268
1197
  ## Licencia
269
1198
 
270
- Licencia MIT. Consulta el archivo [LICENSE.txt](LICENSE.txt) para mas detalles.
1199
+ Licencia MIT. Copyright (c) 2026 Razo.