Код:
import numpy as np
import matplotlib.pyplot as plt
from tqdm import tqdm
import os
import json
from PIL import Image
import autograd.numpy as anp
from autograd import grad
import torch

# 1. Параметры
image_size = 28  # Размер изображения (28x28)
latent_dim = 10  # Размерность латентного пространства
learning_rate = 0.001
epochs = 1000  # Количество эпох обучения
batch_size = 128  # Размер пакета данных
channels = 1 # Количество каналов (1 для оттенков серого)
hidden_units = 128

# Определяем, доступен ли GPU
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"Using device: {device}")

# 2. Функции активации
def relu(x):
    return anp.maximum(0, x)

def relu_derivative(x):
    return (x > 0).astype(float)

def sigmoid(x):
    return 1 / (1 + anp.exp(-x))

def sigmoid_derivative(x):
    return sigmoid(x) * (1 - sigmoid(x))


# 3. Инициализация весов (случайные значения)
def initialize_conv_weights(input_channels, output_channels, kernel_size):
    return np.random.randn(kernel_size, kernel_size, input_channels, output_channels) * 0.01 # Масштабируем, чтобы значения были небольшими

def initialize_weights(input_dim, output_dim):
    return np.random.randn(input_dim, output_dim) * 0.01

# 4. Архитектура CNN
def encoder(x, encoder_weights_1, encoder_weights_2, encoder_weights_3, encoder_weights_4):
    # Сверточные слои + ReLU
    conv1 = relu(anp.dot(x, encoder_weights_1))
    pool1 = conv1[:, ::2, ::2, :]  # Пулинг с шагом 2
    conv2 = relu(anp.dot(pool1, encoder_weights_2))
    pool2 = conv2[:, ::2, ::2, :]  # Пулинг с шагом 2
    if pool2.size == 0:
        return anp.array([]), anp.array([]), anp.array([]), anp.array([]) # Возвращаем пустой массив если pool2 пустой
    # Flatten
    flattened = pool2.reshape(pool2.shape[0], -1)
    # Полносвязный слой + ReLU
    latent_space = relu(anp.dot(flattened, encoder_weights_3))
    # Латентое пространство
    latent_space = anp.dot(latent_space, encoder_weights_4)
    return latent_space, pool1, pool2, flattened
    

def decoder(latent_space, decoder_weights_1, decoder_weights_2, decoder_weights_3, decoder_weights_4, encoder_flattened_shape, encoder_pool2_shape):
    # Полносвязный слой + ReLU
    x = relu(anp.dot(latent_space, decoder_weights_1))
    # Reshape
    x = x.reshape(x.shape[0], encoder_pool2_shape[1], encoder_pool2_shape[2], encoder_pool2_shape[3])
    # Деконволюция + ReLU
    deconv1 = relu(anp.dot(x, decoder_weights_2))
    up1 = anp.repeat(anp.repeat(deconv1, 2, axis=1), 2, axis=2) # Апсемплинг с фактором 2
    deconv2 = relu(anp.dot(up1, decoder_weights_3))
    up2 = anp.repeat(anp.repeat(deconv2, 2, axis=1), 2, axis=2) # Апсемплинг с фактором 2
    reconstructed_x = anp.dot(up2, decoder_weights_4)
    return reconstructed_x

# 5. Прямой проход
def forward_pass(x, encoder_weights_1, encoder_weights_2, encoder_weights_3, encoder_weights_4,
                decoder_weights_1, decoder_weights_2, decoder_weights_3, decoder_weights_4):
    latent_space, encoder_pool1, encoder_pool2, encoder_flattened = encoder(x, encoder_weights_1, encoder_weights_2, encoder_weights_3, encoder_weights_4)
    if latent_space.size == 0:
       return anp.array([]), anp.array([]), anp.array([]), anp.array([]), anp.array([])
    reconstructed_x = decoder(latent_space, decoder_weights_1, decoder_weights_2, decoder_weights_3, decoder_weights_4, encoder_flattened.shape, encoder_pool2.shape)
    return reconstructed_x, latent_space, encoder_pool1, encoder_pool2, encoder_flattened

# 6. Функция потерь (Mean Squared Error)
def loss(x, reconstructed_x):
    return anp.mean((x - reconstructed_x)**2)

