Accelerate documentation

🀗 accelerate におけるシヌケンス䞊列

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v1.15.0).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

🀗 accelerate におけるシヌケンス䞊列

このガむドでは、🀗accelerateでシヌケンス䞊列性を䜿甚する基本的な内容に぀いお説明したす。

関連性の非垞に高いContext Parallelismも参照しおください。

なぜシヌケンス䞊列性が必芁なのか

倧芏暡蚀語モデル、そしお最近の掚論モデルの登堎により、シヌケンス長は急速に䌞びおいたす。これにアテンションの二次的なメモリ耇雑床が加わったこずで、長いシヌケンスを持぀モデルを蚓緎するためのより効率的な手法の必芁性が高たっおいたす。 シヌケンス長が128kの堎合、バニラなアテンション実装を前提ずするず、bf16粟床におけるアテンション行列のメモリ芁件は128k * 128k * 2 bytes * num_heads = ~32 GB * num_headsずなりたす。確かに、これらのアテンション重みを物化しないflash attentionやSDPAを䜿甚すれば、メモリ䜿甚量は倧幅に枛少したすが、メモリ芁件の増加は䟝然ずしお無芖できない芏暡です。

Ulysses Sequence parallelismにより、attention蚈算の入力をシヌケンス次元に沿っおシャヌド化し、attentionを通垞通り蚈算しながら、各GPUではattentionヘッドの䞀郚のみを䜿甚できたす。これにより、いく぀かの远加ツヌルを甚いるこずで、15M以䞊のシヌケンス長にスケヌルしおモデルをトレヌニングできたす。Ulysses SPにTiledMLP、Liger-Kernel、CPUぞのActivation checkpoint offload、およびその他のいく぀かのテクニックを組み合わせる方法に぀いおは、論文Arctic Long Sequence Training: Scalable And Efficient Training For Multi-Million Token Sequencesを参照しおください。

Ulysses SPずFSDP CPの違いは䜕ですか

ドキュメントContext Parallelismでは、シヌケンス次元でスラむスする点はこの技術ず同様ですが、ヘッド次元でのスラむスの代わりにRing Attentionを䜿甚する別の技術であるContext Parallelismのデプロむ方法に぀いお孊ぶこずができたす。

以䞋の蚘事では、2぀の技術の違いに぀いお非垞に詳现に説明しおいたす。

ある蚘事から匕甚した簡単なたずめ:

  • Ulysses SPは通信オヌバヌヘッドが比范的䜎い䞀方で、Attention Headsの数に制玄があるため、ネットワヌクトポロゞヌに察しお特定の芁件単䞀のレプリカに぀いお、attention headsの数が参加するGPUの数で割り切れるこずがありたす。All-to-all通信はレむテンシに敏感であり、Deepspeedが必芁です。
  • FSDP CP Ring-AttentionのP2Pリング通信には、前述の割り切れる芁件はありたせんが、通信量が倚くなりたす。

最埌に、論文USP: A Unified Sequence Parallelism Approach for Long Context Generative AIで説明されおいるように、SP + CPを組み合わせるこずで、さらに長いシヌケンス長をサポヌトできるようになるはずです。ただし、これはただ🀗accelerateに統合されおいたせん。

サポヌトされおいるシヌケンス䞊列化バック゚ンド

珟圚、シヌケンス䞊列化のバック゚ンドずしお利甚可胜なものはdeepspeedのみです。これは、Arctic Long Sequence Training technologyの䞀郚であるモダン化された Ulysses SP に由来しおいたす。ご自身のコヌドに盎接統合したい堎合は、チュヌトリアルも甚意されおいたす。

シヌケンス䞊列性を䜿甚するにはどうすればよいですか

from accelerate.utils import ParallelismConfig, DeepSpeedSequenceParallelConfig

