4,000万件のHN投稿・コメントを埋め込みマップで探索する
(blog.wilsonl.in)- Hacker Newsの公開APIから4,000万件超のアイテムを収集し、3,000万件超のコメントと400万件の投稿に埋め込み・メタデータ・本文を付与した検索・マップ・分析プロジェクトである
- タイトルだけを埋め込んでいた初期方式は、曖昧なタイトルやAsk HN/Show HNへの偏りのため限界があり、リンク先Webページの本文・上位コメント・コメントの祖先コンテキストをあわせて使う方式へ変わった
- 処理規模の拡大に伴い、RunPodの約150基のGPU、Rustのキューサービス、HTTP/2 DBプロキシ、UMAP、Canvasレンダリング、エッジサーバーを組み合わせ、モデル変更後は入力あたりの埋め込み時間が約600msから6msへ短縮された
- 検索ランキングは単純な文字列一致ではなく、コサイン類似度、HNスコア、時間重みをあわせて用い、意味的関連性・社会的シグナル・新しさを反映する
- 公開デモには2024年4月10日ごろまでのデータのみが含まれ、全データとコードはGitHubで公開されており、検索・推薦・ユーザー分析・リアルタイム更新実験に活用できる
プロジェクトの範囲と公開データ
- Hacker Newsのすべての投稿を意味空間に配置したマップを作り、検索・分析・可視化ツールをあわせて構築した
- テキスト埋め込みの実験が出発点であり、HNは選別されたコンテンツが多く、すべてのコンテンツをプログラムから取得できるため、適切なデータセットとして選ばれた
- 埋め込みはテキストを高次元空間上の点として表現し、絶対位置よりも点同士の相対距離が有用である
- 想定していた活用は3つだった
- HNに蓄積されたコンテンツに対する意味ベースの検索
- 関心領域に合わせたパーソナライズ推薦
- コミュニティ内のトピック別の感情、人気、反対意見の分析
- 3,000万件超のコメントと400万件の投稿がデータセットリリースとして公開された
- ID、スコア、投稿者などのメタデータを含む
- 埋め込みを含む
- コメント本文とクロールしたWebページ本文を含む
- コードはhackerverse GitHubリポジトリで公開されている
Hacker Newsデータ収集
- HNはシンプルな公開APIを提供しており、すべてのオブジェクトは
itemとして取得される maxitem.jsonは最大のIDを返し、執筆時点での最大IDは4,000万を超えている- 平均応答時間が10msでも、4,000万件を順次クロールすると4日以上かかるため、並列処理が必要だった
- Node.jsで高速な収集サービスを作ったが、セマフォとPromiseキュー方式ではCPU時間の大半がユーザー空間のJSコードに費やされ、遅かった
- その後、
worker_threadsAPIで全CPUにfetch処理を分散し、全コアを飽和させる方法で性能を改善した - 並列収集では順序が前後するため、中断時に欠落が生じないよう、完了マーカーをID順に記録した
- HN APIではいくつかの特性も観察された
- スコアは-1より下には下がらないように見える
- 投稿のダウンボート数とコメントの投票数は取得できない
- 一部の投稿とコメントは削除・フラグ状態でなくてもタイトル、本文、URLが空である
- コメントIDが祖先より小さい場合があり、コメントツリーの移動が原因の可能性がある
- HNクローラーは別のTypeScriptプロジェクトcrawler-toolkit-hnとしても切り出されている
最初の埋め込みとインフラ
- 当初は投稿タイトルだけでも意味表現として十分だと考え、埋め込みを生成した
- モデル比較にはMassive Text Embedding Benchmarkを参考にし、最初に選んだモデルはBGE-M3だった
- BGE-M3は一般的な密ベクトル埋め込みに加えてlexical weightsも生成でき、BM25のような方式と組み合わせたハイブリッド検索に使える
- 埋め込み生成インフラは単純ではなかった
- 優れたモデルは数百万から数十億のパラメータを持ちうる
- GPUのほうがはるかに効率的だが、GPUクラスターは高価である
- 推論に入力あたり数百msかかると、単一GPUで4,000万入力を処理するにはほぼ1年規模になる
- データ・サーバーとGPUが離れているため、GPUを遊ばせないようパイプラインを維持する必要があった
- RunPodを使ってデータセンターで稼働するGPUマシンをコンテナとして配備し、RTX 4090のような比較的安価なGPUを活用した
- GPUが世界中に分散しており、DB接続遅延と接続オーバーヘッドが問題になったため、db-rpcを作成した
- SQLクエリをHTTP/2経由でローカルDBへプロキシする
- 大きな共有コネクションプールを使う
- HTTP/2マルチプレキシングにより単一接続で複数クエリを処理する
- AWS SQSは数百万件の小さな作業メッセージでは低いスループット制限とメッセージごとのコスト負担が大きかったため、RocksDBベースのRustキューサービスqueuedを作成した
- 単一ノードで100K+ op/sを処理する
- バッチ化、メッセージサイズ、スループット制限、コスト負担を軽減する
- 約150基のGPUまで拡張した結果、4,000万件の投稿とコメントを数時間で埋め込んだ
- 当時の入力あたりの埋め込み時間は約600msで、GPU使用率は全時間を通して高い状態を維持した
Webページクロールによるコンテキスト強化
- タイトルだけを埋め込む方式では不十分だった
- 多くの投稿は変わっていたり、創造的だったり、曖昧だったりするタイトルを持つ
Ask HNとShow HNという文句がタイトル全体で大きな比重を占め、主題と無関係でも一緒にクラスタリングされる傾向があった
- テキスト投稿とコメントは自前の本文を使えばよいが、リンク投稿の大半はリンク先Webページをクロールする必要があった
- RustサービスでURLを取得し、HTMLからタイトル、画像、著者、本文テキストといったメタデータを解析した
- 初期のNode.js版はCPU集約的な処理でRust版より10倍遅く、Rustへの書き換えで性能を改善した
- テキスト抽出はscraperでHTMLを解析し、意味的に主要コンテンツではないHTML5要素を除去したうえで、残ったツリーを走査する方式だった
- リンク切れも大きな問題だった
- 約20万件のURLが404、DNS名前解決失敗、接続タイムアウトで失敗した
- これは400万ページのうち5%未満である
- 欠落を減らすため、Internet ArchiveのWayback APIで古い記事の一部を取得した
- Internet Archiveのレート制限は1分あたり約5件と非常に低かった
2回目の埋め込み戦略
- Webページは長文だが、BGE-M3は8192トークンのコンテキストウィンドウをサポートしている
- ただしBGE-M3は遅いため、jina-embeddings-v2-small-enへ切り替えた
- パラメータ数がはるかに少ない
- MTEB基準でも性能は良好である
- 推論時間は約6msまで減り、100倍高速化した
- 入力が長いため、バッチサイズを増やすとOOMが発生し、GPUを完全には飽和させられなかった
- テキストが少ない、または取得できなかったページを補うため、投稿の上位HNコメントを本文の後ろに追加した
- トップレベルコメントは
item.kidsがすでに順位付けされていると見なして使った - 削除、dead、負のスコアのコメントは除外した
- 入力は最大64KiBに制限した
- トップレベルコメントは
- コメントは単独では意味が不足することがあるため、祖先コメントや投稿タイトルまでさかのぼって、より長いコンテキストを構成した
- 埋め込みやテキストのような大きな値は別の
kvテーブルに保存した- 同じ行に保存すると行が肥大化する
- 小さなカラム更新でも高コストになる
- スキーマ変更も高コストになる
UMAPで2D意味マップを作る
- UMAPは、高次元埋め込みを低次元へ圧縮しつつ意味的な関係を保とうとする次元削減手法
- 1024次元の埋め込みベクトルを2Dの点に圧縮し、散布図や地図の可視化に使用
- UMAPにはPyNNDescentグラフと元の埋め込みを入力し、
metric="cosine"、n_components=2を使用 - 数百万件の高次元入力の学習には時間がかかるため、EC2の
c7i.metal-48xlVMを使用- 96コアのプロセッサを最大限活用
- 約1時間30分後に2D行列が生成
- 生成した2D埋め込みと学習済みのUMAPモデルを保存し、その後は新しい埋め込みも再学習なしで変換できるようにした
- 最初の散布図は点が多すぎたため、グリッドセルごとに最高スコアの投稿だけを選んで密度を下げ、タイトルを表示
- より多くの文脈を入れた2回目の埋め込みでは、タイトルだけでは判断しにくかった投稿も、関連コンテンツの近くにより正確に配置された
コサイン類似度と検索ランキング
- 埋め込み活用の核心は、2つの埋め込み間の類似度を見つけること
- テキスト埋め込みでは、一般的なユークリッド距離よりもコサイン距離・類似度がよく使われる
- コサイン距離は、大きさより方向が重要な場合に有用
- 長いX関連の議論は、長いY関連の議論よりXに近いべき
- 大きさを反映すると、このような関係が歪められる可能性がある
- 使用した中核計算は、埋め込み行列とクエリ埋め込みのdot product
- ベクトルが単位ベクトルなら、追加の大きさによる除算は不要
- 検索結果は純粋な類似度だけでは並べ替えない
- コサイン類似度は大きな要素だが、唯一の要素ではない
- HNスコアは社会的証拠として使われる
- 時間重みは、新しさが重要なクエリで古いコンテンツがすばやく下がるよう、
log(age)に比例する負の要素として反映される
ブラウザ地図アプリ
- 目標は、HN埋め込み空間をGoogle Mapsのように探索できるインタラクティブな地図にすることだった
- 求める動作は明確だった
- ピンチやマウスホイールで拡大すると、より多くの点が表示される
- 点どうしの間隔も広がる
- 一部の点にはラベルが付くが、すべてには付かない
- 点をクリックすると投稿の詳細が表示される
- モバイルとデスクトップの両方でタッチ・マウスをサポートする
- すべての点を一度にクライアントへ送るには数百万件もあり不適切だった
- 地図空間をグリッドタイルに分割し、クライアントが必要なタイルだけ取得する構成を採用
- タイルは
(x, y)座標で識別できる - S3のようなKVストアに保存できる
- サーバー側ロジックなしでデプロイしやすい
- タイルは
- ズームレベルはLOD方式で処理
- レベルごとに各軸を2倍多いグリッドセルへ分割
- 前のレベルで選ばれた点は次のレベルにもコピーし、拡大時に点が消えないようにした
- タイルサイズは圧縮後20KiB未満を目標にした
- 約1,500点に制限された
- 点ごとに
(x, y)で8バイト、IDで4バイト、スコアで2バイトを使用
- Webアプリのレンダリングでは、数千個のDOM要素を使う方式は性能を大きく損ねた
- 最終実装ではCanvasを使い、ビューポートが更新されるたびに再描画する方式を採用
- 毎フレーム数千個の点を描き直しても、滑らかでシンプルに動作した
- ラベリングは最高スコアの投稿を繰り返し選ぶが、既存ラベルと重なったら除外する
- 衝突判定にはRBushのR-tree実装を使用
- ラベル長はブラウザの
measureText()ではなく、タイトル長のバイト配列と調整済みの式で近似
- 初期ラベルボックスと衝突計算はCPU負荷が高いため、Web Workersへ移した
- OffscreenCanvasも試したが、レンダリングロジックがすでに十分効率的だったため大きな効果はなかった
地形、境界、都市ラベル
- 地図は点だけでは方向感覚や視覚的な面白さが乏しいため、地形と都市という概念を追加した
- 実際の地理や政治的境界はないので、地形は点の密度を表す比喩として扱った
- 点密度は、活動、関心、コンテンツ、参加、人気、議論が多い領域を素早く示すシグナルとして使われた
- 当初はKernel Density Estimationを検討したが、標準ライブラリでの試行は時間がかかりすぎた
- 代わりに各点を大きなグリッドセルにマッピングしてセルごとのカウントを作り、その後Gaussian blurを適用した
- 線形の密度値ではほとんどが0に近く見え、地図として見栄えがよくなかった
log(density + 1)を適用すると、はるかに自然な階層が生まれ、異なる密度レベルが接する場所が暗黙の境界のように見えた- 巨大な画像の代わりにSVGパスを生成し、クライアント側で多角形として描画するようにした
- 色は4色しかないので効率的
- 拡大しても境界が鮮明
- OpenCVのcontour関数でレベルごとの閉曲線を計算
- 都市ラベルは、特定半径内の共通テーマを表す
- 都市名は埋め込み化したうえで、保存済みのUMAPモデルにより
(x, y)位置を得る - 自動生成も試みた
- LLMで都市名を作ろうとしたが、望む出力をプロンプトで安定して得るのが難しかった
- K-meansでは、人がまとめそうな意味のあるクラスターをあまり見つけられなかった
- 最終的には地図を実際に探索しながらいくつかの都市を手動で書き込み、約1時間ほどかかった
エッジ配備と応答性
- 地図探索は高速で応答性が高くあるべきなので、データfetchの遅延を減らすことが重要だった
- 当初はすべての地図データをCloudflare R2のENAMリージョンに置いていたが、遅延は600msから数秒に達した
- 物理的な遅延が約200msでも、100msが即時反応のように感じられる閾値であることを考えると十分によくなかった
- 遅延を減らすため、データをユーザーの近くへ移した
- Virginia、San Jose、London、Sydneyに小規模サーバーを置き、Rustサーバーでデータを配信した
- クライアントは複数のエッジの
/healthzを数回呼び出し、最初に応答したサーバーを選ぶ - AnycastやCDNのような方法も可能だが、コストと過剰な複雑さのため使わなかった
- エッジサーバープロセスのメモリ使用量は元データの2〜4倍に膨らみ、疑問が残った
- 型の使い方が誤っている可能性
- struct padding
Vec、HashMapの過剰割り当て- メモリアロケータの断片化や非効率の可能性
意味検索結果と限界
- 「entering the tech industry」のようなシンプルなクエリでは、upvoteの多い結果とあまり注目されなかった結果が混ざって現れ、関連性と有用性は良好に見えた
- HNの既存検索サービスと比べると、意味埋め込み検索は文字どおり一致しなくても結果を見つけられる
- 「what happened to wework」のような質問形式のクエリでも、WeWorkのレイオフ、株価下落、破産など複数年にわたる結果を示した
- 検索結果は「what happened」という語を実際には含まなかったり、疑問文の形でなかったりしてもマッチする
- 一つの問題は、十分に近くない結果をフィルタリングしていないため、完全に無関係な下位結果が入り込むことだった
- これは修正しやすい問題として扱われている
- 「career growth」検索では、その語をそのまま含まない創造的で多様なエッセイが現れる
- HNのキュレーション品質とスコアは検索品質の向上に役立つ
- アプリには「linus rants」、「self bootstrapping」、「cool things with css」のようなクエリ提案がハードコードされている
仮想コミュニティとコメント分析
- 埋め込みを使って仮想サブコミュニティ機能を作れる
- ユーザーがコミュニティ名や説明を入力すると、一定の類似度しきい値を超える投稿がその場でまとめられる
- HNには投稿をさらに細分化する機能がないため、特定の関心事を中心にしたキュレーションを即座に作る方式である
- 結果カードのスニペットと画像は、Webクローラーが保存したページのメタデータから取得する
- サイトアイコンは複雑なメタデータ解析の代わりに、クライアント側でドメインの
/favicon.icoを取得する方式で簡略化した - コメントスレッドも同じ方式で表示できる
- コメントスコアはHN APIで提供されていないため、時系列順での並び替えしかできない
- コメントスコアなしでランキングする方法としては、ユーザーのコメント履歴、そのコメント周辺の参加状況、投稿、トピック、内容などを活用するやり方が考えられる
- 特定のトピックで影響力のある、または活発なユーザーを見つけることも可能である
- 「cloudflare」クエリでは
jgrahamcとeastdakotaが上位に現れる - 2人のユーザーはそれぞれCloudflareのCTOとCEOである
- 「cloudflare」クエリでは
- この作業はコメントを別途分類したりキーワード検索を使ったりせず、行列演算で処理される
- 事前フィルタリングより事後フィルタリングのほうが、通常はより速く十分である
- 事前フィルタリングでは埋め込み行列から対応する行を除去する必要があり、巨大なメモリコピーや遅い部分ベクトル化計算が必要になることがある
- まず類似した行を見つけ、その後で結果をフィルタリングするほうがよいと考えている
- 最小しきい値は重要である
- 無関係な項目でも類似度0.6程度になることがある
- しきい値がないと、コメント数が非常に多いユーザーが単純な規模のために順位を支配してしまう可能性がある
全コメントデータの感情・人気分析
- 3,000万件のコメントで試したかった大規模分析は人気と感情だった
- 目標は、HNが特定のトピックを時間の経過とともにどう感じているか、主要イベントが感情にどのような影響を与えるか、関心トピックがどう成長・衰退するかを見ることだった
- 感情データはなかったため、Hugging Faceのオープンソース感情分類モデルを使用した
- 選んだモデルはTweetEvalで、ソーシャルメディアコンテンツで学習されたモデルである
- TweetEvalは短いツイート向けのモデルなので、埋め込み時のように祖先コンテキストを付けず、コメント自体だけを入力として使用した
- コメントをキューに入れ、GPUクラスタで処理した後に結果を保存した
- モデルが小さいため、バッチサイズを増やしてGPU効率を高めた
- バッチサイズを増やすとVRAMをより多く使うが、ホスト-GPU間のメモリ転送を減らし、並列性を高められる
- Transformerモデルではバッチ入力が長方形である必要があるため、最も長い入力長に合わせてパディングされる
- 短い入力がいくつかある中に長い入力が1つ混ざると、全体の入力サイズと内部状態が大きく増えることがある
- このためメモリスパイクやOOMが発生することがある
- Rust感情分析の例では、Rustに対する肯定的感情が全体的に多かった
- Rust 1.0発表の前後にはポジティブなスパイクがあった
- より否定的な投稿は、モデル基準で否定的なコメントが多いことと相関していた
- 言語別の人気度もスコアと類似度を重み付けして推定した
- HNはコメントスコアを提供していないため、コメントスコアは使えない
- Rustは健闘しているが、他の言語ほど人気ではないように見えた
- 類似度しきい値は調整が必要かもしれず、結果が不正確な可能性がある
GPUによる大規模数値計算の高速化
- 分析クエリは32コアのマシンでも10〜30秒かかり、対話的な実験には遅かった
- インデックスや前処理を検討した末、ベクトル化された数値計算にGPUを使う方式へ切り替えた
- CuPyとcuDFは、それぞれNumPyとpandasに似たAPIを提供しつつGPU上で実行される
- ポーティングは比較的簡単で、クエリ時間は数百ms程度まで短縮された
- 速度が十分に速いため、ANNグラフも使っていない
- 難しかったのは大きな埋め込み行列をGPUに載せることだった
- コメント埋め込み行列は30M x 512の大きさである
- システムメモリやビデオメモリに行列を1倍分以上保持するのは難しかった
- 単純な読み込み方式ではコピーが複数作られる可能性がある
- ディスクからバイトを読む
- NumPy配列として読み込む
- CuPy配列に変換する
- GPUにコピーする
- この過程では合計4つのコピーができる可能性があり、そのうち3つはメモリ上にある
- 最終的な方式は、ディスク上の行列をメモリマップし、同じサイズの未初期化行列をGPU上に事前確保したうえで、チャンク単位でコピーするものだった
- この方式なら、先にPythonメモリへ読み込むことを避けられ、システムRAMとVRAMをそれぞれ正確に1倍分だけ使う
デモと次のステップ
- デモアプリはhn.wilsonl.inで提供されている
- メインページは地図と検索で、右上のボタンからコミュニティと分析ツールにアクセスできる
- コミュニティや分析結果のURLはクエリをURLに保存するため、他の人と共有できる
- デモ用データセットは2024年4月10日ごろで途切れており、最新のライブ投稿やコメントは含まれていない
- 今後さらに探ってみたいアイデアはいくつもある
- 継続的に最新状態へ更新されるライブデータ
- HNが選別したWeb上で動作するディープラーニングベースの推薦システム
- 再ランキング学習による検索結果の改善
- 地図上の興味深い経路とジャーニー
- ユーザー間の類似・対立関係の分析
- 特定のニッチで最も専門性の高いユーザーの分析
- 全体のデータとコードはGitHubで確認できる
2件のコメント
Hacker Newsでの意見
個人プロジェクトとしては特に印象的な取り組み
時間に伴う感情分析グラフが目を引いたし、Rustについてこういう形で見るのは初めてで興味深かった。時間が経つにつれて最もポジティブだったトピックは何だったのか、急に大きく落ち込んだトピックがあったのかも気になる
「HN全体にはネガティブな感情が多いようだ」という一文も、ソーシャルメディアについての体感としてはもっともらしく聞こえる。ソーシャルメディアのプラットフォーム別・時期別の感情比較も見られると面白そう
ネガティブな感情が目立ったのは、もともともっと明確な感情グラフを期待していたため。おおむね中立〜ポジティブで、ポジティブな投稿の周辺ではポジティブに、ネガティブな投稿の周辺ではネガティブに跳ねる形を予想していたが、ほぼすべてのクエリで感情はほとんど常にネガティブだった。ポジティブな投稿も、モデルとアプローチの基準では多くのネガティブさを引き寄せているように見えたし、どちらも間違っている可能性があるので、今後のブログ記事でもっと掘り下げたい
https://openpipe.ai/blog/hn-ai-crypto
根拠はないが、エンジニアは概して批判的で、ポジティブなフィードバックは繰り返し書くよりも+1を押す傾向がありそう。批判はより直接書くし :)
データエンジニアリング/MLOpsに慣れていない人にとって良い例
点に対してHDBSCANで階層的クラスタを作り、モデルで内部クラスタ名を生成する方法を提案する。そうすれば、現在のノードとのつながりに基づいて詳細項目を表示しながら、葉までトピックを探索しやすくなる
グループの色はもっとはっきりしているべきで、クラスタがあれば役立ちそう。個々の投稿のテキストサイズは、全体基準または現在の検索基準での重要度・関連度に応じて変わるべき。内部クラスタの要約がもっと多ければ、拡大するまでは複数の投稿をグループ要約で置き換えられるので、テキストの混雑も減る
https://docs.rapids.ai/api/cuml/stable/api/#clustering / https://developer.nvidia.com/blog/faster-hdbscan-soft-cluste...
地図をより明確にするという指摘も良いし、改善できる簡単なアプローチはかなり多いと思う。これもやることリストに追加した :)
プロジェクトの範囲が驚くほど大きい
ただ、jinaなのかbge-3/flagなのか、埋め込みとトークナイザが技術系トピックにはあまり合っていないように見える。自然言語の単語は問題ないが、「xaml」や「simd」のような技術概念を検索すると、入力をトークン化したうえで、似た響きの単語を拾おうとする方向に流れる
建設的なフィードバックとして、あまりにニッチなトピックで結果がないときに、同じ「HNランキング表」の結果を繰り返し表示しない方法があるとよさそう。埋め込みが慣れていない単語を検索すると、「Stephen Hawking has died」がよく出てくる
感情分析もどれだけうまく機能しているのか確信が持てない。現実に合わないほどネガティブ感情が多すぎるように見えたし、HNが圧倒的にポジティブに見るはずの「Mr Rogers」のようなものを探しても、激しいネガティブのピークが出る。「Carter」を検索すると、Rosalynn Carterの死去に関連して巨大なネガティブのピークがあるが、実際の記事はCarter夫妻が成し遂げた素晴らしいことについて語る投稿だった
「時間に伴う人気」は、その月/年の投稿の中央値投票数で補正する必要がありそう。単に投稿数を描くと、トレンド線が上がり続ける。「diesel」の人気を見ると意味が分かるが、この用語は10年前にピークを迎えている。あるいは投稿スコアではなく、キーワードの出現率や、クエリとのコサイン類似度指数がxより小さい項目数のような方法であるべきかもしれない
投稿をクリックして除外し、類似度しきい値を再計算する動的機能は素晴らしい
ほぼ同じことをどんなデータセットにもやってくれる優れたツールがある: https://github.com/enjalot/latent-scope
もちろん元記事のプロジェクトは規模のために興味深い複雑さが多く追加されており、このツールはその規模までは扱えないが、中規模のデータセットには良い
HNで自己宣伝が増えたのか分析してみたい
ここで自己宣伝は「Show HN: Something ...」ではなく、「Show HN: I ...」形式の投稿と定義する
現在の上位100件の中で、たとえば「Show HN: Exploring HN by mapping and analyzing 40M posts and comments for fun」「Show HN: Browser-based knitting (pattern) software」は自己宣伝タイトルではない。それぞれ主語が探索とソフトウェアだから
一方で「Show HN: I built a non-linear UI for ChatGPT」「Show HN: I created 3,800+ Open Source React Icons」は自己宣伝タイトルだ。それぞれの主語が「I」だから
Algoliaの検索結果で、4月1日から始まる各年について「Show HN: I」で始まるタイトルを単純に確認し、その年全体の結果数で割ってグラフにすると次のようになった
2023 ****************************************
2022 ***********************************
2021 ***************************
2020 **************************************
2019 *************************
2018 *************
2017 *******
2016 **********
2015 ********
2014 ************
2013 *********************
2012 *****************
2011 *********
2010 ***
自分が育った頃は、自己宣伝はだいたい悪い性格特性と見なされていた気がする。行動が自分を宣伝すべきであって、そこに注意を引くべきではないと教わったが、その文化が変わってきている感じがする
自己宣伝が実際に増えているなら、ソーシャルメディアなどの影響なのか気になる。YouTubeでも似た増加を感じるが、「I.....」で始まるおすすめ動画が多いという体感があるだけで、データはない
つまり、あなたが自己宣伝と非自己宣伝に分けたものは、私の基準では、タイトルが自己宣伝であることを非常に明確に示している場合と、それほど明確には示していない場合ということになる。ただし「Show HN」という文言自体が自己宣伝にだけ使われるようなので、「I」がなくても慣例を知っている人には自己宣伝だと分かる
どれも「見て、自分がすごいものを作ったんだけど、どう思う?」という意味だ
たとえば、ドイツ人がEinsteinを自己宣伝していると非難し、逆にアメリカにはセレブ文化があった、というような話だ。周期的な現象なのかもしれない
今年HNで見た投稿の中で、断然いちばんクールな投稿だと思う
最初に見たときは分かりにくかったが、実際のアプリはここにある: https://hn.wilsonl.in/
皮肉ではなく、良い考えだと思う
検索フレーズを単語ごとに埋め込んでいるのか、文書に使ったのと同じモデルを使っているのかも気になる。「lead generation」を検索したところ、きちんとした非単一語の埋め込みなら理解すべき表現なのに、鉛中毒の結果が出てきた
UMAPの現代的な推奨としてParametric UMAPがある: https://umap-learn.readthedocs.io/en/latest/parametric_umap....
小さなKeras MLPを学習させ、UMAP損失を最小化しながら2次元への次元削減を行う。利点は、このモデルが小さいので保存して再利用でき、未知の新しいデータにも予測できることだ。従来の学習済みUMAPモデルは大きい。またGPUを使うため、理論上は学習がはるかに速い
欠点は、PythonのUMAPパッケージの実装があまり良くなく、拡張された全ノード/エッジのデータセットをGPU上に作って押し込む点だ。そのため、メモリ不足になる前に約10万個の埋め込みまでしか学習できない
UMAP → HDBSCAN → AIによるクラスタラベリングへと続く完全な教師なしパイプラインが非常に有用なので、よりスケール可能なParametric UMAP実装を作ってみたくなる
探索的な趣味プロジェクトに見えるものとしては、驚くほど大規模な作業です。成果をけなすつもりはなく、本当に素晴らしいのですが、投入量の大きさに驚きました
埋め込み計算だけのために150基のGPUを使い、サーバー間通信のために db-rpc と queued という2つのカスタムシステムを開発しています。周辺作業や計算もかなりありました
このプロジェクトの文脈が気になります。こうした研究に必要な資金と時間をどう確保したのかも気になります
似たようなことを専門的に多くやってきた立場から言うと、学術論文や特許のランドスケープをマッピングしたことがありますが、150基のGPUが本当に必要だったのかはよく分かりません。結局、2次元への投影とクラスタリングなのであれば、従来のバッグ・オブ・ワーズやトピックモデリングのほうがはるかに簡単で安価で、品質差もほとんど感じられないように思います。投稿者とコメントスレッドのグラフを使っても、似た結果は得られるはずです
GPUは意外と安く、ほとんどは私に忍耐力がなかったのでスケールさせただけです :) クラスタ全体も数時間しか動かしていません
取り組まれた作業へのリンクがあれば見てみたいです。面白そうなので、もっと読んでみたいです
資金と時間の面では、次の仕事や職場の合間にいて、以前のキャリアや事業で経済的に成功し、自費で進めた可能性があります。GPUの利用効率も非常に高いので、費用はそれほど大きくなかったように思います
こうした埋め込みに確率校正SVMのような古典的機械学習を適用すると、分類とクラスタリングで良い結果が得られ、速度はLLMのファインチューニングより100倍以上速いです
通常はこのデモのようにはせず、ベクトルを正規化します
正規化されたベクトルを使う場合、ユークリッド距離は2つのベクトルの終点間の距離を測ります。一方、コサイン距離は一方のベクトルをもう一方のベクトルに射影した長さを測ります
正規化された2次元ベクトルは、実際には1次元ベクトルにすぎません。2次元の関係を示したいなら、自由度を再び2つ確保するために3次元ベクトルを使う必要があります
タイトルが抜けていますね