// SPDX-License-Identifier: Apache-2.0 ; specs/widgets/nn-lstm.t27 -- an LSTM cell's gates: forget, input, output ; Source of truth for public/widgets/nn-lstm/ (gHashTag/trinity): scripts/widget-pages-from-spec.mjs ; compiles this file, checks its constants, evaluates the tests below and writes the page; the page ; hands every constant to tool.js as window.T27_WIDGET. tool.js holds no English and NO FORMULA of ; its own: every value it draws comes from public/widgets/nn-lstm/logic.js -- the fn bodies of ; gHashTag/t27 specs/ml/recurrent/lstm_single.t27 compiled to wasm, beside its copy logic.t27. ; Lesson 23 of the course neural-networks. ASCII only (L3), English only (LANG-EN). ; Numbers are integers (the schema reads no float): a K_ name ending in _C is in hundredths. ; WHAT IT DOES: the reader sets four gate biases from -6 to 6 and the old memory from -2 to 2. With ; every weight 0, each gate is sigmoid(bias); the new memory and output are bias_only(b_i, b_f, b_g, ; b_o, c_prev, which) of the spec. ; WHAT IT DOES NOT CLAIM: one step of a 1-unit cell with all weights 0, so the gates see only their ; biases; that is the spec's own fixture. ; phi^2 + 1/phi^2 = 3 | TRINITY module widget_nn_lstm; pub const KIND : str = "widget-tool"; pub const ID : str = "nn-lstm"; pub const TITLE : str = "LSTM gates: how a cell decides what to keep"; pub const DESCRIPTION : str = "Set the biases of the forget, input and output gates and the old memory: the new memory is forget x old + input x candidate, and the output shows tanh of it through the output gate."; pub const IMAGE_ALT : str = "LSTM card, remember: gate bars forget 0.998, input 0.002 and output 0.998; memory bars old 1.000, new 0.998 and output 0.759. Tiles read new memory 0.9975, output 0.7587, forget 0.9975 and input 0.0025."; pub const HOOK : str = "With the forget gate open (0.9975) and the input gate shut, a memory of 1 comes out as 0.9975: an LSTM can hold a value for a long time."; pub const CATEGORY : str = "compiler"; pub const DATA_SOURCES : [2]str = ["gHashTag/t27 specs/ml/recurrent/lstm_single.t27 (t27 master 239b4b059): every value on the page is its fn bodies, compiled to wasm (logic.js)", "Course 10 of t27.ai, neural-networks (gHashTag/trinity#1695): lesson 23 opens this widget"]; pub const READS_LOCAL_FILES : bool = false; pub const SENDS_NOTHING : bool = true; pub const K_CARD_WIDTH : u16 = 1200; pub const K_CARD_HEIGHT : u16 = 630; ; --- Numbers: ranges, presets, and fixtures the spec holds (held equal by the tests below) pub const K_BIAS_HI_C : u16 = 600; pub const K_C_LO_C : i16 = -200; pub const K_C_HI_C : u16 = 200; pub const K_CELL_LO : i8 = -3; pub const K_CELL_HI : u8 = 3; pub const K_GATE_TICKS_C : [5]u8 = [0, 25, 50, 75, 100]; pub const K_CELL_TICKS : [5]i8 = [-2, -1, 0, 1, 2]; pub const K_PRESET_BF_C : [4]i16 = [600, -600, -600, 600]; pub const K_PRESET_BI_C : [4]i16 = [-600, 0, 600, -600]; pub const K_PRESET_BG_C : [4]i16 = [0, 0, 600, 0]; pub const K_PRESET_BO_C : [4]i16 = [600, 600, 600, -600]; pub const K_PRESET_C_C : [4]i16 = [100, 100, 100, 100]; pub const K_START_PRESET : u8 = 0; ; --- Words on screen ------------------------------------------------------------------------ pub const SAY_PRESETS_LABEL : str = "Start from"; pub const SAY_PRESET_NAMES : [4]str = ["Remember", "Forget", "Write", "Hide"]; pub const SAY_ASK : str = "How does a memory cell decide what to keep and what to forget?"; pub const SAY_BF : str = "forget bias"; pub const SAY_BI : str = "input bias"; pub const SAY_BG : str = "candidate bias"; pub const SAY_BO : str = "output bias"; pub const SAY_C_PREV : str = "old memory c"; pub const SAY_GATES_LABEL : str = "The three gates, each a sigmoid of its bias"; pub const SAY_CELL_LABEL : str = "The memory before and after, and the output"; pub const SAY_FORGET : str = "forget"; pub const SAY_INPUT : str = "input"; pub const SAY_OUTPUT : str = "output"; pub const SAY_C_OLD : str = "old c"; pub const SAY_C_NEW : str = "new c"; pub const SAY_H_NEW : str = "output h"; pub const SAY_NOTE : str = "c' = f c + i g and h' = o tanh(c'). When f is near 1 and i near 0, c passes through almost untouched, and so does its gradient: the long memory the plain cell lacked."; pub const SAY_SOURCE : str = "Logic: t27 spec ml/recurrent/lstm_single.t27, compiled"; test the_card_is_the_share_size { assert K_CARD_WIDTH == 1200; assert K_CARD_HEIGHT == 630; assert K_CARD_WIDTH * 21 == K_CARD_HEIGHT * 40; } test the_biases_are_symmetric { assert K_BIAS_HI_C == 600; assert K_PRESET_BF_C[1] + K_BIAS_HI_C == 0; assert K_PRESET_BG_C[2] == K_BIAS_HI_C; } test the_presets_cover_the_gates { assert K_PRESET_BF_C[0] > 0; assert K_PRESET_BI_C[0] < 0; assert K_PRESET_BO_C[3] < 0; assert K_PRESET_C_C[0] <= K_C_HI_C; }