Установите JupyterLab и PyTorch на GPU-сервер
Чтобы запустить JupyterLab на GPU-сервере, установите его вместе со сборкой PyTorch для CUDA или ROCm в виртуальное окружение Python, настройте службу systemd, которая запускает JupyterLab с паролем на 127.0.0.1:8888, и откройте его в браузере через SSH-туннель. Jupyter-ноутбуки при этом выполняются на GPU сервера, и ни один порт не доступен из интернета. Если при заказе вы выбрали JupyterLab на шаге «ПО», он уже установлен; это руководство описывает, как установить и запустить его самостоятельно.
Выполняйте команды от имени root в Ubuntu 22.04 или 24.04, кроме шагов, где вы переключаетесь на alice — обычного пользователя из руководства Ваш первый час на новом GPU-сервере. Никогда не запускайте JupyterLab от имени root: его ноутбуки и терминал получают права пользователя, от имени которого он работает. Сначала установите драйвер GPU (Драйверы NVIDIA и CUDA; на AMD MI355X — ROCm на MI355X). На NVIDIA в заголовке вывода nvidia-smi должно быть CUDA Version 13.0 или выше: wheel-пакеты PyTorch содержат собственные библиотеки CUDA, а программы для CUDA 13.x работают на драйверах серии 580 и новее (заметки о выпуске CUDA).
adduser alice # пропустите, если alice уже существует
usermod -aG render,video alice # только для AMD MI355X
su - alice
# от имени alice: uv, затем Python 3.13 в отдельном окружении
curl -LsSf https://astral.sh/uv/install.sh | sh
~/.local/bin/uv venv --python 3.13 --seed --managed-python ~/jupyter-env
source ~/jupyter-env/bin/activate
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu132 # NVIDIA
# pip install torch torchvision --index-url https://download.pytorch.org/whl/rocm7.14 # AMD MI355X
pip install jupyterlab
python -c "import torch; print(torch.cuda.is_available(), torch.cuda.device_count())"
Команды для PyTorch — те, что приводит pytorch.org для версии 2.14.1 (проверено 20 октября 2026 г.). На любом GPU NVIDIA используйте сборку для CUDA 13.2, а не вариант CUDA 12.6, который селектор на сайте тоже предлагает: поддержка Blackwell появилась в PyTorch 2.7 вместе со сборками для CUDA 12.8. Команда pip install jupyterlab из руководства по установке JupyterLab заодно устанавливает ipykernel, поэтому ядро Python 3 по умолчанию работает в этом окружении и с этим PyTorch. Подходящие GPU — на страницах об исследованиях и о дообучении.
Запустите JupyterLab как службу systemd
Служба запускается при загрузке системы и перезапускается после сбоя. Сначала задайте пароль — всё ещё от имени alice. Jupyter Server хранит только хеш пароля — в файле ~/.jupyter/jupyter_server_config.json:
jupyter server password # спросит пароль дважды и запишет хеш
exit # вернуться к root
От имени root разместите ноутбуки и кэш Hugging Face на NVMe-диске для данных в /data (Хранилище и данные), затем создайте юнит:
mkdir -p /data/notebooks /data/hf
chown alice:alice /data/notebooks /data/hf
tee /etc/systemd/system/jupyterlab.service >/dev/null <<'EOF'
[Unit]
Description=JupyterLab
After=network.target
[Service]
User=alice
WorkingDirectory=/data/notebooks
Environment=HF_HOME=/data/hf
ExecStart=/home/alice/jupyter-env/bin/jupyter-lab --no-browser --ip=127.0.0.1 --port=8888 --port-retries=0 --notebook-dir=/data/notebooks --MappingKernelManager.cull_idle_timeout=7200
NoNewPrivileges=yes
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now jupyterlab
ss -tln | grep 8888 # 127.0.0.1:8888 и больше ничего
journalctl -u jupyterlab -f # журнал; Ctrl-C прекращает отслеживание
--ip=127.0.0.1оставляет сервер на loopback-адресе. С--port-retries=0он завершается с ошибкой, если порт 8888 занят, а не переходит на один из 50 следующих портов, так что ваш туннель никогда не ведёт на неверный порт.cull_idle_timeout=7200завершает ядра, простаивающие два часа без подключённого браузера, и тем самым освобождает память GPU, занятую забытыми ноутбуками; ядра, которые выполняют код, не завершаются (параметры Jupyter Server).NoNewPrivileges=yesне даёт ничему, что запущено из JupyterLab, повысить привилегии через setuid-программы вродеsudo: административные задачи выполняйте в своей SSH-сессии.
Если пароль не задан, Jupyter Server при каждом запуске создаёт новый случайный токен и записывает в журнал URL для входа с этим токеном; от имени root этот URL также выводит команда su - alice -c '~/jupyter-env/bin/jupyter server list'.
Откройте JupyterLab через SSH-туннель
На своём компьютере пробросьте локальный порт на loopback-адрес удалённого сервера, затем откройте http://localhost:8888 и войдите со своим паролем:
ssh -N -L 8888:127.0.0.1:8888 gpu1
# порт 8888 на вашем компьютере уже занят, например локальным Jupyter
ssh -N -L 8889:127.0.0.1:8888 gpu1 # затем откройте http://localhost:8889
gpu1 — это запись host из раздела Доступ по SSH; если добавить в неё строку LocalForward, туннель будет открываться при каждом подключении. В Windows та же команда работает в PowerShell. Если закрыть браузер или туннель, ваши ядра продолжат работать.
Никогда не запускайте JupyterLab с --ip=0.0.0.0 и никогда не открывайте порт 8888 в файрволе: любой, кто получит доступ, сможет выполнять код и открыть терминал от имени alice. Для команды используйте JupyterHub (см. ниже). В Docker публикуйте порт как -p 127.0.0.1:8888:8888, потому что правила портов Docker обходят ufw (см. Контейнеры).
Проверьте в Jupyter-ноутбуке, что PyTorch видит GPU
Откройте ноутбук с ядром Python 3 (ipykernel) и выполните:
import torch
print(torch.__version__, "CUDA:", torch.version.cuda, "HIP:", torch.version.hip)
print("GPUs:", torch.cuda.device_count(), torch.cuda.is_available())
for i in range(torch.cuda.device_count()):
free, total = torch.cuda.mem_get_info(i)
print(i, torch.cuda.get_device_name(i), f"{free / 2**30:.0f} of {total / 2**30:.0f} GiB free")
print(torch.cuda.get_arch_list()) # MI355X: в списке должен быть gfx950
x = torch.randn(8192, 8192, device="cuda")
print((x @ x).sum().item()) # умножение матриц на GPU 0
Ожидаемый вывод: версия, оканчивающаяся на +cu132 или +rocm7.14, True и по одной строке на каждый GPU с его названием и памятью. Сборка для ROCm использует те же интерфейсы torch.cuda, поэтому этот код без изменений работает и на MI355X (семантика HIP). Если is_available() возвращает False, выполните в терминале nvidia-smi или amd-smi list и вернитесь к руководству по драйверу.
Пакеты из ноутбука устанавливайте командой %pip install <package>: она запускает pip в текущем ядре (магические команды IPython), поэтому пакеты попадают в ~/jupyter-env.
Выбирайте GPU для каждого Jupyter-ноутбука и следите за памятью GPU
Ядро видит все GPU, если его не ограничить. Задайте CUDA_VISIBLE_DEVICES в первой ячейке, до import torch; чтобы изменить значение, перезапустите ядро. Или зарегистрируйте отдельное ядро для каждого GPU — тогда переменная задаётся ещё до запуска ядра:
import os
os.environ["CUDA_VISIBLE_DEVICES"] = "1" # это ядро видит только GPU 1, под именем cuda:0
import torch
# от имени alice: добавляет в список ядро Python (GPU 1)
source ~/jupyter-env/bin/activate
python -m ipykernel install --user --name gpu1 --display-name "Python (GPU 1)" --env CUDA_VISIBLE_DEVICES 1
Номера соответствуют порядку в выводе nvidia-smi, а видимые GPU нумеруются заново с 0 (переменные окружения CUDA). На MI355X используйте HIP_VISIBLE_DEVICES (ROCm на MI355X). Та же команда, запущенная из другого окружения, добавляет в качестве ядра это окружение (установка ядра).
Чтобы найти ядро, которое занимает память GPU, выполните в терминале:
nvidia-smi # в таблице процессов — каждый PID и его память GPU
amd-smi process -G # AMD MI355X: PID, имя процесса, память
ps -o pid,etime,args -p <pid> # ядра ноутбуков — это процессы ipykernel_launcher
В самом ноутбуке:
print(torch.cuda.memory_allocated() / 2**30, torch.cuda.memory_reserved() / 2**30) # ГиБ в тензорах, ГиБ зарезервировано
print(torch.cuda.memory_summary())
del model # удалите то, что больше не нужно
torch.cuda.empty_cache() # верните неиспользуемую память из кэша
Кэширующий аллокатор PyTorch удерживает освобождённую память для повторного использования, а nvidia-smi и amd-smi показывают её как занятую. empty_cache() освобождает эту неиспользуемую часть, но не трогает память, которую ещё занимают тензоры (управление памятью). Чтобы освободить всю память, перезапустите ядро. Если закрыть ноутбук, его ядро продолжит работать и занимать память: завершайте ядра на вкладке Running в левой боковой панели, где перечислены запущенные ядра и терминалы (документация JupyterLab).
Длительное обучение без прерываний
Ядра переживают закрытие браузера, но не остановку самого JupyterLab. Останавливаясь, Jupyter Server завершает свои ядра, а systemd убивает все процессы, оставшиеся в контрольной группе службы (KillMode). Поэтому при перезапуске службы, обновлении, перезагрузке или сбое переменные и модели в памяти теряются; файлы ноутбуков остаются в последнем сохранённом виде.
Всё, что длится часами, запускайте как скрипт вне JupyterLab и сохраняйте чекпоинты в /data. Команда jupyter nbconvert --to script превращает ноутбук в скрипт на Python; удалите из него магические команды вроде %pip, которые работают только в Jupyter (nbconvert). Затем от имени root запустите скрипт как временную (transient) службу systemd:
su - alice -c 'cd /data/notebooks && ~/jupyter-env/bin/jupyter nbconvert --to script train.ipynb'
systemd-run --unit=train --uid=alice --working-directory=/data/notebooks \
-E CUDA_VISIBLE_DEVICES=0 -E HF_HOME=/data/hf \
/home/alice/jupyter-env/bin/python -u train.py
journalctl -u train -f # следить за выводом; Ctrl-C не останавливает запуск
systemctl stop train # остановить запуск
systemctl reset-failed train # после неудачного запуска освобождает имя
Такой запуск переживает завершение SSH-сессии и перезапуски JupyterLab, но не перезагрузку сервера, а -u отключает буферизацию вывода Python, поэтому журнал всегда актуален. Подойдёт и tmux (Доступ по SSH). Чтобы продолжить после прерывания, возобновите обучение с последнего чекпоинта, как в руководстве Дообучение LLM с LoRA и QLoRA.
Альтернатива: JupyterLab в Docker
Сначала установите Docker и NVIDIA Container Toolkit (Контейнеры). Официальные Jupyter Docker Stacks публикуют варианты pytorch-notebook для CUDA; тегам cuda13- нужен драйвер серии 580 или новее. Перед запуском остановите службу, созданную выше, или опубликуйте другой порт хоста, например 127.0.0.1:8890:8888:
mkdir -p /data/work && chown 1000 /data/work # UID 1000 — это jovyan, пользователь в образе
docker run -d --name jupyter --gpus all --restart unless-stopped \
-p 127.0.0.1:8888:8888 \
-v /data/work:/home/jovyan/work \
quay.io/jupyter/pytorch-notebook:cuda13-2026-10-19
docker logs jupyter 2>&1 | grep token # URL для входа
Тег с датой фиксирует все версии; cuda13-latest следует за новыми сборками. При замене контейнера сохраняется только /home/jovyan/work. Образ PyTorch из NVIDIA NGC тоже содержит JupyterLab (4.6.3 в выпуске 26.09): запускайте его с теми же параметрами --gpus all и -p 127.0.0.1:8888:8888 и командой jupyter lab --ip=0.0.0.0 --no-browser --allow-root. Порт, опубликованный на 127.0.0.1, доступен только с самого хоста (публикация портов в Docker), поэтому 0.0.0.0 внутри контейнера не открывает доступ извне. GPU-варианты Docker Stacks собраны для CUDA: на MI355X используйте установку без Docker, описанную выше.
Несколько пользователей: JupyterHub, а не общий JupyterLab
Один сервер JupyterLab — это один пользователь. Каждый, у кого есть пароль, работает от имени alice, с теми же файлами, правами и GPU, а документация Jupyter Server предупреждает, что команды нескольких человек на одном сервере могут конфликтовать и перезаписывать друг друга (запуск публичного сервера).
Чтобы у каждого была своя учётная запись, используйте JupyterHub — многопользовательский хаб, который запускает для каждого человека отдельный однопользовательский сервер, управляет этими серверами и проксирует к ним запросы. По умолчанию пользователи входят под своими локальными учётными записями Unix. The Littlest JupyterHub собирает его в готовый дистрибутив для групп до 100 пользователей на одном сервере. Следуйте его документации: в ней сказано, что в каждом развёртывании нужно включить HTTPS, а для этого требуется доменное имя, направленное на сервер. Пользователи одного сервера всё равно делят его GPU: договоритесь, кто какими GPU пользуется, или выделите каждому свой сервер.
Сделайте резервную копию Jupyter-ноутбуков до окончания срока
Если аренда не продлена, сервер останавливается в конце оплаченного месяца, а его диски очищаются. За несколько дней до даты окончания скопируйте с сервера ноутбуки, созданные вами данные и чекпоинты вместе со списком пакетов, по которому можно воссоздать окружение:
su - alice -c '~/jupyter-env/bin/pip freeze > /data/notebooks/requirements.txt'
# с вашего компьютера
rsync -avhP gpu1:/data/notebooks/ ./notebooks/
На следующем сервере окружение воссоздаёт команда pip install -r requirements.txt --extra-index-url https://download.pytorch.org/whl/cu132 (на MI355X — rocm7.14). Большие датасеты и чекпоинты отправляйте в объектное хранилище через rclone, как показано в разделе Хранилище и данные.
Нужна помощь с этим руководством?
Расскажите нам о своём GPU, командах, которые вы выполнили, и результате, который получили, через форму обратной связи.
