time embedding

ad_official·2025년 8월 12일
0

글 1

좋아요. 아래는 **“멀티주파수 연속시간 임베딩 + dtdt 파라미터화”**가 무엇을 하는지, 좋은지, 수식으로 어떻게 정의되는지, 하이퍼 선택 기준은 무엇인지까지 한 번에 이해할 수 있게 정리한 설명입니다. (전문 용어를 쓰면 바로 옆에 쉬운 뜻도 붙일게요.)


1) 목적 — “시간”을 숫자열로 똑똑하게 알려주기

모델이 시간 정보를 잘 쓰려면, 단순히 “스텝 인덱스(0,1,2,…)”가 아니라 초 단위의 연속값여러 길이의 시간 패턴(짧은 리듬, 긴 리듬)을 함께 알려주는 게 유리합니다.
그걸 위해 **하나의 시각 tt (초)**를 벡터로 바꿉니다.


2) 핵심 수식 — 시간 tt를 벡터로 바꾸는 방법

각 시각 tt에 대해 아래 **임베딩(벡터화)**를 만듭니다.

ϕ(t)=[t, sin(2πf1t), cos(2πf1t), , sin(2πfKt), cos(2πfKt)]R1+2K.\phi(t) = \Big[\,t,\ \sin(2\pi f_1 t),\ \cos(2\pi f_1 t),\ \ldots,\ \sin(2\pi f_K t),\ \cos(2\pi f_K t)\,\Big] \in \mathbb{R}^{\,1+2K}.
  • tt: 초 단위의 실제 시간값(연속 시간성 유지).

  • sin,cos\sin, \cos: 주기 성분(리듬)을 표현.

  • fkf_k: 여러 주파수(여러 길이의 리듬), 보통 로그 간격으로 잡습니다:

    fk  =  fminrk1(k=1,,K).f_k \;=\; f_{\min}\cdot r^{\,k-1}\quad (k=1,\ldots,K).
    • fminf_{\min}: 가장 느린 리듬(긴 패턴),
    • r>1r>1: 간격 배수(예: r=2r{=}2면 두 배씩 증가),
    • KK: 사용하는 주파수 개수.

이렇게 하면 짧은 변화(급가속/급정지 등)부터 긴 흐름(여러 초에 걸친 추세)까지 한 번에 표현됩니다.


3) 왜 sin\sincos\cos을 둘 다 쓰나? (위상 정보 보존)

sin()\sin(\cdot)만 쓰면 “위상(phase, 파형의 시작점)”을 구분하기 어렵습니다. sin\sincos\cos으로 쓰면

sin(a)sin(b)+cos(a)cos(b)=cos(ab)\sin(a)\sin(b) + \cos(a)\cos(b) = \cos(a-b)

가 되어, 두 시각 t,st,s차이에 대한 정보를 깔끔히 담습니다. 점들끼리의 유사도(내적)를 보면

ϕ(t),ϕ(s)=ts  +  k=1Kcos ⁣(2πfk(ts)).\langle \phi(t), \phi(s) \rangle = t\,s \;+\; \sum_{k=1}^K \cos\!\big(2\pi f_k (t-s)\big).

즉, 임베딩 간 유사도는 **시간 차이 (ts)(t-s)**에 주로 의존합니다. 이건 모델이 “시간이 가까우면 비슷하고, 멀면 다르게” 보게 돕습니다.


4) 왜 “연속시간 + dtdt 파라미터화”가 중요한가?

  • **dtdt**는 샘플 간격(초)입니다. 시계열이 10Hz든 20Hz든, 우리는 시간을 초 단위로 넣습니다:

    tn=ndt.t_n = n\cdot dt.
  • 예전처럼 “스텝 인덱스를 0~1로 정규화”하면, 샘플링 레이트가 바뀌면 의미가 달라지는 문제가 생깁니다.
    (예: 같은 2초여도 10Hz에선 20스텝, 20Hz에선 40스텝 → 임베딩이 달라짐)

  • 지금 방식은 절대 시간(초) 기준이라, dtdt가 달라도 같은 물리 시간이면 같은 임베딩이 나옵니다.
    일반화도메인 전이에 유리합니다.


