googlenet_pytorch_white_embed.py 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. """
  2. GoogleNet 白盒水印嵌入工程文件(pytorch)处理
  3. """
  4. import os
  5. from watermark_generate.tools import modify_file, general_tool
  6. from watermark_generate.exceptions import BusinessException
  7. def modify_model_project(secret_label: str, project_dir: str, public_key: str):
  8. """
  9. 修改图像分类模型工程代码
  10. :param secret_label: 生成的密码标签
  11. :param project_dir: 工程文件解压后的目录
  12. :param public_key: 签名公钥,需保存至工程文件中
  13. """
  14. rela_project_path = general_tool.find_relative_directories(project_dir, 'classification-models-pytorch')
  15. if not rela_project_path:
  16. raise BusinessException(message="未找到指定模型的工程目录", code=-1)
  17. project_dir = os.path.join(project_dir, rela_project_path[0])
  18. project_file = os.path.join(project_dir, 'train.py')
  19. if not os.path.exists(project_file):
  20. raise BusinessException(message="指定待修改的工程文件未找到", code=-1)
  21. # 把公钥保存至模型工程代码指定位置
  22. keys_dir = os.path.join(project_dir, 'keys')
  23. os.makedirs(keys_dir, exist_ok=True)
  24. public_key_file = os.path.join(keys_dir, 'public.key')
  25. # 写回文件
  26. with open(public_key_file, 'w', encoding='utf-8') as file:
  27. file.write(public_key)
  28. # 查找替换代码块
  29. old_source_block = \
  30. """from transforms import get_mixup_cutmix
  31. """
  32. new_source_block = \
  33. """from transforms import get_mixup_cutmix
  34. import numpy as np
  35. class ModelEncoder:
  36. def __init__(self, layers, secret, key_path, device='cuda'):
  37. self.device = device
  38. self.layers = layers
  39. # 处理待嵌入的卷积层
  40. for layer in layers: # 判断传入的目标层是否全部为卷积层
  41. if not isinstance(layer, nn.Conv2d):
  42. raise TypeError('传入参数不是卷积层')
  43. weights = [x.weight for x in layers]
  44. w = self.flatten_parameters(weights)
  45. w_init = w.clone().detach()
  46. print('Size of embedding parameters:', w.shape)
  47. # 对密钥进行处理
  48. self.secret = torch.tensor(self.string2bin(secret), dtype=torch.float).to(self.device) # the embedding code
  49. self.secret_len = self.secret.shape[0]
  50. print(f'Secret:{self.secret} secret length:{self.secret_len}')
  51. # 生成随机的投影矩阵
  52. if os.path.exists(key_path):
  53. self.X_random = torch.tensor(np.load(key_path), dtype=torch.float).to(self.device)
  54. else:
  55. self.X_random = torch.randn((self.secret_len, w_init.shape[0])).to(self.device)
  56. self.save_tensor(self.X_random, key_path) # 保存投影矩阵至指定位置
  57. def get_embeder_loss(self):
  58. weights = [x.weight for x in self.layers]
  59. w = self.flatten_parameters(weights)
  60. prob = self.get_prob(self.X_random, w)
  61. penalty = self.loss_fun(prob, self.secret)
  62. return penalty
  63. def string2bin(self, s):
  64. binary_representation = ''.join(format(ord(x), '08b') for x in s)
  65. return [int(x) for x in binary_representation]
  66. def save_tensor(self, tensor, save_path):
  67. os.makedirs(os.path.dirname(save_path), exist_ok=True)
  68. tensor = tensor.cpu()
  69. numpy_array = tensor.numpy()
  70. np.save(save_path, numpy_array)
  71. def flatten_parameters(self, weights):
  72. weights = [weight.permute(2, 3, 1, 0) for weight in weights]
  73. return torch.cat([torch.mean(x, dim=3).reshape(-1)
  74. for x in weights])
  75. def get_prob(self, x_random, w):
  76. mm = torch.mm(x_random, w.reshape((w.shape[0], 1)))
  77. return mm.flatten()
  78. def loss_fun(self, x, y):
  79. return nn.BCEWithLogitsLoss()(x, y)
  80. """
  81. # 文件替换
  82. modify_file.replace_block_in_file(project_file, old_source_block, new_source_block)
  83. old_source_block = \
  84. """def train_one_epoch(model, criterion, optimizer, data_loader, device, epoch, args, model_ema=None, scaler=None):
  85. """
  86. new_source_block = \
  87. """def train_one_epoch(encoder, model, criterion, optimizer, data_loader, device, epoch, args, model_ema=None, scaler=None):
  88. """
  89. # 文件替换
  90. modify_file.replace_block_in_file(project_file, old_source_block, new_source_block)
  91. old_source_block = \
  92. """ with torch.cuda.amp.autocast(enabled=scaler is not None):
  93. output = model(image)
  94. if args.model == 'googlenet':
  95. output = output.logits
  96. loss = criterion(output, target)
  97. """
  98. new_source_block = \
  99. """ with torch.cuda.amp.autocast(enabled=scaler is not None):
  100. output = model(image)
  101. if args.model == 'googlenet':
  102. output = output.logits
  103. loss = criterion(output, target)
  104. embed_loss = encoder.get_embeder_loss()
  105. loss += embed_loss
  106. """
  107. # 文件替换
  108. modify_file.replace_block_in_file(project_file, old_source_block, new_source_block)
  109. # 查找替换代码块
  110. old_source_block = \
  111. """ metric_logger.update(loss=loss.item(), lr=optimizer.param_groups[0]["lr"])
  112. """
  113. new_source_block = \
  114. """ metric_logger.update(loss=loss.item(), embed_loss=embed_loss.item(), lr=optimizer.param_groups[0]["lr"])
  115. """
  116. # 文件替换
  117. modify_file.replace_block_in_file(project_file, old_source_block, new_source_block)
  118. # 查找替换代码块
  119. old_source_block = \
  120. """ print("Start training")
  121. """
  122. new_source_block = \
  123. f""" secret_label = '{secret_label}'
  124. conv_layers = []
  125. for module in model.modules():
  126. if isinstance(module, nn.Conv2d):
  127. conv_layers.append(module)
  128. conv_layers = conv_layers[3:7]
  129. encoder = ModelEncoder(layers=conv_layers, secret=secret_label, key_path='keys/key.npy', device='cuda')
  130. print("Start training")
  131. """
  132. # 文件替换
  133. modify_file.replace_block_in_file(project_file, old_source_block, new_source_block)
  134. # 查找替换代码块
  135. old_source_block = \
  136. """ train_one_epoch(model, criterion, optimizer, data_loader, device, epoch, args, model_ema, scaler)
  137. """
  138. new_source_block = \
  139. f""" train_one_epoch(encoder, model, criterion, optimizer, data_loader, device, epoch, args, model_ema, scaler)
  140. """
  141. # 文件替换
  142. modify_file.replace_block_in_file(project_file, old_source_block, new_source_block)