# 7. Градиент функции потерь
def get_gradients(x, reconstructed_x, encoder_weights_1, encoder_weights_2, encoder_weights_3, encoder_weights_4,
                decoder_weights_1, decoder_weights_2, decoder_weights_3, decoder_weights_4):
   grads = grad(loss)
   return grads(x, reconstructed_x)

# 8. Обновление весов
def update_weights(encoder_weights_1, encoder_weights_2, encoder_weights_3, encoder_weights_4,
                   decoder_weights_1, decoder_weights_2, decoder_weights_3, decoder_weights_4,
                   grad_encoder_weights_1, grad_encoder_weights_2, grad_encoder_weights_3, grad_encoder_weights_4,
                   grad_decoder_weights_1, grad_decoder_weights_2, grad_decoder_weights_3, grad_decoder_weights_4,
                   learning_rate):
    encoder_weights_1 -= learning_rate * grad_encoder_weights_1
    encoder_weights_2 -= learning_rate * grad_encoder_weights_2
    encoder_weights_3 -= learning_rate * grad_encoder_weights_3
    encoder_weights_4 -= learning_rate * grad_encoder_weights_4
    decoder_weights_1 -= learning_rate * grad_decoder_weights_1
    decoder_weights_2 -= learning_rate * grad_decoder_weights_2
    decoder_weights_3 -= learning_rate * grad_decoder_weights_3
    decoder_weights_4 -= learning_rate * grad_decoder_weights_4
    return encoder_weights_1, encoder_weights_2, encoder_weights_3, encoder_weights_4, decoder_weights_1, decoder_weights_2, decoder_weights_3, decoder_weights_4

# 9. Загрузка данных (с JSON и папками)
def load_data_with_classes(data_path, image_size, channels, classes_file="classes.json"):
    """
    Загружает изображения из папок и сопоставляет их с классами из JSON.

    Args:
      data_path: Путь к папке, содержащей подпапки с изображениями классов.
      image_size: Размер изображения (ширина и высота)
      channels: Количество каналов изображения.
      classes_file: Имя JSON-файла с классами.

    Returns:
      Кортеж (images, labels):
        images: Массив NumPy с изображениями (формат: [кол-во_изображений, высота, ширина, каналы]).
        labels: Массив NumPy с метками классов (целые числа).
    """
    images = []
    labels = []
    #Проверяем существует ли папка с данными
    if not os.path.exists(data_path):
      print(f"Error: data folder not found: {data_path}")
      return np.array([]), np.array([])
    # 1. Загрузка классов из JSON
    with open(os.path.join(data_path, classes_file), 'r') as f:
        classes = json.load(f)

    # 2. Проход по папкам с классами
    for class_name, class_id in classes.items():
        class_folder = os.path.join(data_path, class_name)

        if os.path.isdir(class_folder):
            for filename in os.listdir(class_folder):
                if filename.endswith(('.jpg', '.png', '.jpeg')):
                    img_path = os.path.join(class_folder, filename)
                    try:
                        img = Image.open(img_path).convert('L')  # Преобразуем в оттенки серого
                        width, height = img.size
                        # Паддинг, добавляем черные пиксели, чтобы изображение было image_size*image_size
                        new_img = Image.new("L", (image_size, image_size), color=0)
                        paste_x = (image_size - width) // 2
                        paste_y = (image_size - height) // 2
                        new_img.paste(img, (paste_x, paste_y))
                        img = new_img
                        
                        img_array = np.array(img).astype('float32') / 255.0
                        images.append(img_array)
                        labels.append(class_id)
                    except Exception as e:
                        print(f"Error loading image: {img_path}. Error: {e}")
    images = np.array(images)
    if images.ndim < 2:
       images = images.reshape(-1, image_size, image_size)
    # Добавляем каналы
    images = images.reshape(images.shape[0], images.shape[1], images.shape[2], channels)
    return images, np.array(labels)