5) 과거/미래 시간 축 생성(코드와 일치)

  • 과거 VV 스텝(예: 21스텝, 0.1s 간격)일 때:

    {tv}v=1V  =  {dt(V1), , 2dt, dt, 0}.\{t_v\}_{v=1}^V \;=\; \{-dt\,(V-1),\ \ldots,\ -2dt,\ -dt,\ 0\}.

    (예: 2.0,1.9,,0.0-2.0, -1.9, \ldots, 0.0 초)

  • 미래 플랜 FF 스텝(예: 80스텝):

    {tf}f=1F  =  {dt, 2dt, , Fdt}.\{t_f\}_{f=1}^F \;=\; \{dt,\ 2dt,\ \ldots,\ F\,dt\}.

    (예: 0.1,0.2,,8.00.1, 0.2, \ldots, 8.0 초)

tt에 대해 ϕ(t)\phi(t)를 계산해 입력에 붙입니다. 이게 코드의 make_time_feat(times_s)에 해당합니다.


6) 하이퍼파라미터 선택 가이드 (실전 중요)

  • 지평 TT: 미래 총 길이(초). 예: T=8T=8초.

  • fminf_{\min}: 보통 1/T1/T 또는 1/(2T)1/(2T) 근처가 안전.

  • **최대 주파수 fmaxf_{\max}**는 나이퀴스트 한계(샘플링의 물리 한계)를 넘기면 **뒤섞임(에일리어싱)**이 생깁니다.

    fmax    12dt.f_{\max} \;\le\; \frac{1}{2\,dt}.
  • 로그 간격이면 fmax=fminrK1f_{\max} = f_{\min}\, r^{K-1} 이므로,

    K    1+logr ⁣(12dtfmin).K \;\le\; 1 + \log_{r}\!\Big(\frac{1}{2\,dt\,f_{\min}}\Big).

예시 (dt=0.1s, T=8s)

  • 나이퀴스트 한계: 1/(2dt)=5Hz1/(2dt)=5\,\text{Hz}.
  • fmin=1/T=0.125Hzf_{\min}=1/T=0.125\,\text{Hz}, r=2r=2라면
    0.1252K152K140K60.125\cdot 2^{K-1} \le 5 \Rightarrow 2^{K-1}\le 40 \Rightarrow K \le 6.
    권장: K=5K=5~66 정도(너무 큰 KK는 득보다 실).

정리: **fminf_{\min}**은 지평과 맞추고, **KK**는 12dt\frac{1}{2dt}를 넘지 않게 자동 산출하거나 안전 여유를 남겨 잡으세요.


7) 단일 주파수 vs 멀티주파수 — 왜 좋아지나?

  • 단일 주파수(기존): 한 가지 리듬만 있어 짧은 변화/긴 변화를 동시에 잘 표현하기 어렵습니다.
  • 멀티주파수: 짧은/중간/긴 리듬을 동시에 제공 → MLP/어텐션이 상황에 맞는 조합을 학습하기 쉬움.
  • 수렴 속도/일반화에 유리하고, 샘플링 주기 변화에도 의미가 유지됩니다.

8) 모델에 어떤 효과가 있나? (해석 포인트)

  • 시간 근접성: ϕ(t),ϕ(s)\langle \phi(t),\phi(s)\ranglekcos(2πfk(ts))\sum_k \cos(2\pi f_k(t-s)) 형태라,
    가까운 시간끼리 더 비슷하게, 먼 시간은 덜 비슷하게 나타납니다.
  • 부드러운 변화: sin/cos\sin/\cos는 미분 가능하고 부드러워, 학습이 안정적입니다.
  • 과거/미래 분리: 과거는 음의 tt, 미래는 양의 tt라 **경계(0초)**를 기준으로 변화가 또렷합니다.
  • 결합 표현 용이: 위치/속도 등 다른 입력과 같이 들어가도, MLP가 쉽게 섞어 쓸 수 있습니다.

9) 계산/메모리 비용

  • 시점당 추가 차원은 1+2K1+2K.
    K=6K=6이면 13차원 추가에 불과 → 메모리/연산 부담 매우 작음.
  • 코드상 in_ch만 자동으로 늘려놨기 때문에, 드롭인 교체로 끝납니다.

10) 자주 받는 질문 (FAQ)

