1
0

test_metadata.py 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. #!/usr/bin/env python3
  2. import unittest
  3. from pathlib import Path
  4. import os
  5. import sys
  6. # Necessary to load the local gguf package
  7. if "NO_LOCAL_GGUF" not in os.environ and (Path(__file__).parent.parent.parent / 'gguf-py').exists():
  8. sys.path.insert(0, str(Path(__file__).parent.parent))
  9. import gguf
  10. class TestMetadataMethod(unittest.TestCase):
  11. def test_id_to_title(self):
  12. self.assertEqual(gguf.Metadata.id_to_title("Mixtral-8x7B-Instruct-v0.1"), "Mixtral 8x7B Instruct v0.1")
  13. self.assertEqual(gguf.Metadata.id_to_title("Meta-Llama-3-8B"), "Meta Llama 3 8B")
  14. self.assertEqual(gguf.Metadata.id_to_title("hermes-2-pro-llama-3-8b-DPO"), "Hermes 2 Pro Llama 3 8b DPO")
  15. def test_get_model_id_components(self):
  16. # This is the basic standard form with organization marker
  17. self.assertEqual(gguf.Metadata.get_model_id_components("Mistral/Mixtral-8x7B-Instruct-v0.1"),
  18. ('Mixtral-8x7B-Instruct-v0.1', "Mistral", 'Mixtral', 'Instruct', 'v0.1', '8x7B'))
  19. # Similar to basic standard form but without organization marker
  20. self.assertEqual(gguf.Metadata.get_model_id_components("Mixtral-8x7B-Instruct-v0.1"),
  21. ('Mixtral-8x7B-Instruct-v0.1', None, 'Mixtral', 'Instruct', 'v0.1', '8x7B'))
  22. # Missing version
  23. self.assertEqual(gguf.Metadata.get_model_id_components("Mixtral-8x7B-Instruct"),
  24. ('Mixtral-8x7B-Instruct', None, 'Mixtral', 'Instruct', None, '8x7B'))
  25. # Missing finetune
  26. self.assertEqual(gguf.Metadata.get_model_id_components("Mixtral-8x7B-v0.1"),
  27. ('Mixtral-8x7B-v0.1', None, 'Mixtral', None, 'v0.1', '8x7B'))
  28. # Base name and size label only
  29. self.assertEqual(gguf.Metadata.get_model_id_components("Mixtral-8x7B"),
  30. ('Mixtral-8x7B', None, 'Mixtral', None, None, '8x7B'))
  31. # Base name and version only
  32. self.assertEqual(gguf.Metadata.get_model_id_components("Mixtral-v0.1"),
  33. ('Mixtral-v0.1', None, 'Mixtral', None, 'v0.1', None))
  34. ## Edge Cases ##
  35. # This is too ambiguous... best to err on caution and output nothing
  36. self.assertEqual(gguf.Metadata.get_model_id_components("Mixtral"),
  37. ('Mixtral', None, None, None, None, None))
  38. # Basename has numbers mixed in and also size label provided. Must avoid capturing number in basename
  39. self.assertEqual(gguf.Metadata.get_model_id_components("NousResearch/Meta-Llama-3-8B"),
  40. ('Meta-Llama-3-8B', "NousResearch", 'Meta-Llama-3', None, None, '8B'))
  41. # Can't detect all non standard form in a heuristically safe way... best to err in caution and output nothing...
  42. self.assertEqual(gguf.Metadata.get_model_id_components("Qwen1.5-MoE-A2.7B-Chat"),
  43. ('Qwen1.5-MoE-A2.7B-Chat', None, 'Qwen1.5-MoE', 'Chat', None, 'A2.7B'))
  44. # Capture 'sub size labels' e.g. A14B in '57B-A14B' usually refers to activated params/weight count
  45. self.assertEqual(gguf.Metadata.get_model_id_components("Qwen2-57B-A14B-Instruct"),
  46. ('Qwen2-57B-A14B-Instruct', None, 'Qwen2', 'Instruct', None, '57B-A14B'))
  47. # Check that it can handle a real model id with no version code
  48. # Note that 4k in this string is non standard and microsoft were referring to context length rather than weight count
  49. self.assertEqual(gguf.Metadata.get_model_id_components("microsoft/Phi-3-mini-4k-instruct", 4 * 10**9),
  50. ('Phi-3-mini-4k-instruct', 'microsoft', 'Phi-3', '4k-instruct', None, 'mini'))
  51. # There is some legitimate models with only thousands of parameters
  52. self.assertEqual(gguf.Metadata.get_model_id_components("delphi-suite/stories-llama2-50k", 50 * 10**3),
  53. ('stories-llama2-50k', 'delphi-suite', 'stories-llama2', None, None, '50K'))
  54. # None standard and not easy to disambiguate
  55. self.assertEqual(gguf.Metadata.get_model_id_components("DeepSeek-Coder-V2-Lite-Instruct"),
  56. ('DeepSeek-Coder-V2-Lite-Instruct', None, 'DeepSeek-Coder-V2-Lite', 'Instruct', None, None))
  57. # This is a real model_id where they append 2DPO to refer to Direct Preference Optimization
  58. self.assertEqual(gguf.Metadata.get_model_id_components("crestf411/daybreak-kunoichi-2dpo-7b"),
  59. ('daybreak-kunoichi-2dpo-7b', 'crestf411', 'daybreak-kunoichi', '2dpo', None, '7B'))
  60. # This is a real model id where the weight size has a decimal point
  61. self.assertEqual(gguf.Metadata.get_model_id_components("Qwen2-0.5B-Instruct"),
  62. ('Qwen2-0.5B-Instruct', None, 'Qwen2', 'Instruct', None, '0.5B'))
  63. # Uses an underscore in the size label
  64. self.assertEqual(gguf.Metadata.get_model_id_components("smallcloudai/Refact-1_6B-fim"),
  65. ('Refact-1_6B-fim', 'smallcloudai', 'Refact', 'fim', None, '1.6B'))
  66. # Uses Iter3 for the version
  67. self.assertEqual(gguf.Metadata.get_model_id_components("UCLA-AGI/Gemma-2-9B-It-SPPO-Iter3"),
  68. ('Gemma-2-9B-It-SPPO-Iter3', 'UCLA-AGI', 'Gemma-2', 'It-SPPO', 'Iter3', '9B'))
  69. # Has two potential versions in the basename
  70. self.assertEqual(gguf.Metadata.get_model_id_components("NousResearch/Hermes-2-Theta-Llama-3-8B"),
  71. ('Hermes-2-Theta-Llama-3-8B', 'NousResearch', 'Hermes-2-Theta-Llama-3', None, None, '8B'))
  72. # Potential version in the basename
  73. self.assertEqual(gguf.Metadata.get_model_id_components("SeaLLMs/SeaLLMs-v3-7B-Chat"),
  74. ('SeaLLMs-v3-7B-Chat', 'SeaLLMs', 'SeaLLMs-v3', 'Chat', None, '7B'))
  75. # Underscore in the basename, and 1m for the context size
  76. self.assertEqual(gguf.Metadata.get_model_id_components("internlm/internlm2_5-7b-chat-1m", 7 * 10**9),
  77. ('internlm2_5-7b-chat-1m', 'internlm', 'internlm2_5', 'chat-1m', None, '7B'))
  78. # Version before the finetune name
  79. self.assertEqual(gguf.Metadata.get_model_id_components("pszemraj/jamba-900M-v0.13-KIx2"),
  80. ('jamba-900M-v0.13-KIx2', 'pszemraj', 'jamba', 'KIx2', 'v0.13', '900M'))
  81. # TODO: hf suffix which could be ignored but isn't
  82. self.assertEqual(gguf.Metadata.get_model_id_components("state-spaces/mamba-2.8b-hf"),
  83. ('mamba-2.8b-hf', 'state-spaces', 'mamba', 'hf', None, '2.8B'))
  84. # Two sizes, don't merge them, the other is the number of tokens on which it was trained
  85. self.assertEqual(gguf.Metadata.get_model_id_components("abacaj/llama-161M-100B", 161 * 10**6),
  86. ('llama-161M-100B', 'abacaj', 'llama', '100b', None, '161M'))
  87. # It's a trap, there is no size label
  88. self.assertEqual(gguf.Metadata.get_model_id_components("SparseLLM/relu-100B", 1340 * 10**6),
  89. ('relu-100B', 'SparseLLM', 'relu', '100b', None, None))
  90. # Weird size notation
  91. self.assertEqual(gguf.Metadata.get_model_id_components("bigscience/bloom-7b1-petals"),
  92. ('bloom-7b1-petals', 'bigscience', 'bloom', 'petals', None, '7.1B'))
  93. def test_apply_metadata_heuristic_from_model_card(self):
  94. model_card = {
  95. 'tags': ['Llama-3', 'instruct', 'finetune', 'chatml', 'DPO', 'RLHF', 'gpt4', 'synthetic data', 'distillation', 'function calling', 'json mode', 'axolotl'],
  96. 'model-index': [{'name': 'Mixtral-8x7B-Instruct-v0.1', 'results': []}],
  97. 'language': ['en'],
  98. 'datasets': ['teknium/OpenHermes-2.5'],
  99. 'widget': [{'example_title': 'Hermes 2 Pro', 'messages': [{'role': 'system', 'content': 'You are a sentient, superintelligent artificial general intelligence, here to teach and assist me.'}, {'role': 'user', 'content': 'Write a short story about Goku discovering kirby has teamed up with Majin Buu to destroy the world.'}]}],
  100. 'base_model': ["EmbeddedLLM/Mistral-7B-Merge-14-v0", "janai-hq/trinity-v1"]
  101. }
  102. got = gguf.Metadata.apply_metadata_heuristic(gguf.Metadata(), model_card, None, None)
  103. expect = gguf.Metadata()
  104. expect.base_models=[{'name': 'Mistral 7B Merge 14 v0', 'organization': 'EmbeddedLLM', 'version': 'v0', 'repo_url': 'https://huggingface.co/EmbeddedLLM/Mistral-7B-Merge-14-v0'}, {'name': 'Trinity v1', 'organization': 'Janai Hq', 'version': 'v1', 'repo_url': 'https://huggingface.co/janai-hq/trinity-v1'}]
  105. expect.tags=['Llama-3', 'instruct', 'finetune', 'chatml', 'DPO', 'RLHF', 'gpt4', 'synthetic data', 'distillation', 'function calling', 'json mode', 'axolotl']
  106. expect.languages=['en']
  107. expect.datasets=['teknium/OpenHermes-2.5']
  108. self.assertEqual(got, expect)
  109. def test_apply_metadata_heuristic_from_hf_parameters(self):
  110. hf_params = {"_name_or_path": "./hermes-2-pro-llama-3-8b-DPO"}
  111. got = gguf.Metadata.apply_metadata_heuristic(gguf.Metadata(), model_card=None, hf_params=hf_params, model_path=None)
  112. expect = gguf.Metadata(name='Hermes 2 Pro Llama 3 8b DPO', finetune='DPO', basename='hermes-2-pro-llama-3', size_label='8B')
  113. self.assertEqual(got, expect)
  114. def test_apply_metadata_heuristic_from_model_dir(self):
  115. model_dir_path = Path("./hermes-2-pro-llama-3-8b-DPO")
  116. got = gguf.Metadata.apply_metadata_heuristic(gguf.Metadata(), model_card=None, hf_params=None, model_path=model_dir_path)
  117. expect = gguf.Metadata(name='Hermes 2 Pro Llama 3 8b DPO', finetune='DPO', basename='hermes-2-pro-llama-3', size_label='8B')
  118. self.assertEqual(got, expect)
  119. if __name__ == "__main__":
  120. unittest.main()