Repository: flairNLP/flair

Issue:
TextRegressor, AttributeError: 'list' object has no attribute 'labels'
from flair.datasets import WASSA_JOY
corpus = WASSA_JOY()

embeddings = DocumentPoolEmbeddings([WordEmbeddings('glove')], fine_tune_mode='linear')

model = TextRegressor(embeddings, label_name='happiness')

output_folder = 'resources/taggers/regression_test/'

trainer = ModelTrainer(model, corpus)
trainer.train(
    output_folder,
    mini_batch_size=16,
    max_epochs=10,
)

model = TextRegressor.load(output_folder + 'best-model.pt')

sentence = Sentence('I am so happy')
model.predict(sentence)

print(sentence)


########################
got the following error

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-17-b98a96006f68> in <module>()
     17     output_folder,
     18     mini_batch_size=16,
---> 19     max_epochs=10,
     20 )
     21 

4 frames
/usr/local/lib/python3.7/dist-packages/flair/models/text_regression_model.py in <listcomp>(.0)
     36                 [float(label.value) for label in sentence.labels], dtype=torch.float
     37             )
---> 38             for sentence in sentences
     39         ]
     40 

AttributeError: 'list' object has no attribute 'labels'


Discussion:

Resolving patch:
diff --git a/flair/models/text_regression_model.py b/flair/models/text_regression_model.py
--- a/flair/models/text_regression_model.py
+++ b/flair/models/text_regression_model.py
@@ -1,35 +1,63 @@
+import logging
 from pathlib import Path
+from typing import List, Union, Optional
 
+import torch
+import torch.nn as nn
 from torch.utils.data.dataset import Dataset
 
 import flair
 import flair.embeddings
-import torch
-import torch.nn as nn
-from typing import List, Union, Optional
-
+from flair.data import Sentence, Label, DataPoint
 from flair.datasets import DataLoader, SentenceDataset
 from flair.training_utils import MetricRegression, Result, store_embeddings
-from flair.data import Sentence, Label, DataPoint
-import logging
 
 log = logging.getLogger("flair")
 
 
-class TextRegressor(flair.models.TextClassifier):
-    def __init__(self, document_embeddings: flair.embeddings.DocumentEmbeddings, label_name: str = 'label'):
+class TextRegressor(flair.nn.Model):
 
-        super(TextRegressor, self).__init__(
-            document_embeddings=document_embeddings,
-            label_dictionary=flair.data.Dictionary(),
-            multi_label=False,
-            label_type=label_name,
-        )
+    def __init__(self, document_embeddings: flair.embeddings.DocumentEmbeddings, label_name: str = 'label'):
 
+        super().__init__()
         log.info("Using REGRESSION - experimental")
 
+        self.document_embeddings: flair.embeddings.DocumentEmbeddings = document_embeddings
+        self.label_name = label_name
+
+        self.decoder = nn.Linear(self.document_embeddings.embedding_length, 1)
+
+        nn.init.xavier_uniform_(self.decoder.weight)
+
         self.loss_function = nn.MSELoss()
 
+        # auto-spawn on GPU if available
+        self.to(flair.device)
+
+    def label_type(self):
+        return self.label_name
+
+    def forward(self, sentences):
+
+        self.document_embeddings.embed(sentences)
+
+        embedding_names = self.document_embeddings.get_names()
+
+        text_embedding_list = [sentence.get_embedding(embedding_names).unsqueeze(0) for sentence in sentences]
+        text_embedding_tensor = torch.cat(text_embedding_list, 0).to(flair.device)
+
+        label_scores = self.decoder(text_embedding_tensor)
+
+        return label_scores
+
+    def forward_loss(
+            self, data_points: Union[List[Sentence], Sentence]
+    ) -> torch.tensor:
+
+        scores = self.forward(data_points)
+
+        return self._calculate_loss(scores, data_points)
+
     def _labels_to_indices(self, sentences: List[Sentence]):
         indices = [
             torch.tensor(
@@ -176,7 +204,7 @@ def evaluate(
                                     log_header=log_header,
                                     log_line=log_line,
                                     detailed_results=detailed_result,
-            )
+                                    )
 
             return result
 
@@ -197,3 +225,14 @@ def _init_model_with_state_dict(state):
 
         model.load_state_dict(state["state_dict"])
         return model
+
+    @staticmethod
+    def _filter_empty_sentences(sentences: List[Sentence]) -> List[Sentence]:
+        filtered_sentences = [sentence for sentence in sentences if sentence.tokens]
+        if len(sentences) != len(filtered_sentences):
+            log.warning(
+                "Ignore {} sentence(s) with no tokens.".format(
+                    len(sentences) - len(filtered_sentences)
+                )
+            )
+        return filtered_sentences


Test patch: