본문으로 건너뛰기

분자, 스펙트럼, 신호, 로봇 에피소드로 모델 학습하기

연구의 답으로 rdkit-property, peak-cnn, signal-cnn, episode-model을 학습시키고, 예측을 어노테이터에게 보여 주어 수락하거나 고치게 합니다.

v2.14.0의 새 기능

이 튜토리얼은 Potato 연구의 과학 어노테이션으로 모델 네 개를 학습시킵니다. rdkit-property는 분자에 대한 질문에 답하고, peak-cnn은 NMR, IR, 라만, UV-Vis, 질량 스펙트럼에서 피크를 고르고, signal-cnn은 수면 에포크를 단계로 나누거나 EEG, ECG, 센서 기록에서 레이블이 달린 구간을 표시하며, episode-model은 로봇 에피소드의 단계, 결과, 보상 곡선을 표시합니다. 이 페이지는 이미 Potato에서 분자, 스펙트럼, 신호, 로봇 에피소드에 어노테이션하고 있으며 나머지 항목에 사전 레이블을 달 모델이 필요한 팀을 위한 것입니다. 각 트레이너마다 potato validate config.yaml --strict를 통과하는 설정, 실행이 학습하는 것, 읽어야 할 홀드아웃 점수, 예측이 어노테이터에게 전달되는 방식을 설명합니다. 첫 모델 학습시키기는 텍스트 분류기로 Training 페이지를 안내하며, 이 튜토리얼은 그 안내를 읽었다고 전제합니다.

네 가지 트레이너

각 트레이너는 어노테이션 스키마 하나의 답으로 학습하며, 모델의 입력은 스키마가 가리키는 표시 필드나 파일에서 읽습니다.

트레이너스키마입력설치홀드아웃 대표 값
rdkit-property분자에 대한 radio, select, likert, slidermolecule 표시 필드 또는 chemical_structure 답potato-annotation[chemistry]macro-F1, 슬라이더는 정확한 위치 정확도
peak-cnnpeak_pickingJCAMP-DX, mzML, CSV 또는 인라인 데이터의 스펙트럼potato-annotation[train-vision]허용 오차 내 피크 F1
signal-cnn에포크 또는 자유 모드의 interval_labelEDF, BDF, WFDB, CSV, Parquet 또는 인라인 데이터의 신호potato-annotation[train-vision], WFDB와 Parquet에는 [signals]도에포크 macro-F1, 또는 IoU 0.5의 구간 F1
episode-modelepisode_annotationLeRobot, HDF5 또는 Potato의 에피소드 매니페스트의 로봇 에피소드potato-annotation[train-vision]단계 macro-F1

rdkit-property는 scikit-learn 모델을 학습시키고, 나머지 세 트레이너는 model_training.device가 고르는 장치에서 작은 PyTorch 네트워크를 학습시킵니다. 모든 실행은 스키마 하나로 학습하고, 실행의 홀드아웃 val과 test 항목으로 모델 점수를 매기며, writeback.schemas에 나열된 스키마에만 예측을 되씁니다. 실행의 train 분할에 있는 항목에는 사전 레이블이 달리지 않습니다. peak-cnn, signal-cnn, episode-model은 val에서 가장 높은 점수를 낸 에포크의 체크포인트를 유지하므로, Potato는 이 세 네트워크의 홀드아웃 점수를 test에서 가져옵니다. 작은 연구는 test 항목이 적으며, 실행의 test_n 지표가 점수의 바탕이 된 개수를 알려 줍니다.

세 네트워크는 항목의 예측에 그 예측에서 가장 불확실한 부분, 즉 가장 약한 피크, 구간, 단계 또는 결과의 신뢰도를 부여합니다. 따라서 writeback.min_confidence 기준은 어느 한 부분이라도 기준 아래로 떨어지면 항목 전체를 보류합니다. rdkit-property의 슬라이더 예측에는 신뢰도 값이 없으며 항상 기준을 통과합니다.

rdkit-property로 분자 성질 예측하기

rdkit-property는 항목이 보여 주는 분자에 대한 질문의 답을 학습하며, 모델의 입력은 항목의 텍스트가 아니라 분자의 구조입니다. 각 구조는 반지름 2, 2,048비트의 Morgan 지문이 되고, 그 뒤에 RDKit의 2D 기술자(예: 분자량과 logP)가 이어집니다. 반지름 2의 Morgan 지문은 결합 4개의 지름을 가진 확장 연결성 지문인 ECFP4와 같습니다. 기본적으로 로지스틱 회귀가 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"}

