| 551 | } |
| 552 | |
| 553 | class SoftmaxBlockClass extends Block { |
| 554 | constructor() { |
| 555 | super(); |
| 556 | this.name = "softmax"; |
| 557 | } |
| 558 | |
| 559 | getFusedPipeline(workgroups, transpose) { |
| 560 | const pipelineCacheKey = `${this.name}_fused_${workgroups}_${transpose}`; |
| 561 | if (this.pipelineCache.has(pipelineCacheKey)) return this.pipelineCache.get(pipelineCacheKey); |
| 562 | const pipeline = this.initPipeline(this.fusedShader(workgroups, transpose), [this.u_s_Layout, this.r_Layout], `${this.name}_Pipeline_Div`); |
| 563 | this.pipelineCache.set(pipelineCacheKey, pipeline); |
| 564 | return pipeline; |
| 565 | } |
| 566 | |
| 567 | newInstance(rows, cols, inputBuffer, transpose = false) { |
| 568 | const workgroupsX = cols > 4096 ? 256 : 64; |
| 569 | const fusedPipeline = this.getFusedPipeline(workgroupsX, transpose); |
| 570 | |
| 571 | const uniformBuffer = this.initUniform(4, [[0, new Uint32Array([rows, cols])]]); |
| 572 | const resultBuffer = this.initResultBuffer([rows, cols], `${this.name}_ResultBuffer_`); |
| 573 | const bindGroup = this.initBindGroup(this.u_s_Layout, [uniformBuffer, resultBuffer], `${this.name}_BindGroup_`); |
| 574 | const inputBindGroup = this.initBindGroup(this.r_Layout, [inputBuffer], `${this.name}_BindGroup__Input`); |
| 575 | const workgroups = { x: 1, y: wgSize(rows, 1), z: 1 }; |
| 576 | |
| 577 | return { |
| 578 | resultBuffer: resultBuffer, |
| 579 | passes: [ |
| 580 | { |
| 581 | flag: "compute", |
| 582 | pipeline: fusedPipeline, |
| 583 | groups: [bindGroup, inputBindGroup], |
| 584 | workgroups: workgroups, |
| 585 | }, |
| 586 | ], |
| 587 | }; |
| 588 | } |
| 589 | |
| 590 | /* |
| 591 | Possible improvements: Vectorization? Modify input buffer to coalesce better? |
| 592 | */ |
| 593 | fusedShader(wg_size, transpose) { |
| 594 | const outputIndex = transpose ? "i * uniforms.M + row" : "row * N + i"; |
| 595 | return ` |
| 596 | struct Meta { |
| 597 | M: u32, |
| 598 | N: u32, |
| 599 | }; |
| 600 | |
| 601 | const minFloat: f32 = -3.402823e+38f; |
| 602 | const wg_size: u32 = ${wg_size}; |
| 603 | |
| 604 | @group(0) @binding(0) var<uniform> uniforms: Meta; |
| 605 | @group(0) @binding(1) var<storage, read_write> result_array: array<f32>; |
| 606 | @group(1) @binding(0) var<storage, read> input_array: array<f32>; |
| 607 | |
| 608 | var<workgroup> max_row: f32; |
| 609 | var<workgroup> sum_row: f32; |
| 610 | var<workgroup> op_buffer: array<f32, ${wg_size}>; |
nothing calls this directly
no outgoing calls
no test coverage detected