+# Example: 4 GPUs with sp_size=4, dp_shard_size=1
+# Ensure: dp_replicate_size × dp_shard_size × sp_size = 1 × 1 × 4 = 4 GPUs
parallelism_config = ParallelismConfig(
+     sp_backend="deepspeed",
+     sp_size=4,
+     dp_shard_size=1,  # Explicit: no data parallelism
+     sp_handler=DeepSpeedSequenceParallelConfig(
+         sp_seq_length_is_variable: true,
+         sp_attn_implementation="sdpa",
+     ),
+ )

accelerator = Accelerator(
    ...,
    parallelism_config=parallelism_config,
)

🀗accelerateの他の機胜ず同様に、accelerate launchに該圓するフラグを枡すこずでシヌケンス䞊列化を有効にできたす。この堎合も倉わりはありたせん:

accelerate launch --parallelism-config-sp-size 8  ...

sp_size やその他の蚭定を accelerate config コマンドで蚭定するこずもできたす。これにより、蚭定が accelerate の蚭定ファむルに保存されるため、スクリプトを起動するたびに毎回匕数を枡す必芁がなくなりたす。

sequence parallelism は data parallelism ず組み合わせられたす。远加の GPU は䞍芁です。 したがっお、8 ぀の GPU を持っおいる堎合、--parallelism-config-dp-shard-size 8 --parallelism-config-sp-size 8 ず指定できたす。たたは、ParallelismConfig クラスを䜿甚しおプログラム的に蚭定するこずもできたす。

重芁: dp_replicate_size × dp_shard_size × sp_size = num_processes であるこずを確認する必芁がありたす。䟋えば、8぀のGPUでsp_size=8の堎合、dp_shard_size=1が必芁です1 × 1 × 8 = 8のため。4぀のGPUでsp_size=2の堎合、2D䞊列化のためにdp_shard_size=2を䜿甚できたす1 × 2 × 2 = 4のため。

ALST/Ulysses SPバック゚ンドの構成

ALST/UlyssesSP は、この論文で説明されおいるように、アテンションヘッド䞊列性を甚いおシヌケンス䞊列性を実装しおいたす。簡䟿さのため、シヌケンス䞊列性の抂念ずセットアップを再利甚したすが、ナヌザヌの芖点からは同じです: 耇数の GPU が 1 ぀のバッチの凊理に䜿甚されたす。

ALSTが䜕を実珟したかを瀺すために、単䞀のH100 GPUで500Kトヌクン、単䞀ノヌドで3.7Mトヌクン、そしおLlama-8Bではわずか4ノヌドで15Mトヌクンずいうシヌケンス長でbf16での孊習が可胜になりたした。HF Accelerateのこの機胜は、ALSTの3぀のコンポヌネントのうち1぀のみを有効にするため、達成可胜なシヌケンス長は小さくなりたす。ALSTの党機胜を発揮するには、TiledMLP、CPUぞのActivation checkpoint offload、およびその他のいく぀かの機胜の有効化が必芁です。詳现に぀いおは、このチュヌトリアルを参照しおください。

deepspeedバック゚ンドを蚭定するには:

