Project structure:

o1_made_2/
├── models/
│   ├── model.pth
│   └── scaler.gz
├── data_loader.py
├── model.py
├── test.py
└── train.py


Project files:

model.py
```py

import torch
import torch.nn as nn

class BitcoinPricePredictor(nn.Module):
    def __init__(self, input_size, hidden_size=64, num_layers=2):
        super(BitcoinPricePredictor, self).__init__()
        self.hidden_size = hidden_size
        self.num_layers = num_layers

        # LSTM слои
        self.lstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True)

        # Полносвязный слой
        self.fc = nn.Linear(hidden_size, 1)

    def forward(self, x):
        # Инициализируем скрытые состояния
        h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(x.device)
        c0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(x.device)

        # Пропускаем через LSTM
        out, _ = self.lstm(x, (h0, c0))

        # Берём выход последнего временного шага
        out = self.fc(out[:, -1, :])

        return out
```


test.py
```py

import torch
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from model import BitcoinPricePredictor
import joblib

# Определение датасета для тестирования
class BitcoinTestDataset:
    def __init__(self, data, sequence_length=100):
        self.sequence_length = sequence_length
        self.data = data

    def get_random_sequence(self):
        idx = np.random.randint(0, len(self.data) - self.sequence_length - 1)
        seq = self.data.iloc[idx:idx + self.sequence_length].values
        target = self.data.iloc[idx + self.sequence_length]['Close']
        return seq, target, idx

def test():
    # Загружаем данные
    test_df = pd.read_csv('data/test_data.csv')

    # Загружаем скейлер
    scaler = joblib.load('models/scaler.gz')

    # Переносим данные в исходный масштаб для визуализации
    test_df_scaled = pd.DataFrame(scaler.inverse_transform(test_df), columns=test_df.columns)

    # Инициализируем модель
    input_size = test_df.shape[1]
    model = BitcoinPricePredictor(input_size=input_size)
    model.load_state_dict(torch.load('models/model.pth'))
    model.eval()

    # Переносим модель на устройство (CPU или GPU)
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    model.to(device)

    # Создаём датасет
    test_dataset = BitcoinTestDataset(test_df, sequence_length=100)

    # Получаем случайную последовательность
    seq, real_value, idx = test_dataset.get_random_sequence()

    # Подготовка данных для модели
    seq_tensor = torch.tensor(seq, dtype=torch.float32).unsqueeze(0).to(device)

    # Предсказание
    with torch.no_grad():
        predicted_value = model(seq_tensor).cpu().item()

    # Обратное преобразование предсказанного значения
    close_index = test_df.columns.get_loc('Close')
    mean = scaler.mean_[close_index]
    var = scaler.var_[close_index]
    std = np.sqrt(var)

    predicted_value = predicted_value * std + mean
    real_value = real_value * std + mean

    # Подготовка данных для визуализации
    seq_denorm = seq[:, close_index] * std + mean

    print(f"Предсказанное значение: {predicted_value:.2f} USD")
    print(f"Реальное значение: {real_value:.2f} USD")

    # Визуализация
    time_steps = np.arange(len(seq_denorm) + 1)

    # Построение графика
    plt.plot(time_steps[:-1], seq_denorm, color='blue', label='Входная последовательность')
    plt.plot(time_steps[-2:], [seq_denorm[-1], predicted_value], color='orange', marker='o', label='Предсказанный шаг')
    plt.plot(time_steps[-2:], [seq_denorm[-1], real_value], color='green', marker='o', label='Реальный шаг')

    plt.legend()
    plt.xlabel('Временные шаги')
    plt.ylabel('Цена Bitcoin (USD)')
    plt.title('Предсказание цены Bitcoin')

    plt.show()

if __name__ == "__main__":
    test()

```


train.py
```py
import torch
import torch.nn as nn
from torch.utils.data import Dataset, DataLoader
import pandas as pd
from model import BitcoinPricePredictor

# Определение датасета
class BitcoinDataset(Dataset):
    def __init__(self, data, sequence_length=100):
        self.sequence_length = sequence_length
        self.data = data

    def __len__(self):
        return len(self.data) - self.sequence_length

    def __getitem__(self, idx):
        seq = self.data.iloc[idx:idx + self.sequence_length].values
        target = self.data.iloc[idx + self.sequence_length]['Close']
        return torch.tensor(seq, dtype=torch.float32), torch.tensor(target, dtype=torch.float32)

def train():
    # Загружаем данные
    train_df = pd.read_csv('data/train_data.csv')

    # Параметры
    sequence_length = 100
    batch_size = 64
    num_epochs = 5#20
    learning_rate = 0.001
    input_size = train_df.shape[1]  # Количество признаков

    # Создаём датасет и загрузчик
    train_dataset = BitcoinDataset(train_df, sequence_length)
    train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)

    # Инициализируем модель, функцию потерь и оптимизатор
    model = BitcoinPricePredictor(input_size=input_size)
    criterion = nn.MSELoss()
    optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)

    # Переносим модель на устройство (CPU или GPU)
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    model.to(device)

    # Обучение модели
    model.train()
    for epoch in range(num_epochs):
        epoch_loss = 0
        for sequences, targets in train_loader:
            sequences = sequences.to(device)
            targets = targets.to(device)

            # Прямой проход
            outputs = model(sequences)
            loss = criterion(outputs.squeeze(), targets)

            # Обратный проход и оптимизация
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()

            epoch_loss += loss.item()

        avg_loss = epoch_loss / len(train_loader)
        print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {avg_loss:.6f}')

    # Сохраняем модель
    torch.save(model.state_dict(), 'models/model.pth')
    print("Модель сохранена в models/model.pth")

if __name__ == "__main__":
    train()
```


Это моя модель для предсказания цены BitcoinUSDT, основываясь на предыдущих шагах.
Сейчас я сталкиваюсь с тем, что модель плохо предсказывает и почти не угадывает реальный следующий шаг.
Можешь пожалуйста применить все свои навыки ML-специалиста, чтобы исправить это!
Спасибо!

Приведи мне все обновленные файлы, чтобы модель была по настоящему продвинутой!