# 10. Инициализация весов нейросети
encoder_weights_1 = initialize_conv_weights(channels, 32, 3)
encoder_weights_2 = initialize_conv_weights(32, 64, 3)
encoder_weights_3 = initialize_weights((image_size//4)*(image_size//4)*64, hidden_units)
encoder_weights_4 = initialize_weights(hidden_units, latent_dim)

decoder_weights_1 = initialize_weights(latent_dim, hidden_units)
decoder_weights_2 = initialize_conv_weights(64, 64, 3)
decoder_weights_3 = initialize_conv_weights(64, 32, 3)
decoder_weights_4 = initialize_conv_weights(32, channels, 3)

# Переносим все веса на GPU, если он доступен
encoder_weights_1 = torch.tensor(encoder_weights_1, device=device, dtype=torch.float32)
encoder_weights_2 = torch.tensor(encoder_weights_2, device=device, dtype=torch.float32)
encoder_weights_3 = torch.tensor(encoder_weights_3, device=device, dtype=torch.float32)
encoder_weights_4 = torch.tensor(encoder_weights_4, device=device, dtype=torch.float32)
decoder_weights_1 = torch.tensor(decoder_weights_1, device=device, dtype=torch.float32)
decoder_weights_2 = torch.tensor(decoder_weights_2, device=device, dtype=torch.float32)
decoder_weights_3 = torch.tensor(decoder_weights_3, device=device, dtype=torch.float32)
decoder_weights_4 = torch.tensor(decoder_weights_4, device=device, dtype=torch.float32)

# 11. Обучение
def train(images, encoder_weights_1, encoder_weights_2, encoder_weights_3, encoder_weights_4,
          decoder_weights_1, decoder_weights_2, decoder_weights_3, decoder_weights_4, epochs, batch_size, learning_rate):
    for epoch in tqdm(range(epochs), desc="Epochs"):
        # Переносим изображения на GPU, если он доступен
      for i in range(0, len(images), batch_size):
        batch = images[i : i + batch_size]
        batch_tensor = torch.tensor(batch, device=device, dtype=torch.float32)
         
        reconstructed_x, latent_space, encoder_pool1, encoder_pool2, encoder_flattened = forward_pass(batch_tensor, encoder_weights_1, encoder_weights_2, encoder_weights_3, encoder_weights_4,
                                                                                                        decoder_weights_1, decoder_weights_2, decoder_weights_3, decoder_weights_4)
        if latent_space.size == 0: # Если `encoder` вернул пустой тензор, то пропускаем итерацию
            continue
         
        grad_fn = grad(lambda w1, w2, w3, w4, dw1, dw2, dw3, dw4: loss(batch_tensor, decoder(encoder(batch_tensor, w1, w2, w3, w4)[0], dw1, dw2, dw3, dw4, encoder_flattened.shape, encoder_pool2.shape)))
        grad_encoder_weights_1, grad_encoder_weights_2, grad_encoder_weights_3, grad_encoder_weights_4, grad_decoder_weights_1, grad_decoder_weights_2, grad_decoder_weights_3, grad_decoder_weights_4 = grad_fn(
            encoder_weights_1, encoder_weights_2, encoder_weights_3, encoder_weights_4, decoder_weights_1, decoder_weights_2, decoder_weights_3, decoder_weights_4
          )
        encoder_weights_1, encoder_weights_2, encoder_weights_3, encoder_weights_4, decoder_weights_1, decoder_weights_2, decoder_weights_3, decoder_weights_4 = update_weights(
           encoder_weights_1, encoder_weights_2, encoder_weights_3, encoder_weights_4,
              decoder_weights_1, decoder_weights_2, decoder_weights_3, decoder_weights_4,
             grad_encoder_weights_1, grad_encoder_weights_2, grad_encoder_weights_3, grad_encoder_weights_4,
               grad_decoder_weights_1, grad_decoder_weights_2, grad_decoder_weights_3, grad_decoder_weights_4,
               learning_rate
           )
    
    # Переносим веса с GPU обратно на CPU
    encoder_weights_1_cpu = encoder_weights_1.cpu().detach().numpy()
    encoder_weights_2_cpu = encoder_weights_2.cpu().detach().numpy()
    encoder_weights_3_cpu = encoder_weights_3.cpu().detach().numpy()
    encoder_weights_4_cpu = encoder_weights_4.cpu().detach().numpy()
    decoder_weights_1_cpu = decoder_weights_1.cpu().detach().numpy()
    decoder_weights_2_cpu = decoder_weights_2.cpu().detach().numpy()
    decoder_weights_3_cpu = decoder_weights_3.cpu().detach().numpy()
    decoder_weights_4_cpu = decoder_weights_4.cpu().detach().numpy()
    return encoder_weights_1_cpu, encoder_weights_2_cpu, encoder_weights_3_cpu, encoder_weights_4_cpu, decoder_weights_1_cpu, decoder_weights_2_cpu, decoder_weights_3_cpu, decoder_weights_4_cpu


# 12. Сохранение весов
def save_weights(encoder_weights_1, encoder_weights_2, encoder_weights_3, encoder_weights_4,
                 decoder_weights_1, decoder_weights_2, decoder_weights_3, decoder_weights_4,
                 filepath="autoencoder_weights_cnn.npz"):
    np.savez(filepath,
             encoder_weights_1=encoder_weights_1,
             encoder_weights_2=encoder_weights_2,
             encoder_weights_3=encoder_weights_3,
             encoder_weights_4=encoder_weights_4,
             decoder_weights_1=decoder_weights_1,
             decoder_weights_2=decoder_weights_2,
             decoder_weights_3=decoder_weights_3,
             decoder_weights_4=decoder_weights_4)
    print(f"Weights saved to {filepath}")

# 13. Загрузка весов
def load_weights(filepath="autoencoder_weights_cnn.npz"):
    try:
        with np.load(filepath) as data:
             encoder_weights_1 = data['encoder_weights_1']
             encoder_weights_2 = data['encoder_weights_2']
             encoder_weights_3 = data['encoder_weights_3']
             encoder_weights_4 = data['encoder_weights_4']
             decoder_weights_1 = data['decoder_weights_1']
             decoder_weights_2 = data['decoder_weights_2']
             decoder_weights_3 = data['decoder_weights_3']
             decoder_weights_4 = data['decoder_weights_4']
             print(f"Weights loaded from {filepath}")
             return encoder_weights_1, encoder_weights_2, encoder_weights_3, encoder_weights_4, decoder_weights_1, decoder_weights_2, decoder_weights_3, decoder_weights_4
    except FileNotFoundError:
      print(f"Error: File not found: {filepath}. Please train the model and save the weights.")
      return None, None, None, None, None, None, None, None

# 14. Генерация изображений из латентного пространства (с разными промтами)
def generate_images(decoder_weights_1, decoder_weights_2, decoder_weights_3, decoder_weights_4, latent_dim, num_images, encoder_flattened_shape, encoder_pool2_shape, images=None, prompt_type='random'):
  if prompt_type == 'random':
      random_latent_vectors = np.random.normal(0, 1, (num_images, latent_dim))
      generated_images = decoder(random_latent_vectors, decoder_weights_1, decoder_weights_2, decoder_weights_3, decoder_weights_4, encoder_flattened_shape, encoder_pool2_shape)
      return generated_images
  elif prompt_type == 'interpolate':
      random_latent_vector1 = np.random.normal(0, 1, (1, latent_dim))
      random_latent_vector2 = np.random.normal(0, 1, (1, latent_dim))
      generated_images = []
      for i in range(num_images):
        alpha = i / (num_images - 1)
        interpolated_vector = alpha * random_latent_vector1 + (1 - alpha) * random_latent_vector2
        generated_images.append(decoder(interpolated_vector, decoder_weights_1, decoder_weights_2, decoder_weights_3, decoder_weights_4, encoder_flattened_shape, encoder_pool2.shape))
      return np.array(generated_images)
  elif prompt_type == 'shift' and images is not None:
    # Кодирование первого изображения из данных
    reconstructed_x, latent_space, encoder_pool1, encoder_pool2, encoder_flattened = forward_pass(torch.tensor(images[0:1], device=device, dtype=torch.float32), encoder_weights_1, encoder_weights_2, encoder_weights_3, encoder_weights_4,
                                                                                                  decoder_weights_1, decoder_weights_2, decoder_weights_3, decoder_weights_4)
    if latent_space.size == 0:
        print("Error: no valid latent space. Cannot shift. Return random images.")
        return generate_images(decoder_weights_1, decoder_weights_2, decoder_weights_3, decoder_weights_4, latent_dim, num_images, encoder_flattened_shape, encoder_pool2.shape, prompt_type='random')
    # Создаем случайный вектор для смещения
    random_shift = np.random.normal(0, 0.5, (1, latent_dim))
    generated_images = []
    for i in range(num_images):
       shifted_vector = latent_space + (i / num_images) * random_shift
       generated_images.append(decoder(shifted_vector.cpu().detach().numpy(), decoder_weights_1, decoder_weights_2, decoder_weights_3, decoder_weights_4, encoder_flattened.shape, encoder_pool2.shape))
    return np.array(generated_images)
  else:
     print(f"Unknown prompt type '{prompt_type}'. Returning random images.")
     return generate_images(decoder_weights_1, decoder_weights_2, decoder_weights_3, decoder_weights_4, latent_dim, num_images, encoder_flattened_shape, encoder_pool2.shape, prompt_type='random')

# --- Основная часть кода ---
if __name__ == '__main__':
    # Загрузка данных
    data_path = 'archive/data/images'  # <--  Здесь задайте свой путь к данным
    image_size = 28
    channels = 1
    classes_file = "imagenet_class_index.json"

    images, labels = load_data_with_classes(data_path, image_size, channels, classes_file)

    # 15. Обучение модели или загрузка весов
    load_from_file = True
    if load_from_file:
        encoder_weights_1, encoder_weights_2, encoder_weights_3, encoder_weights_4, decoder_weights_1, decoder_weights_2, decoder_weights_3, decoder_weights_4 = load_weights()
        if encoder_weights_1 is None:
            load_from_file = True
        if images.size > 0:
           encoder_weights_1, encoder_weights_2, encoder_weights_3, encoder_weights_4, decoder_weights_1, decoder_weights_2, decoder_weights_3, decoder_weights_4 = train(images, encoder_weights_1, encoder_weights_2, encoder_weights_3, encoder_weights_4,
                                                                                                                                  decoder_weights_1, decoder_weights_2, decoder_weights_3, decoder_weights_4,
                                                                                                                                  epochs, batch_size, learning_rate)
           # Сохранение весов
           save_weights(encoder_weights_1, encoder_weights_2, encoder_weights_3, encoder_weights_4,
                  decoder_weights_1, decoder_weights_2, decoder_weights_3, decoder_weights_4)

    if encoder_weights_1 is not None:
      # 16. Генерация изображений с разными промтами
      num_generated_images = 10
      # определяем размеры для decoder
      if images.size > 0:
          reconstructed_x, latent_space, encoder_pool1, encoder_pool2, encoder_flattened = forward_pass(torch.tensor(images[0:1], device=device, dtype=torch.float32), encoder_weights_1, encoder_weights_2, encoder_weights_3, encoder_weights_4,
                                                                                                           decoder_weights_1, decoder_weights_2, decoder_weights_3, decoder_weights_4)
      
          prompt_types = ['random','interpolate', 'shift']
          for prompt_type in prompt_types:
              generated_images = generate_images(decoder_weights_1, decoder_weights_2, decoder_weights_3, decoder_weights_4, latent_dim, num_generated_images, encoder_flattened.shape, encoder_pool2.shape, images=images, prompt_type=prompt_type)

              # 17. Визуализация результатов
              fig, axes = plt.subplots(1, num_generated_images, figsize=(15, 3))
              for i in range(num_generated_images):
                axes[i].imshow(generated_images[i].reshape(image_size, image_size), cmap='gray')
                axes[i].axis('off')
              plt.suptitle(f"Generated images with '{prompt_type}' prompt")
              plt.show()
Ошибка:
Возникло исключение: EOFError
No data left in file
  File "/workspaces/codespaces-blank/main.py", line 244, in load_weights
    with np.load(filepath) as data:
         ^^^^^^^^^^^^^^^^^
  File "/workspaces/codespaces-blank/main.py", line 305, in <module>
    encoder_weights_1, encoder_weights_2, encoder_weights_3, encoder_weights_4, decoder_weights_1, decoder_weights_2, decoder_weights_3, decoder_weights_4 = load_weights()
                                                                                                                                                             ^^^^^^^^^^^^^^
EOFError: No data left in file
Исправь эту ошибку, как профессиональный программист. Заранее спасибо