# fa_core_news_trf: the whole pipeline on one fine-tuned ParsBERT encoder. # # Differences from the sm/md/lg tiers, all forced by the transformer: # # * One corpus, not two. sm/md/lg train `ner` separately (own embedded tok2vec) and source # it into the dep model. Fine-tuning a 162M-parameter encoder twice would double GPU cost # and ship two encoders in one wheel, and the second would collide on the `transformer` # component name. So every component listens to a single shared transformer and trains # against corpus/joint/, built by scripts/merge_joint_corpus.py (UD layer + the # difflib-transferred NER layer on identical tokenization). # * `use_upper = false` on both transition-based parsers: with a transformer upstream the # extra maxout layer is redundant, and this matches the upstream *_trf configs. # * Adam + warmup_linear and accumulate_gradient=3, not the flat 0.001 the CPU tiers use. # Fine-tuning a pretrained encoder at 1e-3 diverges. # * gpu_allocator = "pytorch" so thinc and torch share one CUDA memory pool. # # Encoder: HooshvareLab/bert-base-parsbert-uncased. NOTE the licence caveat in # docs/MODELS.md ยง3.4 - ParsBERT's model card carries no licence statement, so this wheel is # NOT redistributable on those grounds; HooshvareLab/roberta-fa-zwnj-base (Apache-2.0) is the # publishable alternative and drops in by changing `name` below. [paths] train = null dev = null vectors = null init_tok2vec = null [system] gpu_allocator = "pytorch" seed = 0 [nlp] lang = "fa" pipeline = ["transformer","tagger","morphologizer","trainable_lemmatizer","parser","ner"] batch_size = 128 disabled = [] before_creation = null after_creation = null after_pipeline_creation = null [nlp.tokenizer] @tokenizers = "spacy.Tokenizer.v1" [nlp.vectors] @vectors = "spacy.Vectors.v1" [components] [components.transformer] factory = "transformer" max_batch_items = 4096 [components.transformer.set_extra_annotations] @annotation_setters = "spacy-transformers.null_annotation_setter.v1" [components.transformer.model] @architectures = "spacy-transformers.TransformerModel.v3" name = "HooshvareLab/bert-base-parsbert-uncased" mixed_precision = false [components.transformer.model.get_spans] @span_getters = "spacy-transformers.strided_spans.v1" window = 128 stride = 96 [components.transformer.model.tokenizer_config] use_fast = true [components.transformer.model.transformer_config] [components.transformer.model.grad_scaler_config] [components.tagger] factory = "tagger" label_smoothing = 0.05 overwrite = false neg_prefix = "!" [components.tagger.model] @architectures = "spacy.Tagger.v2" nO = null normalize = false [components.tagger.model.tok2vec] @architectures = "spacy-transformers.TransformerListener.v1" grad_factor = 1.0 upstream = "*" [components.tagger.model.tok2vec.pooling] @layers = "reduce_mean.v1" [components.tagger.scorer] @scorers = "spacy.tagger_scorer.v1" [components.morphologizer] factory = "morphologizer" label_smoothing = 0.05 overwrite = true extend = false [components.morphologizer.model] @architectures = "spacy.Tagger.v2" nO = null normalize = false [components.morphologizer.model.tok2vec] @architectures = "spacy-transformers.TransformerListener.v1" grad_factor = 1.0 upstream = "*" [components.morphologizer.model.tok2vec.pooling] @layers = "reduce_mean.v1" [components.morphologizer.scorer] @scorers = "spacy.morphologizer_scorer.v1" [components.trainable_lemmatizer] factory = "trainable_lemmatizer" backoff = "orth" min_tree_freq = 3 overwrite = false top_k = 1 [components.trainable_lemmatizer.model] @architectures = "spacy.Tagger.v2" nO = null normalize = false [components.trainable_lemmatizer.model.tok2vec] @architectures = "spacy-transformers.TransformerListener.v1" grad_factor = 1.0 upstream = "*" [components.trainable_lemmatizer.model.tok2vec.pooling] @layers = "reduce_mean.v1" [components.trainable_lemmatizer.scorer] @scorers = "spacy.lemmatizer_scorer.v1" [components.parser] factory = "parser" moves = null update_with_oracle_cut_size = 100 learn_tokens = false min_action_freq = 30 [components.parser.model] @architectures = "spacy.TransitionBasedParser.v2" state_type = "parser" extra_state_tokens = false hidden_width = 64 maxout_pieces = 2 use_upper = false nO = null [components.parser.model.tok2vec] @architectures = "spacy-transformers.TransformerListener.v1" grad_factor = 1.0 upstream = "*" [components.parser.model.tok2vec.pooling] @layers = "reduce_mean.v1" [components.parser.scorer] @scorers = "spacy.parser_scorer.v1" [components.ner] factory = "ner" moves = null update_with_oracle_cut_size = 100 incorrect_spans_key = null [components.ner.model] @architectures = "spacy.TransitionBasedParser.v2" state_type = "ner" extra_state_tokens = false hidden_width = 64 maxout_pieces = 2 use_upper = false nO = null [components.ner.model.tok2vec] @architectures = "spacy-transformers.TransformerListener.v1" grad_factor = 1.0 upstream = "*" [components.ner.model.tok2vec.pooling] @layers = "reduce_mean.v1" [components.ner.scorer] @scorers = "spacy.ner_scorer.v1" [corpora] [corpora.train] @readers = "spacy.Corpus.v1" path = ${paths.train} max_length = 0 gold_preproc = false limit = 0 augmenter = null [corpora.dev] @readers = "spacy.Corpus.v1" path = ${paths.dev} max_length = 0 gold_preproc = false limit = 0 augmenter = null [training] dev_corpus = "corpora.dev" train_corpus = "corpora.train" seed = ${system.seed} gpu_allocator = ${system.gpu_allocator} dropout = 0.1 accumulate_gradient = 3 # 3000 steps is ~40 epochs over this 445k-token corpus, measured at ~29 steps/min on a T4 # (~1.8h). The CPU tiers' 20000/1600 would be ~270 epochs and ~12h here, and worse than # wasteful: warmup_linear anneals against `total_steps`, so a run stopped early by patience # never leaves the peak learning rate. Budget and schedule are kept equal on purpose: # training.optimizer.learn_rate.total_steps must track any change to max_steps. patience = 600 max_epochs = 0 max_steps = 3000 eval_frequency = 100 frozen_components = [] annotating_components = [] before_to_disk = null before_update = null [training.optimizer] @optimizers = "Adam.v1" beta1 = 0.9 beta2 = 0.999 L2_is_weight_decay = true L2 = 0.01 grad_clip = 1.0 use_averages = false eps = 1e-08 [training.optimizer.learn_rate] @schedules = "warmup_linear.v1" warmup_steps = 250 total_steps = 3000 initial_rate = 5e-5 [training.batcher] @batchers = "spacy.batch_by_padded.v1" discard_oversize = true size = 2000 buffer = 256 get_length = null [training.logger] @loggers = "spacy.ConsoleLogger.v1" progress_bar = false [training.score_weights] tag_acc = 0.16 pos_acc = 0.08 tag_micro_p = null tag_micro_r = null tag_micro_f = null morph_acc = 0.08 morph_per_feat = null lemma_acc = 0.16 dep_uas = 0.08 dep_las = 0.16 dep_las_per_type = null sents_p = null sents_r = null sents_f = 0.0 ents_f = 0.28 ents_p = 0.0 ents_r = 0.0 ents_per_type = null [initialize] vectors = ${paths.vectors} init_tok2vec = ${paths.init_tok2vec} vocab_data = null lookups = null before_init = null after_init = null [initialize.tokenizer] [initialize.components] [pretraining]