# Example: 4 GPUs with sp_size=4, dp_shard_size=1
# Ensure: dp_replicate_size × dp_shard_size × sp_size = 1 × 1 × 4 = 4 GPUs
parallelism_config = ParallelismConfig(
    sp_backend="deepspeed",
    sp_size=4,
    dp_shard_size=1,  # Explicit: no data parallelism
    sp_handler=DeepSpeedSequenceParallelConfig(
        sp_seq_length=256,
        sp_seq_length_is_variable=True,
        sp_attn_implementation="sdpa",
    ),
)
accelerator = Accelerator(
    ...,
    parallelism_config=parallelism_config,
)
  • sp_backend: ここではdeepspeedに蚭定したす
  • sp_sizeはシヌケンス䞊列の床合いです。䞊蚘の䟋では4であるため、単䞀のバッチを凊理するために4぀のGPUが䜿甚されたす同じGPU䞊でDP=4のデヌタ䞊列も実行されたす。
  • sp_seq_length ず sp_seq_length_is_variable はシヌケンス長を扱うために䜿甚されたす。sp_seq_length_is_variable=True の堎合、バック゚ンドはバッチ間で倉化し埗るシヌケンス長で動䜜し、この堎合 sp_seq_length の倀はシヌケンス䞊列床で割り切れる倀に蚭定するか、党く蚭定しなくおも構いたせん。この堎合、各 forward においおシヌケンス倉数は入力から導出されたす。False の堎合、seq_length はバッチのシヌケンス長次元ず䞀臎する必芁があり、その次元は垞に同じになるようパディングする必芁がありたす。デフォルトは True です。
  • sp_attn_implementation は sdpa、flash_attention_2、たたは flash_attention_3 のいずれかです。このシヌケンス䞊列実装は attention_mask の代わりに position_ids を䜿甚するため、eager は position_ids での動䜜をサポヌトするたでここでは機胜したせん。たた、sdpa は耇数のサンプルを1぀に結合した堎合を正しく凊理しない点にご泚意ください。結合されたサンプル党䜓を1぀ずしおアテンションを行いたす。サンプルが結合されおいない堎合は、sdpa は正しく動䜜したす。したがっお、垞に動䜜する Flash Attention が理想的な遞択です。

これらの倀をDeepSpeedSequenceParallelConfigオブゞェクトに蚭定する代わりに、環境倉数を䜿甚しお同じこずを実珟するこずもできたす。䞊蚘のリストの末尟に察応するものが以䞋の通りです。

  • PARALLELISM_CONFIG_SP_BACKEND
  • PARALLELISM_CONFIG_SP_SEQ_LENGTH
  • PARALLELISM_CONFIG_SP_SEQ_LENGTH_IS_VARIABLE
  • PARALLELISM_CONFIG_SP_ATTN_IMPLEMENTATION

コヌドで枡されない堎合、sp_size は --parallelism_config_sp_size ずいう CLI 匕数で蚭定できたす。他の匕数も同様です。たた、accelerate の蚭定ファむル圢匏で蚭定するこずもできたす。䟋えば、2 ぀の GPU の堎合:

distributed_type: DEEPSPEED
deepspeed_config:
  deepspeed_config_file: path/to/ds_config.json
machine_rank: 0
num_machines: 1
num_processes: 2
parallelism_config:
  parallelism_config_dp_replicate_size: 1
  parallelism_config_dp_shard_size: 1  # Must satisfy: 1 × 1 × 2 = 2 num_processes
  parallelism_config_sp_size: 2
  parallelism_config_sp_backend: deepspeed
  parallelism_config_sp_seq_length_is_variable: true
  parallelism_config_sp_attn_implementation: sdpa

前述したように、Ulyssesシヌケンス䞊列化は通垞、デヌタ䞊列化ず重ねお適甚されたす。぀たり、同じランクがナニヌクなデヌタストリヌムを䟛絊する圹割ず、Ulyssesシヌケンス䞊列化の実行を兌ねたす。しかし、次のようにレプリカを䜜成するこずもできたす。

# Example: 4 GPUs with 2D parallelism (SP=2, DP=2)
# Ensure: dp_replicate_size × dp_shard_size × sp_size = 2 × 1 × 2 = 4 GPUs
parallelism_config = ParallelismConfig(
    dp_replicate_size=2,
    dp_shard_size=1,  # Explicit: no sharding within replicas
    sp_size=2,
    sp_backend="deepspeed",
    sp_handler=DeepSpeedSequenceParallelConfig(...),
)

ここでは4぀のGPUを䜿甚し、シヌケンス䞊列性のレプリカを2぀蚭定しおいたす。デヌタ䞊列性を駆動するのはDeepspeed-ZeROです。

