Sesgo de frecuencia del descenso de gradiente estocástico (SGD) y cómo Adam lo soluciona
BG = “#fafaf8” DARK = “#1a1a1a” # Rampa de color: azul para fichas comunes, rojo para TOKEN_COLORS raros = [“#1a5276”, “#2471a3”, “#5dade2”, “#e67e22”, “#c0392b”, “#7d2a2a”]

pasos = np.arange(N_STEPS) fig = plt.figure(figsize=(16, 11), facecolor=BG) fig.suptitle( “SGD vs. Adam en tokens raros – Normalización de varianza y sesgo de frecuencia”, fontsize=14, fontweight=”bold”, color=DARK, y=0.99 ) gs = gridspec.GridSpec(2, 3, figure=fig, hspace=0.45, wspace=0.35) # ── 1. Trayectorias de peso SGD ──────────────────────────────── ax1 = fig.add_subplot(gs[0, :2]) ax1.set_facecolor(BG) ax1.axhline(1.0, color=DARK, lw=1, ls=”–“, alpha=0.3, label=”Trueweight = 1.0″) para i, (token, color) en enumerate(zip(TOKENS, TOKEN_COLORS)): ax1.plot(steps, sgd_history[:, i]color=color, lw=1.8, etiqueta=f”{token} (freq={FREQ[i]:.3f})”) ax1.set_title(“SGD – Trayectorias de peso\nLos tokens raros apenas se mueven desde cero”, fontsize=11, color=DARK) ax1.set_xlabel(“Paso de entrenamiento”, fontsize=9) ax1.set_ylabel(“Peso aprendido”, fontsize=9) ax1.legend(fontsize=8, loc=”right”) ax1.set_ylim(-0.3, 1.6) ax1.spines[[“top”, “right”]].set_visible(False) # Anotar zona de falla ax1.annotate( “Tokens raros atascados\ncerca de cero”, xy=(N_STEPS * 0.95, sgd_history[-1, 5]), xytext=(N_STEPS * 0.65, -0.15), tamaño de fuente=8.5, color=”#c0392b”, arrowprops=dict(arrowstyle=”->”, color=”#c0392b”, lw=1.2), bbox=dict(boxstyle=”round,pad=0.3″, facecolor=”#fff0f0″, edgecolor=”#c0392b”, alpha=0.85) ) # ── 2. Gráfico de barras de error de peso final ─────────────────────────── ax2 = fig.add_subplot(gs[0, 2]) ax2.set_facecolor(BG) x = np.arange(6) w_sgd = sgd_final w_adam = adam_final ancho = 0.35 bars_sgd = ax2.bar(x – ancho/2, np.abs(w_sgd – TRUE_W), ancho, color=”#c0392b”, alpha=0.85, label=”Error SGD”) bars_adam = ax2.bar(x + ancho/2, np.abs(w_adam – TRUE_W), ancho, color=”#2980b9″, alpha=0.85, label=”Error de Adam”) ax2.set_xticks(x) ax2.set_xticklabels([t[:8] para t en TOKENS]rotación=30, ha=”right”, fontsize=8) ax2.set_ylabel(“|aprendido w − true w|”, fontsize=9) ax2.set_title(“Error de peso final\n(inferior = mejor)”, fontsize=11, color=DARK) ax2.legend(fontsize=8) ax2.spines[[“top”, “right”]].set_visible(False) # ── 3. Trayectorias de peso de Adam ─────────────────────────────── ax3 = fig.add_subplot(gs[1, :2]) ax3.set_facecolor(BG) ax3.axhline(1.0, color=DARK, lw=1, ls=”–“, alpha=0.3, label=”Trueweight = 1.0″) para i, (token, color) en enumerate(zip(TOKENS, TOKEN_COLORS)): ax3.plot(steps, adam_history[:, i]color=color, lw=1.8, etiqueta=f”{token} (freq={FREQ[i]:.3f})”) ax3.set_title(“Adam – Trayectorias de peso\nLos tokens raros convergen mediante la normalización de la varianza”, fontsize=11, color=DARK) ax3.set_xlabel(“Paso de entrenamiento”, fontsize=9) ax3.set_ylabel(“Peso aprendido”, fontsize=9) ax3.legend(fontsize=8, loc=”right”) ax3.set_ylim(-0.3, 1.6) ax3.spines[[“top”, “right”]].set_visible(False) ax3.annotate( “Los tokens raros convergen\na pesar de los gradientes escasos”, xy=(N_STEPS * 0.95, adam_history[-1, 5]), xytext=(N_STEPS * 0.60, 0.3), fontsize=8.5, color=”#27ae60″, arrowprops=dict(arrowstyle=”->”, color=”#27ae60″, lw=1.2), bbox=dict(boxstyle=”round,pad=0.3″, facecolor=”#f0fff4″, edgecolor=”#27ae60″, alpha=0.85) ) # ── 4. LR efectivo vs frecuencia ───────────────────────────── ax4 = fig.add_subplot(gs[1, 2]) ax4.set_facecolor(BG) ax4.scatter(FREQ, Effective_lr, c=TOKEN_COLORS, s=120, zorder=5, edgecolors=”white”, lw=1.5) para i, token en enumerar(TOKENS): ax4.annotate(token, (FREQ[i]efectivo_lr[i]), textcoords=”puntos de desplazamiento”, xytext=(6, 4), tamaño de fuente=7.5, color=TOKEN_COLORS[i]) ax4.axhline(LR, color=OSCURO, lw=1, ls=”–“, alfa=0.4) ax4.text(0.5, LR * 1.05, f”Nominal LR = {LR}”, tamaño de fuente=8, color=OSCURO, alfa=0.6) ax4.set_xscale(“log”) ax4.set_yscale(“log”) ax4.set_xlabel(“Frecuencia del token (escala logarítmica)”, fontsize=9) ax4.set_ylabel(“Adam Effective LR lr/√v̂ (escala logarítmica)”, fontsize=9) ax4.set_title(“Ecualizador automático de Adam\nLos tokens raros obtienen LR amplificado”, fontsize=11, color=DARK) ax4.spines[[“top”, “right”]].set_visible(False) plt.savefig(“sgd_vs_adam.png”, dpi=150, bbox_inches=”tight”, facecolor=BG) plt.show()