@@ -145,7 +145,7 @@ def test_transformer_pipeline_long_token(simple_nlp):
145145 """
146146
147147
148- def test_transformer_pipeline_tagger ():
148+ def test_transformer_pipeline_tagger_listener ():
149149 """Test that a pipeline with just a transformer+tagger runs and trains properly"""
150150 orig_config = Config ().from_str (cfg_string )
151151 nlp = util .load_model_from_config (orig_config , auto_fill = True , validate = True )
@@ -171,7 +171,8 @@ def test_transformer_pipeline_tagger():
171171 losses = {}
172172 nlp .update (train_examples , sgd = optimizer , losses = losses )
173173
174- doc = nlp ("We're interested at underwater basket weaving." )
174+ text = "We're interested at underwater basket weaving."
175+ doc = nlp (text )
175176 doc_tensor = tagger_trf .predict ([doc ])
176177 assert_equal (doc ._ .trf_data .tensors , doc_tensor [0 ].tensors )
177178
@@ -180,12 +181,23 @@ def test_transformer_pipeline_tagger():
180181 file_path = d / "trained_nlp"
181182 nlp .to_disk (file_path )
182183 nlp2 = util .load_model_from_path (file_path )
183- doc = nlp2 ("We're interested at underwater basket weaving." )
184+ doc = nlp2 (text )
184185 tagger2 = nlp2 .get_pipe ("tagger" )
185186 tagger_trf2 = tagger2 .model .get_ref ("tok2vec" ).layers [0 ]
186187 doc_tensor2 = tagger_trf2 .predict ([doc ])
187188 assert_equal (doc_tensor2 [0 ].tensors , doc_tensor [0 ].tensors )
188189
190+ # ensure to_bytes / from_bytes works
191+ nlp_bytes = nlp .to_bytes ()
192+ nlp3 = util .load_model_from_config (orig_config , auto_fill = True , validate = True )
193+ nlp3 .initialize (lambda : train_examples )
194+ nlp3 .from_bytes (nlp_bytes )
195+ doc = nlp3 (text )
196+ tagger3 = nlp3 .get_pipe ("tagger" )
197+ tagger_trf3 = tagger3 .model .get_ref ("tok2vec" ).layers [0 ]
198+ doc_tensor3 = tagger_trf3 .predict ([doc ])
199+ assert_equal (doc_tensor3 [0 ].tensors , doc_tensor [0 ].tensors )
200+
189201
190202def test_transformer_pipeline_empty ():
191203 """Test that the pipeline doesn't fail with empty input"""
@@ -255,3 +267,71 @@ def test_multiprocessing(simple_nlp, texts):
255267
256268 for doc , expected_doc in zip (docs , expecteds ):
257269 assert_docs_equal (doc , expected_doc )
270+
271+ def test_replace_listeners ():
272+ orig_config = Config ().from_str (cfg_string )
273+ nlp = util .load_model_from_config (orig_config , auto_fill = True , validate = True )
274+ text = "This is awesome"
275+ examples = [Example .from_dict (nlp .make_doc (text ), {"tags" : ["A" , "B" , "C" ]})]
276+ optimizer = nlp .initialize (lambda : examples )
277+ # verify correct configuration with transformer listener
278+ transformer = nlp .get_pipe ("transformer" )
279+ tagger = nlp .get_pipe ("tagger" )
280+ tagger_tok2vec = tagger .model .get_ref ("tok2vec" )
281+ tagger_listener = tagger_tok2vec .get_ref ("listener" )
282+ assert isinstance (tagger_listener , TransformerListener )
283+ assert transformer .listener_map ["tagger" ][0 ] == tagger_listener
284+ assert (
285+ nlp .config ["components" ]["transformer" ]["model" ]["@architectures" ]
286+ == "spacy-transformers.TransformerModel.v1"
287+ )
288+ assert (
289+ nlp .config ["components" ]["tagger" ]["model" ]["tok2vec" ]["@architectures" ]
290+ == "spacy-transformers.TransformerListener.v1"
291+ )
292+ # train pipe before replacing listeners
293+ for i in range (2 ):
294+ losses = {}
295+ nlp .update (examples , sgd = optimizer , losses = losses )
296+ doc = nlp (text )
297+
298+ preds = [t .tag_ for t in doc ]
299+ doc_tensor = tagger_tok2vec .predict ([doc ])
300+
301+ # replace listener and verify predictions are still the same
302+ nlp .replace_listeners ("transformer" , "tagger" , ["model.tok2vec" ])
303+ tagger = nlp .get_pipe ("tagger" )
304+ tagger_tok2vec = tagger .model .get_ref ("tok2vec" )
305+ assert tagger_tok2vec .layers [0 ].layers [0 ].name == "transformer"
306+ assert (
307+ nlp .config ["components" ]["tagger" ]["model" ]["tok2vec" ]["@architectures" ]
308+ == "spacy-transformers.Tok2VecTransformer.v1"
309+ )
310+ doc2 = nlp (text )
311+ assert preds == [t .tag_ for t in doc2 ]
312+ assert_equal (doc_tensor , tagger_tok2vec .predict ([doc2 ]))
313+ # attempt training with the new pipeline
314+ optimizer = nlp .resume_training ()
315+ for i in range (2 ):
316+ losses = {}
317+ nlp .update (examples , sgd = optimizer , losses = losses )
318+ assert losses ["tagger" ] > 0.0
319+
320+
321+ def test_replace_listeners_invalid ():
322+ orig_config = Config ().from_str (cfg_string )
323+ nlp = util .load_model_from_config (orig_config , auto_fill = True , validate = True )
324+ text = "This is awesome"
325+ examples = [Example .from_dict (nlp .make_doc (text ), {"tags" : ["A" , "B" , "C" ]})]
326+ optimizer = nlp .initialize (lambda : examples )
327+ for i in range (2 ):
328+ losses = {}
329+ nlp .update (examples , sgd = optimizer , losses = losses )
330+ with pytest .raises (ValueError ):
331+ nlp .replace_listeners ("invalid" , "tagger" , ["model.tok2vec" ])
332+ with pytest .raises (ValueError ):
333+ nlp .replace_listeners ("transformer" , "parser" , ["model.tok2vec" ])
334+ with pytest .raises (ValueError ):
335+ nlp .replace_listeners ("transformer" , "tagger" , ["model.yolo" ])
336+ with pytest .raises (ValueError ):
337+ nlp .replace_listeners ("transformer" , "tagger" , ["model.tok2vec" , "model.yolo" ])
0 commit comments