Customize Multi Output Model

It is very easy to customize your own multi output model. Lets assume you have dataset like this, One input and two output.

Example code at file tests/test_custom_multi_output_classification.py.

  1. x = [
  2. ['我', '想', '全', '部', '回', '复'],
  3. ['我', '想', '上', 'q', 'q', '了'],
  4. ['你', '去', '过', '赌', '场', '吗'],
  5. ['是', '我', '是', '说', '你', '有', '几', '个', '兄', '弟', '姐', '妹', '不', '是', '你', '自', '己', '说'],
  6. ['广', '西', '新', '闻', '网']
  7. ]
  8. output_1 = [
  9. [0. 0. 1.]
  10. [1. 0. 0.]
  11. [1. 0. 0.]
  12. [0. 0. 1.]
  13. [1. 0. 0.]]
  14. output_2 = [
  15. [0. 1. 0.]
  16. [0. 0. 1.]
  17. [0. 0. 1.]
  18. [1. 0. 0.]
  19. [0. 0. 1.]]

Then you need to create a customized processor inhered from the ClassificationProcessor.

  1. import kashgari
  2. import numpy as np
  3. from typing import Tuple, List, Optional, Dict, Any
  4. from kashgari.processors.classification_processor import ClassificationProcessor
  5. class MultiOutputProcessor(ClassificationProcessor):
  6. def process_y_dataset(self,
  7. data: Tuple[List[List[str]], ...],
  8. maxlens: Optional[Tuple[int, ...]] = None,
  9. subset: Optional[List[int]] = None) -> Tuple[np.ndarray, ...]:
  10. # Data already converted to one-hot
  11. # Only need to get the subset
  12. result = []
  13. for index, dataset in enumerate(data):
  14. if subset is not None:
  15. target = kashgari.utils.get_list_subset(dataset, subset)
  16. else:
  17. target = dataset
  18. result.append(np.array(target))
  19. if len(result) == 1:
  20. return result[0]
  21. else:
  22. return tuple(result)

Then build your own model inhered from the BaseClassificationModel

  1. import kashgari
  2. import tensorflow as tf
  3. from typing import Tuple, List, Optional, Dict, Any
  4. from kashgari.layers import L
  5. from kashgari.tasks.classification.base_model import BaseClassificationModel
  6. class MultiOutputModel(BaseClassificationModel):
  7. @classmethod
  8. def get_default_hyper_parameters(cls) -> Dict[str, Dict[str, Any]]:
  9. return {
  10. 'layer_bi_lstm': {
  11. 'units': 256,
  12. 'return_sequences': False
  13. }
  14. }
  15. # Build your own model
  16. def build_model_arc(self):
  17. config = self.hyper_parameters
  18. embed_model = self.embedding.embed_model
  19. layer_bi_lstm = L.Bidirectional(L.LSTM(**config['layer_bi_lstm']), name='layer_bi_lstm')
  20. layer_output_1 = L.Dense(3, activation='sigmoid', name='layer_output_1')
  21. layer_output_2 = L.Dense(3, activation='sigmoid', name='layer_output_2')
  22. tensor = layer_bi_lstm(embed_model.output)
  23. output_tensor_1 = layer_output_1(tensor)
  24. output_tensor_2 = layer_output_2(tensor)
  25. self.tf_model = tf.keras.Model(embed_model.inputs, [output_tensor_1, output_tensor_2])
  26. # Rewrite your predict function
  27. def predict(self,
  28. x_data,
  29. batch_size=None,
  30. debug_info=False,
  31. threshold=0.5):
  32. tensor = self.embedding.process_x_dataset(x_data)
  33. pred = self.tf_model.predict(tensor, batch_size=batch_size)
  34. output_1 = pred[0]
  35. output_2 = pred[1]
  36. output_1[output_1 >= threshold] = 1
  37. output_1[output_1 < threshold] = 0
  38. output_2[output_2 >= threshold] = 1
  39. output_2[output_2 < threshold] = 0
  40. return output_1, output_2

Tada, all done, Now build your own model with customized processor

  1. from kashgari.embeddings import BareEmbedding
  2. # Use your processor to init embedding, You can use any embedding layer provided by kashgari here
  3. processor = MultiOutputProcessor()
  4. embedding = BareEmbedding(processor=processor)
  5. m = MultiOutputModel(embedding=embedding)
  6. m.build_model(train_x, (output_1, output_2))
  7. m.fit(train_x, (output_1, output_2))