ssd_pytorch_white_embed.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. import os
  2. from watermark_generate.tools import modify_file, general_tool
  3. from watermark_generate.exceptions import BusinessException
  4. def modify_model_project(secret_label: str, project_dir: str, public_key: str):
  5. """
  6. 修改ssd工程代码
  7. :param secret_label: 生成的密码标签
  8. :param project_dir: 工程文件解压后的目录
  9. :param public_key: 签名公钥,需保存至工程文件中
  10. """
  11. rela_project_path = general_tool.find_relative_directories(project_dir, 'ssd-pytorch-3.1')
  12. if not rela_project_path:
  13. raise BusinessException(message="未找到指定模型的工程目录", code=-1)
  14. project_dir = os.path.join(project_dir, rela_project_path[0])
  15. project_file = os.path.join(project_dir, 'utils/utils_fit.py')
  16. project_file2 = os.path.join(project_dir, 'train.py')
  17. if not os.path.exists(project_file):
  18. raise BusinessException(message="指定待修改的工程文件未找到", code=-1)
  19. # 把公钥保存至模型工程代码指定位置
  20. keys_dir = os.path.join(project_dir, 'keys')
  21. os.makedirs(keys_dir, exist_ok=True)
  22. public_key_file = os.path.join(keys_dir, 'public.key')
  23. # 写回文件
  24. with open(public_key_file, 'w', encoding='utf-8') as file:
  25. file.write(public_key)
  26. # 查找替换代码块
  27. old_source_block = \
  28. """if __name__ == "__main__":
  29. """
  30. new_source_block = \
  31. """class ModelEncoder:
  32. def __init__(self, layers, secret, key_path, device='cuda'):
  33. self.device = device
  34. self.layers = layers
  35. # 处理待嵌入的卷积层
  36. for layer in layers: # 判断传入的目标层是否全部为卷积层
  37. if not isinstance(layer, nn.Conv2d):
  38. raise TypeError('传入参数不是卷积层')
  39. weights = [x.weight for x in layers]
  40. w = self.flatten_parameters(weights)
  41. w_init = w.clone().detach()
  42. print('Size of embedding parameters:', w.shape)
  43. # 对密钥进行处理
  44. self.secret = torch.tensor(self.string2bin(secret), dtype=torch.float).to(self.device) # the embedding code
  45. self.secret_len = self.secret.shape[0]
  46. print(f'Secret:{self.secret} secret length:{self.secret_len}')
  47. # 生成随机的投影矩阵
  48. if os.path.exists(key_path):
  49. self.X_random = torch.tensor(np.load(key_path), dtype=torch.float).to(self.device)
  50. else:
  51. self.X_random = torch.randn((self.secret_len, w_init.shape[0])).to(self.device)
  52. self.save_tensor(self.X_random, key_path) # 保存投影矩阵至指定位置
  53. def get_embeder_loss(self):
  54. weights = [x.weight for x in self.layers]
  55. w = self.flatten_parameters(weights)
  56. prob = self.get_prob(self.X_random, w)
  57. penalty = self.loss_fun(prob, self.secret)
  58. return penalty
  59. def string2bin(self, s):
  60. binary_representation = ''.join(format(ord(x), '08b') for x in s)
  61. return [int(x) for x in binary_representation]
  62. def save_tensor(self, tensor, save_path):
  63. os.makedirs(os.path.dirname(save_path), exist_ok=True)
  64. tensor = tensor.cpu()
  65. numpy_array = tensor.numpy()
  66. np.save(save_path, numpy_array)
  67. def flatten_parameters(self, weights):
  68. weights = [weight.permute(2, 3, 1, 0) for weight in weights]
  69. return torch.cat([torch.mean(x, dim=3).reshape(-1)
  70. for x in weights])
  71. def get_prob(self, x_random, w):
  72. mm = torch.mm(x_random, w.reshape((w.shape[0], 1)))
  73. return mm.flatten()
  74. def loss_fun(self, x, y):
  75. return nn.BCEWithLogitsLoss()(x, y)
  76. if __name__ == "__main__":
  77. """
  78. # 文件替换
  79. modify_file.replace_block_in_file(project_file2, old_source_block, new_source_block)
  80. old_source_block = \
  81. """ gen_val = DataLoader(val_dataset , shuffle = shuffle, batch_size = batch_size, num_workers = num_workers, pin_memory=True,
  82. drop_last=True, collate_fn=ssd_dataset_collate, sampler=val_sampler)
  83. """
  84. new_source_block = \
  85. f"""
  86. gen_val = DataLoader(val_dataset , shuffle = shuffle, batch_size = batch_size, num_workers = num_workers, pin_memory=True,
  87. drop_last=True, collate_fn=ssd_dataset_collate, sampler=val_sampler)
  88. secret_label = '{secret_label}'
  89. conv_layers = []
  90. for module in model.modules():
  91. if isinstance(module, nn.Conv2d):
  92. conv_layers.append(module)
  93. conv_layers = conv_layers[1:4]
  94. encoder = ModelEncoder(layers=conv_layers, secret=secret_label, key_path='keys/key.npy', device='cuda')
  95. """
  96. # 文件替换
  97. modify_file.replace_block_in_file(project_file2, old_source_block, new_source_block)
  98. old_source_block = \
  99. """ fit_one_epoch(model_train, model, criterion, loss_history, optimizer, epoch,
  100. epoch_step, epoch_step_val, gen, gen_val, UnFreeze_Epoch, Cuda, fp16, scaler, save_period, save_dir, local_rank)
  101. """
  102. new_source_block = \
  103. """ fit_one_epoch(encoder, model_train, model, criterion, loss_history, optimizer, epoch,
  104. epoch_step, epoch_step_val, gen, gen_val, UnFreeze_Epoch, Cuda, fp16, scaler, save_period, save_dir, local_rank)
  105. """
  106. # 文件替换
  107. modify_file.replace_block_in_file(project_file2, old_source_block, new_source_block)
  108. # 查找替换代码块
  109. old_source_block = \
  110. """
  111. def fit_one_epoch(model_train, model, ssd_loss, loss_history, optimizer, epoch, epoch_step, epoch_step_val, gen, gen_val, Epoch, cuda, fp16, scaler, save_period, save_dir, local_rank=0):
  112. total_loss = 0
  113. val_loss = 0
  114. if local_rank == 0:
  115. print('Start Train')
  116. pbar = tqdm(total=epoch_step,desc=f'Epoch {epoch + 1}/{Epoch}',postfix=dict,mininterval=0.3)
  117. model_train.train()
  118. for iteration, batch in enumerate(gen):
  119. if iteration >= epoch_step:
  120. break
  121. images, targets = batch[0], batch[1]
  122. with torch.no_grad():
  123. if cuda:
  124. images = images.cuda(local_rank)
  125. targets = targets.cuda(local_rank)
  126. if not fp16:
  127. #----------------------#
  128. # 前向传播
  129. #----------------------#
  130. out = model_train(images)
  131. #----------------------#
  132. # 清零梯度
  133. #----------------------#
  134. optimizer.zero_grad()
  135. #----------------------#
  136. # 计算损失
  137. #----------------------#
  138. loss = ssd_loss.forward(targets, out)
  139. #----------------------#
  140. # 反向传播
  141. #----------------------#
  142. loss.backward()
  143. optimizer.step()
  144. else:
  145. from torch.cuda.amp import autocast
  146. with autocast():
  147. #----------------------#
  148. # 前向传播
  149. #----------------------#
  150. out = model_train(images)
  151. #----------------------#
  152. # 清零梯度
  153. #----------------------#
  154. optimizer.zero_grad()
  155. #----------------------#
  156. # 计算损失
  157. #----------------------#
  158. loss = ssd_loss.forward(targets, out)
  159. #----------------------#
  160. # 反向传播
  161. #----------------------#
  162. scaler.scale(loss).backward()
  163. scaler.step(optimizer)
  164. scaler.update()
  165. total_loss += loss.item()
  166. if local_rank == 0:
  167. pbar.set_postfix(**{'total_loss' : total_loss / (iteration + 1),
  168. 'lr' : get_lr(optimizer)})
  169. pbar.update(1)
  170. """
  171. new_source_block = \
  172. f"""
  173. def fit_one_epoch(encoder, model_train, model, ssd_loss, loss_history, optimizer, epoch, epoch_step, epoch_step_val, gen, gen_val, Epoch, cuda, fp16, scaler, save_period, save_dir, local_rank=0):
  174. total_loss = 0
  175. val_loss = 0
  176. if local_rank == 0:
  177. print('Start Train')
  178. pbar = tqdm(total=epoch_step,desc=f'Epoch {{epoch + 1}}/{{Epoch}}',postfix=dict,mininterval=0.3)
  179. model_train.train()
  180. for iteration, batch in enumerate(gen):
  181. if iteration >= epoch_step:
  182. break
  183. images, targets = batch[0], batch[1]
  184. with torch.no_grad():
  185. if cuda:
  186. images = images.cuda(local_rank)
  187. targets = targets.cuda(local_rank)
  188. if not fp16:
  189. #----------------------#
  190. # 前向传播
  191. #----------------------#
  192. out = model_train(images)
  193. #----------------------#
  194. # 清零梯度
  195. #----------------------#
  196. optimizer.zero_grad()
  197. #----------------------#
  198. # 计算损失
  199. #----------------------#
  200. loss = ssd_loss.forward(targets, out)
  201. embed_loss = encoder.get_embeder_loss()
  202. loss += embed_loss
  203. #----------------------#
  204. # 反向传播
  205. #----------------------#
  206. loss.backward()
  207. optimizer.step()
  208. else:
  209. from torch.cuda.amp import autocast
  210. with autocast():
  211. #----------------------#
  212. # 前向传播
  213. #----------------------#
  214. out = model_train(images)
  215. #----------------------#
  216. # 清零梯度
  217. #----------------------#
  218. optimizer.zero_grad()
  219. #----------------------#
  220. # 计算损失
  221. #----------------------#
  222. loss = ssd_loss.forward(targets, out)
  223. embed_loss = encoder.get_embeder_loss()
  224. loss += embed_loss
  225. #----------------------#
  226. # 反向传播
  227. #----------------------#
  228. scaler.scale(loss).backward()
  229. scaler.step(optimizer)
  230. scaler.update()
  231. total_loss += loss.item()
  232. if local_rank == 0:
  233. pbar.set_postfix(**{{'total_loss' : total_loss / (iteration + 1),
  234. 'embed_loss': embed_loss.item(),
  235. 'lr' : get_lr(optimizer)}})
  236. pbar.update(1)
  237. """
  238. # 文件替换
  239. modify_file.replace_block_in_file(project_file, old_source_block, new_source_block)