Repository: flairNLP/flair

Issue:
Format of input gold_label_dictionary for dependency parser
Hello,
I am currently trying to implement the DependencyParser for a corpus in the conllu format. It runs smoothly until it hits the evaluation function, where I receive the following error:
`TypeError: unsupported format string passed to Tensor.__format__`

This is both with leaving the gold_label_dictionary empty (is marked as "optional" in the class), or with feeding it a label-dictionary. What needs to be my input in order for the parser to run?

I feel also a little bit unsecure regarding the format of the input corpus. Did I understand correctly that the parser only takes the token and the deprel-feature as input, leaving aside upos and "head"?

Looking forward to your help and exploring more about the dependency parser, thanks for implementing it!


Discussion:

Resolving patch:
diff --git a/flair/models/dependency_parser_model.py b/flair/models/dependency_parser_model.py
--- a/flair/models/dependency_parser_model.py
+++ b/flair/models/dependency_parser_model.py
@@ -23,6 +23,7 @@ def __init__(
         token_embeddings: TokenEmbeddings,
         relations_dictionary: Dictionary,
         tag_type: str = "dependency",
+        use_rnn: Union[bool, str] = True,
         lstm_hidden_size: int = 400,
         mlp_arc_units: int = 500,
         mlp_rel_units: int = 100,
@@ -63,44 +64,45 @@ def __init__(
             self.word_dropout = WordDropout(dropout_rate=word_dropout)
 
         self.tag_type = tag_type
-        self.lstm_input_dim: int = self.token_embeddings.embedding_length
 
-        self.lstm = BiLSTM(
-            input_size=self.lstm_input_dim,
-            hidden_size=self.lstm_hidden_size,
-            num_layers=self.lstm_layers,
-            dropout=self.lstm_dropout,
-        )
+        self.use_rnn = True
 
-        self.mlp_arc_h = MLP(
-            n_in=self.lstm_hidden_size * 2,
-            n_hidden=self.mlp_arc_units,
-            dropout=self.mlp_dropout,
-        )
-        self.mlp_arc_d = MLP(
-            n_in=self.lstm_hidden_size * 2,
-            n_hidden=self.mlp_arc_units,
-            dropout=self.mlp_dropout,
-        )
-        self.mlp_rel_h = MLP(
-            n_in=self.lstm_hidden_size * 2,
-            n_hidden=self.mlp_rel_units,
-            dropout=self.mlp_dropout,
-        )
-        self.mlp_rel_d = MLP(
-            n_in=self.lstm_hidden_size * 2,
-            n_hidden=self.mlp_rel_units,
-            dropout=self.mlp_dropout,
-        )
+        # if there is no RNN
+        if not use_rnn:
+
+            self.use_rnn = False
+            mlp_input_dim = self.token_embeddings.embedding_length
+
+        else:
+
+            self.lstm_input_dim: int = self.token_embeddings.embedding_length
+            mlp_input_dim = self.lstm_hidden_size * 2
+
+            if use_rnn == "Variational":
+                self.lstm = BiLSTM(
+                    input_size=self.lstm_input_dim,
+                    hidden_size=self.lstm_hidden_size,
+                    num_layers=self.lstm_layers,
+                    dropout=self.lstm_dropout,
+                )
+            else:
+                self.lstm = torch.nn.LSTM(
+                    self.lstm_input_dim,
+                    self.lstm_hidden_size,
+                    num_layers=self.lstm_layers,
+                    dropout=lstm_dropout,
+                    bidirectional=True,
+                    batch_first=True,
+                )
+
+        self.mlp_arc_h = MLP(n_in=mlp_input_dim, n_hidden=self.mlp_arc_units, dropout=self.mlp_dropout)
+        self.mlp_arc_d = MLP(n_in=mlp_input_dim, n_hidden=self.mlp_arc_units, dropout=self.mlp_dropout)
+        self.mlp_rel_h = MLP(n_in=mlp_input_dim, n_hidden=self.mlp_rel_units, dropout=self.mlp_dropout)
+        self.mlp_rel_d = MLP(n_in=mlp_input_dim, n_hidden=self.mlp_rel_units, dropout=self.mlp_dropout)
 
         self.arc_attn = Biaffine(n_in=self.mlp_arc_units, bias_x=True, bias_y=False)
 
-        self.rel_attn = Biaffine(
-            n_in=self.mlp_rel_units,
-            n_out=len(relations_dictionary),
-            bias_x=True,
-            bias_y=True,
-        )
+        self.rel_attn = Biaffine(n_in=self.mlp_rel_units, n_out=len(relations_dictionary), bias_x=True, bias_y=True)
 
         self.to(flair.device)
 
@@ -139,16 +141,17 @@ def forward(self, sentences: List[Sentence]):
         if self.use_word_dropout:
             sentence_tensor = self.word_dropout(sentence_tensor)
 
-        x = pack_padded_sequence(sentence_tensor, torch.tensor(lengths), True, False)
+        if self.use_rnn:
+            sentence_tensor = pack_padded_sequence(sentence_tensor, lengths, True, False)
 
-        x, _ = self.lstm(x)
-        x_encoded, _ = pad_packed_sequence(x, True, total_length=seq_len)
+            sentence_tensor, _ = self.lstm(sentence_tensor)
+            sentence_tensor, _ = pad_packed_sequence(sentence_tensor, True, total_length=seq_len)
 
         # apply MLPs for arc and relations to the BiLSTM output states
-        arc_h = self.mlp_arc_h(x_encoded)
-        arc_d = self.mlp_arc_d(x_encoded)
-        rel_h = self.mlp_rel_h(x_encoded)
-        rel_d = self.mlp_rel_d(x_encoded)
+        arc_h = self.mlp_arc_h(sentence_tensor)
+        arc_d = self.mlp_arc_d(sentence_tensor)
+        rel_h = self.mlp_rel_h(sentence_tensor)
+        rel_d = self.mlp_rel_d(sentence_tensor)
 
         # get scores from the biaffine attentions
         # [batch_size, seq_len, seq_len]
@@ -260,8 +263,8 @@ def evaluate(
         lines: List[str] = ["token gold_tag gold_arc predicted_tag predicted_arc\n"]
 
         average_over = 0
-        eval_loss_arc = torch.zeros(1, device=flair.device)
-        eval_loss_rel = torch.zeros(1, device=flair.device)
+        eval_loss_arc = 0.0
+        eval_loss_rel = 0.0
 
         y_true = []
         y_pred = []
@@ -277,8 +280,8 @@ def evaluate(
 
             parsing_metric(arc_prediction, relation_prediction, batch, gold_label_type)
 
-            eval_loss_arc += loss_arc
-            eval_loss_rel += loss_rel
+            eval_loss_arc += loss_arc.item()
+            eval_loss_rel += loss_rel.item()
 
             for (sentence, arcs, sent_tags) in zip(batch, arc_prediction, relation_prediction):
                 for (token, arc, tag) in zip(sentence.tokens, arcs, sent_tags):
@@ -345,7 +348,7 @@ def evaluate(
             log_header=log_header,
             detailed_results=detailed_result,
             classification_report=classification_report_dict,
-            loss=(eval_loss_rel + eval_loss_arc).item(),
+            loss=(eval_loss_rel + eval_loss_arc),
         )
         return result
 
@@ -371,6 +374,7 @@ def _get_state_dict(self):
         model_state = {
             "state_dict": self.state_dict(),
             "token_embeddings": self.token_embeddings,
+            "use_rnn": self.use_rnn,
             "lstm_hidden_size": self.lstm_hidden_size,
             "relations_dictionary": self.relations_dictionary,
             "mlp_arc_units": self.mlp_arc_units,
@@ -387,6 +391,7 @@ def _init_model_with_state_dict(state):
         model = DependencyParser(
             token_embeddings=state["token_embeddings"],
             relations_dictionary=state["relations_dictionary"],
+            use_rnn=state["use_rnn"],
             lstm_hidden_size=state["lstm_hidden_size"],
             mlp_arc_units=state["mlp_arc_units"],
             mlp_rel_units=state["mlp_rel_units"],


Test patch: