Перейти к содержимому

Обучение моделей на молекулах, спектрах, сигналах и эпизодах робота

Обучите rdkit-property, peak-cnn, signal-cnn и episode-model на ответах вашего исследования и покажите предсказания разметчикам, чтобы они приняли или исправили их.

Новое в v2.14.0

Этот учебник обучает четыре модели на научной разметке в исследовании Potato. rdkit-property отвечает на вопрос о молекуле, peak-cnn выбирает пики на спектрах ЯМР, ИК, КР, УФ-видимой области и масс-спектрах, signal-cnn определяет стадии сна по эпохам или отмечает размеченные интервалы на записях ЭЭГ, ЭКГ и датчиков, а episode-model отмечает фазы, исход и кривую награды эпизода робота. Страница предназначена для команд, которые уже размечают молекулы, спектры, сигналы или эпизоды робота в Potato и хотят, чтобы модель разметила предварительными метками оставшиеся объекты. Для каждого тренера на странице есть конфигурация, проходящая potato validate config.yaml --strict, описание того, чему учится запуск, оценка на отложенных объектах, которую нужно прочитать, и то, как предсказания попадают к разметчикам. Обучите первую модель проходит страницу Training на примере текстового классификатора, и этот учебник опирается на то прохождение.

Четыре тренера

Каждый тренер учится на ответах одной схемы разметки и читает вход модели из отображения или из файла, на который указывает схема:

ТренерСхемаВходУстановкаГлавная оценка на отложенных объектах
rdkit-propertyradio, select, likert или slider о молекулеполе отображения molecule или ответ chemical_structurepotato-annotation[chemistry]макро-F1 или точность точной позиции для слайдера
peak-cnnpeak_pickingспектры из JCAMP-DX, mzML, CSV или встроенных данныхpotato-annotation[train-vision]F1 пиков в пределах допуска
signal-cnninterval_label в режиме epoch или freeсигналы из EDF, BDF, WFDB, CSV, Parquet или встроенных данныхpotato-annotation[train-vision], а для WFDB и Parquet ещё [signals]макро-F1 по эпохам или F1 интервалов при IoU 0.5
episode-modelepisode_annotationэпизоды робота из LeRobot, HDF5 или манифеста эпизодов Potatopotato-annotation[train-vision]макро-F1 по фазам

rdkit-property обучает модель scikit-learn, а остальные три тренера обучают небольшие сети PyTorch на устройстве, которое выбирает model_training.device. Каждый запуск обучается на одной схеме, оценивает модель на отложенных объектах val и test этого запуска и записывает предсказания обратно только для схем, перечисленных в writeback.schemas. Объекты из выборки train в запуске никогда не получают предварительной метки. peak-cnn, signal-cnn и episode-model сохраняют контрольную точку той эпохи, которая дала лучшую оценку на val, поэтому Potato берёт оценку на отложенных объектах для этих трёх сетей из test. В небольшом исследовании мало тестовых объектов, а метрика запуска test_n показывает число, на котором держится оценка.

Три сети придают предсказанию объекта уверенность наименее надёжной части предсказания, то есть самого слабого пика, интервала, фазы или исхода. Поэтому порог writeback.min_confidence отсеивает объект целиком, если какая-либо одна часть оказалась ниже порога. У предсказания слайдера от rdkit-property нет значения уверенности, и оно всегда проходит порог.

Свойства молекул с rdkit-property

rdkit-property учится ответам на вопрос о молекуле, которую показывает объект, а входом модели служит структура молекулы, а не текст объекта. Каждая структура превращается в отпечаток Моргана с радиусом 2 и 2048 битами, за которым следуют 2D-дескрипторы RDKit, например молекулярная масса и logP. При радиусе 2 отпечаток Моргана соответствует ECFP4, то есть отпечатку расширенной связности с диаметром 4 связи. Логистическая регрессия по умолчанию обучается на ответе radio, select или likert, а гребневая регрессия на ответе slider. Случайный лес служит альтернативой для обоих. Установите RDKit на сервере, который обучает:

