@@ -402,3 +402,281 @@ define clip_grad_norm as:
402402 scale is max_val / norm_val
403403 return matrix_scale of [gradient, scale]
404404 return gradient
405+
406+
407+ # ═══════════════════════════════════════════════════════════════════════════════
408+ # CROSS-ENTROPY LOSS
409+ # ═══════════════════════════════════════════════════════════════════════════════
410+ # The standard loss function for language models
411+ # CE(y, p) = -sum(y * log(p)) where y is one-hot target, p is prediction
412+
413+ define cross_entropy_loss as:
414+ logits is arg[0]
415+ target_idx is arg[1]
416+ probs is softmax_matrix of logits
417+ prob_list is matrix_to_list of probs
418+ row is prob_list[0]
419+ target_prob is row[target_idx]
420+ target_val is what is target_prob
421+ epsilon is 0.0000001
422+ safe_prob is target_val + epsilon
423+ neg_log_prob is 0.0 - log of safe_prob
424+ return neg_log_prob
425+
426+
427+ define cross_entropy_with_label_smoothing as:
428+ logits is arg[0]
429+ target_idx is arg[1]
430+ smoothing is arg[2]
431+ vocab_size is arg[3]
432+ probs is softmax_matrix of logits
433+ prob_list is matrix_to_list of probs
434+ row is prob_list[0]
435+ target_prob is row[target_idx]
436+ target_val is what is target_prob
437+ epsilon is 0.0000001
438+ smooth_val is what is smoothing
439+ vocab_val is what is vocab_size
440+ confidence is 1.0 - smooth_val
441+ smooth_dist is smooth_val / vocab_val
442+ adjusted_target is confidence * target_val + smooth_dist
443+ safe_prob is adjusted_target + epsilon
444+ neg_log_prob is 0.0 - log of safe_prob
445+ return neg_log_prob
446+
447+
448+ # ═══════════════════════════════════════════════════════════════════════════════
449+ # PERPLEXITY
450+ # ═══════════════════════════════════════════════════════════════════════════════
451+ # PPL = exp(average cross-entropy loss)
452+ # Lower is better; measures how "surprised" the model is
453+
454+ define perplexity_from_loss as:
455+ avg_loss is arg[0]
456+ loss_val is what is avg_loss
457+ ppl is exp of loss_val
458+ return ppl
459+
460+
461+ # ═══════════════════════════════════════════════════════════════════════════════
462+ # ADAMW OPTIMIZER
463+ # ═══════════════════════════════════════════════════════════════════════════════
464+ # AdamW: Adam with decoupled weight decay (standard for LLMs)
465+ # Unlike Adam, weight decay is applied directly to weights, not through gradient
466+
467+ define adamw_step as:
468+ weight is arg[0]
469+ gradient is arg[1]
470+ m_state is arg[2]
471+ v_state is arg[3]
472+ lr is arg[4]
473+ beta1 is arg[5]
474+ beta2 is arg[6]
475+ epsilon is arg[7]
476+ weight_decay is arg[8]
477+ step_num is arg[9]
478+ beta1_val is what is beta1
479+ beta2_val is what is beta2
480+ step_val is what is step_num
481+ one_minus_b1 is 1.0 - beta1_val
482+ one_minus_b2 is 1.0 - beta2_val
483+ new_m is matrix_scale of [m_state, beta1_val]
484+ grad_contrib is matrix_scale of [gradient, one_minus_b1]
485+ new_m is matrix_add of [new_m, grad_contrib]
486+ new_v is matrix_scale of [v_state, beta2_val]
487+ grad_sq is matmul of [transpose of gradient, gradient]
488+ grad_sq_scaled is matrix_scale of [grad_sq, one_minus_b2]
489+ bias_correct1 is 1.0 - (beta1_val * beta1_val)
490+ bias_correct2 is 1.0 - (beta2_val * beta2_val)
491+ lr_val is what is lr
492+ wd_val is what is weight_decay
493+ decay_term is matrix_scale of [weight, wd_val]
494+ weight_after_decay is matrix_add of [weight, matrix_scale of [decay_term, -1.0]]
495+ update is matrix_scale of [new_m, lr_val]
496+ new_weight is matrix_add of [weight_after_decay, matrix_scale of [update, -1.0]]
497+ return [new_weight, new_m, new_v]
498+
499+
500+ # ═══════════════════════════════════════════════════════════════════════════════
501+ # CROSS-ATTENTION (for encoder-decoder models)
502+ # ═══════════════════════════════════════════════════════════════════════════════
503+ # Query from decoder, Key/Value from encoder
504+
505+ define cross_attention as:
506+ decoder_hidden is arg[0]
507+ encoder_output is arg[1]
508+ w_q is arg[2]
509+ w_k is arg[3]
510+ w_v is arg[4]
511+ scale is arg[5]
512+ query is matmul of [decoder_hidden, w_q]
513+ key is matmul of [encoder_output, w_k]
514+ value is matmul of [encoder_output, w_v]
515+ key_t is transpose of key
516+ scores is matmul of [query, key_t]
517+ scores is matrix_scale of [scores, scale]
518+ weights is softmax_matrix of scores
519+ output is matmul of [weights, value]
520+ return output
521+
522+
523+ # ═══════════════════════════════════════════════════════════════════════════════
524+ # KV CACHE (reusable)
525+ # ═══════════════════════════════════════════════════════════════════════════════
526+ # Caches key/value for efficient autoregressive generation
527+
528+ define kv_cache_append as:
529+ cache is arg[0]
530+ new_kv is arg[1]
531+ use_cache is arg[2]
532+ cache_flag is what is use_cache
533+ if cache_flag > 0:
534+ updated is matrix_concat of [cache, new_kv]
535+ return updated
536+ return new_kv
537+
538+
539+ define cached_attention as:
540+ new_q is arg[0]
541+ new_k is arg[1]
542+ new_v is arg[2]
543+ k_cache is arg[3]
544+ v_cache is arg[4]
545+ scale is arg[5]
546+ use_cache is arg[6]
547+ full_k is kv_cache_append of [k_cache, new_k, use_cache]
548+ full_v is kv_cache_append of [v_cache, new_v, use_cache]
549+ key_t is transpose of full_k
550+ scores is matmul of [new_q, key_t]
551+ scores is matrix_scale of [scores, scale]
552+ weights is softmax_matrix of scores
553+ attended is matmul of [weights, full_v]
554+ return [attended, full_k, full_v]
555+
556+
557+ # ═══════════════════════════════════════════════════════════════════════════════
558+ # WEIGHT INITIALIZATION OPTIONS
559+ # ═══════════════════════════════════════════════════════════════════════════════
560+
561+ define he_init as:
562+ shape is arg[0]
563+ fan_in is shape[0]
564+ fan_in_val is what is fan_in
565+ std is sqrt of (2.0 / fan_in_val)
566+ weights is random_matrix of shape
567+ weights is matrix_scale of [weights, std]
568+ return weights
569+
570+
571+ define orthogonal_init as:
572+ shape is arg[0]
573+ weights is random_matrix of shape
574+ weights is layer_norm_matrix of weights
575+ return weights
576+
577+
578+ define normal_init as:
579+ shape is arg[0]
580+ std is arg[1]
581+ weights is random_matrix of shape
582+ std_val is what is std
583+ weights is matrix_scale of [weights, std_val]
584+ return weights
585+
586+
587+ # ═══════════════════════════════════════════════════════════════════════════════
588+ # DECODER BLOCK (full transformer decoder layer)
589+ # ═══════════════════════════════════════════════════════════════════════════════
590+ # Self-attention + optional cross-attention + FFN
591+
592+ define decoder_block as:
593+ input is arg[0]
594+ encoder_out is arg[1]
595+ w_self_q is arg[2]
596+ w_self_k is arg[3]
597+ w_self_v is arg[4]
598+ w_cross_q is arg[5]
599+ w_cross_k is arg[6]
600+ w_cross_v is arg[7]
601+ w_ff1 is arg[8]
602+ w_ff2 is arg[9]
603+ scale is arg[10]
604+ seq_len is arg[11]
605+ normed1 is layer_norm_matrix of input
606+ self_q is matmul of [normed1, w_self_q]
607+ self_k is matmul of [normed1, w_self_k]
608+ self_v is matmul of [normed1, w_self_v]
609+ self_attn is masked_attention of [self_q, self_k, self_v, scale, causal_mask of seq_len]
610+ residual1 is matrix_add of [input, self_attn]
611+ normed2 is layer_norm_matrix of residual1
612+ cross_out is cross_attention of [normed2, encoder_out, w_cross_q, w_cross_k, w_cross_v, scale]
613+ residual2 is matrix_add of [residual1, cross_out]
614+ normed3 is layer_norm_matrix of residual2
615+ ffn_out is feed_forward_network of [normed3, w_ff1, w_ff2]
616+ output is matrix_add of [residual2, ffn_out]
617+ return output
618+
619+
620+ # ═══════════════════════════════════════════════════════════════════════════════
621+ # TEMPERATURE SAMPLING UTILITIES
622+ # ═══════════════════════════════════════════════════════════════════════════════
623+
624+ define apply_temperature as:
625+ logits is arg[0]
626+ temperature is arg[1]
627+ temp_val is what is temperature
628+ inv_temp is 1.0 / temp_val
629+ scaled is matrix_scale of [logits, inv_temp]
630+ return scaled
631+
632+
633+ define apply_repetition_penalty as:
634+ logits is arg[0]
635+ generated_tokens is arg[1]
636+ penalty is arg[2]
637+ penalty_val is what is penalty
638+ token_count is len of generated_tokens
639+ count_val is what is token_count
640+ scale_factor is 1.0 - (count_val * 0.01 * penalty_val)
641+ if scale_factor < 0.5:
642+ scale_factor is 0.5
643+ penalized is matrix_scale of [logits, scale_factor]
644+ return penalized
645+
646+
647+ # ═══════════════════════════════════════════════════════════════════════════════
648+ # SEQUENCE UTILITIES
649+ # ═══════════════════════════════════════════════════════════════════════════════
650+
651+ define pad_sequence as:
652+ tokens is arg[0]
653+ target_len is arg[1]
654+ pad_token is arg[2]
655+ current_len is len of tokens
656+ curr_val is what is current_len
657+ target_val is what is target_len
658+ padded is tokens
659+ pad_idx is curr_val
660+ loop while pad_idx < target_val:
661+ pad_val is what is pad_token
662+ _d is append of [padded, pad_val]
663+ pad_idx is pad_idx + 1
664+ return padded
665+
666+
667+ define truncate_sequence as:
668+ tokens is arg[0]
669+ max_len is arg[1]
670+ current_len is len of tokens
671+ curr_val is what is current_len
672+ max_val is what is max_len
673+ if curr_val <= max_val:
674+ return tokens
675+ truncated is []
676+ idx is 0
677+ loop while idx < max_val:
678+ tok is tokens[idx]
679+ tok_val is what is tok
680+ _d is append of [truncated, tok_val]
681+ idx is idx + 1
682+ return truncated
0 commit comments