Class: Toy::Card
- Inherits:
-
Object
- Object
- Toy::Card
- Defined in:
- lib/toy/dev/toy_card.rb
Overview
A complete algorithm card.
c = Toy::Card.new("Toy::GPT2.forward(x, p_start)", "HF GPT-2 family")
c.add_input("x", "{1..V}^T", "token IDs")
c.add_output("P", "R^{T×V}", "logits")
c.add_hyper("V", cfg.vocab.to_s)
c.add_param("W_e", "R^{V×D}", "")
c.add_param_extra("(total " + Toy.fmt_count(param_count) + ", tied)")
c.step_bind("e", "W_e[x] + W_p[p_start : p_start+T]", "e ∈ R^{T×D}")
c.step_loop("ℓ ← 1, …, N", "")
c.step_update("e", "e + Attn(LN(e; γ_ℓ^1, β_ℓ^1, ε); θ_ℓ^attn)", "e ∈ R^{T×D}", "")
c.step_loop_close
c.step_return("P")
puts c.render_pseudocode
Constant Summary collapse
- SHAPE_COL =
target column for the shape annotation
70
Instance Attribute Summary collapse
-
#family ⇒ Object
Returns the value of attribute family.
-
#hypers ⇒ Object
Returns the value of attribute hypers.
-
#inputs ⇒ Object
Returns the value of attribute inputs.
-
#name_ ⇒ Object
Returns the value of attribute name_.
-
#outputs ⇒ Object
Returns the value of attribute outputs.
-
#param_extras ⇒ Object
Returns the value of attribute param_extras.
-
#params ⇒ Object
Returns the value of attribute params.
-
#steps ⇒ Object
Returns the value of attribute steps.
Class Method Summary collapse
-
.pad_to(body, col, tail) ⇒ Object
Right-pad ‘body` to `col` characters then append `tail` — only if `tail` is non-empty.
Instance Method Summary collapse
- #add_hyper(key, value) ⇒ Object
-
#add_input(name_, type_, note) ⇒ Object
— builder API ————————————————–.
- #add_output(name_, type_, note) ⇒ Object
- #add_param(name_, type_, note) ⇒ Object
-
#add_param_extra(line) ⇒ Object
Free-text continuation lines under “Param:” (e.g. “(total Xxx)”).
-
#hyper(key) ⇒ Object
Look up a hyper by key.
-
#initialize(name_, family) ⇒ Card
constructor
A new instance of Card.
- #render_pseudocode ⇒ Object
- #step_bind(var, expr_str, shape) ⇒ Object
-
#step_loop(header, note) ⇒ Object
‘header` is the loop header without “for”/“do” — the renderer adds those.
- #step_loop_close ⇒ Object
- #step_return(var) ⇒ Object
- #step_update(var, expr_str, shape, note) ⇒ Object
Constructor Details
#initialize(name_, family) ⇒ Card
Returns a new instance of Card.
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/toy/dev/toy_card.rb', line 105 def initialize(name_, family) @name_ = name_ @family = family # Seed-then-pop pins each Array as PtrArray<ConcreteRow> in # Spinel's type inference. Without the seed it would be # untyped-empty and the first push would lock it in incorrectly. @inputs = [Toy::CardItem.new("", "", "")] @inputs.pop @outputs = [Toy::CardItem.new("", "", "")] @outputs.pop @hypers = [Toy::CardHyper.new("", "")] @hypers.pop @params = [Toy::CardItem.new("", "", "")] @params.pop @param_extras = [""] @param_extras.pop @steps = [Toy::Step.new("bind", "", "", "", "")] @steps.pop end |
Instance Attribute Details
#family ⇒ Object
Returns the value of attribute family.
101 102 103 |
# File 'lib/toy/dev/toy_card.rb', line 101 def family @family end |
#hypers ⇒ Object
Returns the value of attribute hypers.
101 102 103 |
# File 'lib/toy/dev/toy_card.rb', line 101 def hypers @hypers end |
#inputs ⇒ Object
Returns the value of attribute inputs.
101 102 103 |
# File 'lib/toy/dev/toy_card.rb', line 101 def inputs @inputs end |
#name_ ⇒ Object
Returns the value of attribute name_.
101 102 103 |
# File 'lib/toy/dev/toy_card.rb', line 101 def name_ @name_ end |
#outputs ⇒ Object
Returns the value of attribute outputs.
101 102 103 |
# File 'lib/toy/dev/toy_card.rb', line 101 def outputs @outputs end |
#param_extras ⇒ Object
Returns the value of attribute param_extras.
101 102 103 |
# File 'lib/toy/dev/toy_card.rb', line 101 def param_extras @param_extras end |
#params ⇒ Object
Returns the value of attribute params.
101 102 103 |
# File 'lib/toy/dev/toy_card.rb', line 101 def params @params end |
#steps ⇒ Object
Returns the value of attribute steps.
101 102 103 |
# File 'lib/toy/dev/toy_card.rb', line 101 def steps @steps end |
Class Method Details
.pad_to(body, col, tail) ⇒ Object
Right-pad ‘body` to `col` characters then append `tail` — only if `tail` is non-empty. Used to align shape annotations.
175 176 177 178 179 180 181 182 183 |
# File 'lib/toy/dev/toy_card.rb', line 175 def self.pad_to(body, col, tail) return body if tail == "" n = body.length if n >= col body + " " + tail else body + (" " * (col - n)) + tail end end |
Instance Method Details
#add_hyper(key, value) ⇒ Object
136 137 138 |
# File 'lib/toy/dev/toy_card.rb', line 136 def add_hyper(key, value) @hypers.push(Toy::CardHyper.new(key, value)) end |
#add_input(name_, type_, note) ⇒ Object
— builder API ————————————————–
128 129 130 |
# File 'lib/toy/dev/toy_card.rb', line 128 def add_input(name_, type_, note) @inputs.push(Toy::CardItem.new(name_, type_, note)) end |
#add_output(name_, type_, note) ⇒ Object
132 133 134 |
# File 'lib/toy/dev/toy_card.rb', line 132 def add_output(name_, type_, note) @outputs.push(Toy::CardItem.new(name_, type_, note)) end |
#add_param(name_, type_, note) ⇒ Object
140 141 142 |
# File 'lib/toy/dev/toy_card.rb', line 140 def add_param(name_, type_, note) @params.push(Toy::CardItem.new(name_, type_, note)) end |
#add_param_extra(line) ⇒ Object
Free-text continuation lines under “Param:” (e.g. “(total Xxx)”).
145 146 147 |
# File 'lib/toy/dev/toy_card.rb', line 145 def add_param_extra(line) @param_extras.push(line) end |
#hyper(key) ⇒ Object
Look up a hyper by key. Returns “” if absent — used by the round-trip emitter (prep/card_to_code.rb) so it can read the IR directly instead of regexing the rendered text.
292 293 294 295 296 297 |
# File 'lib/toy/dev/toy_card.rb', line 292 def hyper(key) @hypers.each do |h| return h.value if h.key == key end "" end |
#render_pseudocode ⇒ Object
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
# File 'lib/toy/dev/toy_card.rb', line 187 def render_pseudocode s = "Algorithm: " + @name_ if @family != "" # Tag in square brackets, padded with a few spaces. pad = " " s = s + pad + "[" + @family + "]" end s = s + "\n" # Input / Output / Hyper / Param headers. first = true @inputs.each do |it| prefix = first ? " Input: " : " " line = prefix + it.name_ + " ∈ " + it.type_ if it.note != "" line = line + " (" + it.note + ")" end s = s + line + "\n" first = false end first = true @outputs.each do |it| prefix = first ? " Output: " : " " line = prefix + it.name_ + " ∈ " + it.type_ if it.note != "" line = line + " (" + it.note + ")" end s = s + line + "\n" first = false end if @hypers.length > 0 line = " Hyper: " @hypers.each do |h| line = line + " " + h.key + "=" + h.value end s = s + line + "\n" end first = true @params.each do |it| prefix = first ? " Param: " : " " line = prefix + it.name_ + " ∈ " + it.type_ if it.note != "" line = line + " (" + it.note + ")" end s = s + line + "\n" first = false end @param_extras.each do |line| s = s + " " + line + "\n" end # Body: walk steps, track step number and indent depth. n = 1 depth = 0 @steps.each do |st| kind = st.kind if kind == "loop_close" depth = depth - 1 end indent = " " * depth head = " " + n.to_s.rjust(2) + ": " + indent body = "" if kind == "bind" || kind == "update" body = head + st.var + " ← " + st.expr_str elsif kind == "loop_open" body = head + "for " + st.expr_str + " do" elsif kind == "loop_close" body = head + "end for" elsif kind == "return" body = head + "return " + st.var elsif kind == "comment" body = head + "▷ " + st.note else body = head + st.expr_str end tail = st.shape if st.note != "" && kind != "loop_close" && kind != "comment" if tail == "" tail = "▷ " + st.note else tail = tail + " ▷ " + st.note end end s = s + Toy::Card.pad_to(body, Toy::Card::SHAPE_COL, tail) + "\n" if kind == "loop_open" depth = depth + 1 end n = n + 1 end s end |
#step_bind(var, expr_str, shape) ⇒ Object
149 150 151 |
# File 'lib/toy/dev/toy_card.rb', line 149 def step_bind(var, expr_str, shape) @steps.push(Toy::Step.new("bind", var, expr_str, shape, "")) end |
#step_loop(header, note) ⇒ Object
‘header` is the loop header without “for”/“do” — the renderer adds those. `note` is an inline ▷ comment shown beside the line.
159 160 161 |
# File 'lib/toy/dev/toy_card.rb', line 159 def step_loop(header, note) @steps.push(Toy::Step.new("loop_open", "", header, "", note)) end |
#step_loop_close ⇒ Object
163 164 165 |
# File 'lib/toy/dev/toy_card.rb', line 163 def step_loop_close @steps.push(Toy::Step.new("loop_close", "", "", "", "")) end |