Q1. 왜 tt 원시값을 첫 채널로 넣나요?
A. sin/cos\sin/\cos만 쓰면 절대 시간의 흐름(증가/감소)을 직접적으로 표현하기 어렵습니다. tt를 함께 주면 “미래로 갈수록 커진다” 같은 단조 정보가 자연히 들어갑니다.

Q2. 시퀀스 길이(스텝 수)가 바뀌면?
A. dtdttt는 초 단위라, 길이가 달라도 같은 물리 시간이면 같은 임베딩 패턴이 유지됩니다.

Q3. fmaxf_{\max}가 나이퀴스트를 넘으면?
A. 서로 다른 시각들이 동일한 임베딩으로 보일 수 있어(뒤섞임) 학습이 흔들릴 수 있습니다.
반드시 fmax1/(2dt)f_{\max}\le 1/(2dt)를 지키거나 여유 있게 더 낮게 잡으세요.


11) 한 줄 요약

  • 시간 ttϕ(t)=[t,sin(2πfkt),cos(2πfkt)]\phi(t) = [t, \sin(2\pi f_k t), \cos(2\pi f_k t)]로 바꾸되,
  • 초 단위 tt여러 주파수 fkf_k를 쓰고,
  • 최대 주파수는 1/(2dt)1/(2dt) 이하로 제한하면,
  • 샘플링 변화에 강하고 짧고 긴 패턴을 동시에 포착하는 튼튼한 시간 표현이 됩니다.

필요하면, 위 수식을 기준으로 **K,fmin,rK,f_{\min},r**를 자동으로 산출하는 작은 헬퍼(“나이퀴스트 안전 KK” 계산) 코드도 바로 드릴게요.




글 2

좋아! 아래는 네가 붙여 넣은 단일 시간 임베더(TimeEmbed) 로직을, 수식 + 쉬운 말로 차근차근 풀어쓴 설명이야. 최대한 전문용어를 줄이고, 꼭 필요한 개념은 바로 옆에 뜻을 달았어.


1) 목표: “시간”을 한눈에 알아듣게 벡터로 바꾸자

우리가 다루는 입력은 과거 [2.0s,,0][-2.0\text{s},\dots,0] 구간과 미래 [0.1s,,8.0s][0.1\text{s},\dots,8.0\text{s}] 구간이 섞여 있어.
모델이 “지금 몇 초 시점의 값인지”, “두 시점이 서로 얼마나 가까운지”를 쉽게 느끼게 하려면, 각 시각 tt정보가 풍부한 벡터로 바꿔서 토큰에 붙여줘야 해. 이 일을 하는 게 시간 임베더(TimeEmbed) 야.


2) 핵심 아이디어(요지)

  • 시각 tt 한 개(스칼라)를 여러 개의 사인/코사인 값으로 펼친다 → 여러 시간 패턴(느린 변화, 빠른 변화)을 한 번에 담게 됨.
  • 거기에 정규화된 시간 tTmax\frac{t}{T_{\max}}부호 sign(t)\mathrm{sign}(t)도 붙여서,
    “전체 구간에서의 위치”와 “과거/미래”를 단서로 준다.

수식으로 한 줄 요약:

ϕ(t)=[sin(ω1t),cos(ω1t), , sin(ωKt),cos(ωKt), tTmax, sign(t)]\boxed{ \phi(t)=\big[\,\sin(\omega_1 t),\cos(\omega_1 t),\ \dots,\ \sin(\omega_{K} t),\cos(\omega_{K} t),\ \tfrac{t}{T_{\max}},\ \mathrm{sign}(t)\,\big] }

여기서 ωk\omega_k주파수(사인의 빠르기)이고, KK는 사용하는 주파수 개수야.


3) 코드와 정확히 1:1로 대응되는 수식

코드의 time_embed_seconds(t, d_fourier=12, Tmax=8.0)는 다음을 계산해:

  1. 주파수 선택(느린→빠른, 로그 스케일)
ωk  =  2kπTmax,k=0,1,,K1\omega_k \;=\; 2^{k}\cdot \frac{\pi}{T_{\max}}, \qquad k=0,1,\dots,K{-}1
  • 왜 이렇게?
    2k2^k 배로 늘리면 아주 느린 파형부터 아주 빠른 파형까지 고르게 덮을 수 있어.
    (느린 변화=장기 추세, 빠른 변화=급격한 이벤트)
  1. 사인/코사인 펼치기(시간을 여러 각도로 비춰본 사진)
