Hub Python 库文档

管理你的 Space

Hugging Face's logo
加入 Hugging Face 社区

并获得增强的文档体验

开始使用

管理你的 Space

在本指南中,我们将了解如何使用 huggingface_hub 管理你的 Space 运行时(secrets硬件存储)。

一个简单的例子:配置 secrets 和硬件。

这是一个端到端的示例,用于在 Hub 上创建和设置 Space。

1. 在 Hub 上创建一个 Space。

>>> from huggingface_hub import HfApi
>>> repo_id = "Wauplin/my-cool-training-space"
>>> api = HfApi()

# For example with a Gradio SDK
>>> api.create_repo(repo_id=repo_id, repo_type="space", space_sdk="gradio")

1. (bis) 复制一个 Space。

如果你想从现有的 Space 构建而不是从头开始,这将证明非常有用。如果你想控制公共 Space 的配置/设置,它也很有用。有关更多详细信息,请参阅 duplicate_space()

>>> api.duplicate_space("multimodalart/dreambooth-training")

2. 使用你首选的解决方案上传你的代码。

这是一个示例,将你机器上的本地文件夹 src/ 上传到你的 Space

>>> api.upload_folder(repo_id=repo_id, repo_type="space", folder_path="src/")

在此步骤中,你的应用程序应该已经在 Hub 上免费运行了!但是,你可能希望使用 secrets 和升级的硬件进一步配置它。

3. 配置 secrets 和变量

你的 Space 可能需要一些 secret 密钥、令牌或变量才能工作。有关更多详细信息,请参阅 文档。例如,一个 HF 令牌,用于在你从 Space 生成后将图像数据集上传到 Hub。

>>> api.add_space_secret(repo_id=repo_id, key="HF_TOKEN", value="hf_api_***")
>>> api.add_space_variable(repo_id=repo_id, key="MODEL_REPO_ID", value="user/repo")

Secrets 和变量也可以被删除

>>> api.delete_space_secret(repo_id=repo_id, key="HF_TOKEN")
>>> api.delete_space_variable(repo_id=repo_id, key="MODEL_REPO_ID")
在你的 Space 中,secrets 可以作为环境变量使用(如果使用 Streamlit,则为 Streamlit Secrets Management)。无需通过 API 获取它们!
你的 Space 配置(secrets 或硬件)的任何更改都将触发你的应用程序重启。

奖励:在创建或复制 Space 时设置 secrets 和变量!

Secrets 和变量可以在创建或复制 Space 时设置

>>> api.create_repo(
...     repo_id=repo_id,
...     repo_type="space",
...     space_sdk="gradio",
...     space_secrets=[{"key"="HF_TOKEN", "value"="hf_api_***"}, ...],
...     space_variables=[{"key"="MODEL_REPO_ID", "value"="user/repo"}, ...],
... )
>>> api.duplicate_space(
...     from_id=repo_id,
...     secrets=[{"key"="HF_TOKEN", "value"="hf_api_***"}, ...],
...     variables=[{"key"="MODEL_REPO_ID", "value"="user/repo"}, ...],
... )

4. 配置硬件

默认情况下,你的 Space 将在 CPU 环境中免费运行。你可以升级硬件以在 GPU 上运行它。需要支付卡或社区资助才能访问升级你的 Space。有关更多详细信息,请参阅 文档

# Use `SpaceHardware` enum
>>> from huggingface_hub import SpaceHardware
>>> api.request_space_hardware(repo_id=repo_id, hardware=SpaceHardware.T4_MEDIUM)

# Or simply pass a string value
>>> api.request_space_hardware(repo_id=repo_id, hardware="t4-medium")

硬件更新不会立即完成,因为你的 Space 必须在我们的服务器上重新加载。在任何时候,你都可以查看你的 Space 正在哪个硬件上运行,以查看你的请求是否已满足。

>>> runtime = api.get_space_runtime(repo_id=repo_id)
>>> runtime.stage
"RUNNING_BUILDING"
>>> runtime.hardware
"cpu-basic"
>>> runtime.requested_hardware
"t4-medium"

你现在有了一个完全配置的 Space。确保在你完成使用后将你的 Space 降级回“cpu-classic”。

