History of hf_model_tree
The changes to the source code of this entry in the repository, newest first, each with the differences it made to the entry's files. They are also listed on GitLab.
[entries] Add the date when each entry was added, and remove icon_hash beff7c9
The dates are those of the commits that first added the entries' files (2020-08-11 for the entries of the initial commit); renamed entries keep the date of their first name. Changed: none
diff --git a/entries/hf_model_tree/__init__.py b/entries/hf_model_tree/__init__.py
index 930acca..10a4ad4 100644
--- a/entries/hf_model_tree/__init__.py
+++ b/entries/hf_model_tree/__init__.py
@@ -47,7 +47,7 @@ citation = [('E. Horwitz, N. Kurer, J. Kahana, L. Amar, Y. Hoshen, "Charting and
# The dataset card states no license (metadata of the public models of the
# Hub)
upstream_license = None
-icon_hash = None
+date_added = '2026-10-31'
# Hugging Face dataset at the commit of 2025-03-18
upstream_prefix = 'https://huggingface.co/datasets/Eliahu/ModelAtlasData/resolve/eb721eb09f8e212968a1251b2833c20dc39a6f72'
[entries] Prefix the properties in the descriptions with (Node), (Edge) or (Graph) bc3dbbd
The lists of properties at the end of the descriptions marked edge properties with "Edge" but left node properties unmarked, or grouped them in "Nodes: `a`, ...; `b`, ..." items, so the kind of a property was often unclear. Every item now starts with (Node), (Edge) or (Graph), followed by the property names, a colon and the explanation, one item per property or group of properties; qualifications (kinds of nodes, networks) follow the names in parentheses. Properties that were only named got a short explanation, and a few items that named the wrong kind of property were corrected.
diff --git a/entries/hf_model_tree/__init__.py b/entries/hf_model_tree/__init__.py
index 3ec3a60..930acca 100644
--- a/entries/hf_model_tree/__init__.py
+++ b/entries/hf_model_tree/__init__.py
@@ -27,8 +27,19 @@ The base models are those declared in the model cards (`base_model`), completed
The network has the following properties:
-- Nodes: `model_id`, the id of the model repository (`<author>/<name>`; its page is `https://huggingface.co/<model_id>`); `author`; `created`, the time of creation (Unix time; -1 if unknown); `last_modified`, the time of the last modification (Unix time; -1 if unknown); `downloads`, the number of downloads of the last 30 days, and `downloads_all_time` (-1 if unknown); `pipeline_tag`, the task of the model (e.g. `text-generation`); `license`; `architectures`, the model class (e.g. `LlamaForCausalLM`); `dataset`, a training dataset given in the tags (`unknown` if none); `tags`, the tags of the repository (as a Python list); `base_model_relation`, the relation of the model to its base models (`finetune`, `adapter`, `quantized`, `merge`, `finetune_adapter`, `finetune_quantized`; `source` for some original models; `unknown` if not declared; `unknown_readme_extracted` and `unknown_annotated` for base models extracted from the model card or annotated by the authors; `virtual_recovered` for virtual models; two values separated by a comma for the merged duplicates). Missing values are `unknown`, as in the data.
-- Edges: `relation`, the relation of the model to its base model (as `base_model_relation` of the model); `base_index`, the position of the base model in the list of base models of the model (from 0)."""
+- (Node) `model_id`: the id of the model repository (`<author>/<name>`; its page is `https://huggingface.co/<model_id>`).
+- (Node) `author`.
+- (Node) `created`: the time of creation (Unix time; -1 if unknown).
+- (Node) `last_modified`: the time of the last modification (Unix time; -1 if unknown).
+- (Node) `downloads`: the number of downloads of the last 30 days, and `downloads_all_time` (-1 if unknown).
+- (Node) `pipeline_tag`: the task of the model (e.g. `text-generation`).
+- (Node) `license`.
+- (Node) `architectures`: the model class (e.g. `LlamaForCausalLM`).
+- (Node) `dataset`: a training dataset given in the tags (`unknown` if none).
+- (Node) `tags`: the tags of the repository (as a Python list).
+- (Node) `base_model_relation`: the relation of the model to its base models (`finetune`, `adapter`, `quantized`, `merge`, `finetune_adapter`, `finetune_quantized`; `source` for some original models; `unknown` if not declared; `unknown_readme_extracted` and `unknown_annotated` for base models extracted from the model card or annotated by the authors; `virtual_recovered` for virtual models; two values separated by a comma for the merged duplicates). Missing values are `unknown`, as in the data.
+- (Edge) `relation`: the relation of the model to its base model (as `base_model_relation` of the model).
+- (Edge) `base_index`: the position of the base model in the list of base models of the model (from 0)."""
tags = ['Informational', 'Technological', 'Software', 'Online', 'Unweighted', 'Metadata']
url = ['https://huggingface.co/datasets/Eliahu/ModelAtlasData', 'https://horwitz.ai/model-atlas']
citation = [('E. Horwitz, N. Kurer, J. Kahana, L. Amar, Y. Hoshen, "Charting and Navigating Hugging Face\'s Model Atlas." arXiv:2503.10633 (2025)',
[entries] Remove unneeded code from the entries 2c69f19
Unneeded "global files" statements, unused imports and variables, f-strings without placeholders, duplicate keys in foodweb_little_rock (keeping the order and the values used), and the second definition of get_lines() in twitter_higgs. Nothing changes in the networks or descriptions. Changed: none
diff --git a/entries/hf_model_tree/__init__.py b/entries/hf_model_tree/__init__.py
index a724999..3ec3a60 100644
--- a/entries/hf_model_tree/__init__.py
+++ b/entries/hf_model_tree/__init__.py
@@ -58,7 +58,6 @@ def count(s):
@coerce_props()
@annotate()
def parse(alts=None):
- global files
name = __name__.split(".")[-1]
with open_upstream_file(name, files[0][0], "rb") as f:
d = pandas.read_csv(f, dtype=str, keep_default_na=False)
[entries] New entry: hf_model_tree d7940d3
diff --git a/entries/hf_model_tree/__init__.py b/entries/hf_model_tree/__init__.py
new file mode 100644
index 0000000..a724999
--- /dev/null
+++ b/entries/hf_model_tree/__init__.py
@@ -0,0 +1,102 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2026 Tiago de Paula Peixoto <tiago@skewed.de>
+#
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU Affero General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option) any
+# later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Affero General Public License along
+# with this program. If not, see <http://www.gnu.org/licenses/>.
+
+from .. import *
+import pandas
+import ast
+
+title = "Hugging Face model atlas (2025)"
+description = """The genealogy of the machine learning models on the Hugging Face Hub, as of March 11, 2025, from the "Model Atlas" of Horwitz, Kurer, Kahana, Amar and Hoshen. Each node is a model repository of the Hub (with weight files), and a directed edge from model u to model v means that v is a base model of u, i.e. that u was derived from v, e.g. by fine-tuning, as an adapter (e.g. LoRA), by quantization, or by merging several models. The network is a directed acyclic graph (mostly a forest of trees, since merged models have several base models).
+
+The base models are those declared in the model cards (`base_model`), completed by the authors with base models extracted from the texts of the model cards with regular expressions, and with over 1,000 manual annotations; they removed loops and self-loops, and the models without weight files. Base models that were removed from the Hub but are still referenced by other models are included as "virtual" models (relation `virtual_recovered`, without attributes). The data derive from the `hub-stats` dataset of Hugging Face. Thirteen models appear twice in the file, with different (annotated) base models; their rows are merged.
+
+The network has the following properties:
+
+- Nodes: `model_id`, the id of the model repository (`<author>/<name>`; its page is `https://huggingface.co/<model_id>`); `author`; `created`, the time of creation (Unix time; -1 if unknown); `last_modified`, the time of the last modification (Unix time; -1 if unknown); `downloads`, the number of downloads of the last 30 days, and `downloads_all_time` (-1 if unknown); `pipeline_tag`, the task of the model (e.g. `text-generation`); `license`; `architectures`, the model class (e.g. `LlamaForCausalLM`); `dataset`, a training dataset given in the tags (`unknown` if none); `tags`, the tags of the repository (as a Python list); `base_model_relation`, the relation of the model to its base models (`finetune`, `adapter`, `quantized`, `merge`, `finetune_adapter`, `finetune_quantized`; `source` for some original models; `unknown` if not declared; `unknown_readme_extracted` and `unknown_annotated` for base models extracted from the model card or annotated by the authors; `virtual_recovered` for virtual models; two values separated by a comma for the merged duplicates). Missing values are `unknown`, as in the data.
+- Edges: `relation`, the relation of the model to its base model (as `base_model_relation` of the model); `base_index`, the position of the base model in the list of base models of the model (from 0)."""
+tags = ['Informational', 'Technological', 'Software', 'Online', 'Unweighted', 'Metadata']
+url = ['https://huggingface.co/datasets/Eliahu/ModelAtlasData', 'https://horwitz.ai/model-atlas']
+citation = [('E. Horwitz, N. Kurer, J. Kahana, L. Amar, Y. Hoshen, "Charting and Navigating Hugging Face\'s Model Atlas." arXiv:2503.10633 (2025)',
+ 'https://arxiv.org/abs/2503.10633')]
+# The dataset card states no license (metadata of the public models of the
+# Hub)
+upstream_license = None
+icon_hash = None
+
+# Hugging Face dataset at the commit of 2025-03-18
+upstream_prefix = 'https://huggingface.co/datasets/Eliahu/ModelAtlasData/resolve/eb721eb09f8e212968a1251b2833c20dc39a6f72'
+files = [('models_for_model_atlas.csv', None, None)]
+
+def fetch_upstream(force=False):
+ return fetch_upstream_files(__name__.split(".")[-1], upstream_prefix, files,
+ force)
+
+def unix(s):
+ t = pandas.to_datetime(s.where(s != ""), format="%Y-%m-%d %H:%M:%S", utc=True)
+ return numpy.where(t.isna(), -1,
+ (t - pandas.Timestamp(0, tz="UTC")) // pandas.Timedelta(seconds=1)).astype("int64")
+
+def count(s):
+ return pandas.to_numeric(s, errors="coerce").fillna(-1).astype("int64").values
+
+@cache_network()
+@coerce_props()
+@annotate()
+def parse(alts=None):
+ global files
+ name = __name__.split(".")[-1]
+ with open_upstream_file(name, files[0][0], "rb") as f:
+ d = pandas.read_csv(f, dtype=str, keep_default_na=False)
+ bases = [ast.literal_eval(s) if s else [] for s in d.base_model]
+ rel = d.base_model_relation.values
+ # duplicated models: the first row is kept, with the relations of all rows
+ first = ~d.id.duplicated()
+ idx = {}
+ for i, m in enumerate(d.id):
+ if first.iat[i]:
+ idx[m] = len(idx)
+ rels = [[] for i in range(len(idx))]
+ edges = []
+ seen = set()
+ for i, m in enumerate(d.id):
+ u = idx[m]
+ if rel[i] not in rels[u]:
+ rels[u].append(rel[i])
+ for j, b in enumerate(bases[i]):
+ if (u, idx[b]) in seen:
+ continue
+ seen.add((u, idx[b]))
+ edges.append((u, idx[b], rel[i], j))
+ d = d[first]
+
+ g = Graph(directed=True)
+ g.add_vertex(len(d))
+ for col, pn in [("id", "model_id"), ("author", "author"),
+ ("pipeline_tag", "pipeline_tag"), ("license", "license"),
+ ("architectures", "architectures"), ("dataset", "dataset"),
+ ("tags", "tags")]:
+ g.vp[pn] = g.new_vp("string", vals=d[col].values)
+ g.vp.created = g.new_vp("int64_t", vals=unix(d.createdAt))
+ g.vp.last_modified = g.new_vp("int64_t", vals=unix(d.lastModified))
+ g.vp.downloads = g.new_vp("int64_t", vals=count(d.downloads))
+ g.vp.downloads_all_time = g.new_vp("int64_t", vals=count(d.downloadsAllTime))
+ g.vp.base_model_relation = g.new_vp("string", vals=[",".join(r) for r in rels])
+ g.ep.relation = g.new_ep("string")
+ g.ep.base_index = g.new_ep("int32_t")
+ g.add_edge_list(edges, eprops=[g.ep.relation, g.ep.base_index])
+ yield None, g