// Matrix Construct // // Copyright (C) Matrix Construct Developers, Authors & Contributors // Copyright (C) 2016-2021 Jason Volk // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. #pragma clang fp exceptions(ignore) #pragma clang fp reassociate(on) #pragma clang fp contract(fast) #include #include #include #include #include #include #include #include // // head // __kernel void __attribute__((visibility("protected"))) ircd_gpt_alloc(__global const void *const restrict model, __global void *const restrict master, __constant const void *const opts, __global void *const restrict ctrl, __global void *const restrict frame0, __global void *const restrict frame1, __global void *const restrict frame2, __global void *const restrict frame3, __global void *const restrict frame4, __global void *const restrict frame5, __global void *const restrict frame6, __global void *const restrict frame7) { } __kernel void __attribute__((visibility("protected"))) ircd_gpt_enter(__global const void *const restrict model, __global void *const restrict state, __global void *const restrict master, __constant const struct ircd_gpt_opts *const opts, __global struct ircd_gpt_ctrl *const restrict ctrl) { const ushort gi = get_global_id(0), li = get_local_id(0), ln = get_local_size(0), cycle = ctrl->clk.cycle; if(li == 0) ctrl->prof.entered = ircd_simt_cycles(); } __kernel void ircd_gpt_lm_embed(__global const struct ircd_gpt_ctrl *const ctrl, __constant const struct ircd_gpt_opts *const opts, __global ircd_gpt_vectorv *const restrict accum, __global const ircd_gpt_vectorv *const restrict pos, __global const ircd_gpt_vectorv *const restrict vocab) { const ushort li = get_local_id(0), ln = get_local_size(0); const uint wo = get_global_offset(0); assume(ln == 192); assume(wo % ln == 0); const ushort wi = wo / ln + get_group_id(0); _ircd_gpt_lm_embed(ctrl, opts, accum, pos, vocab, wi, wi, li); } static void _ircd_gpt_lm_embed(__global const struct ircd_gpt_ctrl *const ctrl, __constant const struct ircd_gpt_opts *const opts, __global ircd_gpt_vectorv *const restrict accum, __global const ircd_gpt_vectorv *const restrict pos, __global const ircd_gpt_vectorv *const restrict vocab, const ushort out_idx, const ushort tok_idx, const ushort elem_idx) { const ushort token = ctrl->token[tok_idx]; const float4 wpe = pos[tok_idx].elem[elem_idx], wte = vocab[token].elem[elem_idx], res = wte + wpe; accum[out_idx].elem[elem_idx] = res; } // // Frontside // void ircd_gpt_ffnn_fcon_tmul(__constant const struct ircd_gpt_opts *const opts, __local ircd_gpt_ffnn_aperaturev *const restrict out, __local const ircd_gpt_vectorv *const restrict in, __global const ircd_gpt_ffnn_aperaturev *const restrict bias, __global const ircd_gpt_ffnn_aperaturev *const restrict weight, const uint li) { const uint lanes = 4, segs = ircd_gpt_ffnn_segs, height = ircd_gpt_vector_elems / lanes; assume(height > 0); assume(height % lanes == 0); for(uint x = 0; x < segs; ++x) out->proj[x][li] = bias->proj[x][li]; for(uint y = 0; y < height; ++y) for(uint k = 0; k < lanes; ++k) for(uint x = 0; x < segs; ++x) { const uint row = y * lanes + k; out->proj[x][li] += in->elem[y][k] * weight[row].proj[x][li]; } } void ircd_gpt_ffnn_fcon(__global const struct ircd_gpt_ctrl *const ctrl, __constant const struct ircd_gpt_opts *const opts, __local ircd_gpt_ffnn_aperaturev *const restrict out, __local const ircd_gpt_vectorv *const restrict in, __global const ircd_gpt_ffnn_aperaturev *const restrict bias, __global const ircd_gpt_ffnn_aperaturev *const restrict weight, const uint ln, const uint li) { const uint segs = ircd_gpt_ffnn_segs; // Fully connected ircd_gpt_ffnn_fcon_tmul ( opts, out, in, bias, weight, li ); for(uint i = 0; i < segs; ++i) ircd_gpt_ffnn_gelu(out, out, i * ln + li); } void ircd_gpt_ffnn_proj_tmul(__constant const struct ircd_gpt_opts *const opts, __local ircd_gpt_vectorv *const restrict out, __local const ircd_gpt_ffnn_aperaturev *const restrict in, __global const ircd_gpt_vectorv *const restrict bias, __global const ircd_gpt_vectorv *const restrict weight, const uint li) { const uint lanes = 4, height = ircd_gpt_ffnn_fcon_elems / lanes; assume(height > 0); assume(height % lanes == 0); out->elem[li] = bias->elem[li]; for(uint y = 0; y < height; ++y) for(uint k = 0; k < lanes; ++k) { const uint row = y * lanes + k; out->elem[li] += in->fcon[y][k] * weight[row].elem[li]; } } void ircd_gpt_ffnn(__global const struct ircd_gpt_ctrl *const ctrl, __constant const struct ircd_gpt_opts *const opts, __local ircd_gpt_vectorv *const restrict token, __local ircd_gpt_ffnn_aperaturev *const restrict buf, __local ircd_gpt_vectorv *const restrict tmp, __global const ircd_gpt_vectorv *const restrict norm_bias, __global const ircd_gpt_vectorv *const restrict norm_weight, __global const ircd_gpt_ffnn_aperaturev *const restrict fcon_bias, __global const ircd_gpt_ffnn_aperaturev *const restrict fcon_weight, __global const ircd_gpt_vectorv *const restrict proj_bias, __global const ircd_gpt_vectorv *const restrict proj_weight, const uint ln, const uint li) { // Layer re-normalization ircd_gpt_norm(token, token, tmp, norm_bias, norm_weight, ln, li); // ln's writes are still pending but fcon reads results across threads. barrier(CLK_LOCAL_MEM_FENCE); // Fully connected ircd_gpt_ffnn_fcon ( ctrl, opts, buf, token, fcon_bias, fcon_weight, ln, li ); // fcon's writes are still pending but proj reads results across threads. barrier(CLK_LOCAL_MEM_FENCE); // Projection ircd_gpt_ffnn_proj_tmul ( opts, token, buf, proj_bias, proj_weight, li ); } static void ircd_gpt_attn_self_samax(__global const struct ircd_gpt_ctrl *const ctrl, __constant const struct ircd_gpt_opts *const opts, __local float self[restrict][12], const uint ln, const uint li, const uint wn, const uint wi) { struct ircd_math_samax samax = { .mu = -10000.0f, .sum = 0.0f, }; __attribute__((opencl_unroll_hint)) for(uint i = 0; i < wn; ++i) samax.mu = max(samax.mu, self[i][li]); __attribute__((opencl_unroll_hint)) for(uint i = 0; i < wn; ++i) self[i][li] -= samax.mu; for(uint i = 0; i < wn; ++i) self[i][li] = native_exp(self[i][li]); __attribute__((opencl_unroll_hint)) for(uint i = 0; i < wn; ++i) samax.sum += self[i][li]; samax.sum += FLT_EPSILON; samax.lambda = 1.0f / samax.sum; __attribute__((opencl_unroll_hint)) for(uint i = 0; i < wn; ++i) self[i][li] *= samax.lambda; } static void ircd_gpt_attn_self_keys(__global const struct ircd_gpt_ctrl *const ctrl, __constant const struct ircd_gpt_opts *const opts, __local float self[restrict][ircd_gpt_attn_rank], __global const ircd_gpt_attn_qkvv *const restrict token, const uint ln, const uint li, const uint wi, const uint kn, const uint i) { assume(i < wi); self[i][li] = 0.0f; __attribute__((opencl_unroll_hint)) for(uint k = 0; k < kn; ++k) { float4 qry = token[wi].qry.attn[li][k], key = token[i].key.attn[li][k], res = qry * key; self[i][li] += ircd_simt_hadd_f4(res); } self[i][li] /= 8.0f; } static void ircd_gpt_attn_self_vals(__global const struct ircd_gpt_ctrl *const ctrl, __constant const struct ircd_gpt_opts *const opts, __local ircd_gpt_vectorv *const restrict out, __local const float self[restrict][ircd_gpt_attn_rank], __global const ircd_gpt_attn_qkvv *const restrict token, const uint li, const uint wi, const uint ki, const uint ti) { out->attn[ti][ki] = 0.0f; __attribute__((opencl_unroll_hint)) for(uint i = 0; i < wi; ++i) { const float4 val = token[i].val.attn[ti][ki], attn = self[i][ti], res = attn * val; out->attn[ti][ki] += res; } } static void ircd_gpt_attn_self(__global struct ircd_gpt_ctrl *const ctrl, __constant const struct ircd_gpt_opts *const opts, __local ircd_gpt_vectorv *const restrict out, __local float self[restrict][ircd_gpt_attn_rank], __global float attns[restrict][ircd_gpt_attn_rank], __global const ircd_gpt_attn_qkvv *const restrict token, const uint ln, const uint li, const uint wi) { //assume(opts->attn_rank == sizeof(self[0]) / sizeof(float)); assume(opts->attn_rank == ircd_gpt_attn_rank); assume(ctrl->count < ircd_gpt_context_tokens); assume(ctrl->tokens <= ircd_gpt_context_tokens); assume(ctrl->tokens > wi); assume(ctrl->tokens > 0); const uint wn = ctrl->tokens, kn = ln / opts->attn_rank, ki = li / opts->attn_rank, ti = li % opts->attn_rank; // Low-rank mask if(li < opts->attn_rank) { // Left attention uint i; for(i = 0; i < wi; ++i) ircd_gpt_attn_self_keys(ctrl, opts, self, token, ln, li, wi, kn, i); // Future mask __attribute__((opencl_unroll_hint)) while(i < wn) self[i++][li] = -10000.0f; // Three-piece softmax ircd_gpt_attn_self_samax(ctrl, opts, self, ln, li, wn, wi); } // Propagate to full width for value dot prod. barrier(CLK_LOCAL_MEM_FENCE); ircd_gpt_attn_self_vals(ctrl, opts, out, self, token, li, wi, ki, ti); // Save softmax results for later analysis/observation. if(li < opts->attn_rank) { __attribute__((opencl_unroll_hint)) for(uint i = 0; i < wn; ++i) attns[i][li] = self[i][li]; } } static void ircd_gpt_attn_proj_tmul(__constant const struct ircd_gpt_opts *const opts, __local ircd_gpt_vectorv *const restrict out, __local const ircd_gpt_vectorv *const restrict in, __global const ircd_gpt_vectorv *const restrict bias, __global const ircd_gpt_vectorv *const restrict weight, const uint li) { const uint lanes = 4, height = ircd_gpt_vector_elems / 4; assume(height > 0); assume(height % lanes == 0); out->elem[li] = bias->elem[li]; for(uint y = 0; y < height; ++y) for(uint k = 0; k < lanes; ++k) { const uint row = y * lanes + k; const float4 a = in->elem[y][k], b = weight[row].elem[li]; out->elem[li] += a * b; } } __kernel void __attribute__((visibility("protected"))) ircd_gpt_coil(__global struct ircd_gpt_ctrl *const ctrl, __constant const struct ircd_gpt_opts *const opts, __private const uint layer, __global ircd_gpt_vectorv *const restrict accum, __global float attns[restrict][ircd_gpt_attn_rank], __global const ircd_gpt_attn_qkvv *const restrict state, __global const ircd_gpt_vectorv *const restrict attn_proj_bias, __global const ircd_gpt_vectorv *const restrict attn_proj_weight, __global const ircd_gpt_vectorv *const restrict ffnn_norm_bias, __global const ircd_gpt_vectorv *const restrict ffnn_norm_weight, __global const ircd_gpt_ffnn_aperaturev *const restrict ffnn_fcon_bias, __global const ircd_gpt_ffnn_aperaturev *const restrict ffnn_fcon_weight, __global const ircd_gpt_vectorv *const restrict ffnn_proj_bias, __global const ircd_gpt_vectorv *const restrict ffnn_proj_weight) { const uint li = get_local_id(0), ln = get_local_size(0), wo = get_global_offset(0), wi = wo / ln + get_group_id(0); assume(ln == 192); assume(wo % ln == 0); __local union { float attn_self[ircd_gpt_context_tokens][ircd_gpt_attn_rank]; ircd_gpt_ffnn_aperaturev ffnn_fcon[2]; ircd_gpt_vectorv vector[8]; } buf; __local ircd_gpt_vectorv buf0, buf1, *const restrict attn_self = &buf1, *const restrict token = &buf0, *const restrict tmp = &buf1; // Self-attention backend; this computes the self-attention result now // that keys and values are globally visible across tokens. ircd_gpt_attn_self ( ctrl, opts, attn_self, buf.attn_self, attns, state, ln, li, wi ); barrier(CLK_LOCAL_MEM_FENCE); // Project result of self-attention. ircd_gpt_attn_proj_tmul ( opts, token, attn_self, attn_proj_bias, attn_proj_weight, li ); // Frontend accumulation { const float4 attn = token->elem[li], resid = accum[wi].elem[li], result = resid + attn; token->elem[li] = result; accum[wi].elem[li] = result; } barrier(CLK_GLOBAL_MEM_FENCE); // Backend mlp ircd_gpt_ffnn ( ctrl, opts, token, buf.ffnn_fcon, tmp, ffnn_norm_bias, ffnn_norm_weight, ffnn_fcon_bias, ffnn_fcon_weight, ffnn_proj_bias, ffnn_proj_weight, ln, li ); // Backend accumulation { const float4 ffnn = token->elem[li], resid = accum[wi].elem[li], result = resid + ffnn; accum[wi].elem[li] = result; } } static void ircd_gpt_attn_fcon_tmul(__constant const struct ircd_gpt_opts *const opts, __local ircd_gpt_attn_aperaturev *const restrict out, __local const ircd_gpt_vectorv *const restrict in, __global const ircd_gpt_attn_aperaturev *const restrict bias, __global const ircd_gpt_attn_aperaturev *const restrict weight, const uint ln, const uint li) { const uint lanes = 4, segs = ircd_gpt_attn_segs, height = ircd_gpt_vector_elems / lanes; assume(height > 0); assume(height % segs == 0); assume(height % lanes == 0); for(uint x = 0; x < segs; ++x) out->proj[x][li] = bias->proj[x][li]; for(uint y = 0; y < height; ++y) for(uint k = 0; k < lanes; ++k) for(uint x = 0; x < segs; ++x) { const uint row = y * lanes + k; const float4 a = in->elem[y][k], b = weight[row].proj[x][li]; out->proj[x][li] += a * b; } } __kernel void ircd_gpt_attn_fcon(__global const struct ircd_gpt_ctrl *const ctrl, __constant const struct ircd_gpt_opts *const opts, __private const uint layer, __global ircd_gpt_attn_aperaturev *const restrict state, __global const ircd_gpt_vectorv *const restrict accum, __global const ircd_gpt_vectorv *const restrict norm_bias, __global const ircd_gpt_vectorv *const restrict norm_weight, __global const ircd_gpt_attn_aperaturev *const restrict fcon_bias, __global const ircd_gpt_attn_aperaturev *const restrict fcon_weight) { const uint li = get_local_id(0), ln = get_local_size(0), wo = get_global_offset(0), wi = wo / ln + get_group_id(0), segs = ircd_gpt_attn_segs; assume(ln == 192); assume(wo % ln == 0); __local ircd_gpt_attn_aperaturev attn; __local ircd_gpt_vectorv token, *const restrict tmp = attn.vector; token.elem[li] = accum[wi].elem[li]; // Layer re-normalization ircd_gpt_norm(&token, &token, tmp, norm_bias, norm_weight, ln, li); // Ln's writes are still pending; fcon requires results across threads. barrier(CLK_LOCAL_MEM_FENCE); // Fully connected ircd_gpt_attn_fcon_tmul ( opts, &attn, &token, fcon_bias, fcon_weight, ln, li ); // Export queries, keys, and values. for(uint x = 0; x < segs; ++x) state[wi].proj[x][li] = attn.proj[x][li]; } __kernel void ircd_gpt_lm_norm(__global const struct ircd_gpt_ctrl *const ctrl, __constant const struct ircd_gpt_opts *const opts, __global ircd_gpt_vectorv *const restrict accum, __global const ircd_gpt_vectorv *const restrict norm_bias, __global const ircd_gpt_vectorv *const restrict norm_weight) { const uint li = get_local_id(0), ln = get_local_size(0), wo = get_global_offset(0), wi = wo / ln + get_group_id(0); assume(ln == 192); assume(wo % ln == 0); __local ircd_gpt_vectorv tmp, token; token.elem[li] = accum[wi].elem[li]; // Final re-normalization ircd_gpt_norm(&token, &token, &tmp, norm_bias, norm_weight, ln, li); accum[wi].elem[li] = token.elem[li]; } __kernel void ircd_gpt_lm_logit(__global const struct ircd_gpt_ctrl *const ctrl, __constant const struct ircd_gpt_opts *const opts, __global float *const restrict logit, __global const ircd_gpt_vectorv *const restrict accum, __global const ircd_gpt_vectorv *const restrict pos, __global const ircd_gpt_vectorv *const restrict vocab) { const uint gi = get_global_id(0), wi = ctrl->count - 1; assume(opts->embed_width == 192); assume(opts->logits <= 65536); if(gi >= opts->logits) { logit[gi] = -10000.0f; return; } float acc = 0.0f; for(uint j = 0; j < opts->embed_width; ++j) { const float4 token = vocab[gi].elem[j], in = accum[wi].elem[j], wpe = pos[wi].elem[j], res = in * token + wpe; acc += ircd_simt_hadd_f4(res); } logit[gi] = acc; } __kernel void __attribute__((reqd_work_group_size(256, 1, 1))) ircd_gpt_lm_logsm(__global struct ircd_gpt_ctrl *const ctrl, __constant const struct ircd_gpt_opts *const opts, __global float logit[restrict 65536]) { const uint li = get_local_id(0), ln = get_local_size(0), //wo = get_global_offset(0), //wi = wo / ln + get_group_id(0), wn = 50432, tn = wn / ln, start = tn * li, stop = min(start + tn, opts->logits); __local float mu[256], sum[256], lambda[256]; __local struct ircd_math_samax samax; assume(ln == 256); mu[li] = -10000.0f; __attribute__((opencl_unroll_hint)) for(uint ti = start; ti < stop; ++ti) mu[li] = max(mu[li], logit[ti]); ircd_simt_reduce_max_flldr(mu, ln, li); if(li == 0) samax.mu = mu[li]; ircd_simt_broadcast_flldr(mu, ln, li); sum[li] = 0.0f; for(uint ti = start; ti < stop; ++ti) { const float sub = logit[ti] - mu[li], res = native_exp(sub); sum[li] += res; } ircd_simt_reduce_add_flldr(sum, ln, li); if(li == 0) sum[li] += FLT_EPSILON, samax.sum = sum[li], samax.lambda = lambda[li] = 1.0f / sum[li]; ircd_simt_broadcast_flldr(lambda, ln, li); for(uint ti = start; ti < stop; ++ti) { const float sub = logit[ti] - mu[li], res = lambda[li] * native_exp(sub); logit[ti] = res; } } void ircd_gpt_lm_result_top(__local struct ircd_gpt_ctrl *const ctrl, __constant const struct ircd_gpt_opts *const opts, __local const ushort *const restrict idx, __global const float *const restrict logsm, const uint i) { const ushort token = idx[i]; const float samax = logsm[token]; ctrl->top[i].token = token; ctrl->top[i].samax = samax; } void ircd_gpt_lm_result_label_mean(__local struct ircd_gpt_ctrl *const ctrl, __constant const struct ircd_gpt_opts *const opts, __local struct ircd_math_mean *const mean, const float last) { const uint div = mean->div + 1, sum_sel = mean->div % 4; const float sum = mean->sum[0] + mean->sum[1] + mean->sum[2] + mean->sum[3] + last, res = sum / div; mean->sum[sum_sel] += last; mean->div = div; mean->last = last; mean->mean = res; } void ircd_gpt_lm_result_label(__local struct ircd_gpt_ctrl *const ctrl, __constant const struct ircd_gpt_opts *const opts, __local struct ircd_gpt_ctrl_label *const label, __global const float *const restrict logsm) { const ushort token = label->logit.token; const float samax = logsm[token], loss = 0.0f - native_log(samax), ppl = (1.0f - samax) * native_log2(opts->logits); label->logit.samax = samax; ircd_gpt_lm_result_label_mean(ctrl, opts, &label->loss, loss); ircd_gpt_lm_result_label_mean(ctrl, opts, &label->ppl, ppl); } ushort ircd_gpt_lm_result_select(__local struct ircd_gpt_ctrl *const ctrl, __constant const struct ircd_gpt_opts *const opts, __local const ushort *const restrict idx, __global const float *const restrict logsm) { const ulong ent_k = max(opts->top_k, 1U) - 1, rnd = ircd_simt_rand_xoshiro256pl(ctrl->rand); const float ent_p = min(max(opts->top_p, 0.0f), 1.0f), thresh = ent_p; float acc = 1.0f; ushort select = 0; for(; select < ent_k; ++select) if((acc -= logsm[idx[select]]) < thresh) break; const ushort token = idx[select]; return token; } static ushort ircd_gpt_lm_result(__local struct ircd_gpt_ctrl *const ctrl, __constant const struct ircd_gpt_opts *const opts, __local const ushort *const restrict idx, __global const float *const restrict logsm) { const ushort token = ircd_gpt_lm_result_select(ctrl, opts, idx, logsm); // Update the dynamic result label. ctrl->select.logit.token = token; ircd_gpt_lm_result_label(ctrl, opts, &ctrl->select, logsm); // Update the dynamic target label. ctrl->target.logit.token = ctrl->count < ctrl->tokens? ctrl->token[ctrl->count]: ctrl->select.logit.token; ircd_gpt_lm_result_label(ctrl, opts, &ctrl->target, logsm); const bool hit = ctrl->select.logit.token == ctrl->target.logit.token; // Update the token context. if(ctrl->count == ctrl->tokens) ctrl->token[ctrl->tokens++] = ctrl->select.logit.token; else ctrl->accept = -2; ctrl->miss += !hit; ctrl->hit += hit; ctrl->count++; return token; } static void ircd_gpt_lm_result_attns(__local struct ircd_gpt_ctrl *const ctrl, __constant const struct ircd_gpt_opts *const opts, __global const float *const restrict attns, const uint ln, const uint li) { const uint layer = li / opts->layers, head = li % opts->attn_rank, base = layer * opts->attn_self_elems; uint best = 0; float bestv = 10000.0f; for(uint i = 0; i < ctrl->count; ++i) { const uint bx = (((i + 1) * i) / 2) * opts->attn_rank, idx = base + bx + i * 12 + head; if(attns[idx] < bestv) bestv = attns[idx], best = i; } ctrl->attn[layer][head] = best; } __kernel void __attribute__((visibility("protected"))) __attribute__((reqd_work_group_size(256, 1, 1))) ircd_gpt_lm_select(__global struct ircd_gpt_ctrl *const restrict ctrl_, __constant const struct ircd_gpt_opts *const opts, __global const float logsm[restrict 65536], __global const float *const restrict attns) { const uint li = get_local_id(0), ln = get_local_size(0), logits_pad = ln - (opts->logits % ln), tn = (opts->logits + logits_pad) / ln, start = tn * li, stop = min(start + tn, opts->logits); __local ushort idx[256]; __local struct ircd_gpt_ctrl ctrl; __private event_t event[1]; assume(ln == 256); assume(start < stop); event[0] = async_work_group_copy ( (__local char16 *)&ctrl, (__global const char16 *)ctrl_, sizeof(struct ircd_gpt_ctrl) / sizeof(char16), 0 ); idx[li] = start; for(uint j = start + 1; j < stop; ++j) if(logsm[j] > logsm[idx[li]]) idx[li] = j; ircd_simt_sort_idx16_flldr(idx, logsm, ln, li); wait_group_events(1, event); if(ctrl.count >= opts->buffer_tokens) return; if(li < opts->top_n) ircd_gpt_lm_result_top(&ctrl, opts, idx, logsm, li); if(li < opts->labels) ircd_gpt_lm_result_label(&ctrl, opts, ctrl.label + li, logsm); if(li < opts->layers * opts->attn_rank) ircd_gpt_lm_result_attns(&ctrl, opts, attns, ln, li); barrier(CLK_LOCAL_MEM_FENCE); if(li == 0) ircd_gpt_lm_result(&ctrl, opts, idx, logsm); barrier(CLK_LOCAL_MEM_FENCE); event[0] = async_work_group_copy ( (__global char16 *)ctrl_, (__local const char16 *)&ctrl, sizeof(struct ircd_gpt_ctrl) / sizeof(char16), 0 ); wait_group_events(1, event); } __kernel void __attribute__((visibility("protected"))) __attribute__((reqd_work_group_size(256, 1, 1))) ircd_gpt_leave(__global const void *const restrict model, __global void *const restrict state, __global void *const restrict master, __constant const struct ircd_gpt_opts *const opts, __global struct ircd_gpt_ctrl *const ctrl_, __global struct ircd_gpt_ctrl *const frame) { const ushort li = get_local_id(0), ln = get_local_size(0); assume(ln == 256); __local struct ircd_gpt_ctrl _ctrl; __local struct ircd_gpt_ctrl *const ctrl = &_ctrl; if(li == 0) *ctrl = *ctrl_; barrier(CLK_LOCAL_MEM_FENCE); if(li == 0 && ctrl->accept < 0) ircd_gpt_accept(ctrl, opts); barrier(CLK_LOCAL_MEM_FENCE); const uint batch_size = opts->batch_size, samps = opts->training_steps + opts->validation_steps + opts->testing_steps, steps = samps / batch_size; const bool accepting = ctrl->accept >= 0, cycling = !accepting, sampling = accepting, stepping = sampling && (ctrl->clk.samp + 1) >= batch_size, epoching = stepping && (ctrl->clk.step + 1) >= steps; if(li == 0) ctrl->prof.finished = ircd_simt_cycles(); if(li == 0) { // BARTS won't update the scalar after the copy. In this case we'll // be setting magic for all remaining frames :/ #if defined(__R600__) ctrl->magic = 0xC7012C70UL; #endif *frame = *ctrl; frame->magic = 0xC7012C70UL; } if(li == 0 && !accepting) { ctrl->clk.cycle += cycling; ctrl->clk.samp += sampling; ctrl->clk.step += stepping; ctrl->clk.epoch += epoching; } if(li == 0 && accepting) ctrl->magic = 0xC7012C70UL; if(li == 0) *ctrl_ = *ctrl; } void ircd_gpt_accept(__local struct ircd_gpt_ctrl *const ctrl, __constant const struct ircd_gpt_opts *const opts) { const bool unlimited = opts->limit < 0, unprocessed = ctrl->accept == -2, acceptable = ctrl->accept < 0 && !unprocessed; const uint batch_size = opts->batch_size, samps = opts->training_steps + opts->validation_steps + opts->testing_steps, steps = samps / batch_size, unproc = ctrl->tokens - ctrl->count, limit = opts->limit; const int cycle_remain = opts->context_tokens - (ctrl->clk.cycle + 1), // cycle not yet incr token_remain = opts->context_tokens - ctrl->count, // but count already incr remain = min(cycle_remain, token_remain); int accept = ircd_gpt_accept_check(ctrl, opts), dispatch = accept < 0? min(abs(accept), (uint)remain): 0; if(opts->limit > 0 && ctrl->clk.cycle >= limit - 1) { accept = accept >= 0? accept: -1; dispatch = 0; } if(opts->limit == 0 && unprocessed) { accept = accept >= 0? accept: -1; dispatch = min((uint)remain, unproc); } if(opts->limit != 0 && !acceptable) { accept = accept >= 0? accept: -1; dispatch = max(dispatch, 1); } ctrl->accept = accept; ctrl->dispatch = min((uint)dispatch, opts->frames); } int ircd_gpt_accept_check(__local struct ircd_gpt_ctrl *const ctrl, __constant const struct ircd_gpt_opts *const opts) { int best = opts->frames; for(uint i = 0; i < 4; ++i) { const int remain = ircd_gpt_accept_match(ctrl, opts, i); if(remain == 0) return i; if(remain < best) best = remain; } return -best; } uint ircd_gpt_accept_match(__local struct ircd_gpt_ctrl *const ctrl, __constant const struct ircd_gpt_opts *const opts, const uint i) { const uint len = ircd_gpt_accept_len(ctrl, opts, i), n = min(ctrl->count, len), maxlen = opts->frames; uint ret = len?: maxlen; for(uint j = 1; j <= n; ++j) { uint match = 0; for(; match < j; ++match) { const uint accept = opts->accept[i][match], token = ctrl->token[ctrl->count - j + match]; if(token != accept) break; } if(match >= j) if(!(ret = len - match)) break; } ret = max(ret, ctrl->tokens - ctrl->count); ret = min(ret, maxlen); return ret; } uint ircd_gpt_accept_len(__local struct ircd_gpt_ctrl *const ctrl, __constant const struct ircd_gpt_opts *const opts, const uint i) { uint len = 0; for(; len < 8; ++len) if(opts->accept[i][len] == (ushort)-1U) break; return len; } // // backside // void __attribute__((always_inline)) ircd_gpt_prop_elem(__global const struct ircd_gpt_ctrl *const ctrl, __constant const struct ircd_gpt_opts *const opts, __global float4 *const restrict param_, __global float4 *const restrict exp_avg_, __global float4 *const restrict exp_avg_sqr_) { const uint li = get_local_id(0), ts = ctrl->clk.step; const float4 param = param_[li], grad = ctrl->target.loss.mean, alpha[2] = { 1.0f - opts->beta[0], 1.0f - opts->beta[1], }, exp_avg = ts? exp_avg_[li]: 0.0f, exp_avg_sqr = ts? exp_avg_sqr_[li]: 0.0f, exp_avg_mul = exp_avg * opts->beta[0], exp_avg_dot = exp_avg_mul + alpha[0] * grad, exp_avg_sqr_mul = exp_avg_sqr * opts->beta[1], exp_avg_sqr_dot = exp_avg_sqr_mul + alpha[1] * grad * grad, denom = native_sqrt(exp_avg_sqr_dot) + FLT_EPSILON, delta = opts->alpha * (exp_avg_dot / denom), update = param - delta; param_[li] = update; exp_avg_[li] = exp_avg_dot; exp_avg_sqr_[li] = exp_avg_sqr_dot; } // // backpropagations // __kernel void __attribute__((always_inline)) ircd_gpt_norm_prop(__global const struct ircd_gpt_ctrl *const ctrl, __constant const struct ircd_gpt_opts *const opts, __global ircd_gpt_vectorv *const restrict bias, __global ircd_gpt_vectorv *const restrict bias_m0, __global ircd_gpt_vectorv *const restrict bias_m1, __global ircd_gpt_vectorv *const restrict weight, __global ircd_gpt_vectorv *const restrict weight_m0, __global ircd_gpt_vectorv *const restrict weight_m1) { ircd_gpt_prop_elem ( ctrl, opts, bias->elem, bias_m0->elem, bias_m1->elem ); ircd_gpt_prop_elem ( ctrl, opts, weight->elem, weight_m0->elem, weight_m1->elem ); } __kernel void ircd_gpt_coil_prop_attn(__global const struct ircd_gpt_ctrl *const ctrl, __constant const struct ircd_gpt_opts *const opts, __global ircd_gpt_vectorv *const restrict norm_bias, __global ircd_gpt_vectorv *const restrict norm_bias_m0, __global ircd_gpt_vectorv *const restrict norm_bias_m1, __global ircd_gpt_vectorv *const restrict norm_weight, __global ircd_gpt_vectorv *const restrict norm_weight_m0, __global ircd_gpt_vectorv *const restrict norm_weight_m1, __global ircd_gpt_attn_aperaturev *const restrict fcon_bias, __global ircd_gpt_attn_aperaturev *const restrict fcon_bias_m0, __global ircd_gpt_attn_aperaturev *const restrict fcon_bias_m1, __global ircd_gpt_attn_aperaturev *const restrict fcon_weight, __global ircd_gpt_attn_aperaturev *const restrict fcon_weight_m0, __global ircd_gpt_attn_aperaturev *const restrict fcon_weight_m1, __global ircd_gpt_vectorv *const restrict proj_bias, __global ircd_gpt_vectorv *const restrict proj_bias_m0, __global ircd_gpt_vectorv *const restrict proj_bias_m1, __global ircd_gpt_vectorv *const restrict proj_weight, __global ircd_gpt_vectorv *const restrict proj_weight_m0, __global ircd_gpt_vectorv *const restrict proj_weight_m1) { const uint fcon_height = opts->embed_elems, proj_height = opts->embed_elems, segs = 3; ircd_gpt_norm_prop ( ctrl, opts, norm_bias, norm_bias_m0, norm_bias_m1, norm_weight, norm_weight_m0, norm_weight_m1 ); for(uint j = 0; j < segs; ++j) ircd_gpt_prop_elem ( ctrl, opts, fcon_bias->proj[j], fcon_bias_m0->proj[j], fcon_bias_m1->proj[j] ); for(uint i = 0; i < fcon_height; ++i) for(uint j = 0; j < segs; ++j) ircd_gpt_prop_elem ( ctrl, opts, fcon_weight[i].proj[j], fcon_weight_m0[i].proj[j], fcon_weight_m1[i].proj[j] ); ircd_gpt_prop_elem ( ctrl, opts, proj_bias->elem, proj_bias_m0->elem, proj_bias_m1->elem ); for(uint i = 0; i < proj_height; ++i) ircd_gpt_prop_elem ( ctrl, opts, proj_weight[i].elem, proj_weight_m0[i].elem, proj_weight_m1[i].elem ); } __kernel void ircd_gpt_coil_prop_ffnn(__global const struct ircd_gpt_ctrl *const ctrl, __constant const struct ircd_gpt_opts *const opts, __global ircd_gpt_vectorv *const restrict norm_bias, __global ircd_gpt_vectorv *const restrict norm_bias_m0, __global ircd_gpt_vectorv *const restrict norm_bias_m1, __global ircd_gpt_vectorv *const restrict norm_weight, __global ircd_gpt_vectorv *const restrict norm_weight_m0, __global ircd_gpt_vectorv *const restrict norm_weight_m1, __global ircd_gpt_ffnn_aperaturev *const restrict fcon_bias, __global ircd_gpt_ffnn_aperaturev *const restrict fcon_bias_m0, __global ircd_gpt_ffnn_aperaturev *const restrict fcon_bias_m1, __global ircd_gpt_ffnn_aperaturev *const restrict fcon_weight, __global ircd_gpt_ffnn_aperaturev *const restrict fcon_weight_m0, __global ircd_gpt_ffnn_aperaturev *const restrict fcon_weight_m1, __global ircd_gpt_vectorv *const restrict proj_bias, __global ircd_gpt_vectorv *const restrict proj_bias_m0, __global ircd_gpt_vectorv *const restrict proj_bias_m1, __global ircd_gpt_vectorv *const restrict proj_weight, __global ircd_gpt_vectorv *const restrict proj_weight_m0, __global ircd_gpt_vectorv *const restrict proj_weight_m1) { const uint fcon_height = opts->embed_elems, proj_height = opts->ffnn_elems, segs = 4; ircd_gpt_norm_prop ( ctrl, opts, norm_bias, norm_bias_m0, norm_bias_m1, norm_weight, norm_weight_m0, norm_weight_m1 ); for(uint j = 0; j < segs; ++j) ircd_gpt_prop_elem ( ctrl, opts, fcon_bias->proj[j], fcon_bias_m0->proj[j], fcon_bias_m1->proj[j] ); for(uint i = 0; i < fcon_height; ++i) for(uint j = 0; j < segs; ++j) ircd_gpt_prop_elem ( ctrl, opts, fcon_weight[i].proj[j], fcon_weight_m0[i].proj[j], fcon_weight_m1[i].proj[j] ); ircd_gpt_prop_elem ( ctrl, opts, proj_bias->elem, proj_bias_m0->elem, proj_bias_m1->elem ); for(uint i = 0; i < proj_height; ++i) ircd_gpt_prop_elem ( ctrl, opts, proj_weight[i].elem, proj_weight_m0[i].elem, proj_weight_m1[i].elem ); } __kernel void ircd_gpt_lm_embed_prop(__global const struct ircd_gpt_ctrl *const ctrl, __constant const struct ircd_gpt_opts *const opts, __global ircd_gpt_vectorv *const restrict pos, __global ircd_gpt_vectorv *const restrict pos_m0, __global ircd_gpt_vectorv *const restrict pos_m1, __global ircd_gpt_vectorv *const restrict token, __global ircd_gpt_vectorv *const restrict token_m0, __global ircd_gpt_vectorv *const restrict token_m1) { const uint ln = get_local_size(0), wi = get_global_offset(0) / ln + get_group_id(0), wn = ctrl->count, cn = opts->context_tokens / wn, ci = cn * wi, tn = opts->logits / wn, ti = tn * wi; for(uint i = ci; i < ci + cn; ++i) ircd_gpt_prop_elem ( ctrl, opts, pos[i].elem, pos_m0[i].elem, pos_m1[i].elem ); for(uint i = ti; i < ti + tn; ++i) ircd_gpt_prop_elem ( ctrl, opts, token[i].elem, token_m0[i].elem, token_m1[i].elem ); } /// Gaussian Error Linear Unit void ircd_gpt_ffnn_gelu(__local ircd_gpt_ffnn_aperaturev *const out, __local const ircd_gpt_ffnn_aperaturev *const in_, const uint i) { const float4 in = in_->fcon[i]; float4 a; a = 0.044715f; a *= in; a *= in; a += 1.0f; a *= 0.7978845608f; a *= in; a = tanh(a); a += 1.0f; a *= in; a *= 0.5f; out->fcon[i] = a; } void ircd_gpt_norm(__local ircd_gpt_vectorv *const out, __local const ircd_gpt_vectorv *const in, __local ircd_gpt_vectorv *const restrict tmp, __global const ircd_gpt_vectorv *const restrict bias, __global const ircd_gpt_vectorv *const restrict weight, const uint ln, const uint li) { // Layer re-normalization ircd_simt_math_norm_f4lldr(out->elem, in->elem, tmp->elem, ln, li); ircd_gpt_norm_fmad(out, out, bias, weight, li); } void ircd_gpt_norm_fmad(__local ircd_gpt_vectorv *const out, __local const ircd_gpt_vectorv *const in, __global const ircd_gpt_vectorv *const restrict bias, __global const ircd_gpt_vectorv *const restrict weight, const uint i) { out->elem[i] = in->elem[i] * weight->elem[i] + bias->elem[i]; }