트레이너는 instance_display의 첫 molecule 필드에서 구조를 가져옵니다. molecule 필드가 없는 연구는 대신 chemical_structure 스키마 옆에 질문을 둘 수 있으며, 그러면 트레이너는 어노테이터가 그린 구조에서 학습합니다. 어노테이터마다 다른 구조를 그렸으면 트레이너는 가장 흔한 그림을 택하고, 아무도 그리지 않았으면 편집기가 시작한 구조(prefill_field)를 택합니다. Training 페이지는 항목의 80% 이상이 molecule 필드를 채우면 그 필드에 rdkit-property를 제공합니다. RDKit이 파싱하지 못하는 구조는 학습에서 제외되고 예측도 받지 못하며, 실행의 n_unparseable 지표에 집계됩니다. 선택 질문이나 리커트 질문에는 항목에 텍스트가 있으므로 Training 페이지가 텍스트 트레이너도 제공합니다.

슬라이더의 예측은 슬라이더의 step에 맞춰 반올림되고 min_value와 max_value 사이로 유지되므로, 모델은 항상 슬라이더에 있는 위치를 제안합니다. 슬라이더의 대표 점수는 정확한 위치 정확도이며, 답이 7인데 예측이 6이면 틀린 것으로 셉니다. 예측이 보여 줄 만큼 가까운지 판단하기 전에 정확도와 함께 평균 절대 오차인 val_mae 또는 test_mae를 읽으십시오. 실행에는 train 분할에 레이블이 달린 분자가 최소 10개 필요합니다. model, class_weight, radius, bits 같은 매개변수는 Training 페이지의 Parameters 필드나 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"}}'

실행 로그는 분자 수, 특징 수, 모델을 알려 줍니다. balanced 클래스 가중치는 드문 답을 더 무겁게 셉니다. 대부분의 화합물이 같은 답을 받을 때 class_weight: balanced를 사용하십시오. 실행이 끝나면 레이블이 없는 화합물을 여는 어노테이터는 슬라이더가 모델의 값으로 맞춰져 있고 모델의 선택이 선택되어 있는 것을 보며, 둘 다 편집할 수 있습니다.

peak-cnn으로 스펙트럼의 피크 고르기

peak-cnn은 어노테이터가 준 peak_picking 답에서 피크 고르는 법을 학습합니다. 트레이너는 스키마의 viewer_field가 보여 주는 스펙트럼을 스펙트럼 표시와 같은 리더로 읽습니다. 학습 목표는 어노테이터가 유지한 모든 피크이며, 수락한 제안과 추가한 피크가 모두 포함됩니다. 어노테이터가 거부한 제안은 피크가 없는 자리를 표시합니다. 모델은 피크 위치만 예측하며, 각 피크의 귀속, 레이블, 다중도는 여전히 어노테이터가 줍니다. 학습하는 머신에 PyTorch를 설치하십시오.

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

아래 설정은 어노테이터에게 1H NMR 스펙트럼에서 제안된 피크를 검토하도록 합니다.

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가 없으면 실행은 스펙트럼 x 범위의 0.5%를 쓰며, 12ppm 1H 창의 0.5%는 0.06ppm입니다. 400MHz에서 7Hz 결합은 다중선의 선들을 0.0175ppm 간격으로 나눕니다. 기본 허용 오차는 그 간격보다 넓으므로 설정에서는 대신 0.02ppm을 지정합니다. 실행은 가장 가까운 것부터 일대일로 짝지은 피크에 대해 정밀도, 재현율, F1을 계산하고 짝지은 피크의 평균 오프셋을 보고합니다. 어노테이터가 피크가 없다고 한 스펙트럼에 예측한 피크는 오경보로 셉니다. 실행에는 train 분할에 어노테이션된 스펙트럼이 최소 5개 필요합니다.

각 스펙트럼은 네트워크가 보기 전에 length개 점으로 리샘플링되며 기본값은 4,096입니다. 피크가 x 범위의 1/length보다 좁을 때(예: 고해상도 질량 스펙트럼) length를 높이십시오. mzML 파일을 읽으려면 스펙트럼 표시 페이지가 설명하는 대로 spectra extra도 필요합니다.

signal-cnn으로 수면 단계와 신호 구간 표시하기

signal-cnn은 EEG, ECG, EMG, 가속도계 데이터 같은 생리 및 센서 기록의 interval_label 답에서 학습합니다. 네트워크는 작은 InceptionTime 모델로, 폭이 세 가지인 병렬 합성곱을 쌓은 구조입니다. 트레이너는 시계열 표시의 리더로 각 기록을 읽고, 표시가 지정한 채널을 가져와, 각 채널을 rate(기본 100Hz)로 리샘플링하고, 각 채널을 표준화합니다. PyTorch를 설치하고, WFDB와 Parquet 기록에는 signals extra도 설치하십시오.

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