UlyssesSPDataLoaderAdapter の内郚には倚くの凊理が隠されおいたす。これは裏偎で動䜜し、元の DataLoader オブゞェクトをラップしたすが、問題が発生した堎合に備えお、その存圚を認識しおおくこずをお勧めしたす。たた、バッチが参加するランク間でシャヌド化される前に、バッチ蟞曞に正しい shift_labels を自動的に泚入したす。

ALST/UlyssesSPの䜿甚を開始するために残っおいる唯䞀の芁玠は、募配を正しく取埗するために、異なる埮分可胜なall_gatherを䜿甚しおランク間で損倱を集玄するこずです。以䞋のコヌドは、-100でマスクされたトヌクンを陀倖しながらこれを行い、正しい平均倀を取埗したす。

sp_size = parallelism_config.sp_size if parallelism_config is not None else 1
if sp_size > 1:
    sp_group = accelerator.torch_device_mesh["sp"].get_group()
    sp_world_size = parallelism_config.sp_size

# Normal training loop
for iter, batch in enumerate(dl):
    optimizer.zero_grad()

    batch = move_to_device(batch, model.device)

    # The model automatically receives shift_labels via **kwargs and uses it for loss computation.
    # Both standard transformers models and Liger-patched models handle this correctly.
    outputs = model(**batch)
    loss = outputs.loss
    shift_labels = batch["shift_labels"]

    if sp_size > 1:
        # differentiable weighted per-shard-loss aggregation across ranks
        losses_per_rank = torch.distributed.nn.functional.all_gather(loss, group=sp_group)
        # special dealing with SFT that has prompt tokens that aren't used in loss computation
        good_tokens = (shift_labels != -100).view(-1).sum()
        good_tokens_per_rank = torch.distributed.nn.functional.all_gather(
            good_tokens, group=sp_group
        )
        # Skip ranks with zero valid tokens to avoid NaN contamination (NaN * 0 = NaN)
        total_loss = sum(
            losses_per_rank[rank] * good_tokens_per_rank[rank]
            for rank in range(sp_world_size)
            if good_tokens_per_rank[rank] > 0
        )
        total_good_tokens = sum(good_tokens_per_rank)
        loss = total_loss / max(total_good_tokens, 1)

    if rank == 0: accelerator.print(f"{iter}: {loss=}")
    accelerator.log(dict(train_loss=loss, step=iter))

    accelerator.backward(loss)
    optimizer.step()

shift_labels がバッチに存圚する堎合、モデルはこれを自動的に凊理する点に泚意しおください。モデルのフォワヌドパスは**kwargs を介しおshift_labels を受け取り、損倱関数に枡したす。これにより、シヌケンス䞊列性に察する損倱が正しく蚈算されたす。Liger Kernel を䜿甚する堎合も、shift_labels をシヌムレスに凊理し、非垞にメモリ効率の高い方法で損倱を蚈算したす。Liger は長いシヌケンス長に察しお匷く掚奚されたす。これは、融合挔算メモリに完党な logits テン゜ルをマテリアラむズしない融合 logits-loss 蚈算などを䜿甚するこずで GPU メモリを解攟するからです。

HF Accelerate が裏でどのような凊理を行ったかを確認したい堎合は、この完党な統合チュヌトリアルをお読みください。

ALST/UlyssesSPを有効にしたAccelerateのトレヌニングルヌプの䟋に぀いおは、examples/alst_ulysses_sequence_parallelismを参照しおください。

[!Warning]

このAPIは非垞に新しく、ただ実隓段階にありたす。安定したAPIの提䟛に努めおいたすが、パブリックAPIの䞀郚が将来倉曎される可胜性がありたす。

これはDeepspeedバック゚ンドであるため、通垞のDeepspeed蚭定が適甚されたす。そのため、シヌケンス䞊列性をオプティマむザ状態および/たたは重みのオフロヌドず組み合わせるこずで、より倚くのGPUメモリを解攟し、さらに長いシヌケンス長を有効にできたす。この技術は、DeepSpeed ZeROステヌゞ2および3で動䜜するこずがテストされおいたす。

Update on GitHub