test_unity_cpp.py 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. import ggml
  2. import ctypes
  3. import torch
  4. import pytest
  5. import numpy as np
  6. import torch
  7. from typing import Any
  8. from pathlib import Path
  9. from typing import Iterator
  10. from ggml import NativeObj
  11. from ggml_convert import convert_model
  12. from seamless_communication.models.unity import load_unity_model
  13. Ctx = ggml.ggml_context_p
  14. UNITY_MODELS = Path(__file__).parent / "examples/unity/models"
  15. PARAMS_16MB = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None)
  16. @pytest.fixture(name="ctx")
  17. def _ctx() -> Iterator[Ctx]:
  18. """Allocate a new context with 16 MB of memory"""
  19. try:
  20. ctx = ggml.ggml_init(params=PARAMS_16MB)
  21. yield ctx
  22. finally:
  23. ggml.ggml_free(ctx)
  24. def test_ggml_bindings_work(ctx: Ctx) -> None:
  25. # Instantiate tensors
  26. x = ggml.ggml_new_tensor_1d(ctx, ggml.GGML_TYPE_F32, 1)
  27. a = ggml.ggml_new_tensor_1d(ctx, ggml.GGML_TYPE_F32, 1)
  28. b = ggml.ggml_new_tensor_1d(ctx, ggml.GGML_TYPE_F32, 1)
  29. # Use ggml operations to build a computational graph
  30. x2 = ggml.ggml_mul(ctx, x, x)
  31. f = ggml.ggml_add(ctx, ggml.ggml_mul(ctx, a, x2), b)
  32. gf = ggml.ggml_build_forward(f)
  33. # Set the input values
  34. ggml.ggml_set_f32(x, 2.0)
  35. ggml.ggml_set_f32(a, 3.0)
  36. ggml.ggml_set_f32(b, 4.0)
  37. # Compute the graph
  38. ggml.ggml_graph_compute_with_ctx(ctx, ctypes.pointer(gf), 1)
  39. # Get the output value
  40. output = ggml.ggml_get_f32_1d(f, 0)
  41. assert output == 16.0
  42. def test_shape_works(ctx: Ctx) -> None:
  43. a = ggml.ggml_new_tensor_1d(ctx, ggml.GGML_TYPE_F32, 10)
  44. assert ggml.shape(a) == (10,)
  45. b = ggml.ggml_new_tensor_2d(ctx, ggml.GGML_TYPE_F32, 11, 21)
  46. assert ggml.shape(b) == (11, 21)
  47. c = ggml.ggml_new_tensor_3d(ctx, ggml.GGML_TYPE_F32, 12, 22, 32)
  48. assert ggml.shape(c) == (12, 22, 32)
  49. @pytest.mark.xfail(
  50. reason="TODO: understand diff between ggml strides and numpy strides"
  51. )
  52. def test_strides_works(ctx: Ctx) -> None:
  53. a = ggml.ggml_new_tensor_1d(ctx, ggml.GGML_TYPE_F32, 10)
  54. assert ggml.strides(a) == np.ones((10,), dtype=np.float32).strides
  55. b = ggml.ggml_new_tensor_2d(ctx, ggml.GGML_TYPE_F32, 11, 21)
  56. assert ggml.strides(b) == np.ones((11, 21), dtype=np.float32).strides
  57. c = ggml.ggml_new_tensor_3d(ctx, ggml.GGML_TYPE_F32, 12, 22, 32)
  58. assert ggml.strides(c) == np.ones((12, 22, 32), dtype=np.float32).strides
  59. def test_to_numpy_works_with_f32(ctx: Ctx) -> None:
  60. a = ggml.ggml_new_tensor_1d(ctx, ggml.GGML_TYPE_F32, 10)
  61. a = ggml.ggml_set_f32(a, 2.14)
  62. assert np.allclose(ggml.to_numpy(a), np.ones((10,)) * 2.14)
  63. b = ggml.ggml_new_tensor_2d(ctx, ggml.GGML_TYPE_F32, 11, 21)
  64. assert np.allclose(ggml.to_numpy(b), np.zeros((11, 21)))
  65. c = ggml.ggml_new_tensor_3d(ctx, ggml.GGML_TYPE_F32, 12, 22, 32)
  66. assert np.allclose(ggml.to_numpy(c), np.zeros((12, 22, 32)))
  67. def test_from_numpy_works_with_f32(ctx: Ctx) -> None:
  68. a = np.random.normal(size=(10,)).astype(dtype=np.float32)
  69. ga = ggml.from_numpy(ctx, a)
  70. assert np.allclose(a, ggml.to_numpy(ga))
  71. a = np.random.normal(size=(11, 21)).astype(dtype=np.float32)
  72. ga = ggml.from_numpy(ctx, a)
  73. assert np.allclose(a, ggml.to_numpy(ga))
  74. a = np.random.normal(size=(12, 22, 32)).astype(dtype=np.float32)
  75. ga = ggml.from_numpy(ctx, a)
  76. assert np.allclose(a, ggml.to_numpy(ga))
  77. def test_to_numpy_works_with_f16(ctx: Ctx) -> None:
  78. # We explicitly fill the tensor otherwise they might have non-zero values in them.
  79. a = ggml.ggml_new_tensor_1d(ctx, ggml.GGML_TYPE_F16, 10)
  80. a = ggml.ggml_set_f32(a, 2.14)
  81. assert np.allclose(ggml.to_numpy(a), np.ones((10,), dtype=np.float16) * 2.14)
  82. b = ggml.ggml_new_tensor_2d(ctx, ggml.GGML_TYPE_F16, 11, 21)
  83. b = ggml.ggml_set_f32(b, 4.18)
  84. assert np.allclose(ggml.to_numpy(b), np.ones((11, 21), dtype=np.float16) * 4.18)
  85. c = ggml.ggml_new_tensor_3d(ctx, ggml.GGML_TYPE_F16, 12, 22, 32)
  86. c = ggml.ggml_set_f32(c, 3.16)
  87. assert np.allclose(ggml.to_numpy(c), np.ones((12, 22, 32), dtype=np.float16) * 3.16)
  88. def test_from_numpy_works_with_f16(ctx: Ctx) -> None:
  89. a = np.random.normal(size=(10,)).astype(dtype=np.float16)
  90. ga = ggml.from_numpy(ctx, a)
  91. assert np.allclose(a, ggml.to_numpy(ga))
  92. a = np.random.normal(size=(11, 21)).astype(dtype=np.float16)
  93. ga = ggml.from_numpy(ctx, a)
  94. assert np.allclose(a, ggml.to_numpy(ga))
  95. a = np.random.normal(size=(12, 22, 32)).astype(dtype=np.float16)
  96. ga = ggml.from_numpy(ctx, a)
  97. assert np.allclose(a, ggml.to_numpy(ga))
  98. def test_ning_model_load(ctx: Ctx) -> None:
  99. model, vocab = ggml.unity_model_load(UNITY_MODELS / "unity-large/ggml-model.bin")
  100. print(model, vocab)
  101. example = ggml.from_file(
  102. ctx, UNITY_MODELS / "unity-large/seqs_before_conformer_block.bin", (1024, 137)
  103. )
  104. with ggml.MeasureArena() as arena:
  105. graph = ggml.unity_audio_encoder_graph(model, example)
  106. # TODO: why the extra memory ?
  107. mem_size = ggml.ggml_allocr_alloc_graph(arena, graph) + ggml.GGML_MEM_ALIGN
  108. with ggml.FixedSizeArena(mem_size) as allocr:
  109. print(
  110. f"unity_audio_encoder_graph: compute buffer size: {mem_size/1024/1024} MB"
  111. )
  112. eval_res_ptr = ggml.unity_eval(allocr, model, example, 1)
  113. eval_res = eval_res_ptr.contents
  114. inpL = ggml.to_numpy(eval_res.nodes[eval_res.n_nodes - 1])
  115. expected_raw = "-0.1308,0.0346,-0.2656,0.2873,-0.0104,0.0574,0.4033,-0.1125,-0.0460,-0.0496"
  116. expected = map(float, expected_raw.split(","))
  117. assert np.allclose(inpL[0, :10], list(expected), atol=1e-4)
  118. @pytest.fixture(scope="module")
  119. def g_model() -> NativeObj:
  120. model_file = Path(__file__).parent / "seamlessM4T_medium.ggml"
  121. if not model_file.exists():
  122. convert_model("seamlessM4T_medium", model_file)
  123. return ggml.load_unity_ggml_file(model_file)
  124. @pytest.fixture(scope="module")
  125. def pt_model() -> Iterator[Any]:
  126. model = load_unity_model("seamlessM4T_medium")
  127. model.eval()
  128. with torch.inference_mode():
  129. yield model
  130. @pytest.mark.xfail(reason="TODO")
  131. def test_hparams_code_is_up_to_date() -> None:
  132. model_file = Path(__file__).parent / "seamlessM4T_medium.ggml"
  133. hparams_header_file = model_file.with_suffix(".hparams.h")
  134. hparams_struct = hparams_header_file.read_text().strip()
  135. actual_code = (UNITY_MODELS.parent / "unity_model_loader.h").read_text()
  136. assert hparams_struct in actual_code
  137. def test_unity_ffn(ctx: Ctx, g_model: NativeObj, pt_model: Any) -> None:
  138. x = torch.empty((1024,))
  139. torch.nn.init.uniform_(x, -1, 1)
  140. # Test FFN without LayerNorm
  141. y_exp = pt_model.text_encoder.layers[0].ffn(x).numpy()
  142. gx = ggml.from_numpy(ctx, x)
  143. gy = ggml.forward(
  144. "StandardFeedForwardNetwork", g_model, "text_encoder.layers.0.ffn", gx
  145. )
  146. gf = ggml.ggml_build_forward(gy)
  147. ggml.ggml_graph_compute_with_ctx(ctx, ctypes.pointer(gf), 1)
  148. y = ggml.to_numpy(gf.nodes[gf.n_nodes - 1]).reshape(-1)
  149. abs_diff = np.max(np.abs(y - y_exp))
  150. assert abs_diff < 1e-2
  151. assert np.allclose(y_exp, y, rtol=1e-3)
  152. def test_unity_layer_norm(ctx: Ctx, g_model: NativeObj, pt_model: Any) -> None:
  153. x = torch.empty((1024,))
  154. torch.nn.init.uniform_(x, -1, 1)
  155. y_exp = pt_model.text_encoder.layers[0].ffn_layer_norm(x).numpy()
  156. gx = ggml.from_numpy(ctx, x)
  157. gy = ggml.forward(
  158. "LayerNorm", g_model, "text_encoder.layers.0.ffn_layer_norm", gx
  159. )
  160. gf = ggml.ggml_build_forward(gy)
  161. ggml.ggml_graph_compute_with_ctx(ctx, ctypes.pointer(gf), 1)
  162. y = ggml.to_numpy(gf.nodes[gf.n_nodes - 1]).reshape(-1)
  163. abs_diff = np.max(np.abs(y - y_exp))
  164. assert np.allclose(y_exp, y)