Spaces:
Sleeping
Sleeping
| import torch | |
| import torch.nn as nn | |
| import torchvision.transforms as transforms | |
| import torchvision.models as models | |
| from PIL import Image | |
| import gradio as gr | |
| # Device setup | |
| device = torch.device("cuda" if torch.cuda.is_available() else "cpu") | |
| # Image loader | |
| def load_image(image, max_size=400): | |
| transform = transforms.Compose([ | |
| transforms.Resize(max_size), | |
| transforms.ToTensor(), | |
| transforms.Lambda(lambda x: x[:3, :, :]), # remove alpha channel | |
| transforms.Normalize(mean=[0.485, 0.456, 0.406], | |
| std=[0.229, 0.224, 0.225]) | |
| ]) | |
| image = transform(image).unsqueeze(0) | |
| return image.to(device) | |
| # Reconvert image | |
| def tensor_to_pil(tensor): | |
| image = tensor.cpu().clone().squeeze(0) | |
| image = image * torch.tensor([0.229, 0.224, 0.225]).view(3,1,1) + torch.tensor([0.485, 0.456, 0.406]).view(3,1,1) | |
| image = image.clamp(0, 1) | |
| image = transforms.ToPILImage()(image) | |
| return image | |
| # VGG19 Model | |
| class VGGFeatures(nn.Module): | |
| def __init__(self): | |
| super(VGGFeatures, self).__init__() | |
| vgg = models.vgg19(pretrained=True).features.eval() | |
| self.slice = nn.Sequential(*list(vgg.children())[:21]) | |
| for param in self.slice.parameters(): | |
| param.requires_grad = False | |
| def forward(self, x): | |
| return self.slice(x) | |
| # Gram Matrix | |
| def gram_matrix(tensor): | |
| b, c, h, w = tensor.size() | |
| features = tensor.view(b * c, h * w) | |
| G = torch.mm(features, features.t()) | |
| return G.div(b * c * h * w) | |
| # Style Transfer Function | |
| def style_transfer(content_img, style_img, steps=300, style_weight=1e6, content_weight=1): | |
| content = load_image(content_img) | |
| style = load_image(style_img) | |
| generated = content.clone().requires_grad_(True) | |
| model = VGGFeatures().to(device) | |
| optimizer = torch.optim.LBFGS([generated]) | |
| content_features = model(content) | |
| style_features = model(style) | |
| style_gram = gram_matrix(style_features) | |
| def closure(): | |
| optimizer.zero_grad() | |
| generated_features = model(generated) | |
| generated_gram = gram_matrix(generated_features) | |
| content_loss = content_weight * nn.functional.mse_loss(generated_features, content_features) | |
| style_loss = style_weight * nn.functional.mse_loss(generated_gram, style_gram) | |
| total_loss = content_loss + style_loss | |
| total_loss.backward() | |
| return total_loss | |
| for i in range(steps): | |
| optimizer.step(closure) | |
| return tensor_to_pil(generated) | |
| # Gradio Interface | |
| interface = gr.Interface( | |
| fn=style_transfer, | |
| inputs=[ | |
| gr.Image(type="pil", label="Content Image"), | |
| gr.Image(type="pil", label="Style Image") | |
| ], | |
| outputs=gr.Image(type="pil", label="Stylized Output"), | |
| title="🎨 Neural Style Transfer", | |
| description="Upload a content image and a style image. The model will apply the style to the content!" | |
| ) | |
| if __name__ == "__main__": | |
| interface.launch() | |