1. 개요

2. 데이터 생성 및 전처리

(1) 데이터 생성

if __name__ == "__main__":
    # 과거 시점 개수 선택 (2 또는 10)
    use_memory_points = 10  # 여기서 2나 10으로 설정
    
    fold = os.path.join(os.getcwd(), f'memory_models_v2_{use_memory_points}points')  # 폴더명에 시점 수 추가
    os.makedirs(fold, exist_ok=True)
    model_save_path = os.path.join(fold, 'lstm_model.pth')

    # 시스템 파라미터 설정
    K = 8  # Number of globa-scale variables X
    J = 32  # Number of local-scale Y variables per single global-scale X variable
    F = 15.0  # Forcing
    b = 10.0  # ratio of amplitudes
    c = 10.0  # time-scale ratio
    h = 1.0  # Coupling coefficient
        
    # 평가 파라미터 설정
    nt_pre = 20000  # Number of time steps for model spinup
    nt = 20000  # Number of time steps
    si = 0.005  # Sampling time interval
    dt = 0.005  # Time step
    dt = dt*2
    si = si*2
    
    noise = 0.03 # 원래 데이터에서는 noise를 추가했으나, noise가 성능에 영향을 주는 정도를 없애기 위해 이번에는 추가하지 않음

    # Initial conditions
    k = np.arange(K)
    j = np.arange(J * K)
    Xinit = s(k, K) * (s(k, K) - 1) * (s(k, K) + 1)
    Yinit = 0 * s(j, J * K) * (s(j, J * K) - 1) * (s(j, J * K) + 1)
    
    # Solving true model
    X, Y, t2, _ = integrate_L96_2t_with_coupling(Xinit, Yinit, si, nt_pre+nt, F, h, b, c, dt=dt)
    X = X[nt_pre:,:]
    Y = Y[nt_pre:,:]

    # Sub-sampling (tmeporal sparsity)
    X_train = X[::2,:]

    # First training routine where we target state at the next time-step
    if use_memory_points == 2:
        n_hist = 2  # 현재 시점과 2개의 과거 시점을 활용. 즉, X(t), X(t-2dt), X(t-4dt)
    else:
        n_hist = 10  # 현재 시점과 10개의 과거 시점을 활용. 즉, X(t), X(t-2dt), ..., X(t-20dt)
        
    # 바로 다음 시점의 coupling term들을 예측. 즉, (X+2dt) 
    n_fut = 1

(2) 전처리

    Xt = []
    for i in range(2*n_hist+1+1):
        Xt.append(X_train[i:-2*n_hist-2+i-n_fut+1,:])
    Xt = np.transpose(np.array(Xt), (1, 0, 2)) # 학습 데이터
    Xtpdt = X_train[2*n_hist+2+n_fut-1:,:]     # 정답 데이터
    Ndata = Xt.shape[0]
    
    mu_X = np.zeros(X_train.shape[1])
    sigma_X = np.max(np.abs(X_train), axis=0)

    # 학습 데이터 준비 (float32로 변경)
    Xt = torch.from_numpy(Xt).float()
    Xtpdt = torch.from_numpy(Xtpdt).float()
    sigma_X = torch.from_numpy(sigma_X).float()
    mu_X = torch.from_numpy(mu_X).float()

3. 모델 정의 및 학습

(1) main


    # LSTM 모델 초기화를 float32로 변경
    model = LSTMMemoryNetwork(
        input_dim=8,      # Lorenz 96의 K값
        hidden_dim=256,   # 은닉 차원
        output_dim=8,     # 출력 차원 (K와 동일)
        num_layers=2,     # LSTM 층 수
        dropout=0.1       # 드롭아웃 비율
    )
    
    # 옵티마이저 설정
    optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
    criterion = torch.nn.MSELoss()    
    
    # 학습 파라미터 수정
    n_epochs = 50
    batch_size = 512
        
    # 학습 루프
    model.train()
    for epoch in tqdm(range(n_epochs)):
        epoch_loss = 0
        batch_count = 0
        
        for i in range(0, len(Xt), batch_size):
            batch_Xt = Xt[i:i+batch_size]
            batch_y = Xtpdt[i:i+batch_size]
            
            optimizer.zero_grad()
            if use_memory_points == 2:
                pred = stepper_2(batch_Xt, model, F, sigma_X, mu_X, dt)
            else:  # use_memory_points == 10
                pred = stepper_10(batch_Xt, model, F, sigma_X, mu_X, dt)
            loss = criterion(pred, batch_y)
            loss.backward()
            optimizer.step()
            
            epoch_loss += loss.item()
            batch_count += 1
                    
        avg_epoch_loss = epoch_loss / batch_count
        print(f'Epoch {epoch}, Average Loss: {avg_epoch_loss:.10f}')
        
    print(f'Training finished')

(2) stepper 함수 내부 로직