저전력 자율 배포를 위한 위성 이상 대응 작업을 위한 인간 정렬 Decision Transformers
요약
저전력 위성 환경에서 인간의 의도와 정렬된 자율 의사결정을 수행하기 위한 Decision Transformers 활용 방안을 다룹니다. 극한의 연산 및 전력 제약 조건 하에서 시퀀스 모델링을 통해 위성 이상 상황에 대응하는 연구 과정을 기록했습니다.
핵심 포인트
- Decision Transformers를 활용한 제어 문제의 시퀀스 모델링
- 저전력/저사양 위성 온보드 환경에서의 머신러닝 최적화 필요성
- 인간의 의도와 에이전트 정책 간의 정렬(Alignment) 중요성
- 보상 형성 대신 시연 데이터를 통한 의사결정 학습
저전력 자율 배포를 위한 위성 이상 대응 작업을 위한 인간 정렬 Decision Transformers
우주급 AI를 향한 나의 학습 여정
깊은 밤이었고, 나는 한 시간 동안 세 번째로 충돌한 CubeSat 시뮬레이션의 텔레메트리 (telemetry) 플롯을 응시하고 있었습니다. 이상 현상—자세 제어 시스템 (attitude control system)에서의 예상치 못한 전력 급증—이 서브시스템 (subsystem) 실패의 연쇄 반응을 일으켰습니다. 지상 GPU에서 몇 주 동안 훈련된 나의 강화학습 (RL) 에이전트는 자이로스코프 (gyroscope)를 재설정할 것인지 태양광 패널 (solar array)의 출력을 조절할 것인지 우선순위를 정하지 못한 채 결정 도중 멈춰버렸습니다. 그 순간, 나는 몇 달 동안 씨름해 온 질문을 명확히 마주하게 되었습니다. 초 단위의 시간이 중요한 상황에서, 밀리와트 (milliwatt) 단위의 전력 예산 하에 인간의 의도와 정렬된 (human-aligned) 결정을 내릴 수 있는 위성용 AI 시스템을 어떻게 구축할 것인가? 이 글은 그 여정에 대한 이야기입니다. Decision Transformers에 대한 탐구, 이상 대응을 위한 적응, 그리고 인간 정렬 (human alignment)이 단순한 윤리적 체크박스가 아니라 자율 우주 시스템을 위한 전력 최적화 전략이라는 발견에 대한 기록입니다.
핵심 문제: 극한의 제약 조건 하에서의 의사 결정
위성 이상 대응은 매우 독특한 영역입니다. 페타바이트 (petabytes) 급의 데이터와 킬로와트 (kilowatts) 급의 연산 능력을 갖춘 클라우드 기반 AI 시스템과 달리, 저궤도 (LEO)의 위성은 100 MHz ARM Cortex-M4 프로세서, 256 KB의 RAM, 그리고 모든 온보드 (onboard) 처리를 위한 0.5와트의 전력 예산을 가질 수 있습니다. 지상 관제소에서 새로운 정책 (policy)을 업로드하는 전통적인 방식은 5~15분의 왕복 지연 시간 (round-trip latency)이 발생하며, 이는 열 폭주 (thermal runaway)나 추진제 누출 (propulsion leaks)과 같은 이상 현상 상황에서는 치명적입니다. 우주 애플리케이션을 위한 온보드 머신러닝 (onboard machine learning)을 연구하면서, 나는 핵심 과제가 단순히 올바른 결정을 내리는 것이 아니라, 최소한의 연산으로 인간이 의도한 결정을 내리는 것이라는 점을 깨달았습니다. 전형적인 RL 에이전트는 과학 장비를 차단함으로써 배터리 보존을 우선시하도록 학습할 수 있지만, 인간 운영자는 대신 덜 중요한 서브시스템을 희생할 것입니다.
학습된 정책 (Policy)과 운영자 의도 사이의 정렬 격차 (Alignment gap)는 자율 미션 실패의 대부분을 야기하는 원인입니다. 여기서 Decision Transformers가 등장합니다: 제어를 위한 시퀀스 모델링 (Sequence Modeling for Control). Decision Transformers (DT)에 대한 저의 탐구는 2021년 Chen 등의 논문을 읽은 후 시작되었습니다. 저에게 깊은 인상을 주었던 핵심 통찰은 매우 심오했습니다. DT는 정책 함수 (state → action)를 학습하는 대신, 최적 행동의 시퀀스 모델 (Sequence model)을 학습한다는 점입니다. 이는 의사결정 문제를 조건부 언어 모델링 (Conditional language modeling) 작업으로 취급하며, 여기서 "언어"는 (state, action, reward) 토큰의 궤적 (Trajectories)입니다. 위성 이상 대응 (Satellite anomaly response)에 있어 이는 게임 체인저입니다. DT는 다음과 같은 일을 수행할 수 있습니다:
- 인간의 시연 (Human demonstrations)을 (단순한 보상 형성 (Reward shaping)뿐만 아니라) 학습 데이터에 직접 통합
- 다중 모드 액션 공간 (Multi-modal action spaces) 처리 (연속적인 추진기 명령 (Continuous thruster commands) + 이산적인 서브시스템 토글 (Discrete subsystem toggles))
- Transformer 어텐션 (Attention)을 사용하여 자기회귀적 (Autoregressively)으로 작동하며, 이는 놀랍게도 희소 계산 (Sparse computation)에 적합함
다음은 제가 실험 단계에서 구축한 단순화된 구현 예시입니다:
import torch
import torch.nn as nn
import torch.nn.functional as F
class DecisionTransformer(nn.Module):
def __init__(self, state_dim, act_dim, max_ep_len=100, embed_dim=64, n_blocks=4):
super().__init__()
self.embed_dim = embed_dim
self.max_ep_len = max_ep_len
# 상태(states), 행동(actions), 남은 보상(returns-to-go)을 위한 토큰 임베딩 (Token embeddings)
self.state_embed = nn.Linear(state_dim, embed_dim)
self.action_embed = nn.Linear(act_dim, embed_dim)
self.return_embed = nn.Linear(1, embed_dim)
# 시간적 순서를 위한 위치 임베딩 (Positional embeddings)
self.pos_embed = nn.Embedding(max_ep_len * 3, embed_dim) # 타임스텝당 3개의 토큰
# Transformer 디코더 블록 (Transformer decoder blocks)
self.blocks = nn.ModuleList([
nn.TransformerDecoderLayer(
d_model=embed_dim,
nhead=4,
dim_feedforward=embed_dim * 4,
batch_first=True
) for _ in range(n_blocks)
])
# 행동 예측 헤드 (Action prediction head)
self.action_head = nn.
Linear ( embed_dim , act_dim ) def forward ( self , states , actions , returns_to_go , timesteps , mask = None ): """ states: (batch, seq_len, state_dim) actions: (batch, seq_len, act_dim) returns_to_go: (batch, seq_len, 1) timesteps: (batch, seq_len) """ batch_size , seq_len = states . shape [: 2 ] # 각 모달리티 임베딩 state_emb = self . state_embed ( states ) action_emb = self . action_embed ( actions ) return_emb = self . return_embed ( returns_to_go ) # 토큰 간 삽입: [R, S, A, R, S, A, ...] tokens = torch . stack ([ return_emb , state_emb , action_emb ], dim = 2 ) tokens = tokens . view ( batch_size , seq_len * 3 , self . embed_dim ) # 위치 인코딩 추가 pos = self . pos_embed ( torch . arange ( seq_len * 3 , device = states . device ). unsqueeze ( 0 )) tokens = tokens + pos # 트랜스포머 블록 통과 for block in self . blocks : tokens = block ( tokens ) # 행동 예측 추출 (인덱스 2부터 3 간격으로 모든 세 번째 토큰) action_tokens = tokens [:, 2 :: 3 , :] action_pred = self . action_head ( action_tokens ) return action_pred 위성 원격 측정 데이터로 이 모델을 학습시키면서 놀라운 점을 발견했습니다. 트랜스포머의 어텐션 메커니즘이 관련 없는 센서 채널을 무시하도록 자연스럽게 학습하여, 명시적인 정규화 없이도 효과적으로 특징 선택(feature selection)을 수행한다는 것입니다. 이는 저전력 배포에 매우 중요합니다. 왜냐하면 모델의 입력 레이어를 가지치기(prune)하여 메모리 대역폭을 줄일 수 있다는 의미이기 때문입니다.
인간 정렬 훈련: 보상 함수를 넘어서
제목에서 언급된 '인간 정렬(human-aligned)' 부분은 흥미로운 지점입니다. 우주 시스템에 대한 정렬 기술 연구를 하면서, 표준 RLHF (Reinforcement Learning from Human Feedback)가 위성에는 비실용적이라는 것을 알게 되었습니다. 보상 모델 자체만으로도 너무 많은 전력을 소모할 것이기 때문입니다. 대신, 전문가 궤적(expert trajectories)으로부터의 행동 복제(behavioral cloning)를 시도했지만, 한 가지 변형을 주었습니다. 바로 훈련 데이터에 부정적인 예시(negative examples)—즉, 인간 운영자가 명시적으로 거부한 결정—를 추가하여 증강하는 것입니다.
이는 Decision Transformer (DT)가 명시적인 보상 모델 (reward model) 없이도 활용할 수 있는 대조 학습 (contrastive learning) 신호를 생성합니다.
```python
def contrastive_dt_loss ( action_pred , action_target , negative_actions , margin = 0.5 ):
""" 긍정적 예시 (positive examples)를 위한 표준 MSE 손실 + 부정적 예시 (negative examples)를 위한 대조 손실 (contrastive loss).
negative_actions: (batch, seq_len, act_dim) - 운영자가 거부한 액션들 """
# Positive loss: 전문가의 액션과의 거리를 최소화
pos_loss = F . mse_loss ( action_pred , action_target )
# Negative loss: 거부된 액션들과의 거리를 최대화
neg_dist = torch . norm ( action_pred - negative_actions , dim =- 1 )
neg_loss = F . relu ( margin - neg_dist ).mean ()
return pos_loss + 0.3 * neg_loss
이 손실 함수를 조사하는 동안, 저는 DT가 때때로 문맥상 적절한 액션임에도 불구하고 부정적 예시와 유사한 모든 액션을 거부하는 방향으로 과적합 (overfitting)되는 현상을 발견했습니다. 해결책은 예상치 못한 곳에서 나왔습니다: 바로 양자 영감 어닐링 (quantum-inspired annealing)입니다. 훈련 중에 부정적 액션 임베딩 (negative action embeddings)에 가우시안 노이즈 (Gaussian noise)를 추가함으로써 ("나쁜" 궤적의 양자 중첩을 시뮬레이션), 모델은 더욱 견고한 결정 경계 (decision boundaries)를 학습할 수 있었습니다.
저전력 배포: 희소 어텐션 (Sparse Attention)의 돌파구
가장 큰 기술적 장애물은 트랜스포머 (transformer) 아키텍처를 위성급 하드웨어에서 실행할 수 있도록 만드는 것이었습니다. 전체 어텐션 (full attention)을 사용하는 표준 트랜스포머는 $O(n^2)$의 메모리를 요구하며, 이는 마이크로컨트롤러 (microcontroller)에서는 감당할 수 없는 수준입니다. 우주 애플리케이션을 위한 모델 압축 (model compression)을 탐구하던 중, 저는 고정된 패턴을 가진 희소 어텐션 (sparse attention with fixed patterns)에 도달했습니다. 위성 이상 대응의 경우, 시간적 의존성 (temporal dependencies)은 일반적으로 국소적(local)이며(마지막 10-20 타임스텝이 가장 중요함), 가끔 전역적 문맥(global context, 예: 궤도 위치)이 나타납니다. 저는 다음과 같은 하이브리드 어텐션 메커니즘을 구현했습니다:
class SparseSatelliteAttention ( nn . Module ):
def __init__ ( self , embed_dim , local_window = 16 , global_stride = 32 ):
super (). __init__ ()
self . local_window = local_window
self . global_stride = global_stride
self . w_q = nn .
Linear ( embed_dim , embed_dim ) self . w_k = nn . Linear ( embed_dim , embed_dim ) self . w_v = nn . Linear ( embed_dim , embed_dim ) def forward ( self , x ): batch , seq , dim = x . shape Q = self . w_q ( x ) K = self . w_k ( x ) V = self . w_v ( x ) # Local attention: each token attends to local_window neighbors local_mask = torch . zeros ( seq , seq , device = x . device ) for i in range ( seq ): start = max ( 0 , i - self . local_window // 2 ) end = min ( seq , i + self . local_window // 2 + 1 ) local_mask [ i , start : end ] = 1.0 # Global attention: every global_stride-th token attends to all global_indices = torch . arange ( 0 , seq , self . global_stride , device = x . device ) global_mask = torch . zeros ( seq , seq , device = x . device ) global_mask [ global_indices , :] = 1.0 # Combined sparse mask mask = ( local_mask + global_mask ). clamp ( 0 , 1 ). bool () # Scaled dot-product with masked softmax scores = torch . matmul ( Q , K . transpose ( - 2 , - 1 )) / ( dim ** 0.5 ) scores = scores . masked_fill ( ~ mask , float ( ' -inf ' )) attn = F . softmax ( scores , dim =- 1 ) return torch . matmul ( attn , V ) When I benchmarked this on an ARM Cortex-M4 emulator, the results were dramatic: Full attention : 142 ms per inference, 8.3 mJ energy Sparse attention : 23 ms per inference, 1.1 mJ energy Accuracy loss : Only 3.2% on anomaly classification tasks The key insight I learned while tuning this was that the global stride parameter should be dynamically adjusted based on orbital phase—during eclipse (when solar panels are inactive), the satellite has more power available for computation, so we can afford denser attention. Real-World Application: The "Luna-1" CubeSat Simulation I tested the full system on a simulated CubeSat mission called "Luna-1" that I built using the FreeRTOS-based satellite simulator. The scenario was a solar panel deployment failure —the port panel was stuck at 30% deployment, causing asymmetric power generation.
시뮬레이션된 MCU에서 실행되는 에이전트 루프는 다음과 같습니다: class AnomalyResponseAgent : def init ( self , model_path , power_budget_mw = 500 ): self . dt = torch . jit . load ( model_path ) # MCU용 양자화(Quantized for MCU) self . power_budget = power_budget_mw self . state_buffer = deque ( maxlen = 30 ) self . action_buffer = deque ( maxlen = 30 ) self . return_buffer = deque ( maxlen = 30 ) def step ( self , telemetry ): # telemetry: 'voltage', 'current', 'temperature', # 'panel_angles', 'gyro_rate', 'mag_field' 등의 키를 가진 dict # 1. 특징 추출 (전력 인식적, power-aware) if telemetry [ ' power_consumption_mw ' ] > self . power_budget * 0.8 : # 저전력 모드: 가장 중요한 4개 센서만 사용 state = self . _extract_low_power_state ( telemetry ) else : state = self . _extract_full_state ( telemetry ) # 2. 히스토리 버퍼 업데이트 self . state_buffer . append ( state ) self . action_buffer . append ( self . last_action ) self . return_buffer . append ( self . _estimate_return_to_go ( telemetry )) # 3. torch.no_grad()를 사용한 DT 추론: states_t = torch . tensor ([ list ( self . state_buffer )], dtype = torch . float32 ) actions_t = torch . tensor ([ list ( self . action_buffer )], dtype = torch . float32 ) returns_t = torch . tensor ([ list ( self . return_buffer )], dtype = torch . float32 ) timesteps_t = torch . arange ( len ( self . state_buffer )). unsqueeze ( 0 ) action_pred = self . dt ( states_t , actions_t , returns_t , timesteps_t ) # 4. 인간 정렬 제약 조건(human-aligned constraints)을 사용한 액션 선택 action = self . _apply_safety_constraints ( action_pred [ 0 , - 1 ]) self . last_action = action return action def _apply_safety_constraints ( self , raw_action ): # 통신 서브시스템이 완전히 비활성화되는 것을 방지해야 함 raw_action [ 3 ] = max ( raw_action [ 3 ], 0.1 ) # comm_power 최소 10% # 기동 중에는 자이로 리셋(gyro reset)을 절대 수행해서는 안 된다면 self .
_is_in_maneuver(): raw_action[1] = 0.0 # gyro_reset = off
return raw_action
100개의 시뮬레이션된 이상 상황(anomaly scenarios) 시나리오 결과:
| 지표 (Metric) | 표준 RL (Standard RL) | Decision Transformer (DT) | DT + 인간 정렬 (Human Alignment) |
|---|---|---|---|
| 이상 해결률 (Anomaly resolution rate) | 67% | 81% | 94% |
| 추론당 평균 전력 (Avg power per inference) | 4.2 mJ | 1.1 mJ | 0.9 mJ |
| 인간 운영자 승인율 (Human operator approval) | 58% | 72% | 96% |
| 무시된 오경보 (False alarms ignored) | 12% | 8% | 3% |
94%의 해결률을 달성할 수 있었던 이유는 인간 정렬(human-aligned)된 DT가 통신 대역폭(communication bandwidth)을 희생하기 전에 과학 장비의 듀티 사이클(duty cycle)을 줄이는 것과 같이, 운영자가
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기