In the vendored gpt-2 fixture, the weight a Conv1d layer creates in build with self.add_weight("cov1d_weights", shape=[...], dtype=tf.float32, initializer=...) has an empty points-to set where call reads it as the second operand of tf.matmul, in every one of the layer's 48 calling contexts. An add_weight call with an explicit dtype whose result never reaches the field read is a modeling gap by this repository's own rule (an empty points-to set is a bug to find, not a behaviour to work around), and it is on the critical path of #937: it blocks both routes by which the matmul could learn its dtype.
Demonstrated
The matmul generator's caller walk for the b operand logs, for every Conv1d context:
getArgumentPointsToSet: caller script layers.feed_forward.py.Conv1d.call.do()LRoot; [ctx#...] instr 42 = invokeFunction < PythonLoader, LCodeBody, do()LRoot; > 43,31,46 @31 ... argValNum=46
getArgumentPointsToSet: caller analysis of tensorflow.functions.matmul.do()LRoot; [ctx#...] found no argument at pos=1 name=b; returning empty.
The argument is located (value 46, the self.weight field read), and its points-to set is empty, so the walk reports no argument. The field read carries no dataflow state either (no tensor variable for value 46 in Conv1d.call's dump). By contrast, the same fixture seeds add_weight results in LayerNormalization.build (gamma, beta) and EmbeddingLayer.build, and a minimal fixture with the same build and call in a layer constructed directly by a model resolves its weight to (4, 4) float32 at the matmul. Nothing is seeded from Conv1d.build at all: no add_weight generator is found for any value in that node, although the node exists in the call graph and its two add_weight invokes dispatch to the keyword trampolines.
What Differs, Inferred
Two things distinguish Conv1d from the layers whose weights resolve, and either could be the cause: it is constructed inside another layer's __init__ (MultiHeadAttention and FeedForward each build two), so its build runs under a doubly nested trampoline context. And its first add_weight passes initializer=tf.random_normal_initializer(stddev=..., mean=...), a call result, where the resolving layers pass an initializer object without keyword arguments. Which one it is would be settled by a fixture that varies them one at a time.
Consequences
The matmul's dtype rule takes a's dtype when resolved and b's otherwise, so with b empty b never decides, and where a's generator-time read is unknown (the second instance of each Conv1d pair, #937) the seed is unknown. The dataflow repair is blocked by the same absence, and this is measured rather than inferred: the matmul's feed composes pairs of both operands' members and b carries none, so the feed composes nothing, and a temporary line in the engine's unfed-seed restore shows the matmul's and the add's suppressed seeds being put back unchanged in every Conv1d context (? of unknown in the second instance's contexts, ? of float32 in the first's). The probe's certificate, so the count reads as measured: its unconditional entry line printed once, entered with 294 suppressed seeds, and 112 restores followed in the same run; two earlier runs of the same probe printed no entry line (one had not compiled, one selected a test method that no longer existed) and their zeros were discarded. A resolved b would give the matmul its dtype at seed time or through the feed, either of which removes the unknown that the residual add's fill later composes into the loop-carried arm (#936). That makes this the second repair path for the same value that is also absent, which is why it is filed on its own rather than folded into either issue.
In the vendored gpt-2 fixture, the weight a
Conv1dlayer creates inbuildwithself.add_weight("cov1d_weights", shape=[...], dtype=tf.float32, initializer=...)has an empty points-to set wherecallreads it as the second operand oftf.matmul, in every one of the layer's 48 calling contexts. Anadd_weightcall with an explicit dtype whose result never reaches the field read is a modeling gap by this repository's own rule (an empty points-to set is a bug to find, not a behaviour to work around), and it is on the critical path of #937: it blocks both routes by which the matmul could learn its dtype.Demonstrated
The matmul generator's caller walk for the
boperand logs, for every Conv1d context:The argument is located (value 46, the
self.weightfield read), and its points-to set is empty, so the walk reports no argument. The field read carries no dataflow state either (no tensor variable for value 46 inConv1d.call's dump). By contrast, the same fixture seedsadd_weightresults inLayerNormalization.build(gamma,beta) andEmbeddingLayer.build, and a minimal fixture with the samebuildandcallin a layer constructed directly by a model resolves its weight to(4, 4) float32at the matmul. Nothing is seeded fromConv1d.buildat all: noadd_weightgenerator is found for any value in that node, although the node exists in the call graph and its twoadd_weightinvokes dispatch to the keyword trampolines.What Differs, Inferred
Two things distinguish
Conv1dfrom the layers whose weights resolve, and either could be the cause: it is constructed inside another layer's__init__(MultiHeadAttentionandFeedForwardeach build two), so itsbuildruns under a doubly nested trampoline context. And its firstadd_weightpassesinitializer=tf.random_normal_initializer(stddev=..., mean=...), a call result, where the resolving layers pass an initializer object without keyword arguments. Which one it is would be settled by a fixture that varies them one at a time.Consequences
The matmul's dtype rule takes
a's dtype when resolved andb's otherwise, so withbemptybnever decides, and wherea's generator-time read is unknown (the second instance of each Conv1d pair, #937) the seed is unknown. The dataflow repair is blocked by the same absence, and this is measured rather than inferred: the matmul's feed composes pairs of both operands' members andbcarries none, so the feed composes nothing, and a temporary line in the engine's unfed-seed restore shows the matmul's and the add's suppressed seeds being put back unchanged in every Conv1d context (? of unknownin the second instance's contexts,? of float32in the first's). The probe's certificate, so the count reads as measured: its unconditional entry line printed once,entered with 294 suppressed seeds, and 112 restores followed in the same run; two earlier runs of the same probe printed no entry line (one had not compiled, one selected a test method that no longer existed) and their zeros were discarded. A resolvedbwould give the matmul its dtype at seed time or through the feed, either of which removes the unknown that the residual add's fill later composes into the loop-carried arm (#936). That makes this the second repair path for the same value that is also absent, which is why it is filed on its own rather than folded into either issue.