| 458 | } |
| 459 | |
| 460 | void gpt2_backward(Context& ctx, GPT2 *model) { |
| 461 | printf("Backward pass\n"); |
| 462 | |
| 463 | // double check we forwarded previously, with targets |
| 464 | if (model->mean_loss == -1.0f) { |
| 465 | printf("Error: must forward with targets before backward\n"); |
| 466 | exit(1); |
| 467 | } |
| 468 | |
| 469 | // lazily allocate the memory for gradients of the weights and activations, if needed |
| 470 | if (model->grads_memory == NULL) { |
| 471 | printf("Allocating %.2f MB for gradients\n", model->num_parameters * sizeof(float) / (1024.0f * 1024.0f)); |
| 472 | model->grads_memory = malloc_and_point_parameters(&model->grads, model->param_sizes); |
| 473 | model->grads_acts_memory = malloc_and_point_activations(&model->grads_acts, model->act_sizes); |
| 474 | gpt2_zero_grad(model); |
| 475 | } |
| 476 | |
| 477 | // convenience shortcuts (and size_t to help prevent int overflow) |
| 478 | size_t B = model->batch_size; |
| 479 | size_t T = model->seq_len; |
| 480 | size_t V = model->config.vocab_size; |
| 481 | size_t Vp = model->config.padded_vocab_size; |
| 482 | size_t L = model->config.num_layers; |
| 483 | size_t NH = model->config.num_heads; |
| 484 | size_t C = model->config.channels; |
| 485 | |
| 486 | // backward pass: go in the reverse order of the forward pass, and call backward() functions |
| 487 | ParameterTensors params = model->params; // for brevity |
| 488 | ParameterTensors grads = model->grads; |
| 489 | ActivationTensors acts = model->acts; |
| 490 | ActivationTensors grads_acts = model->grads_acts; |
| 491 | |
| 492 | // we kick off the chain rule by filling in dlosses with 1.0f/(B*T) |
| 493 | // technically this is a small, inline backward() pass of calculating |
| 494 | // total, final loss as the mean over all losses over all (B,T) positions in the batch |
| 495 | float dloss_mean = 1.0f / (B*T); |
| 496 | for (int i = 0; i < B*T; i++) { grads_acts.losses[i] = dloss_mean; } |
| 497 | |
| 498 | crossentropy_softmax_backward(ctx, grads_acts.logits, grads_acts.losses, acts.probs, model->targets, B, T, V, Vp); |
| 499 | matmul_backward(ctx, grads_acts.lnf, grads.wte, NULL, grads_acts.logits, acts.lnf, params.wte, B, T, C, Vp); |
| 500 | float* residual = acts.residual3 + (L-1) * B * T * C; // last layer's residual |
| 501 | float* dresidual = grads_acts.residual3 + (L-1) * B * T * C; // write to last layer's residual |
| 502 | layernorm_backward(ctx, dresidual, grads.lnfw, grads.lnfb, grads_acts.lnf, residual, params.lnfw, acts.lnf_mean, acts.lnf_rstd, B, T, C); |
| 503 | |
| 504 | for (int l = L-1; l >= 0; l--) { |
| 505 | printf("Backward Pass Layer %d\n", l); |
| 506 | |
| 507 | residual = l == 0 ? acts.encoded : acts.residual3 + (l-1) * B * T * C; |
| 508 | dresidual = l == 0 ? grads_acts.encoded : grads_acts.residual3 + (l-1) * B * T * C; |
| 509 | |
| 510 | // get the pointers of the weights for this layer |
| 511 | float* l_ln1w = params.ln1w + l * C; |
| 512 | float* l_qkvw = params.qkvw + l * 3*C * C; |
| 513 | float* l_attprojw = params.attprojw + l * C * C; |
| 514 | float* l_ln2w = params.ln2w + l * C; |
| 515 | float* l_fcw = params.fcw + l * 4*C * C; |
| 516 | float* l_fcprojw = params.fcprojw + l * C * 4*C; |
| 517 | // get the pointers of the gradients of the weights for this layer |
no test coverage detected