bash
pip install "potato-annotation[chemistry]"

Конфигурация ниже показывает каждое соединение как рисунок структуры и задаёт два вопроса, слайдер от 1 до 10 о том, насколько трудно получить соединение, и выбор да или нет о том, получать ли соединение следующим:

yaml
annotation_task_name: "Compound triage"
task_dir: .
output_annotation_dir: annotation_output
data_files: [data/molecules.jsonl]
item_properties: {id_key: id, text_key: note}
user_config:
  allow_all_users: true
 
instance_display:
  fields:
    - key: smiles                 # SMILES, a molfile, or a .mol, .sdf or .smi file
      type: molecule
      label: "Compound"
 
annotation_schemes:
  - annotation_type: slider
    name: synthesis
    description: "How hard would this compound be to make? 1 is one step from a catalog reagent, 10 is a research project."
    min_value: 1
    max_value: 10
    starting_value: 5
    step: 1
  - annotation_type: radio
    name: advance
    description: "Would you make this compound next?"
    labels: ["yes", "no"]
 
model_training:
  enabled: true
  writeback:
    schemas: [synthesis, advance]
    include_unlabeled: true
    min_confidence: 0.6

Каждая строка файла данных содержит одно соединение:

json
{"id": "cpd_023", "smiles": "CC(=O)Nc1ccc(O)cc1", "note": "Compound 23"}

Тренер берёт структуру из первого поля molecule в instance_display. Исследование без поля molecule может задавать вопрос рядом со схемой chemical_structure, и тогда тренер учится на структуре, которую нарисовали разметчики. Когда разметчики нарисовали разные структуры, тренер берёт самый частый рисунок, а когда никто не рисовал, берёт структуру, с которой стартовал редактор (prefill_field). Страница Training предлагает rdkit-property для поля molecule, когда это поле заполнено не менее чем у 80% объектов. Структура, которую RDKit не может разобрать, исключается из обучения, не получает предсказания и учитывается в метрике запуска n_unparseable. Для вопроса с выбором или шкалой Ликерта страница Training предлагает также текстовые тренеры, потому что у объектов всё равно есть текст.

Предсказание слайдера округляется до step слайдера и удерживается между min_value и max_value, поэтому модель всегда предлагает позицию, которая есть у слайдера. Главная оценка для слайдера это точность точной позиции, которая считает предсказание 6 при ответе 7 ошибочным. Прочитайте val_mae или test_mae, среднюю абсолютную ошибку, рядом с точностью, прежде чем решать, достаточно ли близки предсказания, чтобы их показывать. Для запуска нужно не менее 10 размеченных молекул в выборке train. Параметры вроде model, class_weight, radius и bits задаются в поле Parameters страницы Training или в запросе к API:

bash
curl -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
  http://localhost:8000/admin/training/api/runs \
  -d '{"trainer": "rdkit-property", "schemas": ["advance"],
       "params": {"model": "random_forest", "class_weight": "balanced"}}'

Журнал запуска называет число молекул, число признаков и модель. Сбалансированный вес классов сильнее учитывает редкие ответы. Используйте class_weight: balanced, когда большинство соединений получает один и тот же ответ. Когда запуск завершён, разметчик, который открывает неразмеченное соединение, видит слайдер на значении модели и выбранный вариант модели, оба редактируемые.

Пики на спектрах с peak-cnn

peak-cnn учится выбирать пики по ответам peak_picking, которые дали разметчики. Тренер читает спектр, который показывает viewer_field схемы, теми же читателями, что использует отображение спектров. Обучающая цель это каждый пик, который разметчик оставил, то есть и принятые подсказки, и добавленные пики. Подсказка, которую разметчик отклонил, отмечает место без пика. Модель предсказывает только положения пиков, а разметчики по-прежнему дают каждому пику отнесение, метку или мультиплетность. Установите PyTorch на машине, которая обучает:

bash
pip install "potato-annotation[train-vision]"