[ sin(ωkt), cos(ωkt) ]k=1K\big[\ \sin(\omega_k t),\ \cos(\omega_k t)\ \big]_{k=1}^{K}
  • 사인/코사인은 반복 무늬라서, 다양한 ωk\omega_k를 쓰면
    “시간에 따라 어떻게 흔들리는지”를 여러 눈금으로 관찰하는 효과가 있어.
  1. 정규화된 시간과 부호(거친 힌트)
[tTmax, sign(t)]\left[\,\frac{t}{T_{\max}},\ \mathrm{sign}(t)\,\right]
  • tTmax\tfrac{t}{T_{\max}}: 전체 8초 중에서 얼마나 진행됐나(0에 가까움 vs 8에 가까움).
  • sign(t)\mathrm{sign}(t): 과거(-), 현재(0), **미래(+)**를 즉시 구분하는 한 줄 힌트.

최종 벡터 차원은 2Ksin,cos+2t/Tmax, sign=2K+2\underbrace{2K}_{\sin,\cos} + \underbrace{2}_{t/T_{\max},\ \text{sign}} = 2K+2.


4) 왜 사인/코사인(여러 주파수)을 쓰나? (직관)

  • 느린 파형(작은 ω\omega): “장기적인 추세”에 민감
    (예: 8초 동안 서서히 가속/차선 이동)
  • 빠른 파형(큰 ω\omega): “짧은 순간의 급변”에 민감
    (예: 0.5초 근처의 급제동/합류 타이밍)
  • 여러 ωk\omega_k를 동시에 쓰면, 모델이 여러 시간 눈금을 보며 배울 수 있어.

수학적으로도 좋은 점이 하나 있어:

cos(ω(tτ))=cos(ωt)cos(ωτ)+sin(ωt)sin(ωτ).\cos(\omega (t-\tau))=\cos(\omega t)\cos(\omega\tau)+\sin(\omega t)\sin(\omega\tau).

즉, [sin(ωt),cos(ωt)]\big[\sin(\omega t),\cos(\omega t)\big][sin(ωτ),cos(ωτ)]\big[\sin(\omega \tau),\cos(\omega \tau)\big]내적ttτ\tau시간 차를 반영해.
그래서 어텐션의 점수(내적)가까운 시각끼리 자연히 높게 나오기 쉬워져(학습을 도와주는 “좋은 버릇”).


5) tTmax\tfrac{t}{T_{\max}}sign(t)\mathrm{sign}(t)를 왜 추가하나?

  • tTmax\tfrac{t}{T_{\max}}단조롭게 증가하는 선형 눈금이야.
    모델이 “시작→중간→끝” 같은 전체 흐름을 빠르게 감 잡도록 돕는다.
  • sign(t)\mathrm{sign}(t)과거/미래실수 한 칸으로 즉시 구분.
    사인/코사인만으로도 구분은 가능하지만(주기가 있어 애매해질 수 있음),
    이 한 줄이 들어가면 학습 초기에 안정적으로 방향 감각(과거/미래)을 잡는다.

6) “과거/미래 일관화”가 왜 중요한가?

예전 코드는 모듈마다 시간 스케일을 따로 만들었어(과거는 [2,0][-2,0]을 자체 정규화, 미래는 다시 [0.1,8.0][0.1,8.0] 정규화…).
그러면 같은 “1초 차이”라도 모듈마다 숫자 의미가 달라져서, 모델이 혼란스러울 수 있지.

지금은 초 단위 절대 시간을 그대로 쓰고, 하나의 임베더과거(-)미래(+) 를 같이 표현해.
이렇게 하면:

  • 어디서 쓰든 같은 1초는 같은 1초로 느껴짐(일관성).
  • 토큰 길이가 달라져도(미래가 80스텝이든 1스텝이든) 같은 함수로 처리됨(확장성).

7) 이 임베딩이 실제로 어디 붙나?

(a) 과거 이웃/자차 인코더: AgentFusionEncoder

  • 과거 시각들 t[2.0,0.0]t\in[-2.0,\,0.0]초 단위로 만들어
    ϕ(t)\phi(t)를 계산하고, 각 프레임의 [x,y,cos,sin][x,y,\cos,\sin] 뒤에 붙여 토큰 채널로 합쳐 줘.
  • 그다음 작은 MLP(선형+활성함수) 를 통과해 네트워크 공간으로 투사하고,
    토큰 섞기( Mixer ) 를 하며 요약해.

