1
+# SPDX-License-Identifier: Apache-2.0
2
+"""Utilities for selecting and loading Neuron models in
3
+neuronx-distributed-inference framework."""
4
+# Disabling yapf because yapf and isort have conflicts for the below imports
5
+# yapf: disable
6
+import copy
7
+import hashlib
8
+import importlib
9
+import multiprocessing
10
+import os
11
+import shutil
12
+from typing import Dict, List, Optional, Tuple
13
+
14
+import torch
15
+import torch.nn as nn
16
+from neuronx_distributed_inference.models.config import (
17
+ FusedSpecNeuronConfig, OnDeviceSamplingConfig)
18
+from neuronx_distributed_inference.models.mllama.utils import (
19
+ create_vision_mask)
20
+from neuronx_distributed_inference.utils.hf_adapter import (
21
+ load_pretrained_config)
22
+from transformers import AutoModelForCausalLM, AutoTokenizer, PretrainedConfig
23
+
24
+from vllm.config import (ModelConfig, ParallelConfig, SchedulerConfig,
25
+ SpeculativeConfig)
26
+from vllm.logger import init_logger
27
+from vllm.model_executor.layers.logits_processor import LogitsProcessor
28
+from vllm.model_executor.layers.sampler import Sampler, SamplerOutput
29
+from vllm.model_executor.sampling_metadata import SamplingMetadata
30
+from vllm.sequence import (CompletionSequenceGroupOutput, Logprob,
31
+ SequenceOutput)
32
+
33
+# yapf: enable
34
+logger = init_logger(__name__)
35
+
36
+TORCH_DTYPE_TO_NEURON_AMP = {
37
+ "auto": "float32",
38
+ "half": "float16",
39
+ "float16": "float16",
40
+ "bfloat16": "bfloat16",
41
+ "float": "float32",
42
+ "float32": "float32",
43
+ torch.float16: "float16",
44
+ torch.bfloat16: "bfloat16",
45
+ torch.float32: "float32",
46
+}
47
+
48
+# Models supported by Neuronx distributed for inference.
49
+_NEURON_SUPPORTED_MODELS: Dict[str, Tuple[str, str]] = {
50
+ "LlamaForCausalLM":
51
+ ("neuronx_distributed_inference.models.llama.modeling_llama",
52
+ "NeuronLlamaForCausalLM"),
53
+ "DbrxForCausalLM":
54
+ ("neuronx_distributed_inference.models.dbrx.modeling_dbrx",
55
+ "NeuronDbrxForCausalLM"),
56
+ "MixtralForCausalLM":
57
+ ("neuronx_distributed_inference.models.mixtral.modeling_mixtral",
58
+ "NeuronMixtralForCausalLM"),
59
+ "MllamaForConditionalGeneration":
60
+ ("neuronx_distributed_inference.models.mllama.modeling_mllama",
61
+ "NeuronMllamaForCausalLM"),
62
+}
63
+
64
+
65
+class NeuronCausalLM(nn.Module):
66
+
67
+ def __init__(
68
+ self,
69
+ config: PretrainedConfig,
70
+ ) -> None:
71
+ super().__init__()
72
+ self.config = config
73
+ self.logits_processor = LogitsProcessor(config.vocab_size,
74
+ logits_as_input=True)
75
+ self.sampler = Sampler()
76
+
77
+ # Lazy initialized
78
+ self.model: nn.Module
79
+
80
+ def forward(
81
+ self,
82
+ input_ids: torch.Tensor,
83
+ positions: torch.Tensor,
84
+ input_block_ids: torch.Tensor,
85
+ sampling_params: torch.Tensor,
86
+ ) -> torch.Tensor:
87
+ output = self.model(input_ids,
88
+ attention_mask=None,
89
+ position_ids=positions,
90
+ seq_ids=input_block_ids,
91
+ sampling_params=sampling_params)
92
+ # on-device sampling
93
+ if self.config.neuron_config.on_device_sampling_config:
94
+ return output.hidden_states
95
+ else:
96
+ return output.logits[:, -1, :]
97
+
98
+ def compute_logits(self, hidden_states: torch.Tensor,
99
+ sampling_metadata: SamplingMetadata) -> torch.Tensor:
100
+ logits = self.logits_processor(None, hidden_states, sampling_metadata)
101
+ return logits
102
+
103
+ def sample(
104
+ self,
105
+ logits: torch.Tensor,
106
+ sampling_metadata: SamplingMetadata,
107
+ ) -> Optional[SamplerOutput]:
108
+ # on-device sampling
109
+ if self.config.neuron_config.on_device_sampling_config:
110
+ batch_size = logits.shape
111
+ seq_ids = [
112
+ seq_id for sg in sampling_metadata.seq_groups
113
+ for seq_id in sg.seq_ids
114
+ ]
115
+ assert len(seq_ids) == list(batch_size)[0], "batch size mismatch"
116
+ # Organize input tensors by step instead of by sequence.
117
+ accepted_token_ids_by_step = logits.flatten()
118
+ accepted_token_ids_by_step = accepted_token_ids_by_step.tolist()
119
+
120
+ step_output_token_ids = []
121
+ for i, seq_id in enumerate(seq_ids):
122
+ token_id = accepted_token_ids_by_step[i]
123
+ step_output_token_ids.append(
124
+ CompletionSequenceGroupOutput(samples=[
125
+ SequenceOutput(parent_seq_id=seq_id,
126
+ output_token=token_id,
127
+ logprobs={token_id: Logprob(token_id)})
128
+ ],
129
+ prompt_logprobs=None))
130
+ return SamplerOutput(outputs=step_output_token_ids)
131
+ else:
132
+ return self.sampler(logits, sampling_metadata)
133
+
134
+ def load_weights(self, model_name_or_path: str, **kwargs):
135
+ arch = _get_model_architecture(self.config)
136
+ neuronx_module_path, neuronx_model_cls_name = (
137
+ _NEURON_SUPPORTED_MODELS[arch])
138
+ neuronx_module = importlib.import_module(neuronx_module_path)
139
+ neuronx_model_cls = getattr(neuronx_module, neuronx_model_cls_name)
140
+ neuron_config = neuronx_model_cls.get_neuron_config_cls()(
141
+ **kwargs['neuron_config'])
142
+ self.config.neuron_config = neuron_config
143
+ config = neuronx_model_cls.get_config_cls()(
144
+ neuron_config,
145
+ load_config=load_pretrained_config(model_name_or_path))
146
+ hashed_config = hashlib.md5(
147
+ config.to_json_string().encode('utf-8')).hexdigest()
148
+ if os.getenv("NEURON_COMPILED_ARTIFACTS") is not None:
149
+ compiled_model_path = os.getenv("NEURON_COMPILED_ARTIFACTS")
150
+ elif os.path.exists(model_name_or_path):
151
+ compiled_model_path = os.path.join(model_name_or_path,
152
+ "neuron-compiled-artifacts",
153
+ hashed_config)
154
+ shutil.rmtree(compiled_model_path, ignore_errors=True)
155
+ else:
156
+ compiled_model_path = os.path.join("local-models",
157
+ model_name_or_path,
158
+ "neuron-compiled-artifacts",
159
+ hashed_config)
160
+ shutil.rmtree(compiled_model_path, ignore_errors=True)
161
+ try:
162
+ self.model = neuronx_model_cls(compiled_model_path)
163
+ override_neuron_config = kwargs["override_neuron_config"]
164
+ for k, v in override_neuron_config.items():
165
+ setattr(self.model.config.neuron_config, k, v)
166
+ self.model.load(compiled_model_path)
167
+ return
168
+ except (FileNotFoundError, ValueError) as e:
169
+ logger.warning("Exception: %s", e)
170
+ logger.warning("Failed to load the model from %s, Recompiling...",
171
+ compiled_model_path)
172
+ if not os.path.exists(model_name_or_path):
173
+ hf_model = AutoModelForCausalLM.from_pretrained(model_name_or_path)
174
+ saved_path = os.path.join("local-models", model_name_or_path)
175
+ hf_model.save_pretrained(saved_path)
176
+ model_name_or_path = saved_path
177
+ self.model = neuronx_model_cls(model_name_or_path, config)
178
+ self.model.compile(compiled_model_path)
179
+ self.model.load(compiled_model_path)
180
+
181
+
182
+class NeuronMllamaForCausalLM(nn.Module):
183
+
184
+ def __init__(self,
185
+ config: PretrainedConfig,
186
+ on_device_sampling_disabled: bool = False) -> None:
187
+ super().__init__()
188
+ self.config = config
189
+ self.logits_processor = LogitsProcessor(
190
+ config.get_text_config().vocab_size, logits_as_input=True)
191
+
192
+ self.on_device_sampling_disabled = on_device_sampling_disabled
193
+ if self.on_device_sampling_disabled:
194
+ # Use default sampler
195
+ self.sampler = Sampler()
196
+
197
+ # Lazy initialized
198
+ self.model: nn.Module
199
+
200
+ def forward(self, input_ids: torch.Tensor, positions: torch.Tensor,
201
+ seq_ids: torch.Tensor, pixel_values: torch.Tensor,
202
+ aspect_ratios: torch.Tensor, num_chunks: torch.Tensor,
203
+ has_image: torch.Tensor, sampling_params) -> torch.Tensor:
204
+ self.vision_mask = create_vision_mask(input_ids, self.vision_token_id)
205
+ output = self.model(
206
+ input_ids.to(torch.int32),
207
+ attention_mask=None,
208
+ position_ids=positions.to(torch.int32),
209
+ seq_ids=seq_ids.flatten().to(torch.int32),
210
+ pixel_values=pixel_values.to(
211
+ self.config.vision_config.torch_dtype),
212
+ aspect_ratios=aspect_ratios.to(torch.int32),
213
+ vision_mask=self.vision_mask.to(torch.int32),
214
+ sampling_params=sampling_params,
215
+ num_chunks=num_chunks.to(torch.int32),
216
+ has_image=has_image.to(torch.int32),
217
+ )
218
+ if self.config.neuron_config.on_device_sampling_config:
219
+ return output.hidden_states
220
+ return output.logits[:, -1, :]
221
+
222
+ def compute_logits(self, hidden_states: torch.Tensor,
223
+ sampling_metadata: SamplingMetadata) -> torch.Tensor:
224
+ logits = self.logits_processor(None, hidden_states, sampling_metadata)
225
+ return logits
226
+
227
+ def sample(self, hidden_states, sampling_metadata):
228
+ if not self.on_device_sampling_disabled:
229
+ with torch.profiler.record_function("sample"):
230
+ hidden_states = hidden_states.flatten()
231
+ res = []
232
+ sample_idx = 0
233
+ for seq_group in sampling_metadata.seq_groups:
234
+ seq_ids = seq_group.seq_ids
235
+ samples = []
236
+ for seq_id in seq_ids:
237
+ token_id = hidden_states[sample_idx].item()
238
+ samples.append(
239
+ SequenceOutput(
240
+ parent_seq_id=seq_id,
241
+ output_token=token_id,
242
+ logprobs={token_id: Logprob(token_id)}))
243
+ sample_idx += 1
244
+ res.append(
245
+ CompletionSequenceGroupOutput(samples=samples,
246
+ prompt_logprobs=None))
247
+ next_tokens = SamplerOutput(outputs=res)
248
+ else:
249
+ next_tokens = self.sampler(None, hidden_states, sampling_metadata)
250
+ return next_tokens
251
+
252
+ def load_weights(self, model_name_or_path: str, **kwargs):
253
+ arch = _get_model_architecture(self.config)
254
+ neuronx_module_path, neuronx_model_cls_name = (
255
+ _NEURON_SUPPORTED_MODELS[arch])
256
+ neuronx_module = importlib.import_module(neuronx_module_path)
257
+ neuronx_model_cls = getattr(neuronx_module, neuronx_model_cls_name)
258
+ neuron_config = neuronx_model_cls.get_neuron_config_cls()(
259
+ **kwargs['neuron_config'])
260
+ self.config.neuron_config = neuron_config
261
+ logger.info("neuron_config buckets: %s",
262
+ self.config.neuron_config.buckets)
263
+ config = neuronx_model_cls.get_config_cls()(
264
+ neuron_config,
265
+ load_config=load_pretrained_config(model_name_or_path))
266
+ hashed_config = hashlib.md5(
267
+ config.to_json_string().encode('utf-8')).hexdigest()
268
+ if os.getenv("NEURON_COMPILED_ARTIFACTS") is not None:
269
+ compiled_model_path = os.getenv("NEURON_COMPILED_ARTIFACTS")
270
+ elif os.path.exists(model_name_or_path):
271
+ compiled_model_path = os.path.join(model_name_or_path,
272
+ "neuron-compiled-artifacts",
273
+ hashed_config)
274
+ else:
275
+ compiled_model_path = os.path.join("local-models",
276
+ model_name_or_path,
277
+ "neuron-compiled-artifacts",
278
+ hashed_config)
279
+ try:
280
+ self.model = neuronx_model_cls(compiled_model_path)
281
+ tokenizer = AutoTokenizer.from_pretrained(model_name_or_path)
282
+ self.vision_token_id = tokenizer(
283
+ "<|image|>", add_special_tokens=False).input_ids
284
+ self.model.load(compiled_model_path)
285
+ return
286
+ except (FileNotFoundError, ValueError):
287
+ logger.warning("Failed to load the model from %s, Recompiling...",
288
+ compiled_model_path)
289
+ if not os.path.exists(model_name_or_path):
290
+ hf_model = AutoModelForCausalLM.from_pretrained(model_name_or_path)
291
+ saved_path = os.path.join("local-models", model_name_or_path)
292
+ hf_model.save_pretrained(saved_path)
293
+ model_name_or_path = saved_path
294
+ self.model = neuronx_model_cls(model_name_or_path, config)
295
+
296
+ logger.info("\nCompiling and saving model to %s", model_name_or_path)
297
+
298
+ p = multiprocessing.Process(target=compile_model,
299
+ args=(self, compiled_model_path))
300
+ p.start()
301
+ p.join()
302
+
303
+ tokenizer = AutoTokenizer.from_pretrained(model_name_or_path)
304
+ tokenizer.save_pretrained(compiled_model_path)
305
+ logger.info("Successfully compiled and saved the model in %s",
306
+ compiled_model_path)
307
+
308
+ # Read "<|image|>" token_id from the tokenizer
309
+ self.vision_token_id = tokenizer("<|image|>",
310
+ add_special_tokens=False).input_ids
311
+ logger.info("\nLoading model from compiled checkpoint...")
312
+ self.model.load(compiled_model_path)
313
+
314
+
315
+def compile_model(neuron_model, traced_model_path):
316
+ neuron_model.model.compile(traced_model_path)
317
+
318
+
319
+class NeuronSpeculationCausalLM(nn.Module):
320
+ """A Neuron-optimized causal language model with speculative decoding."""
321
+
322
+ def __init__(
323
+ self,
324
+ config: PretrainedConfig,
325
+ ) -> None:
326
+ super().__init__()
327
+ self.config = config
328
+ self.logits_processor = LogitsProcessor(config.vocab_size,
329
+ logits_as_input=True)
330
+ # Lazy initialized
331
+ self.model: nn.Module
332
+
333
+ def forward(
334
+ self,
335
+ input_ids: torch.Tensor,
336
+ positions: torch.Tensor,
337
+ input_block_ids: torch.Tensor,
338
+ sampling_params: torch.Tensor,
339
+ ) -> torch.Tensor:
340
+ output = self.model(input_ids,
341
+ attention_mask=None,
342
+ position_ids=positions,
343
+ seq_ids=input_block_ids,
344
+ sampling_params=sampling_params)
345
+ # CTX encoding
346
+ if (positions[:, 0]).sum().item() == 0:
347
+ return output.fused_outputs[0][:, 0:1]
348
+
349
+ # Fused Spec (Generation)
350
+ accepted_tokens_with_padding = output.fused_outputs[0]
351
+ next_pos_ids = output.fused_outputs[-1]
352
+ generated_token_counts = next_pos_ids - positions
353
+
354
+ assert torch.any(generated_token_counts == 0).item() is False, \
355
+ "NxDI model generated no output for one or more sequences."
356
+
357
+ batch_size, steps = accepted_tokens_with_padding.shape
358
+ mask = torch.arange(steps).expand(batch_size,
359
+ -1) >= generated_token_counts
360
+ accepted_tokens_with_padding[mask] = -1
361
+
362
+ return accepted_tokens_with_padding
363
+
364
+ def sample(
365
+ self,
366
+ logits: torch.Tensor,
367
+ sampling_metadata: SamplingMetadata,
368
+ ) -> Optional[List[SamplerOutput]]:
369
+ batch_size, num_steps = logits.shape
370
+ seq_ids = [
371
+ seq_id for sg in sampling_metadata.seq_groups
372
+ for seq_id in sg.seq_ids
373
+ ]
374
+ # Organize input tensors by step instead of by sequence.
375
+ accepted_token_ids_by_step = logits.transpose(0, 1)
376
+ accepted_token_ids_by_step = accepted_token_ids_by_step.tolist()
377
+
378
+ sampler_output_list = []
379
+ for step_index in range(num_steps):
380
+ if all(token_id == -1
381
+ for token_id in accepted_token_ids_by_step[step_index]):
382
+ break
383
+ step_output_token_ids = []
384
+ for sequence_index in range(batch_size):
385
+ token_id = accepted_token_ids_by_step[step_index][
386
+ sequence_index]
387
+ step_output_token_ids.append(
388
+ CompletionSequenceGroupOutput(samples=[
389
+ SequenceOutput(parent_seq_id=seq_ids[sequence_index],
390
+ output_token=token_id,
391
+ logprobs={token_id: Logprob(token_id)})
392
+ ],
393
+ prompt_logprobs=None))
394
+ sampler_output_list.append(
395
+ SamplerOutput(outputs=step_output_token_ids))
396
+ return sampler_output_list
397
+
398
+ def load_weights(self, model_name_or_path: str,
399
+ draft_model_name_or_path: str, **kwargs):
400
+ arch = _get_model_architecture(self.config)
401
+ neuronx_module_path, neuronx_model_cls_name = (
402
+ _NEURON_SUPPORTED_MODELS[arch])
403
+ neuronx_module = importlib.import_module(neuronx_module_path)
404
+ neuronx_model_cls = getattr(neuronx_module, neuronx_model_cls_name)
405
+ neuron_config = neuronx_model_cls.get_neuron_config_cls()(
406
+ **kwargs['neuron_config'])
407
+ config = neuronx_model_cls.get_config_cls()(
408
+ neuron_config,
409
+ load_config=load_pretrained_config(model_name_or_path))
410
+
411
+ draft_neuron_config = copy.deepcopy(config.neuron_config)
412
+ if not config.neuron_config.enable_eagle_speculation:
413
+ draft_neuron_config.speculation_length = 0
414
+ draft_neuron_config.trace_tokengen_model = True
415
+ draft_neuron_config.enable_fused_speculation = False
416
+ if config.neuron_config.enable_eagle_speculation:
417
+ draft_neuron_config.is_eagle_draft = True
418
+ draft_neuron_config.sequence_parallel_enabled = False
419
+ draft_config = neuronx_model_cls.get_config_cls()(
420
+ draft_neuron_config,
421
+ load_config=load_pretrained_config(draft_model_name_or_path))
422
+ fused_spec_config = (FusedSpecNeuronConfig(
423
+ neuronx_model_cls._model_cls,
424
+ draft_config=draft_config,
425
+ draft_model_path=draft_model_name_or_path))
426
+ config.fused_spec_config = fused_spec_config
427
+ self.config.neuron_config = neuron_config
428
+
429
+ hashed_config = hashlib.md5(
430
+ config.to_json_string().encode('utf-8')).hexdigest()
431
+ if os.getenv("NEURON_COMPILED_ARTIFACTS") is not None:
432
+ compiled_model_path = os.getenv("NEURON_COMPILED_ARTIFACTS")
433
+ elif os.path.exists(model_name_or_path):
434
+ compiled_model_path = os.path.join(model_name_or_path,
435
+ "neuron-compiled-artifacts",
436
+ hashed_config)
437
+ shutil.rmtree(compiled_model_path, ignore_errors=True)
438
+ else:
439
+ compiled_model_path = os.path.join("local-models",
440
+ model_name_or_path,
441
+ "neuron-compiled-artifacts",
442
+ hashed_config)
443
+ shutil.rmtree(compiled_model_path, ignore_errors=True)
444
+ try:
445
+ self.model = neuronx_model_cls(compiled_model_path)
446
+ override_neuron_config = kwargs["override_neuron_config"]
447
+ for k, v in override_neuron_config.items():
448
+ setattr(self.model.config.neuron_config, k, v)
449
+ self.model.load(compiled_model_path)
450
+ return
451
+ except (FileNotFoundError, ValueError) as e:
452
+ logger.warning("Exception: %s", e)
453
+ logger.warning("Failed to load the model from %s Recompiling...",
454
+ compiled_model_path)
455
+ if not os.path.exists(model_name_or_path):
456
+ hf_model = AutoModelForCausalLM.from_pretrained(model_name_or_path)
457
+ saved_path = os.path.join("local-models", model_name_or_path)
458
+ hf_model.save_pretrained(saved_path)
459
+ model_name_or_path = saved_path
460
+ if not os.path.exists(draft_model_name_or_path):
461
+ if draft_model_name_or_path != model_name_or_path:
462
+ hf_model = AutoModelForCausalLM.from_pretrained(
463
+ draft_model_name_or_path)
464
+ saved_path = os.path.join("local-models",
465
+ draft_model_name_or_path)
466
+ hf_model.save_pretrained(saved_path)
467
+ draft_model_name_or_path = saved_path
468
+ else:
469
+ draft_model_name_or_path = model_name_or_path
470
+ config.fused_spec_config.draft_model_path = draft_model_name_or_path
471
+ self.model = neuronx_model_cls(model_name_or_path, config)
472
+ self.model.compile(compiled_model_path)
473
+ self.model.load(compiled_model_path)
474
+
475
+
476
+def _get_model_architecture(config: PretrainedConfig) -> str:
477
+ architectures = getattr(config, "architectures", [])
478
+ for arch in architectures:
479
+ if arch in _NEURON_SUPPORTED_MODELS:
480
+ return arch
481
+ raise ValueError(
482
+ f"Model architectures {architectures} are not supported on Neuron "
483
+ f"for now. Supported architectures: "
484
+ f"{list(_NEURON_SUPPORTED_MODELS.keys())}")
485
+
486
+
487
+def _get_default_neuron_config(model_config: ModelConfig,
488
+ parallel_config: ParallelConfig,
489
+ scheduler_config: SchedulerConfig):
490
+ """Generate a neuron config based on vllm config args."""
491
+ on_device_sampling_config = OnDeviceSamplingConfig(dynamic=True,
492
+ deterministic=False)
493
+ batch_size = scheduler_config.max_num_seqs
494
+
495
+ neuron_config = dict(
496
+ tp_degree=parallel_config.tensor_parallel_size,
497
+ ctx_batch_size=1,
498
+ batch_size=batch_size,
499
+ max_context_length=scheduler_config.max_model_len,
500
+ seq_len=scheduler_config.max_model_len,
501
+ enable_bucketing=True,
502
+ is_continuous_batching=(batch_size > 1),
503
+ quantized=False,
504
+ torch_dtype=TORCH_DTYPE_TO_NEURON_AMP[model_config.dtype],
505
+ padding_side="right",
506
+ on_device_sampling_config=on_device_sampling_config,
507
+ sequence_parallel_enabled=True,
508
+ )
509
+ return neuron_config
510
+
511
+
512
+def _get_default_speculation_config(model_config: ModelConfig,
513
+ parallel_config: ParallelConfig,
514
+ scheduler_config: SchedulerConfig,
515
+ speculation_config: SpeculativeConfig):
516
+ """Generate a neuron config for speculative decoding based on vllm config
517
+ args."""
518
+ neuron_config = dict(
519
+ tp_degree=parallel_config.tensor_parallel_size,
520
+ batch_size=scheduler_config.max_num_seqs,
521
+ max_context_length=scheduler_config.max_model_len,
522
+ seq_len=scheduler_config.max_model_len,
523
+ speculation_length=speculation_config.num_speculative_tokens,
524
+ trace_tokengen_model=False,
525
+ enable_fused_speculation=True,
526
+ enable_bucketing=True,
527
+ quantized=False,
528
+ torch_dtype=TORCH_DTYPE_TO_NEURON_AMP[model_config.dtype],
529
+ on_device_sampling_config=dict(
530
+ top_k=1,
531
+ do_sample=False,
532
+ ))
533
+ return neuron_config
534
+
535
+
536
+def _get_neuron_config_after_override(default_neuron_config,
537
+ overridden_neuron_config):
538
+ """Update default neuron config values with override args"""
539
+ overridden_neuron_config = overridden_neuron_config or {}
540
+ default_neuron_config.update(overridden_neuron_config)
541
+ return default_neuron_config
542
+
543
+
544
+def get_neuron_model(model_config: ModelConfig,
545
+ parallel_config: ParallelConfig,
546
+ scheduler_config: SchedulerConfig) -> nn.Module:
547
+ """Initializes a neuron-optimized model for inference."""
548
+ model_arch = _get_model_architecture(model_config.hf_config)
549
+ if model_arch == "MllamaForConditionalGeneration":
550
+ model = NeuronMllamaForCausalLM(model_config.hf_config)
551
+ else:
552
+ model = NeuronCausalLM(model_config.hf_config)
553
+ default_neuron_config_args = _get_default_neuron_config(
554
+ model_config, parallel_config, scheduler_config)
555
+ neuron_config = _get_neuron_config_after_override(
556
+ default_neuron_config_args, model_config.override_neuron_config)
557
+
558
+ override_neuron_config = model_config.override_neuron_config
559
+ model.load_weights(model_config.model,
560
+ neuron_config=neuron_config,
561
+ override_neuron_config=override_neuron_config)
562
+ return model.eval()
563
+
564
+
565
+def get_neuron_speculation_model(model_config: ModelConfig,
566
+ parallel_config: ParallelConfig,
567
+ scheduler_config: SchedulerConfig,
568
+ speculation_config: SpeculativeConfig):
569
+ """Initializes a neuron-optimized speculation model for inference.
570
+
571
+ This model handles speculation using both a draft model and an EAGLE draft.
572
+ """
573
+ model = NeuronSpeculationCausalLM(model_config.hf_config)
574
+ default_neuron_config_args = _get_default_speculation_config(
575
+ model_config, parallel_config, scheduler_config, speculation_config)
576
+ neuron_config = _get_neuron_config_after_override(
577
+ default_neuron_config_args, model_config.override_neuron_config)
578
+
579
+ override_neuron_config = model_config.override_neuron_config
580
+ model.load_weights(model_config.model,
581
+ speculation_config.draft_model_config.model,
582
+ neuron_config=neuron_config,
583
+ override_neuron_config=override_neuron_config)
584
+ return model.eval()