Конфигурация ниже просит разметчиков проверять предложенные пики на спектрах 1H ЯМР:

yaml
annotation_task_name: "1H NMR peak picking"
task_dir: .
media_directory: media
output_annotation_dir: annotation_output
data_files: [data/spectra.jsonl]
item_properties: {id_key: id, text_key: note}
user_config:
  allow_all_users: true
 
instance_display:
  fields:
    - key: spectrum
      type: spectrum
      label: "1H NMR"
      display_options:
        prepick:
          method: auto            # item peaks, then model, then file peak table, then detector
          prominence: 0.05
          max_peaks: 30
 
annotation_schemes:
  - annotation_type: peak_picking
    name: peaks
    description: "Accept or reject each suggested peak, and add any the suggestions missed"
    viewer_field: spectrum
    peak_fields:
      - name: assignment
        placeholder: "e.g. OCH2"
    require_review: true
    label_requirement: {required: true}
 
model_training:
  enabled: true
  trainer_params:
    peak-cnn:
      tolerance: 0.02             # ppm
  writeback:
    schemas: [peaks]
    include_unlabeled: true

Пики модели доходят до разметчиков только через настройку prepick отображения, а без prepick отображение вообще не показывает подсказок. При method: auto отображение предлагает сначала собственные peaks объекта, затем пики модели, затем таблицу пиков из файла, а затем пики, которые находит детектор. До первого запуска разметчики проверяют подсказки детектора, а после запуска те же объекты показывают пики модели без перезапуска. При method: model отображение показывает только пики модели. Используйте method: model, чтобы измерить, как часто разметчики принимают пики модели без примеси подсказок детектора. Каждый пик модели в списке отмечен "· model", отображение оставляет max_peaks самых уверенных, а принятый пик модели сохраняется с source: model.

Параметр tolerance задаёт, насколько далеко, в единицах оси x, предсказанный пик может отстоять от размеченного и всё же считаться найденным. Без tolerance запуск использует 0.5% диапазона x спектра, а 0.5% окна 1H в 12 м.д. составляют 0.06 м.д. При 400 МГц константа взаимодействия 7 Гц разделяет линии мультиплета на 0.0175 м.д. Допуск по умолчанию шире этого интервала, и конфигурация вместо него задаёт 0.02 м.д. Запуск оценивает точность, полноту и F1 по пикам, сопоставленным один к одному, начиная с ближайшего, и сообщает среднее смещение сопоставленных пиков. Пик, предсказанный на спектре, о котором разметчик сказал, что пиков нет, считается ложной тревогой. Для запуска нужно не менее 5 размеченных спектров в выборке train.

Каждый спектр передискретизируется до length точек, по умолчанию 4096, прежде чем сеть увидит спектр. Увеличьте length, когда пики уже, чем 1/length диапазона x, например на масс-спектре высокого разрешения. Чтение файлов mzML требует также дополнительного пакета spectra, как описывает страница отображения спектров.

Стадии сна и интервалы сигналов с signal-cnn

signal-cnn учится на ответах interval_label для физиологических записей и записей датчиков, таких как ЭЭГ, ЭКГ, ЭМГ и данные акселерометра. Сеть это небольшая модель InceptionTime, стопка параллельных сверток трёх ширин. Тренер читает каждую запись читателями отображения временных рядов, берёт каналы, которые называет отображение, передискретизирует каждый канал до rate (по умолчанию 100 Гц) и стандартизирует каждый канал. Установите PyTorch и дополнительный пакет signals для записей WFDB и Parquet:

bash
pip install "potato-annotation[train-vision,signals]"

Конфигурация ниже оценивает сон 30-секундными эпохами по ночной полисомнографии так, как человек-оценщик помечает каждую эпоху как бодрствование, N1, N2, N3 или REM:

yaml
annotation_task_name: "Sleep staging"
task_dir: .
media_directory: media
output_annotation_dir: annotation_output
data_files: [data/psg.jsonl]
item_properties: {id_key: id, text_key: note}
user_config:
  allow_all_users: true
 