(b) 미래 플랜 인코더: EgoFutureEncoder

  • 미래 시각들 t(0.1,8.0]t\in(0.1,\,8.0]에 대해서도 똑같이 ϕ(t)\phi(t)를 만들어서
    각 미래 스텝 토큰에 붙여 줘(이 토큰들은 풀링 없이 스텝별로 유지).

요컨대, 모든 시계열 토큰같은 스타일의 시간 꼬리표를 달고 흐른다.


8) 이 설계가 주는 실질적 이득

  1. 정렬력(시간 매칭)↑
    비슷한 시각끼리 임베딩이 “비슷하게” 생겨,
    어텐션/MLP가 쉽게 “누가 누구랑 맞는지” 배운다.
  2. 일관성↑
    과거/미래/모듈을 가리지 않고 같은 수학으로 처리 →
    다른 모듈 조합/하이퍼파라미터 바뀌어도 행동이 예측 가능.
  3. 일반화↑
    시퀀스 길이 FF가 바뀌어도, ϕ(t)\phi(t)초 단위로만 보니 그대로 쓸 수 있다.
  4. 빠른 학습 초반
    tTmax\tfrac{t}{T_{\max}}, sign(t)\mathrm{sign}(t) 같은 저주파 힌트가 있어서,
    초기엔 거친 패턴부터, 학습이 깊어지면 사인/코사인의 세밀 패턴까지 흡수.

9) 수학적 뒷받침(부담 없이 읽기)

  • 어떤 시간에 따른 함수도(궤적 속성, 상호작용 강도 등) 충분한 사인/코사인 합으로 가깝게 표현 가능해.
    이건 푸리에(삼각) 급수의 기본 사실이야.
    \Rightarrow ϕ(t)\phi(t)를 입력으로 받는 작은 MLP만으로도 다양한 시간 패턴을 근사할 수 있어.

  • 위에 썼던 항등식

    cos(ω(tτ))=cos(ωt)cos(ωτ)+sin(ωt)sin(ωτ)\cos(\omega (t-\tau))=\cos(\omega t)\cos(\omega\tau)+\sin(\omega t)\sin(\omega\tau)

    덕분에, 두 시각 t,τt,\tau차이가 벡터들의 내적(즉, 어텐션 점수)과 직결돼.
    \Rightarrow “가까운 시간끼리 주목”이 자연스럽게 일어나기 쉬움.


10) 하이퍼파라미터(쉽게 고르는 법)

  • K(=d_fourier)K(=\texttt{d\_fourier}): 12–16 권장.
    작으면 너무 둔감(세밀 타이밍 못 잡음), 너무 크면 잡음↑·계산↑.
  • TmaxT_{\max}: 예측 지평(현재 8초)에 맞춰 두면 충분.
    더 긴 지평을 다룰 때만 늘리자.
  • dtdt: 데이터의 실제 샘플 간격(예: 0.1초)을 그대로 넣자.

11) 마지막 한 줄 정리

  • 시간 임베더는

    ϕ(t)=[sin(ωkt),cos(ωkt)]k=1K  [tTmax,sign(t)]\phi(t)=\big[\sin(\omega_k t),\cos(\omega_k t)\big]_{k=1}^K\ \oplus\ \big[\tfrac{t}{T_{\max}},\mathrm{sign}(t)\big]

    로 시각을 풍부한 벡터로 바꾼다.

  • 이렇게 과거/미래를 같은 좌표계(초 단위) 로 통일하면,
    모델이 시점과 시점 사이의 관계(누가 누구와 맞물리는가)를 쉽고 안정적으로 배운다.

  • 구현은 단순하지만, 정렬력·일관성·일반화를 동시에 끌어올리는 데 효과적이야.

원하면, 여기에 어텐션 “시간 가산점” logitst,τ+=βtτ\text{logits}_{t,\tau} {+}{=} -\beta|t-\tau| 을 더했을 때 왜 시점 매칭이 더 쉬워지는지까지(간단한 도식 포함) 이어서 설명해줄게.

profile
ad_official

0개의 댓글