@@ -252,31 +252,90 @@ private static void scalarMicrokernel(FlatMatrixF A, FlatMatrixF B, FlatMatrixF
252252 }
253253
254254 // ====================== ELEMENTWISE ======================
255- public void geluInPlace () {
256- int len = rows * cols , idx = 0 ;
255+ /**
256+ * Slower than Bert, but MORE accurate GELU in-place using the Sigmoid-based
257+ * exact identity math. Matches standard Tanh approximation curves
258+ * perfectly.
259+ */
260+ public void geluInPlaceSigmoid () {
261+ int len = rows * cols ;
262+ int idx = 0 ;
263+
257264 if (HAS_VECTOR && isContiguous ()) {
265+ // 2 * 0.79788456f = 1.59576912f
266+ final FloatVector V_C1 = FloatVector .broadcast (F_SPECIES , 1.59576912f );
267+ final FloatVector V_C2 = FloatVector .broadcast (F_SPECIES , 0.044715f );
268+ final FloatVector V_ONE = FloatVector .broadcast (F_SPECIES , 1.0f );
269+
258270 for (; idx < F_SPECIES .loopBound (len ); idx += VF_LEN ) {
259- var v = FloatVector .fromArray (F_SPECIES , data , offset + idx );
260- var x2 = v .mul (v );
261- var inner = v .add (x2 .mul (v ).mul (V_GELU_C2 )).mul (V_GELU_C1 );
262- var t = inner .lanewise (VectorOperators .TANH );
263- v .mul (V_HALF ).mul (t .add (V_ONE )).intoArray (data , offset + idx );
271+ var x = FloatVector .fromArray (F_SPECIES , this .data , this .offset + idx );
272+
273+ var x3 = x .mul (x ).mul (x );
274+ var z = x .add (x3 .mul (V_C2 )).mul (V_C1 );
275+
276+ // Compute the denominator: 1 + e^(-z)
277+ var denominator = V_ONE .add (fastExp (z .neg ()));
278+
279+ // Divide x directly by the denominator to get x * sigmoid(z)
280+ var result = x .div (denominator );
281+
282+ result .intoArray (this .data , this .offset + idx );
264283 }
265284 }
285+
286+ // Scalar fallback matching the exact Tanh/Sigmoid curve behavior
266287 for (; idx < len ; idx ++) {
267- float x = data [offset + idx ];
288+ float x = this . data [this . offset + idx ];
268289 float x3 = x * x * x ;
269- float t = (float ) Math .tanh (GELU_C1 * (x + GELU_C2 * x3 ));
270- data [offset + idx ] = 0.5f * x * (1.0f + t );
290+ float t = (float ) Math .tanh (0.79788456f * (x + 0.044715f * x3 ));
291+ this . data [this . offset + idx ] = 0.5f * x * (1.0f + t );
271292 }
272293 }
273294
274295 /**
275- * GeGLU in-place: output = inputs[0] ⊙ GELU(inputs[1])
296+ * Faster than sigmoid, but less accurate GELU in-place using the fast
297+ * BERT/OpenAI 1.702 * x approximation. Eliminates cubic calculations
298+ * entirely for maximum throughput.
299+ */
300+ public void geluInPlaceBert () {
301+ int len = rows * cols ;
302+ int idx = 0 ;
303+
304+ if (HAS_VECTOR && isContiguous ()) {
305+ final FloatVector V_BERT_C = FloatVector .broadcast (F_SPECIES , 1.702f );
306+ final FloatVector V_ONE = FloatVector .broadcast (F_SPECIES , 1.0f );
307+
308+ for (; idx < F_SPECIES .loopBound (len ); idx += VF_LEN ) {
309+ var x = FloatVector .fromArray (F_SPECIES , this .data , this .offset + idx );
310+
311+ // z = 1.702 * x
312+ var z = x .mul (V_BERT_C );
313+
314+ // sigmoid(z) = 1 / (1 + fastExp(-z))
315+ var denominator = V_ONE .add (fastExp (z .neg ()));
316+
317+ // x * sigmoid(z)
318+ var result = x .div (denominator );
319+ result .intoArray (this .data , this .offset + idx );
320+ }
321+ }
322+
323+ // Scalar fallback matching the exact 1.702 sigmoid calculation
324+ for (; idx < len ; idx ++) {
325+ float x = this .data [this .offset + idx ];
326+ float sigmoid = 1.0f / (1.0f + (float ) Math .exp (-1.702f * x ));
327+ this .data [this .offset + idx ] = x * sigmoid ;
328+ }
329+ }
330+
331+ /**
332+ * Slower than Bert, but MORE accurate GeGLU in-place using the
333+ * Sigmoid-based exact identity math. Computes: output = value *
334+ * GELU_sigmoid(gate)
276335 *
277- * @param gate
336+ * @param gate The gating matrix (inputs[1])
278337 */
279- public void gegluInPlaceOld (FlatMatrixF gate ) { // gate is inputs[1]
338+ public void gegluInPlaceSigmoid (FlatMatrixF gate ) {
280339 if (rows != gate .rows || cols != gate .cols ) {
281340 throw new IllegalArgumentException ("Shape mismatch for GeGLU" );
282341 }
@@ -285,35 +344,88 @@ public void gegluInPlaceOld(FlatMatrixF gate) { // gate is inputs[1]
285344 int idx = 0 ;
286345
287346 if (HAS_VECTOR && isContiguous () && gate .isContiguous ()) {
347+ // 2 * 0.79788456f = 1.59576912f
348+ final FloatVector V_C1 = FloatVector .broadcast (F_SPECIES , 1.59576912f );
349+ final FloatVector V_C2 = FloatVector .broadcast (F_SPECIES , 0.044715f );
350+ final FloatVector V_ONE = FloatVector .broadcast (F_SPECIES , 1.0f );
351+
288352 for (; idx < F_SPECIES .loopBound (len ); idx += VF_LEN ) {
289353 var value = FloatVector .fromArray (F_SPECIES , this .data , this .offset + idx );
290354 var g = FloatVector .fromArray (F_SPECIES , gate .data , gate .offset + idx );
291355
292- // GELU on gate
293- var g2 = g .mul (g );
294- var g3 = g2 .mul (g );
295- var inner = g .add (g3 .mul (V_GELU_C2 )).mul (V_GELU_C1 );
296- var t = inner .lanewise (VectorOperators .TANH );
297- var geluGate = g .mul (V_HALF ).mul (t .add (V_ONE ));
356+ // z = 1.59576912 * (g + 0.044715 * g^3)
357+ var g3 = g .mul (g ).mul (g );
358+ var z = g .add (g3 .mul (V_C2 )).mul (V_C1 );
359+
360+ // GELU(gate) = g / (1 + fastExp(-z))
361+ var denominator = V_ONE .add (fastExp (z .neg ()));
362+ var geluGate = g .div (denominator );
298363
299364 // value * GELU(gate)
300365 value .mul (geluGate ).intoArray (this .data , this .offset + idx );
301366 }
302367 }
303368
304- // Scalar fallback
369+ // Scalar fallback matching the exact Tanh/Sigmoid curve behavior
305370 for (; idx < len ; idx ++) {
306371 float value = this .data [this .offset + idx ];
307372 float g = gate .data [gate .offset + idx ];
308373
309374 float g3 = g * g * g ;
310- float t = (float ) Math .tanh (GELU_C1 * (g + GELU_C2 * g3 ));
375+ float t = (float ) Math .tanh (0.79788456f * (g + 0.044715f * g3 ));
311376 float geluGate = 0.5f * g * (1.0f + t );
312377
313378 this .data [this .offset + idx ] = value * geluGate ;
314379 }
315380 }
316381
382+ /**
383+ * Faster than sigmoid, but less accurate GeGLU in-place using the fast
384+ * BERT/OpenAI 1.702 * g approximation. Computes: output = value *
385+ * GELU_bert(gate)
386+ *
387+ * @param gate The gating matrix (inputs[1])
388+ */
389+ public void gegluInPlaceBert (FlatMatrixF gate ) {
390+ if (rows != gate .rows || cols != gate .cols ) {
391+ throw new IllegalArgumentException ("Shape mismatch for GeGLU" );
392+ }
393+
394+ int len = rows * cols ;
395+ int idx = 0 ;
396+
397+ if (HAS_VECTOR && isContiguous () && gate .isContiguous ()) {
398+ final FloatVector V_BERT_C = FloatVector .broadcast (F_SPECIES , 1.702f );
399+ final FloatVector V_ONE = FloatVector .broadcast (F_SPECIES , 1.0f );
400+
401+ for (; idx < F_SPECIES .loopBound (len ); idx += VF_LEN ) {
402+ var value = FloatVector .fromArray (F_SPECIES , this .data , this .offset + idx );
403+ var g = FloatVector .fromArray (F_SPECIES , gate .data , gate .offset + idx );
404+
405+ // z = 1.702 * g
406+ var z = g .mul (V_BERT_C );
407+
408+ // GELU(gate) = g / (1 + fastExp(-z))
409+ var denominator = V_ONE .add (fastExp (z .neg ()));
410+ var geluGate = g .div (denominator );
411+
412+ // value * GELU(gate)
413+ value .mul (geluGate ).intoArray (this .data , this .offset + idx );
414+ }
415+ }
416+
417+ // Scalar fallback matching the exact 1.702 sigmoid calculation
418+ for (; idx < len ; idx ++) {
419+ float value = this .data [this .offset + idx ];
420+ float g = gate .data [gate .offset + idx ];
421+
422+ float sigmoid = 1.0f / (1.0f + (float ) Math .exp (-1.702f * g ));
423+ float geluGate = g * sigmoid ;
424+
425+ this .data [this .offset + idx ] = value * geluGate ;
426+ }
427+ }
428+
317429 public void gegluInPlace (FlatMatrixF gate ) {
318430 if (rows != gate .rows || cols != gate .cols ) {
319431 throw new IllegalArgumentException ("Shape mismatch for GeGLU" );
0 commit comments