奖励:在创建或复制 Space 时请求硬件!

升级的硬件将在你的 Space 构建完成后自动分配给它。

>>> api.create_repo(
...     repo_id=repo_id,
...     repo_type="space",
...     space_sdk="gradio"
...     space_hardware="cpu-upgrade",
...     space_storage="small",
...     space_sleep_time="7200", # 2 hours in secs
... )
>>> api.duplicate_space(
...     from_id=repo_id,
...     hardware="cpu-upgrade",
...     storage="small",
...     sleep_time="7200", # 2 hours in secs
... )

5. 暂停和重启你的 Space

默认情况下,如果你的 Space 在升级的硬件上运行,它将永远不会停止。但是,为了避免被计费,你可能希望在你不使用它时暂停它。这可以使用 pause_space() 完成。暂停的 Space 将处于非活动状态,直到 Space 的所有者重新启动它,可以使用 UI 或通过 API 使用 restart_space()。有关暂停模式的更多详细信息,请参阅 此部分

# Pause your Space to avoid getting billed
>>> api.pause_space(repo_id=repo_id)
# (...)
# Restart it when you need it
>>> api.restart_space(repo_id=repo_id)

另一种可能性是为你的 Space 设置超时时间。如果你的 Space 处于非活动状态的时间超过超时时长,它将进入睡眠状态。任何访问你 Space 的访客都将重新启动它。你可以使用 set_space_sleep_time() 设置超时时间。有关睡眠模式的更多详细信息,请参阅 此部分

# Put your Space to sleep after 1h of inactivity
>>> api.set_space_sleep_time(repo_id=repo_id, sleep_time=3600)

注意:如果你正在使用“cpu-basic”硬件,则无法配置自定义睡眠时间。你的 Space 将在不活动 48 小时后自动暂停。

奖励:在请求硬件时设置睡眠时间

升级的硬件将在你的 Space 构建完成后自动分配给它。

>>> api.request_space_hardware(repo_id=repo_id, hardware=SpaceHardware.T4_MEDIUM, sleep_time=3600)

奖励:在创建或复制 Space 时设置睡眠时间!

>>> api.create_repo(
...     repo_id=repo_id,
...     repo_type="space",
...     space_sdk="gradio"
...     space_hardware="t4-medium",
...     space_sleep_time="3600",
... )
>>> api.duplicate_space(
...     from_id=repo_id,
...     hardware="t4-medium",
...     sleep_time="3600",
... )

6. 向你的 Space 添加持久存储

你可以选择你选择的存储层来访问在你的 Space 重启后仍然存在的磁盘空间。这意味着你可以像使用传统硬盘驱动器一样从磁盘读取和写入。有关更多详细信息,请参阅 文档

>>> from huggingface_hub import SpaceStorage
>>> api.request_space_storage(repo_id=repo_id, storage=SpaceStorage.LARGE)

你也可以删除你的存储,永久丢失所有数据。

>>> api.delete_space_storage(repo_id=repo_id)

注意:一旦授予你的 Space 存储层,你就无法降低它。要这样做,你必须先删除存储,然后请求新的所需层。

奖励:在创建或复制 Space 时请求存储!

>>> api.create_repo(
...     repo_id=repo_id,
...     repo_type="space",
...     space_sdk="gradio"
...     space_storage="large",
... )
>>> api.duplicate_space(
...     from_id=repo_id,
...     storage="large",
... )

更高级:临时升级你的 Space!

Spaces 允许很多不同的用例。有时,你可能希望在特定的硬件上临时运行 Space,做一些事情,然后关闭它。在本节中,我们将探讨如何利用 Spaces 按需微调模型。这只是解决这个特定问题的一种方法。它必须被视为一个建议,并根据你的用例进行调整。

假设我们有一个 Space 来微调模型。这是一个 Gradio 应用程序,它将模型 ID 和数据集 ID 作为输入。工作流程如下:

  1. (提示用户输入模型和数据集)
  2. 从 Hub 加载模型。
  3. 从 Hub 加载数据集。
  4. 在数据集上微调模型。
  5. 将新模型上传到 Hub。

