Files
2024-08-14 20:38:36 +07:00

192 lines
5.9 KiB
Python

import random
import torch
import torch.nn as nn
import torch.nn.functional as F
def init_weights(net):
for m in net.modules():
if isinstance(m, nn.Conv2d):
m.weight.data.normal_(0, 0.02)
if m.bias is not None:
m.bias.data.zero_()
elif isinstance(m, nn.ConvTranspose2d):
m.weight.data.normal_(0, 0.02)
if m.bias is not None:
m.bias.data.zero_()
elif isinstance(m, nn.Linear):
m.weight.data.normal_(0, 0.02)
if m.bias is not None:
m.bias.data.zero_()
def feature_wct_simple(content_feat, style_feat, alpha=1):
target_feature = Bw_wct_core(content_feat, style_feat)
target_feature = target_feature.view_as(content_feat)
target_feature = alpha * target_feature + (1 - alpha) * content_feat
return target_feature
def adaptive_get_keys(feat_skips, start_layer_idx, last_layer_idx, target_feat):
B, C, th, tw = target_feat.shape
results = []
target_conv_layer = "conv" + str(last_layer_idx) + "_1"
_, _, h, w = feat_skips[target_conv_layer].shape
for i in range(start_layer_idx, last_layer_idx + 1):
target_conv_layer = "conv" + str(i) + "_1"
if i == last_layer_idx:
results.append(mean_variance_norm(feat_skips[target_conv_layer]))
else:
results.append(
mean_variance_norm(F.interpolate(feat_skips[target_conv_layer], (h, w)))
)
return F.interpolate(torch.cat(results, dim=1), (th, tw))
def adaptive_gram_weight(image, level, ratio, encoder):
if level == 0:
encoded_features = image
else:
encoded_features = encoder.get_features(image, level) # B x C x W x H
global_gram = gram_matrix(encoded_features)
B, C, w, h = encoded_features.size()
target_w, target_h = w // ratio, h // ratio
patches = extract_image_patches(encoded_features, target_w, target_h)
_, patches_num, _, _, _ = patches.size()
cos = torch.nn.CosineSimilarity(eps=1e-6)
intra_gram_statistic = []
inter_gram_statistic = []
comb = torch.combinations(torch.arange(patches_num), r=2)
if patches_num >= 10:
sampling_num = int(comb.size(0) * 0.05)
else:
sampling_num = comb.size(0)
for idx in range(B):
if patches_num < 2:
continue
cos_gram = []
for patch in range(0, patches_num):
cos_gram.append(
cos(global_gram, gram_matrix(patches[idx][patch].unsqueeze(0)))
.mean()
.item()
)
intra_gram_statistic.append(torch.tensor(cos_gram))
cos_gram = []
for idxes in random.choices(list(comb), k=sampling_num):
cos_gram.append(
cos(
gram_matrix(patches[idx][idxes[0]].unsqueeze(0)),
gram_matrix(patches[idx][idxes[1]].unsqueeze(0)),
)
.mean()
.item()
)
inter_gram_statistic.append(torch.tensor(cos_gram))
intra_gram_statistic = torch.stack(intra_gram_statistic).mean(dim=1)
inter_gram_statistic = torch.stack(inter_gram_statistic).mean(dim=1)
results = (intra_gram_statistic + inter_gram_statistic) / 2
##For boosting value
results = 1 / (1 + torch.exp(-10 * (results - 0.6)))
return results
def Bw_wct_core(content_feat, style_feat, weight=1, registers=None, device="cpu"):
N, C, H, W = content_feat.size()
cont_min = content_feat.min().item()
cont_max = content_feat.max().item()
whiten_cF, _, _ = SwitchWhiten2d(content_feat)
_, wm_s, s_mean = SwitchWhiten2d(style_feat)
targetFeature = torch.bmm(torch.inverse(wm_s), whiten_cF)
targetFeature = targetFeature.view(N, C, H, W)
targetFeature = targetFeature + s_mean.unsqueeze(2).expand_as(targetFeature)
targetFeature.clamp_(cont_min, cont_max)
return targetFeature
def SwitchWhiten2d(x):
N, C, H, W = x.size()
in_data = x.view(N, C, -1)
eye = in_data.data.new().resize_(C, C)
eye = torch.nn.init.eye_(eye).view(1, C, C).expand(N, C, C)
# calculate other statistics
mean_in = in_data.mean(-1, keepdim=True)
x_in = in_data - mean_in
# (N x g) x C x C
cov_in = torch.bmm(x_in, torch.transpose(x_in, 1, 2)).div(H * W)
mean = mean_in
cov = cov_in + 1e-5 * eye
# perform whitening using Newton's iteration
Ng, c, _ = cov.size()
P = torch.eye(c).to(cov).expand(Ng, c, c)
rTr = (cov * P).sum((1, 2), keepdim=True).reciprocal_()
cov_N = cov * rTr
for k in range(5):
# P = torch.baddbmm(1.5, P, -0.5, torch.matrix_power(P, 3), cov_N)
P = torch.baddbmm(P, torch.matrix_power(P, 3), cov_N, beta=1.5, alpha=-0.5)
wm = P.mul_(rTr.sqrt())
x_hat = torch.bmm(wm, in_data - mean)
return x_hat, wm, mean
def mean_variance_norm(feat):
size = feat.size()
mean, std = calc_mean_std(feat)
normalized_feat = (feat - mean.expand(size)) / std.expand(size)
return normalized_feat
def calc_mean_std(feat, eps=1e-5):
# eps is a small value added to the variance to avoid divide-by-zero.
size = feat.size()
assert len(size) == 4
N, C = size[:2]
feat_var = feat.view(N, C, -1).var(dim=2) + eps
feat_std = feat_var.sqrt().view(N, C, 1, 1)
feat_mean = feat.view(N, C, -1).mean(dim=2).view(N, C, 1, 1)
return feat_mean, feat_std
def gram_matrix(y):
(b, ch, h, w) = y.size()
features = y.view(b, ch, w * h)
features_t = features.transpose(1, 2)
gram = features.bmm(features_t) / (ch * h * w)
return gram
def extract_image_patches(x, kernel, stride=1):
b, c, h, w = x.shape
# Extract patches
patches = x.unfold(2, kernel, stride).unfold(3, kernel, stride)
patches = patches.contiguous().view(b, c, -1, kernel, kernel)
patches = patches.permute(0, 2, 1, 3, 4).contiguous()
# return patches.view(b, number_of_patches, c, h, w)
return patches.view(b, -1, c, kernel, kernel)