Loading...
Loading...
Use when migrating a MAX model from the V2 graph API (max.nn, TensorValue, explicit Graph construction) to ModuleV3 (max.experimental.nn, Tensor, F.lazy() + compile()). Triggers on: "migrate to ModuleV3", "port a max.nn model to max.experimental", "convert TensorValue to Tensor", "update my model to the V3 API", "ModuleV3 migration". Workflow: read the concept map, rewrite imports and __call__ signatures, replace graph building with compile(weights=...), align weight names with the new module hierarchy, move the KV cache unflatten into forward(), port sharding to a DeviceMesh when the V2 model is sharded, then verify greedy outputs match the V2 implementation.
npx skill4agent add modular/skills migrate-max-v2-to-v3$ARGUMENTSmax.experimental.nnGraphTensorValuemax.nnforward()TensorF.lazy()compile()F.lazy()compile(weights=...)auto_castforward()__call__()max.nnGraphTensorValuemax.experimental.nnModulegrep -rn "max.experimental" <model-path>
grep -rEn "^\s*(from|import) max\.nn" <model-path>max.graphTensorTypeDeviceRefmax.graph<name>_modulev3_ModuleV3max serve --prefer-module-v3# REMOVE:
from max.graph import Graph, TensorValue, BufferValue, ops
from max.nn.layer import Module, LayerList
from max.nn.linear import Linear
from max.nn.norm.rms_norm import RMSNorm
# ADD:
from max.experimental import functional as F
from max.experimental.tensor import Tensor
from max.experimental.nn import Module
from max.experimental.nn.linear import Linear
from max.experimental.nn.norm import RMSNorm
from max.experimental.nn.sequential import ModuleList
# KEEP (TensorValue-free, shared with V2):
from max.nn.kv_cache import KVCacheParams, KVCacheParamInterface
from max.nn.attention import MHAMaskVariantTensorTypeDeviceRefmax.graphmax.nnTensorValuePagedCacheValuesmax.experimental.nn.common_layers.kv_cachemax.nnPagedCacheValuesfrom_upstream()max.experimental__call__()forward()TensorValueBufferValueTensorModuleclass MyModel(Module[[Tensor, ...], tuple[Tensor, ...]])...forward()*argsdtype=device=model.to(device)LayerListModuleListmax.experimental.nn.sequentialModuleListlistModuleList(layers)ModuleList(*layers)TypeErrorTensorTensor.zeros()max.experimental.random.*ops.*F.*ops.gather()F.gather()Tensorreshape()transpose()permute()squeeze()unsqueeze()split()cast()flatten()F.flatten(tensor, start_dim)compile()nn_model = MyModel(config)
nn_model.load_state_dict(state_dict)
with Graph("my_model", input_types=input_types) as graph:
outputs = nn_model(*graph.inputs)
graph.output(*outputs)
model = session.load(graph, weights_registry=state_dict)with F.lazy():
nn_model = MyModel(config)
nn_model.to(device)
model = nn_model.compile(*input_types, weights=state_dict)F.lazy()compile(weights=...)auto_cast=Truemodel(tokens, ...)TensorBuffer.driver_tensorcompile(weights=...)self.language_model = ...language_model.lm_headembed_tokens.weight.Tforward()tie_word_embeddingsforward()max.nnmax.experimental.nn.common_layers.kv_cachekv_paramsPagedCacheValues.from_upstream()def forward(self, tokens: Tensor, ..., *variadic_args: Tensor):
kv_inputs = iter(arg._graph_value for arg in variadic_args)
symbolic_inputs = self.kv_params.unflatten_kv_inputs(kv_inputs)
kv = PagedCacheValues.from_upstream(symbolic_inputs, tokens.mapping)._graph_valuevariadic_argsTensorMultiKVCacheParamsunflatten_basic_kv_tree()PagedCacheValues.from_upstream()ShardingStrategy.shard(devices)DeviceMeshfrom max.experimental.nn.common_layers.linear import row_parallel
from max.experimental.sharding import DeviceMesh
model.mesh = DeviceMesh(devices, (n_devices,), ("tp",))
linear = row_parallel(Linear(in_dim, out_dim))col_parallel()row_parallel()default_device(mesh)model.to(mesh)Signals.shard()Module[[...], ...]max/pipelines/architectures/olmo3/gpt_oss_modulev3/llama3_modulev3/kimik2_5_modulev3/gemma3_modulev3/deepseekV3_modulev3/nemotron_h_modulev3/gpt_oss/llama3/TensorTensorTensorValueTensor