步骤 3 需要自定义硬件,但你不希望你的 Space 一直在付费 GPU 上运行。一种解决方案是动态请求硬件进行训练,然后在之后关闭它。由于请求硬件会重启你的 Space,因此你的应用程序必须以某种方式“记住”它当前正在执行的任务。有很多方法可以做到这一点。在本指南中,我们将看到一种使用数据集作为“任务调度器”的解决方案。

应用骨架

以下是你的应用程序的样子。在启动时,检查是否已计划任务,如果已计划,则在正确的硬件上运行它。完成后,将硬件设置回免费计划 CPU,并提示用户执行新任务。

这样的工作流程不支持像普通演示那样的并发访问。特别是,当训练发生时,界面将被禁用。最好将你的仓库设置为私有,以确保你是唯一用户。
# Space will need your token to request hardware: set it as a Secret !
HF_TOKEN = os.environ.get("HF_TOKEN")

# Space own repo_id
TRAINING_SPACE_ID = "Wauplin/dreambooth-training"

from huggingface_hub import HfApi, SpaceHardware
api = HfApi(token=HF_TOKEN)

# On Space startup, check if a task is scheduled. If yes, finetune the model. If not,
# display an interface to request a new task.
task = get_task()
if task is None:
    # Start Gradio app
    def gradio_fn(task):
        # On user request, add task and request hardware
        add_task(task)
        api.request_space_hardware(repo_id=TRAINING_SPACE_ID, hardware=SpaceHardware.T4_MEDIUM)

    gr.Interface(fn=gradio_fn, ...).launch()
else:
    runtime = api.get_space_runtime(repo_id=TRAINING_SPACE_ID)
    # Check if Space is loaded with a GPU.
    if runtime.hardware == SpaceHardware.T4_MEDIUM:
        # If yes, finetune base model on dataset !
        train_and_upload(task)

        # Then, mark the task as "DONE"
        mark_as_done(task)

        # DO NOT FORGET: set back CPU hardware
        api.request_space_hardware(repo_id=TRAINING_SPACE_ID, hardware=SpaceHardware.CPU_BASIC)
    else:
        api.request_space_hardware(repo_id=TRAINING_SPACE_ID, hardware=SpaceHardware.T4_MEDIUM)

任务调度器

调度任务可以通过多种方式完成。这是一个示例,说明如何使用存储为数据集的简单 CSV 完成此操作。

# Dataset ID in which a `tasks.csv` file contains the tasks to perform.
# Here is a basic example for `tasks.csv` containing inputs (base model and dataset)
# and status (PENDING or DONE).
#     multimodalart/sd-fine-tunable,Wauplin/concept-1,DONE
#     multimodalart/sd-fine-tunable,Wauplin/concept-2,PENDING
TASK_DATASET_ID = "Wauplin/dreambooth-task-scheduler"

def _get_csv_file():
    return hf_hub_download(repo_id=TASK_DATASET_ID, filename="tasks.csv", repo_type="dataset", token=HF_TOKEN)

def get_task():
    with open(_get_csv_file()) as csv_file:
        csv_reader = csv.reader(csv_file, delimiter=',')
        for row in csv_reader:
            if row[2] == "PENDING":
                return row[0], row[1] # model_id, dataset_id

def add_task(task):
    model_id, dataset_id = task
    with open(_get_csv_file()) as csv_file:
        with open(csv_file, "r") as f:
            tasks = f.read()

    api.upload_file(
        repo_id=repo_id,
        repo_type=repo_type,
        path_in_repo="tasks.csv",
        # Quick and dirty way to add a task
        path_or_fileobj=(tasks + f"\n{model_id},{dataset_id},PENDING").encode()
    )

def mark_as_done(task):
    model_id, dataset_id = task
    with open(_get_csv_file()) as csv_file:
        with open(csv_file, "r") as f:
            tasks = f.read()

    api.upload_file(
        repo_id=repo_id,
        repo_type=repo_type,
        path_in_repo="tasks.csv",
        # Quick and dirty way to set the task as DONE
        path_or_fileobj=tasks.replace(
            f"{model_id},{dataset_id},PENDING",
            f"{model_id},{dataset_id},DONE"
        ).encode()
    )
< > 更新 在 GitHub 上