Not a member of GistPad yet?
Sign Up,
it unlocks many cool features!
- # Generation service: проверенный CPU-запуск и повторение на чистом pod
- ## Что было сделано и проверено
- 11 октября 2026 поднят локальный generation daemon на CPU с моделью `RT_ALTERNATIVE_TEXTS_GENERATION_BIBABOBA_FOUR_TITLES` из `~/models`. Использован бинарник prod-neuro application layer Sandbox 13662792630 и model config FOUR_TITLES из prod2 application layer 12691698810.
- В model config заменены GPU backend на CPU (1 backend), добавлено преобразование fp16 → fp32, batch_size=1, memory chunk=256 MiB, max_out_len=40, timeout=30 s и min_generation_time=1000 ms. Vocabulary `bpe.voc` извлечён из того же `model.npz`; ссылка на внешний YT vocabulary заменена на локальный файл. Сопоставление vocabulary с историческими байтами внешнего YT-объекта отдельно не проверялось.
- Модель реально загрузилась. `/ready`, `/v2/health/ready` и readiness модели вернули HTTP 200. Настоящий KServe inference вернул HTTP 200 примерно за 3.55 секунды. Ответ декодирован из UnitedNN protobuf/Base64 в текст. Это проверка загрузки и inference, а не качества/скорости production.
- REX/reloader не запускались, Deploy/stages/pods не изменялись. Веса и исходные архивы не менялись. Не использовалась dummy readiness. Локальный процесс оставлен на HTTP 18080.
- Модель по metadata: FOUR_TITLES, версия `2026-02-19T19:00:00`. Локальный repository номер `1` — технический номер версии, не версия production snapshot.
- ## Условия повторения
- Нужен чистый выделенный Linux x86_64 pod для диагностики, с writable диском, достаточной RAM и возможностью открыть TCP 18080. GPU/Docker для этого CPU-варианта не нужны. Нужны уже доступные `ya tool yt` со штатной авторизацией на чтение kolmogorov, Python 3, GNU tar, zstd, xz, sha256sum, md5sum и curl. Python-скрипты ниже используют только стандартную библиотеку; PyYAML/Arcadia checkout/пересборка не нужны. Если какого-то инструмента нет — используйте согласованный образ/способ установки; токены в команды не вставляйте.
- Сохранённый бинарник зависит от совместимого Linux/glibc/libstdc++; проверьте `ldd` до запуска. Архивы скачиваются целиком, поэтому оставьте достаточно диска для скачанных файлов, распакованного snapshot и daemon (размер daemon 6398274536 bytes).
- Допущение по просьбе владельца: нужная модель обязательно находится внутри `part_1/rephrase/archive.tar.xz` по пути `models/RT_ALTERNATIVE_TEXTS_GENERATION_BIBABOBA_FOUR_TITLES/`. Полное дерево этого архива на этапе написания инструкции не проверялось. Ниже её извлекает уже оператор чистого pod. Если путь/сумма не совпали — остановитесь, не подменяйте модель.
- ## 1. Новый рабочий каталог и скачивание ИЗ YT
- Все команды ниже выполнять на выделенном чистом pod; они создают только локальные рабочие файлы и диагностический сервер. Это не команды восстановления production.
- ```bash
- set -euo pipefail
- umask 077
- workdir=$(mktemp -d "$PWD/rephrase-generation-cpu.XXXXXXXX")
- cd "$workdir"
- YT_ROOT='//home/ads/users/npytincev/backup/runtime/part_1/rephrase'
- ARCHIVE='yabs-rephrase-generation-service-all-stages-configs-resources-2026-10-11.tar.zst'
- MODEL='RT_ALTERNATIVE_TEXTS_GENERATION_BIBABOBA_FOUR_TITLES'
- ya tool yt --proxy kolmogorov read-file "$YT_ROOT/generation/$ARCHIVE" >"$ARCHIVE"
- printf '%s %s\n' 'f342c573888a4fa57eab8c1c4213072ca1735f2bb2d5a7f5621ddb31567e479d' "$ARCHIVE" | sha256sum -c -
- printf '%s %s\n' '1d235f8f2918fdee61e707955828a0b1' "$ARCHIVE" | md5sum -c -
- ya tool yt --proxy kolmogorov read-file "$YT_ROOT/archive.tar.xz" >models.archive.tar.xz
- printf '%s %s\n' 'bd8374f2bec462d9cad0044bb410e621' 'models.archive.tar.xz' | md5sum -c -
- ```
- Архив сервиса: 14298411371 bytes. Архив моделей: 6628264024 bytes; MD5 взята из текущего YT-атрибута файла. Hash model.npz ниже соответствует весам, на которых выполнен успешный локальный запуск. При несовпадении считайте это другим/повреждённым артефактом и остановитесь.
- ## 2. Распаковка и выбор нужных артефактов
- Выполняется оператором только после проверки скачанных архивов:
- ```bash
- mkdir snapshot layer prod2-configs
- tar --zstd -tf "$ARCHIVE" >/dev/null
- tar --zstd -xf "$ARCHIVE" -C snapshot
- (cd snapshot && sha256sum -c SHA256SUMS)
- DAEMON_LAYER="$PWD/snapshot/sandbox/13662792630/payload/yabs-rephrase-transformer-service.layer.837ce4247535af89ac662d31b1863d21f5ced191.YABSRANKING-1111-cuda129-freeze.tar.zst"
- PROD2_LAYER="$PWD/snapshot/sandbox/12691698810/payload/yabs-rephrase-transformer-service.layer.e182ae2587bee4967621bf2df3c0a5850ad554eb.trunk.tar.zst"
- tar --zstd -xf "$DAEMON_LAYER" -C layer workloads/ml_inference/daemon
- tar --zstd -xf "$PROD2_LAYER" -C prod2-configs "workloads/ml_inference/model_configs/$MODEL/config.yaml"
- tar -xJf models.archive.tar.xz -C "$PWD" "models/$MODEL"
- printf '%s %s\n' 'ed16cb05521e31d9df5431f34073600ce90cb78b2c1dfb9de428e92d39134a1e' "models/$MODEL/model/model.npz" | sha256sum -c -
- chmod u+x layer/workloads/ml_inference/daemon
- ldd layer/workloads/ml_inference/daemon
- ./layer/workloads/ml_inference/daemon --help >daemon-help.txt
- ```
- Не запускайте deployment init/start scripts на обычном pod: они предполагают системные `/workloads`, `/rex` и другие пути. Здесь daemon запускается напрямую с абсолютными путями в отдельной рабочей папке.
- ## 3. Подготовка CPU repository и config
- Сохраните следующий Python-скрипт и выполните из того же workdir. Он повторно проверяет hash/metadata модели, извлекает vocabulary из имеющихся весов, создаёт symlink на локальные данные и адаптирует архивный config. Файлы исходной модели не изменяются. Известный старый setup_repo не используется: он создал неподходящее для нашей структуры дерево; repository здесь строится явно.
- ```bash
- cat >prepare.py <<'PY_PREPARE'
- from pathlib import Path
- import json,zipfile,hashlib
- b=Path.cwd().resolve();model='RT_ALTERNATIVE_TEXTS_GENERATION_BIBABOBA_FOUR_TITLES'
- dump=b/'models'/model/'model';weight=dump/'model.npz'
- h=hashlib.sha256()
- with weight.open('rb') as f:
- for chunk in iter(lambda:f.read(8*1024*1024),b''):h.update(chunk)
- assert h.hexdigest()=='ed16cb05521e31d9df5431f34073600ce90cb78b2c1dfb9de428e92d39134a1e','Wrong/corrupted weights; stop'
- meta=json.loads((b/'models'/model/'meta/meta.json').read_text())
- assert meta['model']['model_name']==model,meta['model']
- with zipfile.ZipFile(weight) as z:(b/'vocab-from-dump.model').write_bytes(z.read('bpe.voc'))
- config=(b/'prod2-configs/workloads/ml_inference/model_configs'/model/'config.yaml').read_text()
- changes=[(' gpu_backend:\n gpu_ids:\n - 0\n use_cublas_lt: true\n use_decoder_fused_attention: true\n',' cpu_backend:\n num_backends: 1\n convert_float16_to_float32: true\n'),(' batch_size: 32\n',' batch_size: 1\n'),(' host_mem_chunk_size_mi_b: 2048\n',' host_mem_chunk_size_mi_b: 256\n'),(' response_timeout_ms: 70\n',' response_timeout_ms: 30000\n'),(' min_generation_time_ms: 10\n',' min_generation_time_ms: 1000\n'),(' max_out_len: 100\n',' max_out_len: 40\n'),(' vocab:\n yt_path:\n path: //home/gena/vocabs/sp_20230413_128k_vital__1533_span_tokens.model\n cluster: hahn\n',' vocab:\n local_path: '+json.dumps(str(b/'vocab-from-dump.model'))+'\n')]
- for old,new in changes:
- assert old in config,'Unexpected source config, stop: '+old.splitlines()[0]
- config=config.replace(old,new,1)
- version=b/'repo'/model/'1';version.mkdir(parents=True)
- (version/'model').symlink_to(dump,target_is_directory=True)
- configs=b/'configs'/model;configs.mkdir(parents=True)
- for path in [version/'config.yaml',version/'model_config.yaml',version.parent/'config.yaml',configs/'config.yaml',configs/'model_config.yaml']:path.write_text(config)
- required='models:\n - name: '+model+'\n'
- (b/'required_models.yaml').write_text(required);(b/'repo/required_models.yaml').write_text(required)
- (b/'local.cfg').write_text('''ProgramConfig: {
- ServerConfig: { Port: 18080 RequestThreads: 2 }
- YtServerConfig { Port: 18080 InflightLimit: 4 ServiceName: "rephrase-local" }
- CPUConfig: { InfraVCPUGuarantee: 1000 }
- }
- RuntimeConfig: {
- InferencePoolSize: 1
- SharedBatcherConfig: { BatchingThreads: 1 }
- PinnedExecutorConfig: { MaxActiveInstances: 1 }
- ModelRepositoryConfig: { Path: '''+json.dumps(str(b/'repo'))+''' ConfigsPath: '''+json.dumps(str(b/'configs'))+''' }
- RequiredModelsManagerConfig: { ManagedByReloader: false ConfigPath: '''+json.dumps(str(b/'required_models.yaml'))+''' }
- }
- ''')
- request={'inputs':[{'name':'request','shape':[1],'datatype':'BYTES','data':['Переформулируй рекламное объявление. Оригинальное объявление: Магазин сантехники. Большой выбор, доставка по России. Запрос: купить смеситель. Переформулировка: ']}]}
- (b/'request.json').write_text(json.dumps(request,ensure_ascii=False,indent=2)+'\n')
- print('Prepared CPU repository from verified local dump:',meta['model'])
- PY_PREPARE
- python3 prepare.py
- ```
- Скрипт подготовки проверен на уже имеющихся файлах: полученные server/model configs совпадают с конфигурациями успешного запуска после замены абсолютного корня. End-to-end скачивание и запуск в новом pod не выполнялись; исходное успешное испытание использовало локально сохранённые артефакты.
- Структура после подготовки:
- ```text
- layer/workloads/ml_inference/daemon
- models/<MODEL>/model/model.npz
- models/<MODEL>/meta/meta.json
- repo/required_models.yaml
- repo/<MODEL>/config.yaml
- repo/<MODEL>/1/config.yaml
- repo/<MODEL>/1/model -> models/<MODEL>/model
- configs/<MODEL>/config.yaml
- vocab-from-dump.model
- required_models.yaml
- local.cfg
- request.json
- ```
- ## 4. Запуск
- В первом терминале из workdir:
- ```bash
- ulimit -c 0
- ./layer/workloads/ml_inference/daemon -c local.cfg -g 0 >daemon.stdout.log 2>daemon.stderr.log
- ```
- Это foreground-процесс. `-g 0` отключает gRPC. HTTP port — 18080; YT HTTP server в этой версии слушает wildcard address, поэтому запускайте в изолированном диагностическом pod, не публикуйте его как внешний endpoint. Monitoring exporter может открыть отдельный порт 3401.
- Из другого терминала перейдите в тот же workdir и проверьте:
- ```bash
- curl --fail --noproxy '*' http://127.0.0.1:18080/ready
- curl --fail --noproxy '*' http://127.0.0.1:18080/v2/health/ready
- curl --fail --noproxy '*' http://127.0.0.1:18080/v2/models/RT_ALTERNATIVE_TEXTS_GENERATION_BIBABOBA_FOUR_TITLES/ready
- curl --fail --noproxy '*' http://127.0.0.1:18080/v2/models/RT_ALTERNATIVE_TEXTS_GENERATION_BIBABOBA_FOUR_TITLES >metadata.json
- ```
- В логах должно быть `Loaded model successfully`, а readiness конкретной модели — HTTP 200. Readiness без реальной модели не засчитывается.
- ## 5. Настоящий inference и декодирование
- ```bash
- curl --fail --noproxy '*' --max-time 65 \
- -H 'Content-Type: application/json' --data-binary @request.json \
- ```
- Выход responses в этой версии имеет encoding=unitednn: JSON содержит Base64 protobuf, а не готовую строку. Следующий небольшой декодер извлекает CHAR values по offsets из tensor.proto (`yt/ml/unn/cpp_lib/tensor/serialization/proto/tensor.proto`). Он предназначен для этого проверенного ответа, не универсален для любых типов/батчей.
- ```bash
- cat >decode_response.py <<'PY_DECODE'
- import base64,json
- from pathlib import Path
- def varint(b,p):
- v=s=0
- while True:
- c=b[p];p+=1;v|=(c&127)<<s
- if c<128:return v,p
- s+=7
- if s>63:raise ValueError('Invalid varint')
- def fields(b):
- p=0;result={}
- while p<len(b):
- tag,p=varint(b,p);n=tag>>3;wire=tag&7
- if wire==0:v,p=varint(b,p)
- elif wire==2:
- size,p=varint(b,p);v=b[p:p+size];p+=size
- elif wire in (1,5):size=8 if wire==1 else 4;v=b[p:p+size];p+=size
- else:raise ValueError('Unsupported protobuf wire type')
- result.setdefault(n,[]).append(v)
- return result
- response=json.loads(Path('response.json').read_text());texts=[]
- for output in response['outputs']:
- if output.get('parameters',{}).get('encoding')!='unitednn':continue
- for encoded in output['data']:
- tensor=fields(base64.b64decode(encoded));header=fields(tensor[1][0]);values=fields(header[4][0]);assert values[3][0]==5,'Expected CHAR'
- offset=values.get(1,[0])[0];size=values[2][0];data=tensor[2][0]
- assert offset+size<=len(data)
- texts.append(data[offset:offset+size].decode('utf-8'))
- Path('decoded-response.txt').write_text('\n'.join(texts)+'\n');print('\n'.join(texts))
- PY_DECODE
- python3 decode_response.py
- ```
- В выполненном испытании модель выдала строку с несколькими вариантами, разделёнными `[SEP]`, например «Оригинальное объявление: магазин сантехники». Точный текст не обязан воспроизводиться побайтово; качество и формат production-запросов отдельно не проверялись.
- ## 6. Остановка и диагностика
- Остановка локального foreground-процесса — Ctrl+C в терминале запуска. Не используйте массовый pkill и не останавливайте существующие production workloads.
- - `Address already in use`: порт занят; найдите свой процесс, не убивайте чужой. После остановки дождитесь освобождения порта.
- - `Operation not permitted` при bind: runtime policy запрещает сокет; используйте согласованный pod/runtime с разрешённым локальным listener.
- - `bad model, should have ensemble or model config`: проверьте наличие именно `config.yaml` и сохранённые секции `model_config`/`backend_custom_config`; одного model_config.yaml в нашем случае не хватало.
- - Config parse error: в proto ServerConfig вложен в ProgramConfig. `Grpc` не является полем ServerConfig в этом бинарнике; используйте `-g 0`. Не задавайте одновременно InferencePoolSize и UseExternalPool: это один oneof.
- - Required-model manager ждёт модель: смотрите loader errors, symlink и путь к model.npz, а не включайте dummy readiness.
- - Ошибка library/ELF loader: сопоставьте ldd и совместимость Linux/glibc с сохранённым binary; текущий checkout не обязателен.
- - Проверка checksum не прошла: остановитесь и выясните происхождение артефакта; не обходите проверку.
- Не подменяйте FOUR_TITLES весами из папки NEURO: в исследованном локальном наборе metadata NEURO фактически описывала NEURO_USE_LINK. Другие модели не проверялись в этом запуске.
- Это диагностический CPU-вариант: prod-neuro binary + prod2 config + существующий dump FOUR_TITLES. Это не точное восстановление prod-neuro/prod2 stages и не гарантия качества production inference. Действия с Deploy, dctl put и восстановление файловых систем production pods этой инструкцией не предусмотрены.
RAW Paste Data
Copied