instance_display:
  fields:
    - key: signal
      type: time_series
      label: "PSG"
      display_options:
        window: 30
        channels: ["EEG Fpz-Cz", "EOG", "EMG chin"]   # also the channels signal-cnn reads
 
annotation_schemes:
  - annotation_type: interval_label
    name: stage
    description: "Sleep stage of each 30-second epoch"
    signal_field: signal
    mode: epoch
    epoch_length: 30
    require_all_epochs: true
    label_requirement: {required: true}
    labels:
      - {name: W, key_value: "1"}
      - {name: N1, key_value: "2"}
      - {name: N2, key_value: "3"}
      - {name: N3, key_value: "4"}
      - {name: REM, key_value: "5"}
 
model_training:
  enabled: true
  writeback:
    schemas: [stage]
    include_unlabeled: true

Режим схемы mode задаёт задачу. В режиме epoch каждая размеченная эпоха служит одним обучающим примером, а модель размечает каждую эпоху новой записи. Последняя эпоха, у которой записано менее половины длины эпохи, не получает метки. Главная оценка на отложенных объектах это макро-F1 по размеченным эпохам. Макро-F1 придаёт редкой стадии вроде N1 тот же вес, что и N2. По умолчанию потеря при обучении взвешивает каждую стадию обратно частоте метки (balanced: true), и тогда эпоха N1 значит больше, чем эпоха N2. Каждая запись читается с каналами первой обучающей записи в том же порядке, а запись, в которой нет одного из обучающих каналов, получает прямую линию вместо отсутствующего канала. Отображение, которое не называет каналов, отдаёт тренеру все каналы, не более max_channels (16).

Режим free обучается вместо этого на отмеченных отрезках. Добавьте вторую схему interval_label с mode: free к тому же signal_field, чтобы отмечать артефакты или пробуждения:

yaml
  - annotation_type: interval_label
    name: artifacts
    description: "Mark artifacts"
    signal_field: signal
    mode: free
    labels:
      - {name: artifact, key_value: "a"}
      - {name: spike, key_value: "s", kind: event}

В режиме free сеть обучается на случайных 30-секундных фрагментах (window_s), размечает каждый 1-секундный кадр (frame_s), объединяет подряд идущие кадры с одной меткой в интервал и отбрасывает интервалы короче min_duration. Главная оценка это F1 интервалов, которая сопоставляет предсказанный интервал с размеченным с той же меткой при IoU 0.5. Точечные события вроде метки spike выше не обучаются и не предсказываются. Для запуска нужно не менее 3 размеченных записей в выборке train, а режиму epoch нужно ещё не менее двух разных меток в данных.

Интервалы модели появляются на записи как пунктирная предварительная разметка, в списке отмеченная "· from the model", и сохраняются, когда разметчик вносит первое изменение или нажимает "Keep these". Собственная разметка записи имеет приоритет. Файл EDF+ с гипнограммой показывает гипнограмму, а не интервалы модели, и то же относится к объекту с интервалами preannotation_field. Параметр схемы pre_annotations: false отключает оба вида.

Эпизоды робота с episode-model

episode-model учится трём слоям ответа episode_annotation, то есть фазам, исходу и кривой награды за прогресс. Вход модели это каждый числовой ряд, который записывает эпизод, например положения суставов и состояние захвата, по одной строке на кадр. Вход включает ряды, которые series_shown не выводит на экран, и не включает видео. Модель не может найти фазу, которая видна только на камере и не меняет измерений робота. Установите PyTorch, а также pyarrow для наборов LeRobot или h5py для демонстраций HDF5:

bash
pip install "potato-annotation[train-vision]"

Конфигурация ниже собирает все три слоя на демонстрациях взять и поставить, как описывает страница эпизодов робота:

yaml
annotation_task_name: "Robot episode review"
task_dir: .
media_directory: media
output_annotation_dir: annotation_output
data_files: [data/episodes.jsonl]
item_properties: {id_key: id, text_key: note}
user_config:
  allow_all_users: true
 