아래 설정은 사람 판독자가 각 에포크를 각성, N1, N2, N3, REM으로 레이블하는 방식대로, 야간 수면다원검사에서 30초 에포크 단위로 수면을 판독합니다.

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가 작업을 정합니다. 에포크 모드에서는 어노테이션된 각 에포크가 학습 예시 하나이며, 모델은 새 기록의 각 에포크에 레이블을 답니다. 기록된 길이가 에포크 길이의 절반 미만인 마지막 에포크에는 레이블이 달리지 않습니다. 홀드아웃 대표 값은 어노테이션된 에포크에 대한 macro-F1입니다. macro-F1은 N1 같은 드문 단계에 N2와 같은 가중치를 줍니다. 기본적으로 학습 손실은 각 단계를 레이블 빈도의 역수로 가중하므로(balanced: true), N1 에포크는 N2 에포크보다 더 크게 셉니다. 모든 기록은 첫 번째 학습 기록의 채널을 그 순서대로 사용해 읽으며, 학습 채널 중 하나가 없는 기록은 빠진 채널 자리에 평평한 선을 받습니다. 채널을 지정하지 않은 표시는 트레이너에게 max_channels(16)까지의 모든 채널을 줍니다.

자유 모드는 대신 표시된 구간으로 학습합니다. 아티팩트나 각성을 표시하려면 같은 signal_field에 mode: free인 두 번째 interval_label 스키마를 추가하십시오.

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}

자유 모드에서 네트워크는 무작위 30초 크롭(window_s)으로 학습하고, 1초 프레임(frame_s)마다 레이블을 달고, 같은 레이블이 이어지는 프레임을 하나의 구간으로 병합하고, min_duration보다 짧은 구간은 버립니다. 대표 값은 구간 F1이며, 예측한 구간을 같은 레이블의 어노테이션된 구간과 IoU 0.5에서 짝짓습니다. 위의 spike 레이블 같은 점 이벤트는 학습도 예측도 하지 않습니다. 실행에는 train 분할에 어노테이션된 기록이 최소 3개 필요하며, 에포크 모드에는 데이터에 서로 다른 레이블이 최소 두 개 있어야 합니다.

모델의 구간은 기록에 점선 사전 어노테이션으로 나타나며 "· from the model"과 함께 나열되고, 어노테이터가 처음 변경하거나 "Keep these"를 클릭하면 저장됩니다. 기록 자체의 어노테이션이 우선합니다. 수면 단계도(hypnogram)가 든 EDF+ 파일은 모델의 구간이 아니라 그 수면 단계도를 보여 주며, preannotation_field 구간이 있는 항목도 마찬가지입니다. 스키마에 pre_annotations: false를 설정하면 두 종류 모두 꺼집니다.

episode-model로 로봇 에피소드 분석하기

episode-model은 episode_annotation 답의 세 층, 즉 단계, 결과, 진행 보상 곡선을 학습합니다. 모델의 입력은 관절 위치와 그리퍼 상태처럼 에피소드가 기록하는 모든 수치 시리즈이며, 프레임마다 한 행입니다. 입력에는 series_shown이 화면에서 뺀 시리즈가 포함되고 비디오는 제외됩니다. 모델은 카메라에서만 보이고 로봇의 측정값은 바뀌지 않는 단계를 찾을 수 없습니다. PyTorch를 설치하고, LeRobot 데이터셋에는 pyarrow를, HDF5 데모에는 h5py를 함께 설치하십시오.

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(2,000)보다 긴 에피소드는 무작위 크롭으로 학습합니다.

예측은 저장된 답의 형태를 띠며, 스키마가 보여 주는 층에 대해 스키마 목록의 단계, 스키마의 결과 중 하나, reward_range 안의 50점 보상 곡선을 담습니다. 예측은 타임라인을 미리 채우며 어노테이터가 타임라인을 편집하면 저장됩니다. 실패 원인과 지시문은 어노테이터에게 맡깁니다. 홀드아웃 대표 값은 0.1초 격자에서의 단계 macro-F1입니다. 실행은 IoU 0.5의 단계 구간 F1, 결과 정확도, 곡선이 그려진 곳에서의 보상 곡선의 Pearson r도 보고합니다. 단계가 없는 스키마는 결과 정확도를 대표 값으로 삼고, 그다음 보상 상관을 씁니다. 실행에는 train 분할에 어노테이션된 에피소드가 최소 5개 필요합니다. 롤아웃 선호는 비디오를 비교하고 episode-model은 비디오를 읽지 않으므로, Potato에는 rollout_evaluation용 트레이너가 없습니다.

실행을 시작하고 결과 확인하기

model_training을 추가한 뒤 서버를 다시 시작하십시오.

bash
potato start config.yaml -p 8000

/admin/training을 열어 스키마와 트레이너를 고른 다음 Train now를 클릭하십시오. 이 페이지는 각 스키마에 맞는 트레이너만 제공하며, 설치되지 않은 트레이너는 설치 명령과 함께 "not installed"로 나열됩니다. 실행이 끝나면 Potato는 실행 표에 홀드아웃 점수를 나열하며, 분할과 지표는 툴팁에 나옵니다. 실행 페이지에는 모든 지표와 항목별 분할이 나열됩니다. 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