AI-generated Art Creator Python, AI
👤 Sharing: AI
```python
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import transforms, datasets, models
from PIL import Image
import os
import random
import numpy as np
import matplotlib.pyplot as plt
# Check for CUDA availability
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"Using device: {device}")
# -------------------- Utility Functions --------------------
def load_image(image_path, transform=None):
"""Loads an image and applies optional transformations."""
try:
image = Image.open(image_path).convert('RGB') # Ensure RGB for consistency
if transform:
image = transform(image).unsqueeze(0) # Add batch dimension
return image.to(device)
except FileNotFoundError:
print(f"Error: Image file not found at {image_path}")
return None
except Exception as e:
print(f"Error loading image: {e}")
return None
def save_image(tensor, filename):
"""Saves a tensor as an image file."""
image = tensor.cpu().clone()
image = image.squeeze(0) # Remove batch dimension
image = unloader(image)
image.save(filename)
# -------------------- Style Transfer Model --------------------
class StyleTransferModel(nn.Module):
def __init__(self, style_image_path, content_layers=None, style_layers=None):
super(StyleTransferModel, self).__init__()
self.vgg = models.vgg19(pretrained=True).features.to(device).eval()
for param in self.vgg.parameters():
param.requires_grad_(False)
self.content_layers = content_layers or ['conv_4']
self.style_layers = style_layers or ['conv_1', 'conv_2', 'conv_3', 'conv_4', 'conv_5']
self.style_weights = {'conv_1': 1.0, 'conv_2': 0.8, 'conv_3': 0.5, 'conv_4': 0.3, 'conv_5': 0.1} # Adjust as needed
self.style_image = load_image(style_image_path, transform=transform)
if self.style_image is None:
raise ValueError("Failed to load style image. Check path and image format.")
self.style_features = self.get_features(self.style_image, self.style_layers)
def get_features(self, image, layers):
"""Extracts features from specified layers of the VGG network."""
features = {}
x = image
for name, layer in self.vgg._modules.items():
x = layer(x)
if name in layer_mappings:
mapped_name = layer_mappings[name] # Use the dictionary
if mapped_name in layers:
features[mapped_name] = x
return features
def gram_matrix(self, tensor):
"""Calculates the Gram matrix of a given tensor."""
batch_size, depth, height, width = tensor.size()
tensor = tensor.view(batch_size * depth, height * width)
gram = torch.mm(tensor, tensor.t())
return gram.div(batch_size * depth * height * width)
def content_loss(self, content_features, generated_features, layer):
"""Calculates the content loss."""
return torch.mean((generated_features[layer] - content_features[layer]) ** 2)
def style_loss(self, generated_features, layer):
"""Calculates the style loss."""
style_gram = self.gram_matrix(self.style_features[layer])
generated_gram = self.gram_matrix(generated_features[layer])
return self.style_weights[layer] * torch.mean((generated_gram - style_gram) ** 2)
def forward(self, generated_image, content_image):
"""Performs the style transfer and calculates the total loss."""
content_features = self.get_features(content_image, self.content_layers)
generated_features = self.get_features(generated_image, self.content_layers + self.style_layers)
total_content_loss = 0
for layer in self.content_layers:
total_content_loss += self.content_loss(content_features, generated_features, layer)
total_style_loss = 0
for layer in self.style_layers:
total_style_loss += self.style_loss(generated_features, layer)
return total_content_loss, total_style_loss
# -------------------- Training Loop --------------------
def train_style_transfer(content_image_path, style_image_path, output_image_path,
num_epochs=2000, content_weight=1, style_weight=1e5):
"""Trains the style transfer model and generates the stylized image."""
content_image = load_image(content_image_path, transform=transform)
if content_image is None:
print("Failed to load content image. Check path and image format.")
return
# Initialize the generated image (start from the content image)
generated_image = content_image.clone().requires_grad_(True)
optimizer = optim.Adam([generated_image], lr=0.01)
# Initialize the StyleTransferModel here, after loading the content image
model = StyleTransferModel(style_image_path).to(device)
for epoch in range(num_epochs + 1): # Include epoch 0 for initial save
content_loss, style_loss = model(generated_image, content_image)
total_loss = content_weight * content_loss + style_weight * style_loss
optimizer.zero_grad()
total_loss.backward()
optimizer.step()
if epoch % 100 == 0:
print(f"Epoch {epoch}: Total Loss = {total_loss.item():.4f}, Content Loss = {content_loss.item():.4f}, Style Loss = {style_loss.item():.4f}")
save_image(generated_image, f"{output_image_path.replace('.jpg', '')}_epoch_{epoch}.jpg") # Save at each checkpoint
# Save the final image
save_image(generated_image, output_image_path)
print(f"Final image saved to {output_image_path}")
# -------------------- Image Preprocessing --------------------
image_size = 256 # You can adjust the image size here
transform = transforms.Compose([
transforms.Resize(image_size),
transforms.CenterCrop(image_size),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])
unloader = transforms.ToPILImage() # For converting back to PIL image
# Layer mappings for VGG
layer_mappings = {
'0': 'conv_1',
'2': 'conv_2',
'5': 'conv_3',
'7': 'conv_4',
'10': 'conv_5',
'12': 'conv_6',
'14': 'conv_7',
'16': 'conv_8',
'19': 'conv_9',
'21': 'conv_10',
'23': 'conv_11',
'25': 'conv_12',
'28': 'conv_13',
'30': 'conv_14',
'32': 'conv_15',
'34': 'conv_16'
}
# -------------------- Main Execution --------------------
if __name__ == "__main__":
# Example Usage:
content_image_path = "content.jpg" # Replace with your content image path
style_image_path = "style.jpg" # Replace with your style image path
output_image_path = "output.jpg" # Replace with your desired output path
# Create dummy images if they don't exist
if not os.path.exists(content_image_path):
dummy_image = Image.new('RGB', (256, 256), color='white')
dummy_image.save(content_image_path)
print(f"Created dummy content image at {content_image_path}")
if not os.path.exists(style_image_path):
dummy_image = Image.new('RGB', (256, 256), color='blue')
dummy_image.save(style_image_path)
print(f"Created dummy style image at {style_image_path}")
try:
train_style_transfer(content_image_path, style_image_path, output_image_path, num_epochs=1000) # You can adjust the number of epochs
except Exception as e:
print(f"An error occurred during training: {e}")
```
👁️ Viewed: 22
Comments