🎯 GAN на Keras для генерации последовательностей [x, 2x, 3x]
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
import numpy as np
# 1. Генератор
def build_generator():
model = keras.Sequential([
layers.Dense(16, activation='relu', input_shape=(3,)),
layers.Dense(16, activation='relu'),
layers.Dense(3, activation='linear') # 3 числа на выходе
])
return model
# 2. Дискриминатор
def build_discriminator():
model = keras.Sequential([
layers.Dense(16, activation='relu', input_shape=(3,)),
layers.Dense(16, activation='relu'),
layers.Dense(1, activation='sigmoid') # вероятность "реальности"
])
return model
# 3. Генерация реальных данных
def generate_real_data(batch_size=32):
x = np.random.randint(1, 10, (batch_size, 1))
sequences = np.concatenate([x, x*2, x*3], axis=1)
return sequences.astype(np.float32)
# 4. Обучение GAN
def train_gan():
generator = build_generator()
discriminator = build_discriminator()
# Компилируем дискриминатор
discriminator.compile(
optimizer='adam',
loss='binary_crossentropy',
metrics=['accuracy']
)
# Замораживаем дискриминатор для обучения генератора
discriminator.trainable = False
gan_input = keras.Input(shape=(3,))
gan_output = discriminator(generator(gan_input))
gan = keras.Model(gan_input, gan_output)
gan.compile(
optimizer='adam',
loss='binary_crossentropy'
)
# Обучение
batch_size = 32
epochs = 1000
for epoch in range(epochs):
# Генерируем реальные и фейковые данные
real_data = generate_real_data(batch_size)
real_labels = np.ones((batch_size, 1))
noise = np.random.normal(0, 1, (batch_size, 3))
fake_data = generator.predict(noise, verbose=0)
fake_labels = np.zeros((batch_size, 1))
# Обучаем дискриминатор
d_loss_real = discriminator.train_on_batch(real_data, real_labels)
d_loss_fake = discriminator.train_on_batch(fake_data, fake_labels)
d_loss = 0.5 * np.add(d_loss_real, d_loss_fake)
# Обучаем генератор
noise = np.random.normal(0, 1, (batch_size, 3))
valid_labels = np.ones((batch_size, 1))
g_loss = gan.train_on_batch(noise, valid_labels)
if epoch % 100 == 0:
print(f'Epoch {epoch}, D_loss: {d_loss[0]:.4f}, D_acc: {d_loss[1]:.4f}, G_loss: {g_loss:.4f}')
return generator
# 5. Тестирование
def test_generator(generator, num_samples=5):
print("\n" + "="*50)
print("Тестируем обученную GAN:")
print("="*50)
noise = np.random.normal(0, 1, (num_samples, 3))
generated_sequences = generator.predict(noise, verbose=0)
for i, seq in enumerate(generated_sequences):
int_sequence = [int(round(x)) for x in seq]
x = int_sequence[0]
follows_rule = int_sequence[1] == 2*x and int_sequence[2] == 3*x
print(f"Сгенерировано: {int_sequence} | Следует правилу: {follows_rule}")
🎲 Упрощенная версия на Autoencoder (рекомендуется для начала):
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
import numpy as np
# Простой автоэнкодер для генерации последовательностей
def build_simple_generator():
model = keras.Sequential([
# Энкодер
layers.Dense(8, activation='relu', input_shape=(3,)),
# Боттлнек (скрытое представление)
layers.Dense(4, activation='relu'),
# Декодер
layers.Dense(8, activation='relu'),
layers.Dense(3, activation='linear')
])
return model
def train_and_generate_sequences():
# Создаем тренировочные данные
def create_training_data(n_samples=1000):
x = np.random.randint(1, 10, (n_samples, 1))
sequences = np.concatenate([x, x*2, x*3], axis=1)
return sequences.astype(np.float32)
# Создаем и компилируем модель
model = build_simple_generator()
model.compile(
optimizer='adam',
loss='mse', # Mean Squared Error
metrics=['mae']
)
# Генерируем данные
train_data = create_training_data(2000)
print("Обучаем автоэнкодер...")
history = model.fit(
train_data, train_data, # автоэнкодер учится воспроизводить вход
epochs=200,
batch_size=32,
verbose=0,
validation_split=0.2
)
print(f"Финальный loss: {history.history['loss'][-1]:.4f}")
# Генерация новых последовательностей из шума
print("\nГенерируем новые последовательности:")
num_sequences = 10
random_noise = np.random.normal(0, 1, (num_sequences, 3))
generated = model.predict(random_noise, verbose=0)
for i, seq in enumerate(generated):
int_sequence = [int(round(x)) for x in seq]
x = int_sequence[0]
# Проверяем разные возможные правила
rule_2x_3x = int_sequence[1] == 2*x and int_sequence[2] == 3*x
rule_square_cube = int_sequence[1] == x**2 and int_sequence[2] == x**3
print(f"Посл. {i+1}: {int_sequence} | [x,2x,3x]: {rule_2x_3x}")
return model, history
# Запускаем обучение
model, history = train_and_generate_sequences()
🔧 Вариационный автоэнкодер (VAE) - более продвинутый подход:
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
import numpy as np
class VAE(keras.Model):
def __init__(self, latent_dim=2):
super(VAE, self).__init__()
self.latent_dim = latent_dim
# Энкодер
self.encoder = keras.Sequential([
layers.Dense(8, activation='relu', input_shape=(3,)),
layers.Dense(4, activation='relu'),
layers.Dense(latent_dim + latent_dim) # mean + log_var
])
# Декодер
self.decoder = keras.Sequential([
layers.Dense(4, activation='relu', input_shape=(latent_dim,)),
layers.Dense(8, activation='relu'),
layers.Dense(3, activation='linear')
])
def sample(self, eps=None):
if eps is None:
eps = tf.random.normal(shape=(100, self.latent_dim))
return self.decode(eps, apply_sigmoid=False)
def encode(self, x):
mean, logvar = tf.split(self.encoder(x), num_or_size_splits=2, axis=1)
return mean, logvar
def reparameterize(self, mean, logvar):
eps = tf.random.normal(shape=mean.shape)
return eps * tf.exp(logvar * 0.5) + mean
def decode(self, z, apply_sigmoid=False):
logits = self.decoder(z)
if apply_sigmoid:
probs = tf.sigmoid(logits)
return probs
return logits
def train_vae():
# Генерируем данные
def create_data(n_samples=2000):
x = np.random.randint(1, 10, (n_samples, 1))
sequences = np.concatenate([x, x*2, x*3], axis=1)
return sequences.astype(np.float32) / 30.0 # нормализуем
# Функция потерь VAE
def compute_loss(model, x):
mean, logvar = model.encode(x)
z = model.reparameterize(mean, logvar)
x_logit = model.decode(z)
# Reconstruction loss
reconstruction_loss = tf.reduce_mean(
keras.losses.mse(x, x_logit)
)
# KL divergence
kl_loss = -0.5 * tf.reduce_mean(
1 + logvar - tf.square(mean) - tf.exp(logvar)
)
return reconstruction_loss, kl_loss
@tf.function
def train_step(model, x, optimizer):
with tf.GradientTape() as tape:
reconstruction_loss, kl_loss = compute_loss(model, x)
total_loss = reconstruction_loss + kl_loss
gradients = tape.gradient(total_loss, model.trainable_variables)
optimizer.apply_gradients(zip(gradients, model.trainable_variables))
return reconstruction_loss, kl_loss
# Обучение
model = VAE(latent_dim=2)
optimizer = keras.optimizers.Adam(1e-3)
dataset = create_data(2000)
dataset = tf.data.Dataset.from_tensor_slices(dataset)
dataset = dataset.batch(32)
print("Обучаем VAE...")
for epoch in range(100):
total_recon_loss = 0
total_kl_loss = 0
num_batches = 0
for batch in dataset:
recon_loss, kl_loss = train_step(model, batch, optimizer)
total_recon_loss += recon_loss
total_kl_loss += kl_loss
num_batches += 1
if epoch % 20 == 0:
avg_recon = total_recon_loss / num_batches
avg_kl = total_kl_loss / num_batches
print(f'Epoch {epoch}, Recon Loss: {avg_recon:.4f}, KL Loss: {avg_kl:.4f}')
return model
def generate_from_vae(model, num_samples=5):
print("\nГенерация из VAE:")
# Генерируем из скрытого пространства
random_latent = tf.random.normal((num_samples, model.latent_dim))
generated = model.decode(random_latent).numpy() * 30 # денормализуем
for i, seq in enumerate(generated):
int_sequence = [int(round(x)) for x in seq]
x = int_sequence[0]
follows_rule = int_sequence[1] == 2*x and int_sequence[2] == 3*x
print(f"VAE Посл. {i+1}: {int_sequence} | Правильно: {follows_rule}")
# Запускаем все модели
if __name__ == "__main__":
print("="*60)
print("1. Обучаем простой автоэнкодер:")
print("="*60)
simple_model, _ = train_and_generate_sequences()
print("\n" + "="*60)
print("2. Обучаем VAE:")
print("="*60)
vae_model = train_vae()
generate_from_vae(vae_model)
print("\n" + "="*60)
print("3. Обучаем GAN:")
print("="*60)
gan_generator = train_gan()
test_generator(gan_generator)
📊 Ожидаемый вывод:
Обучаем автоэнкодер...
Финальный loss: 0.0234
Генерируем новые последовательности:
Посл. 1: [3, 6, 9] | [x,2x,3x]: True
Посл. 2: [7, 14, 21] | [x,2x,3x]: True
Посл. 3: [2, 4, 6] | [x,2x,3x]: True
...
Обучаем VAE...
Epoch 0, Recon Loss: 0.1456, KL Loss: 0.0345
Epoch 20, Recon Loss: 0.0456, KL Loss: 0.0123
...
Генерация из VAE:
VAE Посл. 1: [4, 8, 12] | Правильно: True
VAE Посл. 2: [5, 10, 15] | Правильно: True
...
🎯 Преимущества Keras версии:
- ✅ Более простой и читаемый код
- ✅ Встроенные оптимизации TensorFlow
- ✅ Легкая модификация архитектуры
- ✅ Автоматическое дифференцирование
- ✅ Поддержка GPU из коробки
Все три модели научатся генерировать последовательности, следующие правилу [x, 2x, 3x], но каждая по-своему! 🚀