grx-tensor 0.1.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 ADDED
@@ -0,0 +1,1199 @@
1
+ # GRX-Tensor
2
+
3
+ **Ruby habla. C calcula.**
4
+
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
+
7
+ [![Ruby](https://img.shields.io/badge/ruby-%3E%3D%203.0-CC342D?logo=ruby)](https://www.ruby-lang.org)
8
+ [![Licencia: MIT](https://img.shields.io/badge/license-MIT-blue)](LICENSE.txt)
9
+ [![Plataforma](https://img.shields.io/badge/platform-Linux%20%7C%20macOS%20%7C%20Windows-lightgrey)](https://github.com/Gabo-Razo/grx-tensor)
10
+
11
+ ---
12
+
13
+ ## Flujo Arquitectonico del Sistema
14
+
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
48
+
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
+ ---
61
+
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
+ ---
129
+
130
+ ## Caracteristicas Principales
131
+
132
+ | Caracteristica | Especificacion |
133
+ |---|---|
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 |
147
+
148
+ ---
149
+
150
+ ## Instalacion
151
+
152
+ ### Instalacion Estandar con RubyGems
153
+
154
+ ```bash
155
+ gem install grx-tensor
156
+ ```
157
+
158
+ O agregalo al `Gemfile` de tu proyecto:
159
+
160
+ ```ruby
161
+ gem "grx-tensor"
162
+ ```
163
+
164
+ La extension nativa en C se compila y enlaza de forma automatica y transparente durante la instalacion.
165
+
166
+ ---
167
+
168
+ ## Tutoriales Basicos de Inicio Rapido
169
+
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)"
202
+ ```
203
+
204
+ ---
205
+
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:
209
+
210
+ ```ruby
211
+ require "grx"
212
+
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])
216
+
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
+ )
224
+
225
+ opt = GRX::Optim::Adam.new(red_xor.parameters, lr: 0.05)
226
+ loss_fn = GRX::Loss::BCELoss.new
227
+
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) }}"
237
+ ```
238
+
239
+ ---
240
+
241
+ ### 3. Matematicas Tensoriales Cotidianas en 4 Lineas
242
+
243
+ ```ruby
244
+ require "grx"
245
+
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"
397
+
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)
401
+
402
+ y = (x * w) + b
403
+ loss = y.sum
404
+ loss.backward
405
+
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]
409
+ ```
410
+
411
+ ---
412
+
413
+ ## Computacion Cientifica y Numerica (Mas Alla del Deep Learning)
414
+
415
+ Los tensores son motores matematicos multidimensionales de proposito general ideales para procesamiento de senales, finanzas cuantitativas, fisica computacional y optimizacion matematica.
416
+
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:
420
+
421
+ ```ruby
422
+ require "grx"
423
+
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
450
+ end
451
+ end
452
+
453
+ bordes = GRX.tensor(mapa_bordes, [filas_out, cols_out])
454
+ puts "Dimension del Mapa de Bordes: #{bordes.shape}"
455
+ ```
456
+
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)
480
+ end
481
+ end
482
+ retornos = GRX.tensor(retornos_data, [4, 3])
483
+
484
+ medias = Array.new(3) do |activo|
485
+ col = 4.times.map { |d| retornos.get(d, activo) }
486
+ col.sum / 4.0
487
+ end
488
+
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)}"
549
+ ```
550
+
551
+ ---
552
+
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$$
557
+
558
+ ```ruby
559
+ require "grx"
560
+
561
+ punto = GRX.tensor([-1.5, 2.0], [2], requires_grad: true)
562
+ lr = 0.002
563
+
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])
579
+ end
580
+
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)
687
+ )
688
+
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:
709
+
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(
723
+ GRX::NN::Linear.new(4, 16),
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),
762
+ GRX::NN::Tanh.new,
763
+ GRX::NN::Linear.new(64, tamano_vocabulario)
764
+ )
765
+
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])
770
+
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)
873
+ end
874
+ end
875
+
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]
912
+
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"
918
+ ```
919
+
920
+ ---
921
+
922
+ ## Funciones de Perdida (`GRX::Loss`)
923
+
924
+ Todas las funciones de perdida retornan un tensor escalar diferenciable listo para `loss.backward`.
925
+
926
+ | Clase de Perdida | Constructor y Parametros | Por Defecto | Explicacion Matematica y Uso |
927
+ |---|---|---|---|
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.
1194
+
1195
+ ---
1196
+
1197
+ ## Licencia
1198
+
1199
+ Licencia MIT. Copyright (c) 2026 Razo.