annotation_schemes:
  - annotation_type: episode_annotation
    name: episode_review
    description: "Mark the phases, judge the outcome, and draw the progress."
    source_field: episode
    layers: [phases, outcome, reward]
    phases:
      - {name: reach, key_value: "1"}
      - {name: grasp, key_value: "2"}
      - {name: transport, key_value: "3"}
      - {name: place, key_value: "4"}
      - {name: retract, key_value: "5"}
    outcomes: [success, partial, failure]
    failure_causes: [missed grasp, object slipped, collision]
    reward_range: [0.0, 1.0]
    series_shown: [gripper, wrist_force, shoulder_lift, elbow]
 
model_training:
  enabled: true
  writeback:
    schemas: [episode_review]
    include_unlabeled: true

Сеть пропускает ряды через свёртку в двунаправленную GRU с тремя выходами, по одному для фазы каждого кадра, для исхода эпизода и для награды на каждом кадре. Слой, который ответ оставляет пустым, исключается из потерь этого эпизода, поэтому эпизод, размеченный только исходом, всё равно обучает выход исхода. Выход исхода обучается, когда обучающие эпизоды включают не менее двух разных исходов. Выход награды обучается только на отрезке, где разметчик нарисовал кривую, потому что вне этого отрезка разметчик не дал ответа. Эпизоды длиннее max_frames (2000) обучаются на случайных фрагментах.

Предсказание имеет форму сохранённого ответа, с фазами из списка схемы, одним из исходов схемы и кривой награды из 50 точек внутри reward_range, для тех слоёв, которые показывает схема. Предсказание предзаполняет временную шкалу и сохраняется, когда разметчик правит шкалу. Причина сбоя и инструкция остаются разметчику. Главная оценка на отложенных объектах это макро-F1 по фазам на сетке 0.1 секунды. Запуск также сообщает F1 сегментов фаз при IoU 0.5, точность исхода и r Пирсона кривой награды там, где кривая была нарисована. Схема без фаз берёт главной оценкой точность исхода, а затем корреляцию награды. Для запуска нужно не менее 5 размеченных эпизодов в выборке train. В Potato нет тренера для rollout_evaluation, потому что предпочтение между прогонами сравнивает видео, а episode-model не читает видео.

Начало запуска и проверка результата

Перезапустите сервер после добавления model_training:

bash
potato start config.yaml -p 8000

Откройте /admin/training, выберите схему и тренер и нажмите Train now. Страница предлагает только тренеры, подходящие к каждой схеме, а тренер, который не установлен, показан как "not installed" вместе с командой установки. Когда запуск завершается, Potato показывает оценку на отложенных объектах в таблице Runs, а выборка и метрика указаны во всплывающей подсказке. Страница запуска перечисляет каждую метрику и выборку каждого объекта. Отчёт об обратной записи в GET /admin/training/api/status считает опубликованные предсказания и те, которые задержала каждая проверка, например n_skipped_low_confidence.

Предварительные метки привязывают разметчиков к ответу модели, поэтому включайте include_unlabeled в новом исследовании только после того, как оценка на отложенных объектах оправдывает показ ответов модели. Проверка предварительных меток модели в цикле рассматривает показ наименее уверенных предварительных меток первыми и переобучение на исправлениях, а Конфигурация перечисляет все ключи, бэкенды и проверки обратной записи.

Дополнительные материалы

Литература

  • Ismail Fawaz, H., Lucas, B., Forestier, G., Pelletier, C., Schmidt, D. F., Weber, J., Webb, G. I., Idoumghar, L., Muller, P.-A., and Petitjean, F. (2020). InceptionTime: Finding AlexNet for Time Series Classification. Data Mining and Knowledge Discovery, 34(6), 1936-1962. https://doi.org/10.1007/s10618-020-00710-y
  • Rogers, D., and Hahn, M. (2010). Extended-Connectivity Fingerprints. Journal of Chemical Information and Modeling, 50(5), 742-754. https://doi.org/10.1021/ci100050t