NVIDIA NeMo を用いた金融 AI 研究のための合成データ生成
NVIDIA は、金融分野の AI 研究におけるデータ不足を解消するため、NeMo Data Designer と Curator を活用した反復型合成データ生成パイプラインの詳細と、82 回のイテレーションを経て 50 万件以上の独自ニュース見出しを生成する手法を公開している。
キーポイント
金融データの偏りと課題
実世界の金融ニュースは earnings や株価変動に偏っており、信用格下げや製品承認などの稀な事象が不足しているため、LLM の微調整には合成データ生成が不可欠である。
反復型生成パイプラインの構築
単一のバッチ処理ではなく、「生成→フィルタリング→グローバル重複排除→特徴的な few-shot 例の選択→カテゴリ重みの修正」を 82 回繰り返すことで、多様性を確保したデータセットを構築している。
大規模計算リソースと効率化
単一の NVIDIA B200 ノード(8 GPU)上で約 6 日間稼働し、チェックポイント機能や SLURM ジョブチェーンを活用して 50 万件以上のユニークな見出しを生成した。
再現性とオープンソース化
使用された NeMo Curator、Data Designer、vLLM のバージョンやハードウェア構成を明記し、他の研究者が同様のワークフローを再現・適用できるよう完全な手順を提供している。
反復型パイプラインによるカバレッジの改善
単発生成では earnings reports などの偏りが生じるため、カテゴリ重みを調整し、重複除去と多様性のある few-shot 例を選択する閉ループ構造で稀な事象も網羅する。
大規模バッチの非効率性と重複問題
50K のヘッドラインを単発処理した場合、意味的な重複除去後でもユニークな記事は約 17,348 件に留まり、バッチサイズ増がカバレッジ拡大に直結しないことが示された。
堅牢なチェックポイント管理
各イテレーションでコーパス状態やカテゴリ重みなどを永続化し、クラッシュ復旧と SLURM ジョブの連鎖処理を可能にすることで大規模生成の安定性を担保している。
重要な引用
Real-world financial news overrepresents earnings and stock movements, while rarer events such as credit-rating changes, product approvals, and labor issues are harder to capture at scale.
In a naive run of 50,000 headlines, 65% were removed as near-duplicates. Instead of scaling a single batch, the pipeline iterates: generate, filter, deduplicate globally...
Our full run produced 502,536 unique headlines across 13 categories in 82 iterations, using approximately 6 days of compute on a single 8-way NVIDIA B200 node.
Financial headline generation fails as a single-pass problem because real-world feeds are imbalanced
In a 50K-headline baseline, semantic deduplication retained only 17,348 unique headlines, showing that larger batches add many near-duplicates rather than proportionally more coverage
Figure 1. Iterative headline generation pipeline. Each batch is generated, filtered, deduplicated against the accumulated corpus, sampled for few-shot examples, and reweighted by category before the next iteration
影響分析・編集コメントを表示
影響分析
この記事は、LLM の実社会適用において最大の障壁の一つである「高品質かつ多様なトレーニングデータの不足」に対し、具体的な技術的解決策と再現可能なワークフローを提供する点で重要です。特に金融のような専門性が高くデータが偏在する領域において、合成データ生成のベストプラクティスを確立したことは、業界全体の AI 研究開発効率を大幅に向上させる可能性があります。
編集コメント
金融分野特有のデータ偏りを解消するための、非常に実践的な合成データ生成アプローチが示されています。単なるツールの紹介ではなく、なぜ反復処理が必要なのかという根本的な理由と、それをどう実装したかの詳細は、同様の課題を抱える研究者にとって即戦力となる内容です。
金融自然言語処理(NLP)のための大規模言語モデル(LLM)のファインチューニングは、限られたデータと不均衡なデータ構造によって制約されています。実世界の金融ニュースでは収益や株価変動が過剰に代表される一方、格付け変更、製品承認、労働問題といった稀な事象をスケーラブルに捉えることは困難です。合成データの生成は、取引研究、リスクモデリング、監視においてこれらのギャップを埋めるのに役立ちますが、多様性を確保するには単一の大量生成実行だけでは不十分です。
本稿では、12 のトピックと「その他」カテゴリを含む 50 万件の一意な金融ニュース見出しを生成するための反復的なパイプラインについて解説します。このワークフローは、構造化された生成には NVIDIA NeMo Data Designer を、意味的な重複排除には NVIDIA NeMo Curator を、そして高スループットの見出し合成には NVIDIA Nemotron モデルを組み合わせています。さらに、各ラウンドで新規の出力を指向させるために、中心点から最も遠い少数ショット(few-shot)戦略を追加しています。
単純な 50,000 件見出しの生成実行では、約 65% がほぼ重複するものとして削除されました。単一のバッチをスケールするのではなく、本パイプラインは反復処理を行います:生成、フィルタリング、グローバルな重複排除、特徴的な少数ショット例の選択、カテゴリ重みの修正、そしてコーパスが目標サイズに達するまでこれを繰り返します。私たちの完全な実行では、82 回の反復を経て 13 のカテゴリ全体で 502,536 件の一意な見出しを生成しました。これはチェックポイント機能、クラッシュ回復機能、および SLURM ジョブチェーンを活用した単一の 8 ウェイ NVIDIA B200 ノード上で約 6 日間の計算リソースを使用しています。
最終的には、生成と重複排除のループを再現する方法や、それを独自の金融研究ワークフローに適応させる方法、あるいはオープンソース化されたデータセットから直接開始する方法を理解できるようになります。
再現性
バージョン
コンポーネントバージョン
NeMo Curator1.0.0rc0.dev0
NeMo Data Designer0.1.5
vLLM0.12.0
Modelnvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-FP8
sentence-transformers≥ 2.2.0
*表 1. このガイドで使用されたソフトウェアおよびモデルのバージョン*
ハードウェア: 単一の 8 ウェイ NVIDIA B200 ノード。GPU 0–3 は vLLM 推論に専用(4 ウェイトンネル並列化、448 同時リクエスト);GPU 4–7 は Ray を用いた NeMo Curator の意味的重複排除を実行。
パイプラインパラメータ: バッチあたり 35K の見出し(初期反復では 50K)、余弦類似度による重複排除閾値 90%、k-means クラスタ数 500、カテゴリあたりの Few-shot 例 8 個、例選択のためのクロス反復類似度カットオフ 80%。
チェックポイント: 各反復でコパス状態、カテゴリ重み、Few-shot 例、メトリクス、使用済み例の埋め込みを永続化し、クラッシュ回復および SLURM ジョブチェーンに対応。
金融ニュース見出し生成は単一パスの問題としては失敗します。なぜなら、現実世界のフィードには不均衡があるからです:決算報告や株価変動が支配的である一方、格付け変更、製品承認、その他の稀な事象はsparse(希薄)です。50K 件見出しのベースラインでは、意味的な重複排除により、一意な見出しはわずか 17,348 件しか残らず、バッチサイズを大きくしても被りが増えるだけで、カバー範囲が比例して拡大するわけではないことが示されました。
この反復型パイプラインはクローズドループ(閉ループ)によってこの課題に対処します。各イテレーションでは、カテゴリ重み付けされたバッチを生成し、不正な出力をフィルタリングし、蓄積された全コーパスに対して重複排除を行い、多様な few-shot 例を選択し、次のイテレーション前にカテゴリ重みを調整します。
以下の図 1 は全体アーキテクチャを示しています。
image*図 1. 反復型見出し生成パイプライン。各バッチは生成され、フィルタリングされ、蓄積コーパスに対して重複排除が行われ、few-shot 例のためにサンプリングされ、カテゴリごとに再重み付けされた後、次のイテレーションに進みます***
重要な設計判断はグローバルな重複排除です。各バッチは自分自身だけでなく、以前に保持されたすべての見出しと比較されます。これにより、バッチ間の重複を防ぎ、50 万件のコーパス全体で意味的な一意性を維持します。
ステップ 1. NeMo Data Designer を用いた見出し生成
Nemotron 3 Nano(パラメータ数 30B、アクティブパラメータ数 3B)を vLLM を介して提供しており、4 方向のテンソル並列処理と 448 の同時リクエストに対応しています。このモデルの Mixture-of-Experts (MoE) アーキテクチャは、スループットと品質のバランスを保ちつつ、1 つのフォワードパスあたり 3B のアクティブパラメータを 30B パラメータを持つモデル内で使用します。
NeMo Data Designer は宣言型設定を通じて生成をオーケストレーションします。これは 12 のトピックと「その他」にわたる重み付けカテゴリサンプラー、およびサンプリングされたカテゴリと現在の few-shot 例を条件として見出しを生成する LLM カラムで構成されています。
カテゴリの重みは、各イテレーション後に分布補正(ステップ 5)を通じて更新されます。
データデザイナー設定:
config_builder = DataDesignerConfigBuilder()
local_model = ModelConfig(
alias="local-nemotron",
model="nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-FP8",
provider="local-vllm",
inference_parameters=InferenceParameters(
max_parallel_requests=448,
temperature=0.95,
top_p=0.95,
),
)
config_builder.add_model_config(local_model)
config_builder.add_column(
SamplerColumnConfig(
name="category",
sampler_type=SamplerType.CATEGORY,
params=CategorySamplerParams(
values=CATEGORIES,
weights=current_weights,
),
)
)
config_builder.add_column(
LLMTextColumnConfig(
name="headline",
model_alias="local-nemotron",
system_prompt="You are a financial news headline writer.",
prompt=f
高多様性サンプリング(温度パラメータ=0.95、頻度ペナルティ 0.3、存在ペナルティ 0.2)を使用し、後段のフィルタリングと意味的な重複排除によって、破損した出力や冗長な出力を除去します。
プロンプト構造
プロンプトには、役割設定を行うシステムプロンプト、カテゴリ別にグループ化された Few-shot(少サンプル)例、およびサンプリング対象のカテゴリに対する指示が含まれます。Data Designer は、Jinja テンプレート(テンプレートエンジン)を用いてランタイムでカテゴリを注入し、Few-shot 例は各イテレーション(反復処理)ごとに更新されます(ステップ 4)。
プロンプト構造(簡略化版):
SYSTEM:
あなたは金融ニュースの見出し作成者です。現実的で専門的な金融ニュースの見出しを生成してください。出力は見出しテキストのみとし、それ以外の情報は含めないでください。
USER:
カテゴリ「{{ category }}」に対する現実的な金融ニュースの見出しを生成してください。
カテゴリ別の例:
- 決算:"Google の親会社アルファベットが EPS 1.84 ドル、収益 635 億ドルを発表"
- 決算:"Myriad Genetics が第 4 四半期の予想を上回り、収益が 15% 急増"
- 決算:"Codec Solutions が第 3 四半期調整後 EPS を 0.31 ドルとし、...を突破"
- 株価目標:"J.P. モーガンがサーモフィッシャーの目標を引き下げ、格下げ"
- 株価目標:"三菱 UFJ フィナンシャル・グループが三井物産に買い推奨"
- 株価目標:"Credence Resources が目標を 12.50 ドルに引き上げ"
- 株価変動:"株式全体が上昇、ダウ平均が 180 ポイント増"
- ...
(3 例×12 トピック+その他=最大 39 の Few-shot 例)
"{{ category }}" カテゴリの見出しを 1 つ生成してください。
必ず JSON 形式で返してください。translation フィールドのみ。他のフィールド (technical_terms など) は一切追加しないこと — 余計なフィールドを書こうとして本文翻訳がトークン上限で打ち切られる事故を防ぐため:
{"translation": "翻訳全文"}
見出しは 10〜25 語程度とし、現実的な内容で、専門的な金融ニュースのスタイルに合致させること。
見出し:
ステップ 2. 品質フィルタリング
意味的重複除去の前段階として、軽量のルールベース処理により、切り捨てられたもの、暴走した出力、または文字化けした見出しなどの不具合のある出力を除外します。
フィルター閾値目的
最小単語数>= 5 語切り捨てや断片化した出力の除去
最小文字数>= 25 文字非常に短い出力の除去
最大単語数<= 100 語暴走生成の除去
最大文字数<= 1,000 文字エッジケースの捕捉
括弧数< 5 個フォーマットアーティファクトの除去
特殊文字比率<= 25% 文字化け出力の除去
*表 2. 生成された見出しに適用される品質フィルター、各フィルターの閾値と根拠*
実際には、これらのフィルターによりバッチあたりの見出しのうち 1% 未満が除外されるため、品質管理の大部分は次のステップにおける意味的重複除去によって行われます。
ステップ 3. NeMo Curator を用いた意味的重複除去
これが中核的な品質メカニズムです。各バッチ処理後、パイプラインは新たに生成された見出しと蓄積されたコーパスを結合し、NeMo Curator の TextSemanticDeduplicationWorkflow(テキスト意味的重複除去ワークフロー)を実行します。見出しは all-MiniLM-L6-v2 を用いて埋め込みされ、K-means 法でクラスタリングされ、クラスタ内ではペアワイズコサイン類似度を用いて比較されます。90% の類似度閾値を超える見出しはすべて除外されます。
NeMo Curator 意味的重複除去設定:
workflow = TextSemanticDeduplicationWorkflow(
input_path=input_path,
output_path=output_path,
cache_path=cache_path,
perform_removal=True,
text_field="headline",
model_identifier="sentence-transformers/all-MiniLM-L6-v2",
embedding_max_seq_length=512,
embedding_model_inference_batch_size=1024,
n_clusters=500,
eps=0.10,
id_field="id",
ranking_strategy=RankingStrategy(
metadata_cols=["cosine_dist_to_cent"],
ascending=True,
),
pairwise_batch_size=4096,
input_filetype="parquet",
output_filetype="parquet",
)
workflow.run()
なぜ 500 クラスターなのか?
ペアワイズ類似度計算は高価です。なぜなら、各クラスター内での比較数が二次関数的に増加するからです。50 万件の見出しという終点において、500 クラスターを使用すれば、平均的なクラスターあたりの見出し数は約 1,000 件となり、総比較回数は約 5 億回(500M)に抑えられます。一方、カテゴリごとに 1 つずつの 13 クラスターを使用すると、総比較回数は約 190 億回(19B)に達してしまいます。クラスター数を多く設定することで、コーパスが成長してもグローバルな重複排除処理を現実的な範囲内に保つことができます。
類似度分布のモニタリング
各イテレーションの後、パイプラインはペアワイズコサイン類似度の ECDF(経験的累積分布関数)をプロットします。赤い線は 0.90 の重複排除閾値を示しており、1.0 の付近で急激な上昇が見られる場合は多くのニア・デュプリケート(ほぼ同一の文書)が存在することを意味し、一方、左側にシフトした滑らかな曲線はより広範なカバレッジを示唆します。
図 2 は、代表的な反復回数である 5, 20, 40, 60, 82 の曲線を重ねて表示しています。初期の曲線は右に歪んでおり、これはモデルが限られた few-shot(少数ショット)例から一般的なパターンを繰り返しているためです。後の曲線は左へシフトして安定し、コーパスが約 50 万件の見出しに近づいても、更新された few-shot 例が生成を新たなコンテンツへと導き続けていることを示しています。
image*図 2. 反復回数 5, 20, 40, 60、および最終反復 82 にわたるコサイン類似度分布の結合 ECDF(経験的累積分布関数)*
重複除去後、パイプラインは次のバッチ用の few-shot 例を選択します。その目的は、モデルがすでに生成したパターンから遠ざけることです。
重心からの最遠点選択
重複除去ステップにおける K-means クラスタリング(K-means clustering)により、各見出しにクラスタの重心が割り当てられます。見出しをその重心からのコサイン距離でランク付けし、最も遠い例を選択します。これらは意味的な近傍内では典型的でないため、新たな出力を促すプロンプトとして有用です。
反復間での意味的フィルタリング
距離だけでは不十分です。パイプラインはさらに、各候補をこれまでに使用されたすべての few-shot 例と比較し、コサイン類似度が 80% 以上のものは拒否します。これにより、反復間で意味的に重複するプロンプト信号が生じるのを防ぎます。
表 3 は、選択の優先順位を要約しています。各カテゴリから 3 つの例が選択され、1 回の反復あたり合計 39 個となります。また、使用済みの例セットと埋め込みベクトルは回復のためにチェックポイントされます。
優先順位戦略目的
- 主戦略K-means 中心から最も遠い点最も典型的でない=最も情報量の多いfew-shot シグナル
- セマンティックフィルタ使用済み例とのコサイン類似度が80%未満反復間での意味的な重複を防ぐ
- フォールバックカテゴリプールからのランダムサンプリング外れ値が枯渇した場合の網羅性を確保
- 最後の手段手動で選定したシード例埋めにくいカテゴリのためのコールドスタートベースライン
*表3. few-shot 例選択の優先順位*
few-shot 候補フィルタリングのためのセマンティック類似度チェック:
def is_semantically_distinct(
candidate_embedding, used_embeddings, threshold=0.80
):
if used_embeddings.size == 0:
return True
candidate_norm = candidate_embedding / (
np.linalg.norm(candidate_embedding) + 1e-9
)
used_norms = used_embeddings / (
np.linalg.norm(used_embeddings, axis=1, keepdims=True) + 1e-9
)
similarities = np.dot(used_norms, candidate_norm)
return np.max(similarities) < threshold
以下の表4は、最終反復までに選択された例がどのようにより具体的になっていくかを示しています。
カテゴリ反復1の例反復82の例
決算Google親会社アルファベットがEPS 1.84ドル、収益635億ドルを報告し予測を上回るサーモグローが第2四半期で予想を上回り、超低VOC自動車用接着剤への記録的な受注により通期ガイダンスを引き上げ
M&Aマーズがノードストロームのホーム部門を18億ドルで買収Siemensがメンター・グラフィックスを35億ドルで買収に合意、EUは重複するEDAツールの売却を要求
格付評価
S&P、主要欧州銀行に対するムーディーズの展望を安定に引き上げ
Fitch、財政圧力と生産量減少を理由にアルゼンチンの国営石油会社 YPF を B- に格下げ
*表 4. イテレーション 1(初期)およびイテレーション 82(最終)からの Few-shot 例。後の例では、より具体的な実体、ニッチな金融商品、そしてより長く詳細な構造が特徴であり、これはパイプラインが先端的なコンテンツへとシフトしていることを反映しています。
ステップ 5. ダイナミック分布の補正
重み付きサンプリングだけではカテゴリを目標値に維持できません。なぜならモデルは「その他」や「株価変動」のような容易なクラスを好むからです。各イテレーションの後、パイプラインは目標と実際のカテゴリ比率を比較し、過小評価されたカテゴリの重みを増やし、極端な値を制限(クランプ)して、次のバッチのために重みを正規化します。
重み調整アルゴリズム:
def compute_adjusted_weights(current_dist, target_dist, floor=0.005):
adjusted = []
for category in CATEGORIES:
target = target_dist.get(category, 0.01)
current = current_dist.get(category, 0.0)
if current > 0:
ratio = target / current
ratio = max(0.2, min(5.0, ratio))
weight = target * ratio
else:
weight = target * 2.0
adjusted.append(max(floor, weight))
total = sum(adjusted)
return [w / total for w in adjusted]
82 回目のイテレーションまでに、「Credit Ratings」や「Product Approval」といった稀なカテゴリは、それぞれ 1% の目標値にほぼ一致するようになりましたが、「Other」カテゴリはまだ過剰に存在しています。この修正ループにより、モデルのバイアスは十分に低減され、すべてのカテゴリにおけるカバレッジが維持されています。
image*図 3. イテレーション 82 時点での目標対実際のカテゴリ分布(502,536 のヘッドライン)***
結果
パイプライン実行サマリー:**50 万というターゲットは、生成が固定された 35K バッチ単位で進行し、閾値を超えた時点で停止するため、わずかにオーバーシュートしています。過剰な 2,536 の例は、過剰に存在する「Other」カテゴリからトリミングされます。
- 合計ユニークヘッドライン数:502,536(ターゲット:500,000)
- 合計イテレーション回数:82
- バッチサイズ:イテレーションあたり 35,000 のヘッドライン
- 生成総数(重複除去前):約 287 万のヘッドライン
- 全体の重複除去率:約 82%(累積)
- イテレーションあたりの新規ユニーク数:約 5,000〜6,000 のユニークヘッドライン
- カテゴリ:12 の広範なトピック+Other
- 類似度閾値:90% コサイン類似度(cosine similarity)
- イテレーションあたりの Few-shot 例数:39 件(カテゴリあたり 3 件)
重複除去の効率性
意味的な重複排除が主要なフィルタであり、その役割は実行過程を通じて変化しました。1 回目のイテレーションではカテゴリごとに手動の例を 1 つずつシードした結果、50,000 の見出しのうち 17,348 が保持され、残りの 32,652(65%)がほぼ重複するものでした。2~3 回目のイテレーションでは、前回の出力から中心からの距離が最も遠い例を使用し、バッチあたり 50,000 で 15,000~17,000 の新規見出しという高い収率を維持しましたが、コーパスが大きくなるにつれてバッチ間の衝突が増加し始めました。
4 回目以降のイテレーションでは、重複排除による削減率が約 80% を超えた時点で、バッチサイズを 50,000 から 35,000 に縮小しました。より大きな SLURM ジョブは主に下流で破棄される見出しを生産するのみでしたが、小さな 35,000 のバッチでは同様の純粋な新規収率を得つつ、計算資源の浪費を減らすことができました。
コーパスが約 100,000 の見出しを超えた後、新しい見出しはより大きなプールに対して一意である必要がありました。40 回目以降のイテレーションでは、収率はバッチあたり 35,000 で約 5,000~6,000 の新規見出し(約 15%)に安定し、バッチあたり約 30,000 が破棄されました。表 4 はこの移行を示しています:初期の重複は主にバッチ内の繰り返しですが、後期の重複は蓄積されたコーパスとの衝突が主です。500,000 に近い地点でも持続的なゼロでない収率が見られることは、進化し続ける Few-shot(少数ショット)例が生成を新たな領域へと導き続けていることを示しています。
イテレーションバッチサイズ純粋な新規破棄収率後のコーパスサイズ
150,00017,34832,65235%17,348
250,00017,19932,80134%34,547
350,00015,20934,79130%49,756
550,00016,91733,08334%80,028
4235,000~5,700~29,30016%268,724
8235,000~5,155~29,84515%502,536
*表5. 代表的な反復における重複排除の収率。クロスバッチでの衝突が支配的となるにつれ、収率は初期の小規模コーパスでは約35%から、後期の大規模コーパスでは約15%まで低下します*
下流アプリケーション:モデル蒸留
生成されたデータセットは、AI Model Distillation for Financial Data developer example(金融データ向けのAIモデル蒸留開発者向け例)をサポートしています。ここでは、49B〜70Bのパラメータを持つ教師モデルが合成された見出しにラベルを付け、より小さな1B、3B、8Bのパラメータを持つ学生モデルがLoRAを用いてファインチューニングされます。25K件のラベル付き例を使用することで、この金融見出し分類タスクにおいて、3Bの学生モデルは教師モデルのF1スコアの95%を達成します。
ここで重要なのはデータセットの多様性です:意味的な一意性とカテゴリのバランスが、実世界のソースから収集することが困難な稀な金融事象やエッジケースに対して学生モデルを曝露させます。
実践的な道筋
グローバルな意味的重複を伴う反復的な合成データ生成において、4つの原則が浮き彫りになりました:
- 反復的に実行し、バッチ処理に依存しないこと。単一の50万回の生成パスでは主に重複したデータが生産されます。一方、進化するプロンプトを用いた82回の小規模な反復は、はるかに多様なコーパスをもたらします。
- ローカルではなくグローバルに重複排除を行うこと。各反復では、クロスバッチでの重複を防ぐために、蓄積された完全なデータセット全体に対して重複排除を行う必要があります。
- フューショット例が操縦桿です。セマンティック類似性フィルタリングを伴う重心からの最遠距離選択は、生成の多様性を高める上で最も効果的なレバーとなります。
- 分布補正は不可欠です。動的な重み調整を行わないと、モデルは人気のあるカテゴリを過剰に生成し、稀なカテゴリが枯渇してしまいます。
はじめに
- データセットを使用する — Hugging Face で FinHeadlineMix をダウンロードし、ヘッドライン分類、ファインチューニング、または独自の蒸留パイプラインのトレーニングデータとして直接使用してください。
- レシピを実行する — 構造化された合成生成には NeMo Data Designer を、スケーラブルな意味的な重複排除には NeMo Curator (Curator) を使用して、このパイプラインを再現または拡張してください。
- 蒸留モデルをトレーニングする — 「金融データのための AI モデル蒸留」の開発者例に従い、このデータセット上でコンパクトな学生モデルをファインチューニングしてください。
さらに進むために
- NVIDIA Build 上の Nemotron-3-Nano-30B-A3B — 生成に使用される MoE (Mixture of Experts) モデルで、蒸留ワークフローに承認されています
- タスク固有の LLM 蒸留のスケーリング法則 — 生成された FinHeadlineMix データセットを活用して蒸留のスケーリング法則を導き出す研究論文
- AI モデル蒸留による効率的な金融データワークフローの構築 — 関連ブログ記事
- ライセンス準拠型合成データパイプラインの構築方法 — 関連資料
原文を表示
Fine-tuning LLMs for financial natural language processing (NLP) is constrained by limited, imbalanced data. Real-world financial news overrepresents earnings and stock movements, while rarer events such as credit-rating changes, product approvals, and labor issues are harder to capture at scale. Synthetic generation can help fill those gaps for trading research, risk modeling, and surveillance, but diversity requires more than a single large generation run.
This post walks through an iterative pipeline for generating 500,000 unique financial news headlines across 12 topics plus an “Other” category. The workflow combines NVIDIA NeMo Data Designer for structured generation, NVIDIA NeMo Curator for semantic deduplication, and NVIDIA Nemotron models for high-throughput headline synthesis. It also adds a farthest-from-centroid few-shot strategy to steer each round toward novel outputs.
In a naive run of 50,000 headlines, 65% were removed as near-duplicates. Instead of scaling a single batch, the pipeline iterates: generate, filter, deduplicate globally, select distinctive few-shot examples, correct category weights, and repeat until the corpus reaches the target size. Our full run produced 502,536 unique headlines across 13 categories in 82 iterations, using approximately 6 days of compute on a single 8-way NVIDIA B200 node with checkpointing, crash recovery, and SLURM job chaining.
By the end, you’ll understand how to reproduce the generation-deduplication loop, adapt it for your own financial research workflows, or start directly from the open-sourced dataset.
Reproducibility
Versions
Hardware: Single 8-way NVIDIA B200 node. GPUs 0–3 dedicated to vLLM inference (4-way tensor parallelism, 448 concurrent requests); GPUs 4–7 ran NeMo Curator semantic deduplication with Ray.
Pipeline parameters: 35K headlines per batch (50K in early iterations), 90% cosine-similarity deduplication threshold, 500 K-means clusters, 3 few-shot examples per category, 80% cross-iteration similarity cutoff for example selection.
Checkpointing: Each iteration persisted corpus state, category weights, few-shot examples, metrics, and used-example embeddings for crash recovery and SLURM job chaining.
Pipeline overview
Financial headline generation fails as a single-pass problem because real-world feeds are imbalanced: earnings reports and stock movements dominate, while credit-rating changes, product approvals, and other rarer events are sparse. In a 50K-headline baseline, semantic deduplication retained only 17,348 unique headlines, showing that larger batches add many near-duplicates rather than proportionally more coverage.
The iterative pipeline addresses this with a closed loop. Each iteration generates a category-weighted batch, filters malformed outputs, deduplicates against the full accumulated corpus, selects diverse few-shot examples, and adjusts category weights before the next iteration.
Figure 1, below, illustrates the overall architecture.

The key design decision is global deduplication. Each batch is compared with all previously retained headlines, not just with itself, preventing cross-batch duplicates and preserving semantic uniqueness across the 500K corpus.
Step 1. Generate headlines with NeMo Data Designer
We serve Nemotron 3 Nano (30B parameters, 3B active) via vLLM with 4-way tensor parallelism and 448 concurrent requests. The model’s Mixture-of-Experts (MoE) architecture balances throughput and quality, using 3B active parameters per forward pass within a 30B-parameter model.
NeMo Data Designer orchestrates generation through a declarative configuration: a weighted category sampler across 12 topics plus “Other,” and an LLM column that generates headlines conditioned on the sampled category and current few-shot examples.
Category weights are updated after each iteration through distribution correction (Step 5).
Data Designer configuration:
config_builder = DataDesignerConfigBuilder()
local_model = ModelConfig(
alias="local-nemotron",
model="nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-FP8",
provider="local-vllm",
inference_parameters=InferenceParameters(
max_parallel_requests=448,
temperature=0.95,
top_p=0.95,
),
)
config_builder.add_model_config(local_model)
config_builder.add_column(
SamplerColumnConfig(
name="category",
sampler_type=SamplerType.CATEGORY,
params=CategorySamplerParams(
values=CATEGORIES,
weights=current_weights,
),
)
)
config_builder.add_column(
LLMTextColumnConfig(
name="headline",
model_alias="local-nemotron",
system_prompt="You are a financial news headline writer.",
prompt=f
,
)
)
We use high-diversity sampling (temperature=0.95, frequency penalty 0.3, presence penalty 0.2) and rely on downstream filtering and semantic deduplication to remove malformed or redundant outputs.
Prompt structure
The prompt includes a role-setting system prompt, few-shot examples grouped by category, and an instruction for the sampled category. Data Designer injects the category at runtime through Jinja templating, and the few-shot examples are refreshed each iteration (Step 4).
Prompt structure (simplified):
SYSTEM:
You are a financial news headline writer. Generate realistic,
professional financial news headlines. Output ONLY the headline
text, nothing else.
USER:
Generate a realistic financial news headline for the category:
{{ category }}
Examples by category:
- Earnings: "Google Parent Alphabet Posts $1.84 EPS, $63.5B Revenue"
- Earnings: "Myriad Genetics Beats Q4 Estimates with 15% Revenue Surge"
- Earnings: "Codec Solutions Posts Q3 Adjusted EPS $0.31, Surpasses ..."
- Price Targets: "J.P. Morgan Cuts Target for Thermo Fisher, Downgrades ..."
- Price Targets: "Mitsubishi UFJ Secures Buy Rating on Mitsui & Co. ..."
- Price Targets: "Credence Resources Upgrades Target to $12.50 ..."
- Stock price movement: "Equities Rise Broadly, Dow Gains 180 Points ..."
- ...
(3 examples x 12 topics + Other = up to 39 few-shot examples)
Generate a single headline for the "{{ category }}" category.
The headline should be 10-25 words long, realistic, and match
the style of professional financial news.
Headline:
Step 2. Quality filtering
Before semantic deduplication, a lightweight rule-based pass removes malformed outputs such as truncated, runaway, or garbled headlines.
In practice, these filters removed fewer than 1% of headlines per batch, so most quality control comes from semantic deduplication in the next step.
Step 3. Semantic deduplication with NeMo Curator
This is the core quality mechanism. After each batch, the pipeline combines newly generated headlines with the accumulated corpus and runs NeMo Curator’s TextSemanticDeduplicationWorkflow. Headlines are embedded with all-MiniLM-L6-v2, clustered with K-means, and compared within clusters using pairwise cosine similarity. Any headline above the 90% similarity threshold is removed.
NeMo Curator semantic deduplication configuration:
workflow = TextSemanticDeduplicationWorkflow(
input_path=input_path,
output_path=output_path,
cache_path=cache_path,
perform_removal=True,
text_field="headline",
model_identifier="sentence-transformers/all-MiniLM-L6-v2",
embedding_max_seq_length=512,
embedding_model_inference_batch_size=1024,
n_clusters=500,
eps=0.10,
id_field="id",
ranking_strategy=RankingStrategy(
metadata_cols=["cosine_dist_to_cent"],
ascending=True,
),
pairwise_batch_size=4096,
input_filetype="parquet",
output_filetype="parquet",
)
workflow.run()
Why 500 clusters?
Pairwise similarity is expensive because comparisons scale quadratically within each cluster. At the 500K-headline endpoint, 500 clusters keep the average cluster near ~1,000 headlines and total comparisons near ~500M. Using 13 clusters, one per category, would push total comparisons toward ~19B. The higher cluster count keeps global deduplication tractable as the corpus grows.
Similarity distribution monitoring
After each iteration, the pipeline plots an ECDF (Empirical Cumulative Distribution Function) of pairwise cosine similarities. The red line marks the 0.90 deduplication threshold: a steep rise near 1.0 signals many near-duplicates, while a smoother left-shifted curve indicates broader coverage.
Figure 2, below, overlays representative iterations 5, 20, 40, 60, and 82. Early curves skew right because the model repeats common patterns from limited few-shot examples. Later curves shift left and stabilize, showing that updated few-shot examples continue to push generation toward novel content even as the corpus approaches 500K headlines.

After deduplication, the pipeline selects few-shot examples for the next batch. The goal is to steer the model away from patterns it has already produced.
Farthest-from-centroid selection
K-means clustering from the deduplication step gives each headline a cluster centroid. We rank headlines by cosine distance from that centroid and select farthest examples, which are atypical within their semantic neighborhood and useful for prompting novel outputs.
Cross-iteration semantic filtering
Distance alone is not enough. The pipeline also compares each candidate against all previously used few-shot examples and rejects any candidate with >=80% cosine similarity. This prevents semantically repeated prompt signals across iterations.
Table 3, below, summarizes the selection priority. Three examples are selected per category, for 39 total per iteration, and the used-example set plus embeddings are checkpointed for recovery.
Semantic similarity check for few-shot candidate filtering:
def is_semantically_distinct(
candidate_embedding, used_embeddings, threshold=0.80
):
if used_embeddings.size == 0:
return True
candidate_norm = candidate_embedding / (
np.linalg.norm(candidate_embedding) + 1e-9
)
used_norms = used_embeddings / (
np.linalg.norm(used_embeddings, axis=1, keepdims=True) + 1e-9
)
similarities = np.dot(used_norms, candidate_norm)
return np.max(similarities) < threshold
Table 4, below, shows how selected examples become more specific by the final iteration.
Step 5. Dynamic distribution correction
Weighted sampling alone doesn’t keep categories on target because the model favors easier classes such as “Other” and “Stock Movement.” After each iteration, the pipeline compares target and actual category proportions, boosts underrepresented categories, clamps extremes, and normalizes weights for the next batch.
Weight adjustment algorithm:
def compute_adjusted_weights(current_dist, target_dist, floor=0.005):
adjusted = []
for category in CATEGORIES:
target = target_dist.get(category, 0.01)
current = current_dist.get(category, 0.0)
if current > 0:
ratio = target / current
ratio = max(0.2, min(5.0, ratio))
weight = target * ratio
else:
weight = target * 2.0
adjusted.append(max(floor, weight))
total = sum(adjusted)
return [w / total for w in adjusted]
By iteration 82, rare categories such as “Credit Ratings” and “Product Approval” closely match their 1% targets, while “Other” remains overrepresented. The correction loop still reduces model bias enough to preserve coverage across all categories.

Results
Pipeline run summary: The 500K target is slightly overshot because generation proceeds in fixed 35K batches and halts only after the threshold is crossed; the excess 2,536 examples are trimmed from the over-represented “Other” category.
- Total unique headlines: 502,536 (target: 500,000)
- Total iterations: 82
- Batch size: 35,000 headlines per iteration
- Total generated (pre-deduplication): ~2.87M headlines
- Overall deduplication rate: ~82% (cumulative)
- Net new per iteration: ~5,000–6,000 unique headlines
- Categories: 12 broad topics + Other
- Similarity threshold: 90% cosine similarity
- Few-shot examples per iteration: 39 (3 per category)
Deduplication efficiency
Semantic deduplication was the dominant filter, and its role shifted over the run. In iteration 1, seeded by only one manual example per category, the pipeline retained 17,348 of 50K headlines; the remaining 32,652 (65%) were near-duplicates. Iterations 2–3 used farthest-from-centroid examples from previous outputs and maintained higher yields of 15K–17K new headlines per 50K batch, though cross-batch collisions began rising as the corpus grew.
From iteration 4 onward, we reduced batch size from 50K to 35K once the deduplication drop rate exceeded ~80%. Larger SLURM jobs were mostly producing headlines discarded downstream, while smaller 35K batches delivered similar net-new yield with less wasted compute.
After the corpus passed ~100K headlines, each new headline had to be distinct from a much larger pool. By iteration 40+, yield stabilized at ~5K–6K new headlines per 35K batch, or roughly 15%, with about 30K discarded per batch. Table 4 shows the transition: early duplicates are mostly within-batch repetition, while later duplicates are mostly collisions with the accumulated corpus. The steady nonzero yield near 500K shows that evolving few-shot examples continued to steer generation into novel regions.
Downstream application: Model distillation
The generated dataset supports the AI Model Distillation for Financial Data developer example, where a 49B–70B teacher model labels synthetic headlines and smaller 1B, 3B, and 8B student models are fine-tuned with LoRA. With 25K labeled examples, a 3B student reaches 95% of the teacher’s F1-score on this financial headline classification task.
Dataset diversity matters here: semantic uniqueness and category balance expose the student to rare financial events and edge cases that are difficult to collect from real-world sources.
A practical path
Four principles emerged for iterative synthetic data generation with global semantic duplication:
- Iterate, don’t batch. A single 500K generation pass produces mostly duplicates. Eighty-two smaller iterations with evolving prompts yield a far more diverse corpus.
- Deduplicate globally, not locally. Each iteration must deduplicate against the full accumulated dataset to prevent cross-batch duplicates.
- Few-shot examples are the steering wheel. Farthest-from-centroid selection with semantic similarity filtering is the most impactful lever for generation diversity.
- Distribution correction is essential. Without dynamic weight adjustment, models over-generate popular categories and starve rare ones.
Getting started
- Use the dataset — Download FinHeadlineMix on Hugging Face and use it directly for headline classification, fine-tuning, or as training data for your own distillation pipeline.
- Run the recipe — Reproduce or extend this pipeline using NeMo Data Designer for structured synthetic generation and NeMo Curator for scalable semantic deduplication.
- Train a distilled model — Follow the AI Model Distillation for Financial Data developer example to fine-tune a compact student model on this dataset.
Going further
- Nemotron-3-Nano-30B-A3B on NVIDIA Build — the MoE model used for generation, approved for distillation workflows
- Scaling Laws for Task-Specific LLM Distillation — research paper leveraging the produced FinHeadlineMix dataset to derive distillation scaling laws
- Build Efficient Financial Data Workflows with AI Model Distillation — companion blog
- How to Build License-Compliant Synthetic Data Pipelines — related reading
関連記事
今日のまとめ
AI日報で今日の重要ニュースをまとめ読み