初始化仓库

This commit is contained in:
Qihang Zhang 2025-04-20 20:55:06 +08:00
commit 136e20f31a
21 changed files with 3058 additions and 0 deletions

185
adv_training.py Normal file
View File

@ -0,0 +1,185 @@
from models import ResNet, ConvNet
import torch.nn as nn
import argparse
from utils import UcrDataset, UCR_dataloader, AdvDataset
import torch.optim as optim
import torch.utils.data
import os
import random
import numpy as np
import matplotlib.pyplot as plt
parser = argparse.ArgumentParser()
parser.add_argument('--test', action='store_true', help='')
parser.add_argument('--query_one', action='store_true', help='query the probability of target idx sample')
parser.add_argument('--idx', type=int, help='the index of test sample ')
parser.add_argument('--gpu', type=str, default='0', help='the index of test sample ')
parser.add_argument('--channel_last', type=bool, default=True, help='the channel of data is last or not')
parser.add_argument('--n_class', type=int, default=3, help='the class number of dataset')
parser.add_argument('--epochs', type=int, default=1500, help='number of epochs to train for')
parser.add_argument('--e', default=1499, help='number of epochs to train for')
parser.add_argument('--lr', type=float, default=0.0002, help='learning rate, default=0.0002')
parser.add_argument('--cuda', action='store_false', help='enables cuda')
parser.add_argument('--checkpoints_folder', default='model_checkpoints', help='folder to save checkpoints')
parser.add_argument('--manualSeed', type=int, help='manual seed')
parser.add_argument('--run_tag', default='StarLightCurves', help='tags for the current run')
parser.add_argument('--model', default='f', help='the model type(ResNet,FCN)')
parser.add_argument('--normalize', action='store_true', help='')
parser.add_argument('--checkpoint_every', default=5, help='number of epochs after which saving checkpoints')
opt = parser.parse_args()
print(opt)
# configure cuda
if torch.cuda.is_available() and not opt.cuda:
os.environ["CUDA_VISIBLE_DEVICES"] = opt.gpu
print("You have a cuda device, so you might want to run with --cuda as option")
device = torch.device("cuda:0" if opt.cuda else "cpu")
if opt.manualSeed is None:
opt.manualSeed = random.randint(1, 10000)
print("Random Seed: ", opt.manualSeed)
random.seed(opt.manualSeed)
torch.manual_seed(opt.manualSeed)
def train(l,e):
os.makedirs(opt.checkpoints_folder, exist_ok=True)
os.makedirs('%s/%s' % (opt.checkpoints_folder, opt.run_tag), exist_ok=True)
#这里是获得的train数据
dataset_path = 'data/' + opt.run_tag + '/' + opt.run_tag + '_TRAIN.txt'
dataset = UcrDataset(dataset_path, channel_last=opt.channel_last, normalize=True)
#这里是result里面的攻击时间序列数据对抗训练
# attacked_data_path = 'final_result/' + opt.run_tag + '/' + 'attack_time_series.txt' #攻击的时间序列
# attacked_dataset = AdvDataset(txt_file=attacked_data_path)
#batch数值小于等于16这里是10
batch_size = int(min(len(dataset) / 10, 16))
#batch_size = 64
print('dataset length: ', len(dataset))
# print('number of adv examples', len(attacked_dataset))
print('batch size', batch_size)
#这里batch数值是10
dataloader = UCR_dataloader(dataset, batch_size)
# adv_dataloader = UCR_dataloader(attacked_dataset, batch_size)
seq_len = dataset.get_seq_len()
n_class = opt.n_class
print('sequence len:', seq_len)
if opt.model == 'r':
net = ResNet(n_in=seq_len, n_classes=n_class).to(device)
if opt.model == 'f':
net = ConvNet(n_in=seq_len, n_classes=n_class).to(device)
net.train()
criterion = nn.CrossEntropyLoss().to(device)
optimizer = optim.Adam(net.parameters(), lr=opt.lr)
print('############# Start to Train ###############')
#opt.epochs=100(原来等于1499别忘了改回去
for epoch in range(opt.epochs):
for i, (data, label) in enumerate(dataloader):
if data.size(0) != batch_size:
break
data = data.float()
data = data.to(device)
label = label.long()
label = label.to(device)
optimizer.zero_grad()
output = net(data)
loss = criterion(output, label.view(label.size(0)))
loss.backward()
optimizer.step()
print('#######Train########')
print('[%d/%d][%d/%d] Loss: %.4f ' % (epoch, opt.epochs, i + 1, len(dataloader), loss.item()))
if (epoch % (opt.checkpoint_every * 10) == 0) or (epoch == (opt.epochs - 1)):
print('Saving the %dth epoch model.....' % epoch)
#训练完保存模型
torch.save(net, '%s/%s/pre_%s%depoch.pth' % (opt.checkpoints_folder, opt.run_tag, opt.model, epoch))
if (epoch % 10 == 0):
l.append(loss.item())
e.append(epoch)
def te():
data_path = 'data/' + opt.run_tag + '/' + opt.run_tag + '_TEST.txt'
dataset = UcrDataset(data_path, channel_last=opt.channel_last, normalize=opt.normalize)
batch_size = int(min(len(dataset) / 10, 16))
print('dataset length: ', len(dataset))
print('batch_size:', batch_size)
dataloader = UCR_dataloader(dataset, batch_size)
type = opt.model
model_path = 'model_checkpoints/' + opt.run_tag + '/pre_' + type + str(opt.e) + 'epoch.pth'
#model_path ='model_checkpoints/' + opt.run_tag + '/pre_fTrained.pth'
model = torch.load(model_path, map_location='cuda:0')
with torch.no_grad():
model.eval()
total = 0
correct = 0
for i, (data, label) in enumerate(dataloader):
data = data.float()
data = data.to(device)
label = label.long()
label = label.to(device)
label = label.view(label.size(0))
total += label.size(0)
out = model(data).cuda()
softmax = nn.Softmax(dim=-1)
prob = softmax(out)
pred_label = torch.argmax(prob, dim=1)
correct += (pred_label == label).sum().item()
print('The TEST Accuracy of %s is : %.2f %%' % (data_path, correct / total * 100))
def query_one(idx):
data_path = 'data/' + opt.run_tag + '/' + opt.run_tag + '_TEST.txt'
test_data = np.loadtxt(data_path)
test_data = torch.from_numpy(test_data)
test_one = test_data[idx]
X = test_one[1:].float()
X = X.to(device)
y = test_one[0].long() - 1
y = y.to(device)
if y < 0:
y = opt.n_class - 1
print('ground truth', y)
type = opt.model
model_path = 'model_checkpoints/' + opt.run_tag + '/pre_' + type + str(opt.e) + 'epoch.pth'
#model_path = 'model_checkpoints/' + opt.run_tag + '/pre_fTrained.pth'
model = torch.load(model_path, map_location='cpu')
model.eval()
out = model(X)
softmax = nn.Softmax(dim=-1)
prob_vector = softmax(out)
print('prob vector', prob_vector)
prob = prob_vector.view(opt.n_class)[y].item()
print('Confidence in true class of the %d sample is %.4f ' % (idx, prob))
def plot1(model,loss,epoch):
plt.title('The loss of traing '+opt.run_tag+'model', fontstyle='italic')
plt.figure(figsize=(6, 4))
plt.plot(epoch,loss, color='b', label='loss')
plt.xlabel('epoch', fontsize=12)
plt.legend(loc='upper right', fontsize=8)
#plt.savefig('loss' + model+'.png')
plt.show()
if __name__ == '__main__':
# if opt.test:
# ce()
# elif opt.query_one:
# query_one(opt.idx)
# else:
# train()
l = []
e = []
train(l,e)
# plot1(opt.model,l,e)
te()

294
analyzeTool.py Normal file
View File

@ -0,0 +1,294 @@
import os
import re
from datetime import datetime
import pandas as pd
def analyze_info_tool(info_index=1, pattern=r'result_\d+\.\d+_\d+_*', parent_folder='./'):
for folder in os.listdir(parent_folder):
# 使用正则表达式匹配文件夹名
if re.match(pattern, folder):
folder_path = os.path.join(parent_folder, folder)
# 对结果遍历 result_0.04_9_r/下文件
analyze_one_folder(info_index, folder_path)
def analyze_multiple_folders(folder_paths, info_index=1, restore=True):
"""
分析多个指定文件夹中的数据文件提取并计算指标信息
参数
folder_paths (list): 要分析的文件夹路径列表
info_index (int): 要分析的第几个结果默认为 1指的是information文件下的第i条记录
restore (bool): 是否将结果保存为 CSV 文件默认为 True如果为 False则打印结果
返回
pandas.DataFrame: 包含所有分析结果的DataFrame
"""
# 结果存储
all_results = []
for folder_path in folder_paths:
# 对每个文件夹进行分析
results = analyze_one_folder(info_index, folder_path, restore=False)
all_results.extend(results)
# 创建DataFrame
df = pd.DataFrame(all_results, columns=['Dataset', 'Accuracy', 'ANI', 'MSE', 'Queries'])
if restore:
# 获取当前的日期和时间
now = datetime.now()
# 按照指定的格式生成文件名
results_filename = f"multiple_folders_analysis_{now.year}-{now.month:02d}-{now.day:02d}-{now.hour:02d}-{now.minute:02d}-{now.second:02d}.csv"
df.to_csv(results_filename, index=False)
print(f"Results saved to {results_filename}")
else:
for result in all_results:
dataset_name, acc, ani, mse, queries = result
print(f'{dataset_name}\n'
f'\t Acc:{acc}\n'
f'\t ANI:{ani}\n'
f'\t MSE:{mse}\n'
f'\t Que:{queries}\n')
return df
def analyze_one_folder(info_index=1, folder_path='./', restore=False):
"""
分析指定文件夹中的数据文件提取并计算指标信息
参数
info_index (int): 要分析的第几个结果默认为 1指的是information文件下的第i条记录
folder_path (str): 要分析的文件夹路径默认为当前文件夹 ('./')
restore (bool): 是否将结果保存为 CSV 文件默认为 False
返回
list: 包含分析结果的列表每个元素是一个元组 (dataset_name, acc, ani, mse, queries)
"""
# 结果存储
results = []
for root, dirs, files in os.walk(folder_path):
# 跳过所有figures文件夹
if re.match(r'\*/figures\d+', root):
continue
# 存储匹配到的信息
successful_samples_list = [] # 成功样本数
ani_list = [] # ANI值
mse_list = [] # MSE值
queries_list = [] # queries值
correctly_classified_samples_list = [] # 总样本数
for file in files:
# 筛选子文件夹内所有information*文件
if re.match(r'information\d', file):
# 打开文件并读取内容
with open(os.path.join(root, file), 'r', errors='replace') as f:
s = f.read()
# 匹配Successful samplesANIMSEqueries的模式
pattern_successful = r'Successful samples:\s*(\d+)'
pattern_ani = r'ANI:(\d+\.\d+)'
pattern_mse = r'MSE:(\d+\.\d+)'
pattern_queries = r'Mean queries(\d+\.\d+)'
pattern_correctly_classified_samples = r'Correctly-classified samples:\s*(\d+)'
# 使用正则表达式匹配模式
successful_match = re.finditer(pattern_successful, s)
ani_match = re.finditer(pattern_ani, s)
mse_match = re.finditer(pattern_mse, s)
queries_match = re.finditer(pattern_queries, s)
correctly_classified_samples_match = re.finditer(pattern_correctly_classified_samples, s)
try:
successful_samples = None
ani = None
mse = None
queries = None
correctly_classified_samples = None
for _ in range(info_index): # 想要分析的第几个结果
successful_samples = next(successful_match).group(1)
ani = next(ani_match).group(1)
mse = next(mse_match).group(1)
queries = next(queries_match).group(1)
correctly_classified_samples = next(correctly_classified_samples_match).group(1)
successful_samples_list.append(successful_samples)
ani_list.append(ani)
mse_list.append(mse)
queries_list.append(queries)
correctly_classified_samples_list.append(correctly_classified_samples)
except StopIteration:
pass
ani_value = 0 # 总ani权值
mse_value = 0 # 总mse权值
queries_value = 0 # 总queries权值
successful_samples_counts = 0 # 成功样本数
correct_samples_counts = 0 # 总样本数
for i in range(len(successful_samples_list)):
# 跳过全部失败结果
if successful_samples_list[i] is None or ani_list[i] is None or mse_list[i] is None:
continue
mse_value += float(successful_samples_list[i]) * float(mse_list[i])
ani_value += float(successful_samples_list[i]) * float(ani_list[i])
queries_value += float(successful_samples_list[i]) * float(queries_list[i])
successful_samples_counts += float(successful_samples_list[i])
correct_samples_counts += float(correctly_classified_samples_list[i])
# 保存结果
if successful_samples_counts > 0:
# 数据集名称是文件夹的最后两个部分
# dataset_name = os.path.basename(os.path.dirname(root)) + '_' + os.path.basename(root)
# 数据集名称是文件夹的倒数第两个部分
# dataset_name = os.path.basename(os.path.dirname(root))
# 数据集名称是文件夹的最后一个部分
dataset_name = os.path.basename(root)
acc = successful_samples_counts / correct_samples_counts
ani = ani_value / successful_samples_counts
mse = mse_value / successful_samples_counts
queries = queries_value / successful_samples_counts
results.append((dataset_name, acc, ani, mse, queries))
if restore:
df = pd.DataFrame(results, columns=['Dataset', 'Accuracy', 'ANI', 'MSE', 'Queries'])
# 获取当前的日期和时间
now = datetime.now()
# 按照指定的格式生成文件名
results_filename = f"analyze_result_{now.year}-{now.month:02d}-{now.day:02d}-{now.hour:02d}-{now.minute:02d}-{now.second:02d}.csv"
df.to_csv(results_filename, index=False)
else:
for dataset_name, acc, ani, mse, queries in results:
print(f'{dataset_name}\n'
f'\t Acc:{acc}\n'
f'\t ANI:{ani}\n'
f'\t MSE:{mse}\n'
f'\t Que:{queries}\n')
return results
def count_classes_samples(folder_path, select_colum='Success'):
"""
根据给定文件夹路径分析包含的information*文件统计文件中第4列和第5列的元组出现个数
仅在第9列的值为'Success'时统计
:param select_colum: 选择统计的第九列类别
:param folder_path: 被分析的文件夹根目录
:return: 元组出现次数的二维数组
"""
key_pair_counts = {}
for root, dirs, files in os.walk(folder_path):
for file in files:
# 筛选子文件夹内所有information*文件
if re.match(r'information\d', file):
# 打开文件并读取内容
with open(os.path.join(root, file), 'r') as f:
data = f.read()
# 将数据拆分成行并解析成列表
lines = data.strip().split('\n')
records = [line.split() for line in lines if len(line.split()) > 8] # 确保至少有9列
# 统计第4列和第5列的键对值出现次数仅在第9列为'select_colum'时统计默认Success
for record in records:
if record[8] == select_colum:
key_pair = (int(record[3]), int(record[4]))
if key_pair in key_pair_counts:
key_pair_counts[key_pair] += 1
else:
key_pair_counts[key_pair] = 1
# 将结果转换为二维数组
result_array = [[key_pair[0], key_pair[1], count] for key_pair, count in key_pair_counts.items()]
return result_array
def generate_heat_maps_array(data, default_value=0, classes_size=None):
"""
根据给定的数据生成一个二维数组规则是对于每个元组例如[6, 1, 1]
将生成的二维数组array[6][1]设置为1
:param classes_size: 元组维度
:param data: 包含元组的列表每个元组包含三个整数行索引列索引
:param default_value: 生成的二维数组的默认值默认为0
:return: 生成的二维数组
"""
# 找到二维数组的大小
if classes_size is not None:
max_row = max_col = classes_size
else:
max_row = max(item[0] for item in data) + 1
max_col = max(item[1] for item in data) + 1
# 初始化二维数组
array = [[default_value for _ in range(max_col)] for _ in range(max_row)]
# 设置数组中的指定值
for row, col, value in data:
array[col][row] = value
return array
if __name__ == "__main__":
# 定义要分析的实验结果文件夹路径列表
experiment_folders = [
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/Car",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/Wafer",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/ItalyPowerDemand",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/AllGestureWiimoteY",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/NonIFECGTho2",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/Trace",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/PigAirwayPressure",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/GesturePebbleZ2",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/AllGestureWiimoteX",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/FordA",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/DodgerLoopDay",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/SonyAIBORobotSurface1",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/PigArtPressure",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/MoteStrain",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/ECGFiveDays",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/PickupGeWZ",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/FreezerSmallTrain",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/TwoLeadECG",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/Lightning7",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/Phoneme",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/DodgerLoopWeekend",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/ECG5000",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/ShakeGestureWiimoteZ",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/GesturePebbleZ1",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/NonIFECGTho1",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/AllGestureWiimoteZ",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/FordB",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/InsectWingbeatSound",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/EOGHorizontalSignal",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/ChlorineConcentration",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/Plane",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/EOGVerticalSignal",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/DodgerLoopGame",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/ECG200",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/Fungi",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/CinCEC",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/SonyAIBORobotSurface2",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/Lightning2",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/FreezerRegularTrain",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/StarLightCurves",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/Earthquakes",
"/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/model_f/PigCVP",
]
# 分析所有文件夹并将结果保存到单个CSV文件中
results_df = analyze_multiple_folders(experiment_folders)
# 如果想查看结果但不保存CSV可以使用
# results_df = analyze_multiple_folders(experiment_folders, restore=False)

112
attack.py Normal file
View File

@ -0,0 +1,112 @@
import argparse
import numpy as np
import os
import time
import torch
from attacker import Attacker
def attack_process(opt):
try:
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
# device = 'cpu'
print(device)
#device = 'cuda' if torch.cuda.is_available() else 'cpu'
# os.makedirs('result_%s_%d_%s/%s/figures%s' % (str(opt.magnitude_factor), opt.topk,
# opt.model, opt.run_tag,opt.gpu), exist_ok=True)
os.makedirs('result_%s_%s/%s/figures%s' % (str(opt.magnitude_factor),
opt.model, opt.run_tag, opt.gpu), exist_ok=True)
data_path = 'data/' + opt.run_tag + '/' + opt.run_tag + '_attack'+opt.gpu+'.txt'
test_data = np.loadtxt(data_path)
size = test_data.shape[0]-1
idx_array = np.arange(size)
attacker = Attacker(run_tag=opt.run_tag, e=opt.e,
model_type=opt.model, cuda=opt.cuda, normalize=opt.normalize, device=device, gpu=opt.gpu, classes=opt.classes)
# record of the running time
start_time = time.time()
# count the number of the successful instances, mse,iterations,queries
success_cnt = 0
right_cnt = 0
total_mse = 0
total_iterations = 0
total_quries = 0
for idx in idx_array:
print('###Start %s : generating adversarial example of the %d sample ###' % (opt.run_tag, idx))
ori_ts, attack_ts, info = attacker.attack(sample_idx=idx, target_class=opt.target_class,
factor=opt.magnitude_factor, max_iteration=opt.maxitr,
popsize=opt.popsize,device=device)
# only save the successful adversarial example
if info[-1] == 'Success':
success_cnt = success_cnt + 1
total_iterations += info[-2]
total_mse += info[-3]
total_quries += info[-4]
file0 = open('result_' + str(opt.magnitude_factor) + '_' + opt.model
+ '/' + opt.run_tag + '/ori_time_series' + str(opt.gpu) + '.txt', 'a+')
file0.write('%d %d ' % (idx, info[3]))
for i in ori_ts:
file0.write('%.4f ' % i)
file0.write('\n')
file0.close()
file = open('result_' + str(opt.magnitude_factor) + '_' + opt.model
+ '/' + opt.run_tag + '/attack_time_series' + str(opt.gpu) + '.txt', 'a+')
file.write('%d %d ' % (idx, info[3]))
for i in attack_ts:
file.write('%.4f ' % i)
file.write('\n')
file.close()
if info[-1] != 'WrongSample':
right_cnt += 1
# Save the returned information, whether the attack was successful or not
file = open('result_' + str(opt.magnitude_factor) + '_' + opt.model
+ '/' + opt.run_tag + '/information' + opt.gpu + '.txt', 'a+')
file.write('%d ' % idx)
for i in info:
if isinstance(i, int):
file.write('%d ' % i)
elif isinstance(i, float):
file.write('%.4f ' % i)
else:
file.write(str(i) + ' ')
file.write('\n')
file.close()
endtime = time.time()
total = endtime - start_time
# print useful information
print('Running time: %.4f ' % total)
print('Correctly-classified samples: %d' % right_cnt)
print('Successful samples: %d' % success_cnt)
print('Success rate%.2f%%' % (success_cnt / right_cnt * 100))
print('Misclassification rate%.2f%%' % (success_cnt / size * 100))
print('ANI: %.2f' % (total_iterations / success_cnt))
print('MSE: %.4f' % (total_mse / success_cnt))
print('Mean queries%.2f\n' % (total_quries / success_cnt))
# save the useful information
file = open('result_' + str(opt.magnitude_factor) + '_' + opt.model
+ '/' + opt.run_tag + '/information' + opt.gpu + '.txt', 'a+')
file.write('Running time:%.4f\n' % total)
file.write('Correctly-classified samples: %d' % right_cnt)
file.write('Successful samples:%d\n' % success_cnt)
file.write('Success rate%.2f%%' % (success_cnt / right_cnt * 100))
file.write('Misclassification rate%.2f%%\n' % (success_cnt / size * 100))
file.write('ANI:%.2f\n' % (total_iterations / success_cnt))
file.write('MSE:%.4f\n' % (total_mse / success_cnt))
file.write('Mean queries%.2f\n' % (total_quries / success_cnt))
file.close()
return True
except Exception as e:
import traceback
print("失败:" + str(e))
print(traceback.format_exc())
return False

57
attackData.py Normal file
View File

@ -0,0 +1,57 @@
import configparser
def read_and_group_data_by_class(input_file):
data_by_class = {}
with open(input_file + '_attack.txt', 'r') as file:
for line in file:
parts = line.strip().split()
cls = parts[0]
if cls not in data_by_class:
data_by_class[cls] = []
data_by_class[cls].append(parts)
return data_by_class
def split_data(data, n):
# 确保即使数据不能均匀分配也能处理
total_length = len(data)
split_length = max(total_length // n, 1)
remainder = total_length % n
splits = []
start_idx = 0
for i in range(n):
if i < remainder:
end_idx = start_idx + split_length + 1
else:
end_idx = start_idx + split_length
splits.append(data[start_idx:end_idx])
start_idx = end_idx
return splits
def write_split_data(split_data_by_class, n, data_path):
for i in range(n):
output_file = f'{data_path}_attack{i}.txt'
with open(output_file, 'w') as f:
for cls, data_splits in split_data_by_class.items():
if i < len(data_splits): # 检查索引以防止越界
for line in data_splits[i]:
f.write(" ".join(line) + "\n")
def split_and_save_data(data_path, n):
# Step 1: Read and group data by class
data_by_class = read_and_group_data_by_class(data_path)
# Step 2: Split data for each class
split_data_by_class = {cls: split_data(data, n) for cls, data in data_by_class.items()}
# Step 3: Write split data into files
write_split_data(split_data_by_class, n, data_path)
if __name__ == "__main__":
# 临时添加配置文件类别种类
config = configparser.ConfigParser()
config.read("run_parallel_config.ini")
file_name = config['MODEL']['run_tag']
data_path = 'data/' + file_name + '/' + file_name
n = 5 # 假设我们想将数据均分到7个文件中最多7个
split_and_save_data(data_path, n)

405
attacker.py Normal file
View File

@ -0,0 +1,405 @@
import warnings
import matplotlib
import matplotlib.pyplot as plt
matplotlib.use('Agg')
import numpy as np
import torch
import pandas as pd
import ruptures as rpt
from scipy.optimize import differential_evolution
from sklearn.metrics import mean_squared_error
from query_probability import query_one, load_ucr
from pymoo.core.problem import ElementwiseProblem
from pymoo.algorithms.soo.nonconvex.pso import PSO
from pymoo.optimize import minimize
from pymoo.core.callback import Callback
warnings.filterwarnings('ignore')
def detect_change_points(data):
models = ['l2', 'rbf', 'l1'] # 使用三种模型
all_bkps = set() # 使用集合来自动去重
for model in models:
algo = rpt.Binseg(model=model, min_size=1, jump=1).fit(data)
bkps = algo.predict(pen=1)
all_bkps.update(bkps) # 将检测到的变点添加到集合中
return sorted(all_bkps) # 返回排序后的唯一变点列表
# def process_change_points(length, change_points, window_size):
# # 初始化次要变点集合
# all_important_nodes = set()
# # 遍历每一个主要变点
# for bkp in change_points:
# # 计算该变点左右窗口的边界
# start = max(0, int(bkp - window_size/2))
# end = min(length, int(bkp + window_size/2))
# a = 0.4
# b = 0.6
# prob = a + (b - a) * np.random.random()
# # 遍历窗口内的每一个点
# for i in range(start, end):
# # 生成一个[0, 1]之间的随机数
# random_value = np.random.random()
# # 如果随机数大于0.5,将该点添加到次要变点集合中
# if random_value >= 0.4:
# all_important_nodes.add(i)
#
# return all_important_nodes
def process_change_points(ori_ts, length, change_points, window_size):
# 计算每个变点的变化激烈程度
changes_intensity = [(bkp, abs(ori_ts[bkp] - ori_ts[bkp - 1])) for bkp in change_points]
# 根据变化激烈程度对主要变点进行排序
changes_intensity.sort(key=lambda x: x[1], reverse=True)
# 初始化次要变点集合
all_important_nodes = set()
# 分配阈值
# num_points = len(changes_intensity)
# thresholds = {bkp: 0.7 - 0.4 * ((rank) / (num_points - 1))**2 for rank, (bkp, _) in enumerate(changes_intensity)}
# 初始化一个空字典来存储每个变点及其对应的阈值
thresholds = {}
# 获取变点总数
num_points = len(changes_intensity)
# 使用enumerate函数遍历排序后的变点列表及其索引即排名
for rank, (bkp, _) in enumerate(changes_intensity):
# 计算归一化排名比例
normalized_rank = 1 - ((num_points - 1-rank) / (num_points - 1))
# 计算阈值降低的量,即缩放因子乘以归一化排名比例的平方
decrement = 0.4 * (normalized_rank ** 2)
# 计算并设置当前变点的阈值
thresholds[bkp] = 0.3+decrement
# 此时thresholds字典中包含了每个变点的位置和对应的阈值
# 遍历每一个主要变点
for bkp, intensity in changes_intensity:
# 计算该变点左右窗口的边界
start = max(0, int(bkp - window_size / 2))
end = min(length, int(bkp + window_size / 2))
threshold = thresholds[bkp]
# 遍历窗口内的每一个点
for i in range(start, end):
# 生成一个[0, 1]之间的随机数
random_value = np.random.random()
# 如果随机数大于分配的阈值,将该点添加到次要变点集合中
if random_value >= threshold:
all_important_nodes.add(i)
return all_important_nodes
def get_magnitude(run_tag, factor, normalize,gpu):
'''
:param run_tag:
:param factor:
:return: Perturbed Magnitude
'''
data = load_ucr('data/' + run_tag + '/' + run_tag + '_attack'+gpu+'.txt', normalize=normalize)
X = data[:, 1:]
max_magnitude = X.max(1)
min_magnitude = X.min(1)
mean_magnitude = np.mean(max_magnitude - min_magnitude)
perturbed_mag = mean_magnitude * factor
print('Perturbed Magnitude:', perturbed_mag)
return perturbed_mag
class Attacker:
def __init__(self, run_tag, model_type, cuda, normalize, e,device,gpu,classes):
self.run_tag = run_tag
self.model_type = model_type
self.cuda = cuda
#self.intervals = get_attack_position(self.run_tag, self.top_k)
self.normalize = normalize
self.e = e
self.device = device
self.gpu = gpu
self.classes = classes
def perturb_ts(self, perturbations, ts, attack_pos):
'''
:param perturbations:formalized as a tuplex,e),x(int) is the x-coordinatee(float) is the epsilon,e.g.,(2,0.01)
:param ts: time series
:return: perturbed ts
'''
# first we copy a ts
ts_tmp = np.copy(ts)
coordinate = 0 # 初始化perturbations数组的索引
for i in range(len(attack_pos)):
if attack_pos[i] == 1:
ts_tmp[i] += perturbations[coordinate]
coordinate += 1
# for interval in self.intervals:
# for i in range(int(interval[0]), int(interval[1])):
# ts_tmp[i] += perturbations[coordinate]
# coordinate += 1
return ts_tmp
def plot_per(self, perturbations, ts, target_class, sample_idx,attack_pos, prior_probs, attack_probs, factor):
# Obtain the perturbed ts
ts_tmp = np.copy(ts)
ts_perturbed = self.perturb_ts(perturbations=perturbations, ts=ts, attack_pos=attack_pos)
# Start to plot
plt.figure(figsize=(6, 4))
plt.plot(ts_tmp, color='b', label='Original %.2f' % prior_probs)
plt.plot(ts_perturbed, color='r', label='Perturbed %.2f' % attack_probs)
plt.xlabel('Time', fontsize=12)
if target_class == -1:
plt.title('Untargeted: Sample %d, eps_factor=%.3f' %
(sample_idx, factor), fontsize=14)
else:
plt.title('Targeted(%d): Sample %d, eps_factor=%.3f' %
(target_class, sample_idx, factor), fontsize=14)
plt.legend(loc='upper right', fontsize=8)
plt.savefig('result_' + str(factor) + '_' + str(self.model_type) + '/'
+ self.run_tag + '/figures'+self.gpu+'/' + self.run_tag +'_' + str(sample_idx) + '.png')
# plt.show()
def fitness(self, device,perturbations, ts, sample_idx, queries,attack_pos, target_class=-1):
#device = torch.device("cuda:0" if self.cuda else "cpu")
perturbations = torch.tensor(perturbations)
#ts = torch.tensor(ts, device='cuda')
# perturbations = torch.tensor(perturbations, dtype=torch.float32)
# perturbations = perturbations.to(device)
queries[0] += 1
ts_perturbed = self.perturb_ts(perturbations, ts,attack_pos = attack_pos)
mse = mean_squared_error(ts, ts_perturbed)
prob, _, _, _, _ = query_one(run_tag=self.run_tag,device=device, idx=sample_idx, attack_ts=ts_perturbed,
target_class=target_class, normalize=self.normalize,
cuda=self.cuda, model_type=self.model_type, e=self.e,gpu=self.gpu,n_class=self.classes)
# decimal_places = -int(np.floor(np.log10(prob))) + 1
# # 计算需要标准化的数字的标准化因子
# scale_factor = 10 ** decimal_places
# # 标准化目标数字
# normalized = np.round(scale_factor * mse, 0) / scale_factor
# 确保标准化后的数字至少为0.01
#normalized = max(normalized, 0.01)
prob = torch.tensor(prob)
if target_class != -1:
prob = 1 - prob
return prob # The fitness function is to minimize the fitness value
def attack_success(self, device, perturbations, ts, sample_idx, attack_pos, iterations, target_class=-1,
verbose=True):
iterations[0] += 1
print('The %d iteration' % iterations[0])
ts_perturbed = self.perturb_ts(perturbations, ts, attack_pos)
# ts_perturbed = torch.tensor(ts_perturbed, device='cuda')
# Obtain the perturbed probability vector and the prior probability vector
prob, prob_vector, prior_prob, prior_prob_vec, real_label = query_one(self.run_tag, device, idx=sample_idx,
attack_ts=ts_perturbed,
target_class=target_class,
normalize=self.normalize,
verbose=verbose, cuda=self.cuda,
model_type=self.model_type,
e=self.e, gpu=self.gpu,n_class=self.classes)
predict_class = torch.argmax(prob_vector).to(device)
prior_class = torch.argmax(prior_prob_vec).to(device)
real_label = real_label.to(device)
# Conditions for early termination(empirical-based estimation), leading to save the attacking time
# But it may judge incorrectly that this may decrease the success rate of the attack.
if (iterations[0] > 20 and prob > 0.9):
print('The %d sample is not expected to successfully attack.' % sample_idx)
print('prob: ', prob)
return True
if prior_class != real_label:
print('The %d sample cannot be classified correctly, no need to attack' % sample_idx)
return True
if prior_class == target_class:
print(
'The true label of %d sample equals to target label, no need to attack' % sample_idx)
return True
if verbose:
print('The Confidence of current iteration: %.4f' % prob)
print('########################################################')
# The criterion of attacking successfully:
# Untargeted attack: predicted label is not equal to the original label.
# Targeted attack: predicted label is equal to the target label.
if ((target_class == -1 and predict_class != prior_class) or
(target_class != -1 and predict_class == target_class)):
print('##################### Attack Successfully! ##########################')
return True
def attack(self, sample_idx,device, target_class=-1, factor=0.04,
max_iteration=50, popsize=200, verbose=True):
class MyProblem(ElementwiseProblem):
def __init__(self, outer, ts, sample_idx, queries, attack_pos, target_class, device, bounds,perturbed_magnitude):
#self, device, perturbations, ts, sample_idx, queries, attack_pos, target_class = -1
self.perturbed_magnitude=perturbed_magnitude
super().__init__(n_var=len(bounds), n_obj=1, n_constr=0, xl=-perturbed_magnitude * np.ones(len(bounds)), # 下界
xu=perturbed_magnitude * np.ones(len(bounds)))
self.outer = outer
self.ts = ts
self.sample_idx = sample_idx
self.queries = queries
self.attack_pos = attack_pos
self.target_class = target_class
self.device = device
def _evaluate(self, x, out, *args, **kwargs):
f = self.outer.fitness(self.device,x , self.ts, self.sample_idx,self.queries, self.attack_pos, self.target_class,
)
# self, device,perturbations, ts, sample_idx, queries,attack_pos, target_class=-1
out["F"] = np.array([f])
class MyCallback(Callback):
def __init__(self, outer, device, ts, sample_idx, queries, attack_pos, target_class, verbose,iterations):
super().__init__()
self.outer = outer
self.device = device
self.ts = ts
self.sample_idx = sample_idx
self.queries = queries
self.attack_pos = attack_pos
self.target_class = target_class
self.iterations = iterations
self.verbose = verbose
self.generation = 0
def notify(self, algorithm):
x = algorithm.pop.get("X")[np.argmin(algorithm.pop.get("F"))] # Current best solution
ifsuccess=self.outer.attack_success(self.device, x, self.ts,
self.sample_idx, self.attack_pos,
self.iterations, self.target_class,
self.verbose)
#self,device,perturbations, ts, sample_idx, attack_pos, iterations, target_class=-1, verbose=True
# best_f = min(algorithm.pop.get("F"))
# best_x = algorithm.pop.get("X")[np.argmin(algorithm.pop.get("F"))]
# print(f"Generation {self.generation}: Best solution so far: {best_x}, Fitness: {best_f}")
# print('-------',should_terminate)
if ifsuccess:
algorithm.termination.force_termination = True
self.generation += 1
test = load_ucr('data/' + self.run_tag + '/' + self.run_tag + '_attack'+self.gpu+'.txt'
, normalize=self.normalize)
#attack_poses = np.loadtxt('data/' + self.run_tag + '/' + self.run_tag + '_attackPos'+self.gpu+'.txt')
ori_ts = test[sample_idx][1:]
attacked_probs, attacked_vec, prior_probs, prior_vec, real_label = query_one(self.run_tag,device,idx=sample_idx,
attack_ts=ori_ts,
target_class=target_class,
normalize=self.normalize,
verbose=False,
cuda=self.cuda, e=self.e,
model_type=self.model_type,gpu=self.gpu,n_class=self.classes)
prior_class = torch.argmax(prior_vec).to(device)
if prior_class != real_label:
print('The %d sample cannot be classified correctly, no need to attack' % sample_idx)
return ori_ts,ori_ts, [prior_probs, attacked_probs, 0, 0, 0, 0, 0, 'WrongSample']
# Get the maximum perturbed magnitude
perturbed_magnitude = get_magnitude(self.run_tag, factor, normalize=self.normalize,gpu=self.gpu)
bounds = []
# 变点检测找区间
length = ori_ts.shape
all_bkps = detect_change_points(ori_ts)
all_bkps = [x - 1 for x in all_bkps]
window_size = int(length[0] / len(all_bkps)) # 窗口大小
sequence = np.zeros(len(ori_ts), dtype=int)
# secondary_changes = process_change_points(length[0], all_bkps, window_size)
# sequence[list(secondary_changes)] = 1
# sequence[list(all_bkps)] = 1
# 处理变点
if len(all_bkps)<0.7*length[0] :
secondary_changes = process_change_points(ori_ts, length[0], all_bkps, window_size)
sequence[list(secondary_changes)] = 1
sequence[list(all_bkps)] = 1
else:
sequence[list(all_bkps)] = 1
attack_pos = sequence
steps_count = attack_pos.sum()
for i in range(len(attack_pos)):
if attack_pos[i] == 1:
bounds.append((-1 * perturbed_magnitude, perturbed_magnitude))
print('The length of shapelet interval', steps_count)
#print('The length of bounds', len(bounds))
popmul = max(1, popsize // len(bounds))
# Record of the number of iterations
iterations = [0]
queries = [0]
problem = MyProblem(self, ori_ts, sample_idx, queries, attack_pos, target_class, device,bounds,perturbed_magnitude)
algorithm = PSO(pop_size=50, w=0.9, c1=1.2, c2=2.2)
callback1 = MyCallback(self, device, ori_ts, sample_idx, queries, attack_pos, target_class, verbose,iterations)
res = minimize(problem, algorithm, ('n_gen', max_iteration), callback=callback1, seed=1, verbose=verbose)
attack_result = res.X # 最优解
# attack_result = differential_evolution(func=fitness_fn, bounds=bounds
# , maxiter=max_iteration, popsize=popmul
# , recombination=0.7, callback=callback_fn,
# atol=-1, polish=False)
attack_ts = self.perturb_ts(attack_result, ori_ts, attack_pos)
mse = mean_squared_error(ori_ts, attack_ts)
attacked_probs, attacked_vec, prior_probs, prior_vec, real_label = query_one(self.run_tag,device, idx=sample_idx,
attack_ts=attack_ts,
target_class=target_class,
normalize=self.normalize,
verbose=False,
cuda=self.cuda, e=self.e,
model_type=self.model_type,gpu=self.gpu,n_class=self.classes)
predicted_class = torch.argmax(attacked_vec).to(device)
prior_class = torch.argmax(prior_vec).to(device)
if prior_class != real_label:
success = 'WrongSample'
elif prior_class == target_class:
success = 'NoNeedAttack'
else:
if (predicted_class.item() != prior_class.item() and target_class == -1) \
or (predicted_class.item() == target_class and target_class != -1):
success = 'Success'
else:
success = 'Fail'
if success == 'Success':
self.plot_per(perturbations=attack_result, ts=ori_ts, target_class=target_class,
sample_idx=sample_idx, attack_pos=attack_pos, prior_probs=prior_probs, attack_probs=attacked_probs, factor=factor)
return ori_ts, attack_ts, [prior_probs, attacked_probs, prior_class.item(),
predicted_class.item(), queries[0], mse, iterations[0], success]

55
dataPre.py Normal file
View File

@ -0,0 +1,55 @@
# -*- coding: utf-8 -*-
import configparser
def process_and_split_data(file_name):
# 读取文件内容
data_path = 'data/' + file_name + '/' + file_name
with open(data_path+'_TEST.txt', 'r') as file:
lines = file.readlines()
# 解析数据,并按类别排序
data = [line.strip().split() for line in lines]
data.sort(key=lambda x: x[0]) # 假设类别在每行的第一列
# 按类别分组
from collections import defaultdict
categorized_data = defaultdict(list)
for row in data:
categorized_data[row[0]].append(row)
# 分别存储每个类别的前50%和剩余的数据
cp_file_name = data_path + '_cp.txt'
attack_file_name = data_path + '_attack.txt'
with open(cp_file_name, 'w') as cp_file, open(attack_file_name, 'w') as attack_file:
for category, rows in categorized_data.items():
#如果数据量很大找区间不用这么多条数据cp文件里面应该少一些
if len(rows)>100:
half_index = len(rows) // 10
#half_index = 6
#half = len(rows) // 10
#StarLightCurves这个数据集太长了截取每一类的后百分之十
half = (len(rows) // 2)
else:
half_index = len(rows) // 2
# half = (len(rows) // 10)*9
half = (len(rows) // 2)
# 存储前50%的数据
for row in rows[:half_index]:
cp_file.write(' '.join(row) + '\n')
# 存储剩余的数据
for row in rows[half:]:
attack_file.write(' '.join(row) + '\n')
# 假设文件名为'Car.txt'
if __name__ == '__main__':
# 临时添加配置文件类别种类
config = configparser.ConfigParser()
config.read("run_parallel_config.ini")
file_name = config['MODEL']['run_tag']
process_and_split_data(file_name)

43
datasets_config.csv Normal file
View File

@ -0,0 +1,43 @@
dataset_name,cuda,total_gpus,classes,target_class,pop_size,magnitude_factor,max_itr,run_tag,model,normalize,e,done
Car,store_true,5,4,-1,1,0.04,50,Car,r,store_true,1499,0
Wafer,store_true,7,2,-1,1,0.04,50,Wafer,r,store_true,1499,0
ItalyPowerDemand,store_true,4,2,-1,1,0.04,50,ItalyPowerDemand,r,store_true,1499,0
AllGestureWiimoteY,store_true,7,10,-1,1,0.04,50,AllGestureWiimoteY,r,store_true,1499,0
NonIFECGTho2,store_true,4,42,-1,1,0.04,50,NonIFECGTho2,r,store_true,1499,0
Trace,store_true,1,4,-1,1,0.04,50,Trace,r,store_true,1499,0
PigAirwayPressure,store_true,1,52,-1,1,0.04,50,PigAirwayPressure,r,store_true,1499,0
GesturePebbleZ2,store_true,5,6,-1,1,0.04,50,GesturePebbleZ2,r,store_true,1499,0
AllGestureWiimoteX,store_true,7,10,-1,1,0.04,50,AllGestureWiimoteX,r,store_true,1499,0
FordA,store_true,6,2,-1,1,0.04,50,FordA,r,store_true,1499,0
DodgerLoopDay,store_true,5,7,-1,1,0.04,50,DodgerLoopDay,r,store_true,1499,0
SonyAIBORobotSurface1,store_true,4,2,-1,1,0.04,50,SonyAIBORobotSurface1,r,store_true,1499,0
PigArtPressure,store_true,7,52,-1,1,0.04,50,PigArtPressure,r,store_true,1499,0
MoteStrain,store_true,4,2,-1,1,0.04,50,MoteStrain,r,store_true,1499,0
ECGFiveDays,store_true,5,2,-1,1,0.04,50,ECGFiveDays,r,store_true,1499,0
PickupGeWZ,store_true,1,10,-1,1,0.04,50,PickupGeWZ,r,store_true,1499,0
FreezerSmallTrain,store_true,7,2,-1,1,0.04,50,FreezerSmallTrain,r,store_true,1499,0
TwoLeadECG,store_true,7,2,-1,1,0.04,50,TwoLeadECG,r,store_true,1499,0
Lightning7,store_true,4,7,-1,1,0.04,50,Lightning7,r,store_true,1499,0
Phoneme,store_true,7,39,-1,1,0.04,50,Phoneme,r,store_true,1499,0
DodgerLoopWeekend,store_true,5,2,-1,1,0.04,50,DodgerLoopWeekend,r,store_true,1499,0
ECG5000,store_true,6,5,-1,1,0.04,50,ECG5000,r,store_true,1499,0
ShakeGestureWiimoteZ,store_true,1,10,-1,1,0.04,50,ShakeGestureWiimoteZ,r,store_true,1499,0
GesturePebbleZ1,store_true,5,6,-1,1,0.04,50,GesturePebbleZ1,r,store_true,1499,0
NonIFECGTho1,store_true,7,42,-1,1,0.04,50,NonIFECGTho1,r,store_true,1499,0
AllGestureWiimoteZ,store_true,7,10,-1,1,0.04,50,AllGestureWiimoteZ,r,store_true,1499,0
FordB,store_true,4,2,-1,1,0.04,50,FordB,r,store_true,1499,0
InsectWingbeatSound,store_true,4,11,-1,1,0.04,50,InsectWingbeatSound,r,store_true,1499,0
EOGHorizontalSignal,store_true,7,12,-1,1,0.04,50,EOGHorizontalSignal,r,store_true,1499,0
ChlorineConcentration,store_true,6,3,-1,1,0.04,50,ChlorineConcentration,r,store_true,1499,0
Plane,store_true,4,7,-1,1,0.04,50,Plane,r,store_true,1499,0
EOGVerticalSignal,store_true,7,12,-1,1,0.04,50,EOGVerticalSignal,r,store_true,1499,0
DodgerLoopGame,store_true,7,2,-1,1,0.04,50,DodgerLoopGame,r,store_true,1499,0
ECG200,store_true,2,2,-1,1,0.04,50,ECG200,r,store_true,1499,0
Fungi,store_true,1,18,-1,1,0.04,50,Fungi,r,store_true,1499,0
CinCEC,store_true,6,4,-1,1,0.04,50,CinCEC,r,store_true,1499,0
SonyAIBORobotSurface2,store_true,4,2,-1,1,0.04,50,SonyAIBORobotSurface2,r,store_true,1499,0
Lightning2,store_true,4,2,-1,1,0.04,50,Lightning2,r,store_true,1499,0
FreezerRegularTrain,store_true,7,2,-1,1,0.04,50,FreezerRegularTrain,r,store_true,1499,0
StarLightCurves,store_true,6,3,-1,1,0.04,50,StarLightCurves,r,store_true,1499,0
Earthquakes,store_true,4,2,-1,1,0.04,50,Earthquakes,r,store_true,1499,0
PigCVP,store_true,7,52,-1,1,0.04,50,PigCVP,r,store_true,1499,0
1 dataset_name cuda total_gpus classes target_class pop_size magnitude_factor max_itr run_tag model normalize e done
2 Car store_true 5 4 -1 1 0.04 50 Car r store_true 1499 0
3 Wafer store_true 7 2 -1 1 0.04 50 Wafer r store_true 1499 0
4 ItalyPowerDemand store_true 4 2 -1 1 0.04 50 ItalyPowerDemand r store_true 1499 0
5 AllGestureWiimoteY store_true 7 10 -1 1 0.04 50 AllGestureWiimoteY r store_true 1499 0
6 NonIFECGTho2 store_true 4 42 -1 1 0.04 50 NonIFECGTho2 r store_true 1499 0
7 Trace store_true 1 4 -1 1 0.04 50 Trace r store_true 1499 0
8 PigAirwayPressure store_true 1 52 -1 1 0.04 50 PigAirwayPressure r store_true 1499 0
9 GesturePebbleZ2 store_true 5 6 -1 1 0.04 50 GesturePebbleZ2 r store_true 1499 0
10 AllGestureWiimoteX store_true 7 10 -1 1 0.04 50 AllGestureWiimoteX r store_true 1499 0
11 FordA store_true 6 2 -1 1 0.04 50 FordA r store_true 1499 0
12 DodgerLoopDay store_true 5 7 -1 1 0.04 50 DodgerLoopDay r store_true 1499 0
13 SonyAIBORobotSurface1 store_true 4 2 -1 1 0.04 50 SonyAIBORobotSurface1 r store_true 1499 0
14 PigArtPressure store_true 7 52 -1 1 0.04 50 PigArtPressure r store_true 1499 0
15 MoteStrain store_true 4 2 -1 1 0.04 50 MoteStrain r store_true 1499 0
16 ECGFiveDays store_true 5 2 -1 1 0.04 50 ECGFiveDays r store_true 1499 0
17 PickupGeWZ store_true 1 10 -1 1 0.04 50 PickupGeWZ r store_true 1499 0
18 FreezerSmallTrain store_true 7 2 -1 1 0.04 50 FreezerSmallTrain r store_true 1499 0
19 TwoLeadECG store_true 7 2 -1 1 0.04 50 TwoLeadECG r store_true 1499 0
20 Lightning7 store_true 4 7 -1 1 0.04 50 Lightning7 r store_true 1499 0
21 Phoneme store_true 7 39 -1 1 0.04 50 Phoneme r store_true 1499 0
22 DodgerLoopWeekend store_true 5 2 -1 1 0.04 50 DodgerLoopWeekend r store_true 1499 0
23 ECG5000 store_true 6 5 -1 1 0.04 50 ECG5000 r store_true 1499 0
24 ShakeGestureWiimoteZ store_true 1 10 -1 1 0.04 50 ShakeGestureWiimoteZ r store_true 1499 0
25 GesturePebbleZ1 store_true 5 6 -1 1 0.04 50 GesturePebbleZ1 r store_true 1499 0
26 NonIFECGTho1 store_true 7 42 -1 1 0.04 50 NonIFECGTho1 r store_true 1499 0
27 AllGestureWiimoteZ store_true 7 10 -1 1 0.04 50 AllGestureWiimoteZ r store_true 1499 0
28 FordB store_true 4 2 -1 1 0.04 50 FordB r store_true 1499 0
29 InsectWingbeatSound store_true 4 11 -1 1 0.04 50 InsectWingbeatSound r store_true 1499 0
30 EOGHorizontalSignal store_true 7 12 -1 1 0.04 50 EOGHorizontalSignal r store_true 1499 0
31 ChlorineConcentration store_true 6 3 -1 1 0.04 50 ChlorineConcentration r store_true 1499 0
32 Plane store_true 4 7 -1 1 0.04 50 Plane r store_true 1499 0
33 EOGVerticalSignal store_true 7 12 -1 1 0.04 50 EOGVerticalSignal r store_true 1499 0
34 DodgerLoopGame store_true 7 2 -1 1 0.04 50 DodgerLoopGame r store_true 1499 0
35 ECG200 store_true 2 2 -1 1 0.04 50 ECG200 r store_true 1499 0
36 Fungi store_true 1 18 -1 1 0.04 50 Fungi r store_true 1499 0
37 CinCEC store_true 6 4 -1 1 0.04 50 CinCEC r store_true 1499 0
38 SonyAIBORobotSurface2 store_true 4 2 -1 1 0.04 50 SonyAIBORobotSurface2 r store_true 1499 0
39 Lightning2 store_true 4 2 -1 1 0.04 50 Lightning2 r store_true 1499 0
40 FreezerRegularTrain store_true 7 2 -1 1 0.04 50 FreezerRegularTrain r store_true 1499 0
41 StarLightCurves store_true 6 3 -1 1 0.04 50 StarLightCurves r store_true 1499 0
42 Earthquakes store_true 4 2 -1 1 0.04 50 Earthquakes r store_true 1499 0
43 PigCVP store_true 7 52 -1 1 0.04 50 PigCVP r store_true 1499 0

223
draw_main.py Normal file
View File

@ -0,0 +1,223 @@
import numpy as np
from analyzeTool import generate_heat_maps_array, count_classes_samples
from drawing_tool import draw_ori_perturbed, draw_times_diff_bar, draw_ori_perturbed_with_inset, draw_diff_pert_info, \
heat_maps_of_classes
if __name__ == '__main__':
# # ECG 0.04
# original_data = "6.410247599999999712e-01 7.814486200000000382e-01 8.841660900000000156e-01 1.235362999999999989e+00 1.782253300000000040e+00 2.219029200000000035e+00 2.350801099999999977e+00 2.111025199999999824e+00 1.595795800000000098e+00 1.063145000000000007e+00 5.214278199999999863e-01 8.905684099999999770e-02 1.531264400000000026e-01 2.324356599999999884e-01 -1.149376899999999951e-01 -1.651973100000000139e-01 5.011464799999999602e-03 -1.478869999999999907e-01 -6.105320999999999665e-02 3.645349999999999979e-02 -4.441071200000000219e-01 -6.793092099999999967e-01 -5.299733599999999489e-01 -6.467437299999999611e-01 -7.079432799999999526e-01 -6.633238200000000084e-01 -8.606828899999999782e-01 -9.597856700000000352e-01 -9.276052399999999976e-01 -1.140874799999999967e+00 -1.364474799999999988e+00 -1.286232400000000053e+00 -1.193629000000000051e+00 -1.332616500000000093e+00 -1.469505899999999921e+00 -1.489589899999999911e+00 -1.600690200000000063e+00 -1.777332799999999935e+00 -1.810176000000000007e+00 -1.735597099999999893e+00 -1.704956899999999997e+00 -1.724591900000000066e+00 -1.707795699999999917e+00 -1.594449299999999958e+00 -1.396698400000000007e+00 -1.187054700000000018e+00 -9.916590499999999864e-01 -7.708646200000000004e-01 -5.576156799999999469e-01 -3.874625899999999956e-01 -1.684684999999999933e-01 1.158190000000000053e-01 3.144081799999999816e-01 3.764868499999999840e-01 4.204736399999999819e-01 4.975668799999999892e-01 5.742429000000000006e-01 6.478606900000000168e-01 6.616984399999999988e-01 6.051487300000000236e-01 6.295551700000000528e-01 7.117260399999999487e-01 6.740077100000000376e-01 6.155466400000000338e-01 6.777178400000000158e-01 7.207244900000000509e-01 6.626562999999999759e-01 6.158657499999999896e-01 6.617521699999999729e-01 7.109475100000000047e-01 6.147269899999999732e-01 5.231166299999999714e-01 5.887229699999999566e-01 5.911069100000000409e-01 5.855090899999999543e-01 6.948123600000000177e-01 5.469097400000000331e-01 3.645842599999999933e-01 6.602078500000000405e-01 8.684830799999999629e-01 6.410247599999999712e-01 5.403232999999999508e-01 6.355810499999999807e-01 7.083335299999999890e-01 7.426267199999999624e-01 6.175198499999999813e-01 5.871576699999999649e-01 8.247907500000000169e-01 9.697120799999999763e-01 9.259981499999999643e-01 5.296564000000000272e-01 -1.374844299999999908e-01 -4.576849700000000243e-01 -1.061242400000000030e+00 -2.023360600000000176e+00 -1.376014099999999907e+00"
# perturbed_data = "0.6444 0.7856 0.8888 1.2418 1.7713 2.0436 2.2346 2.1930 1.6804 1.0748 0.3897 -0.0399 0.0686 0.4267 -0.1309 -0.2164 0.0050 -0.1487 -0.0614 0.0366 -0.4464 -0.6829 -0.5328 -0.6501 -0.7117 -0.6668 -0.9808 -1.0112 -1.0913 -1.0141 -1.4900 -1.4651 -1.1812 -1.2940 -1.5742 -1.3882 -1.6847 -1.7861 -1.9346 -1.7152 -1.8077 -1.6203 -1.6006 -1.6807 -1.3937 -1.3646 -1.1665 -0.6113 -0.5605 -0.3895 -0.1694 0.1164 0.3161 0.3785 0.4227 0.5002 0.5773 0.6513 0.6652 0.6083 0.6329 0.7155 0.6775 0.6188 0.6813 0.7245 0.6661 0.6191 0.6652 0.7147 0.6180 0.5259 0.5918 0.5942 0.5886 0.6985 0.5498 0.3665 0.6637 0.8730 0.7138 0.4777 0.6356 0.8395 0.9112 0.5005 0.7421 0.9235 0.9903 1.1184 0.6624 -0.0234 -0.5430 -0.8738 -2.0340 -1.3832"
# scale = (25, 50)
# xy = (45, 0.85)
# xytext = (40, -0.4)
# loc_sample = 'upper right'
# loc_sub = 'upper center'
# draw_ori_perturbed(original_data, perturbed_data,
# filename='论文插图2/figure3_ECG004对比图.pdf',
# loc_sample=loc_sample,
# loc_sub=loc_sub,
# inset_range=scale,
# dashed_lists=[scale],
# xy=xy,
# xytext=xytext)
#
# # ECG 0.02
# perturbed_data = "0.6444 0.7856 0.8888 1.2418 1.8865 2.1496 2.3434 2.1861 1.5822 1.0904 0.5405 0.0347 0.1713 0.3206 -0.1030 -0.1754 0.0050 -0.1487 -0.0614 0.0366 -0.4464 -0.6829 -0.5328 -0.6501 -0.7117 -0.6668 -0.9112 -0.9741 -1.0095 -1.1322 -1.3230 -1.3910 -1.2761 -1.3497 -1.5226 -1.4313 -1.6892 -1.8592 -1.7471 -1.7912 -1.6806 -1.6637 -1.7026 -1.6638 -1.4444 -1.1879 -1.0551 -0.8528 -0.5605 -0.3895 -0.1694 0.1164 0.3161 0.3785 0.4227 0.5002 0.5773 0.6513 0.6652 0.6083 0.6329 0.7155 0.6775 0.6188 0.6813 0.7245 0.6661 0.6191 0.6652 0.7147 0.6180 0.5259 0.5918 0.5942 0.5886 0.6985 0.5498 0.3665 0.6637 0.8730 0.6238 0.5742 0.6817 0.7971 0.7187 0.7069 0.6060 0.8689 1.0034 1.0273 0.5092 -0.2091 -0.3818 -0.9827 -2.0340 -1.3832"
# draw_ori_perturbed(original_data, perturbed_data,
# filename='论文插图2/figure3_ECG002对比图.pdf',
# loc_sample=loc_sample,
# loc_sub=loc_sub,
# inset_range=scale,
# dashed_lists=[scale],
# xy=xy,
# xytext=xytext)
#
# # ECG 0.01
# perturbed_data = "0.6444 0.7856 0.8888 1.2762 1.7566 2.2411 2.3631 2.1221 1.6042 1.0687 0.4979 0.0412 0.1737 0.2803 -0.1073 -0.1920 0.0453 -0.1498 -0.0614 0.0366 -0.4464 -0.6829 -0.5328 -0.6501 -0.7117 -0.6668 -0.8652 -1.0050 -0.9247 -1.1196 -1.3812 -1.3010 -1.1999 -1.3396 -1.4772 -1.4974 -1.6091 -1.7867 -1.8197 -1.7447 -1.7139 -1.6926 -1.6829 -1.6361 -1.3716 -1.1626 -1.0194 -0.7482 -0.5426 -0.4157 -0.1808 0.1277 0.3185 0.4245 0.4058 0.5200 0.5515 0.6634 0.6617 0.5656 0.6466 0.7155 0.6775 0.6188 0.6813 0.7245 0.6661 0.6191 0.6652 0.7147 0.6180 0.5259 0.5918 0.5942 0.5794 0.6845 0.5835 0.3818 0.6755 0.8561 0.6444 0.5432 0.6389 0.7121 0.7465 0.6208 0.5902 0.8291 0.9838 0.9516 0.5245 -0.1788 -0.4601 -1.0668 -2.0340 -1.3832"
# draw_ori_perturbed(original_data, perturbed_data,
# filename='论文插图2/figure3_ECG001对比图.pdf',
# loc_sample=loc_sample,
# loc_sub=loc_sub,
# inset_range=scale,
# dashed_lists=[scale],
# xy=xy,
# xytext=xytext)
# # Sony 0.04
# original_data = "0.0599 0.0599 0.0599 0.0599 -0.7742 -1.3302 -0.4962 0.3379 1.4499 1.1719 0.3379 0.8939 1.7280 1.7280 0.6159 -1.0521 -1.0521 -0.2181 -0.4962 -0.7742 -1.0521 -1.0521 -1.0521 -0.4962 0.0599 0.0599 0.3379 -0.2181 0.3379 0.0599 0.3379 0.3379 -0.7742 -0.4962 -0.4962 -0.4962 -0.2181 -0.2181 -0.2181 0.0599 -0.2181 -0.2181 0.0599 -1.6082 -1.0521 0.6159 0.3379 -0.7742 1.1719 2.8400 3.3960 2.2840 0.8939 -2.1642 -2.1642 -0.4962 0.0599 -0.2181 -0.4962 -0.4962 0.6159 0.6159 0.0599 -0.2181 0.0599"
# perturbed_data = "0.0599 0.0599 0.0599 0.0310 -0.6830 -1.1319 -0.3566 0.3379 1.4499 1.2683 0.4334 0.9029 1.8575 1.9152 0.6944 -1.0521 -1.0521 -0.2181 -0.4962 -0.7742 -1.0521 -1.0521 -1.0521 -0.4962 0.0599 0.0599 0.3379 -0.2181 0.3379 0.0599 0.3379 0.3379 -0.7742 -0.4962 -0.4962 -0.4962 -0.2181 -0.2181 -0.2181 0.0599 -0.2181 -0.2181 0.0599 -1.6082 -1.0521 0.5199 0.1594 -0.7803 1.1256 2.9534 3.5492 2.3713 0.7483 -2.0346 -2.1955 -0.3492 0.0359 -0.1742 -0.3939 -0.6957 0.4353 0.4462 0.0599 -0.2181 0.0599"
# scale = (7, 15)
# xy = (33, 1.4)
# xytext = (15, 0.8)
# loc_sample = 'upper right'
# loc_sub = 'upper center'
# draw_ori_perturbed(original_data, perturbed_data,
# filename='论文插图2/figure3_Sony004对比图.pdf',
# loc_sample=loc_sample,
# loc_sub=loc_sub,
# inset_range=scale,
# dashed_lists=[scale],
# xy=xy,
# xytext=xytext)
#
# # Sony 0.02
# perturbed_data = "0.0599 0.0599 0.0599 0.0374 -0.7051 -1.3549 -0.4990 0.3379 1.4499 1.0861 0.3807 0.9880 1.7390 1.7361 0.6788 -1.0521 -1.0521 -0.2181 -0.4962 -0.7742 -1.0521 -1.0521 -1.0521 -0.4962 0.0599 0.0599 0.3379 -0.2181 0.3379 0.0599 0.3379 0.3379 -0.7742 -0.4962 -0.4962 -0.4962 -0.2181 -0.2181 -0.2181 0.0599 -0.2181 -0.2181 0.0599 -1.6082 -1.0521 0.6970 0.2896 -0.7888 1.1938 2.7924 3.4649 2.3376 0.8073 -2.0784 -2.1942 -0.5223 0.0861 -0.2344 -0.5798 -0.5959 0.5172 0.5588 0.0599 -0.2181 0.0599"
# draw_ori_perturbed(original_data, perturbed_data,
# filename='论文插图2/figure3_Sony002对比图.pdf',
# loc_sample=loc_sample,
# loc_sub=loc_sub,
# inset_range=scale,
# dashed_lists=[scale],
# xy=xy,
# xytext=xytext)
#
# # Sony 0.01
# perturbed_data = "0.0599 0.0599 0.0599 0.0169 -0.7642 -1.3113 -0.4875 0.3379 1.4499 1.1723 0.3651 0.9393 1.6804 1.7290 0.6672 -1.0521 -1.0521 -0.2181 -0.4962 -0.7742 -1.0521 -1.0521 -1.0521 -0.4962 0.0599 0.0599 0.3379 -0.2181 0.3379 0.0599 0.3379 0.3379 -0.7742 -0.4962 -0.4962 -0.4962 -0.2181 -0.2181 -0.2181 0.0599 -0.2181 -0.2181 0.0599 -1.6082 -1.0521 0.6248 0.3447 -0.7442 1.1737 2.7967 3.4208 2.2884 0.8680 -2.1330 -2.1518 -0.5447 0.0130 -0.2304 -0.5026 -0.4783 0.5671 0.6399 0.0599 -0.2181 0.0599"
# draw_ori_perturbed(original_data, perturbed_data,
# filename='论文插图2/figure3_Sony001对比图.pdf',
# loc_sample=loc_sample,
# loc_sub=loc_sub,
# inset_range=scale,
# dashed_lists=[scale],
# xy=xy,
# xytext=xytext)
#
# 随机区间成功
# scale = [(13, 29), (33, 47), (56, 72)]
# # xy = (95, -5)
# # xytext = (40, -0.4)
# loc_sample = 'lower right'
# loc_sub = 'lower right'
# original_data = "0.7105 0.6894 0.6551 1.2894 1.9932 1.9182 1.5860 1.6460 1.5084 0.7529 0.0330 -0.1929 -0.1509 -0.1136 -0.2392 -0.5039 -0.6020 -0.4257 -0.3627 -0.6225 -0.8194 -0.7298 -0.6382 -0.7202 -0.9134 -1.0540 -1.0283 -1.0828 -1.2669 -1.2678 -1.2946 -1.4921 -1.3886 -1.2382 -1.5695 -1.8409 -1.7606 -1.7878 -1.8247 -1.7041 -1.7095 -1.7474 -1.6194 -1.4682 -1.3479 -1.2382 -1.0846 -0.8102 -0.6451 -0.6373 -0.3964 -0.0379 0.0010 -0.0685 0.0609 0.2248 0.3061 0.3292 0.3028 0.3230 0.3998 0.4567 0.5148 0.5269 0.4515 0.4403 0.5410 0.5968 0.5534 0.4987 0.4910 0.5554 0.6822 0.7272 0.6650 0.7387 0.8708 0.7335 0.5975 0.8433 1.0931 1.0070 0.9677 1.0794 0.8658 0.6264 0.9619 1.1341 0.7718 0.9090 1.3177 1.1296 1.0961 1.3177 0.8113 0.1427"
# perturbed_data = '0.7105 0.6894 0.6551 1.2894 1.9932 1.9182 1.5860 1.6460 1.5084 0.7529 0.0330 -0.1929 -0.1509 0.0662 -0.1203 -0.3538 -0.5494 -0.5772 -0.5440 -0.5975 -0.8799 -0.6269 -0.8194 -0.5960 -0.9585 -1.2015 -0.8784 -1.0897 -1.4161 -1.2678 -1.2946 -1.4921 -1.3886 -1.0961 -1.4944 -1.9683 -1.6469 -1.6565 -1.9820 -1.6598 -1.5989 -1.7915 -1.8038 -1.3032 -1.2258 -1.3837 -1.0666 -0.8102 -0.6451 -0.6373 -0.3964 -0.0379 0.0010 -0.0685 0.0609 0.2248 0.3491 0.5100 0.4655 0.5169 0.3829 0.4692 0.5358 0.4554 0.5778 0.5362 0.4921 0.5452 0.6070 0.5404 0.4519 0.6364 0.6822 0.7272 0.6650 0.7387 0.8708 0.7335 0.5975 0.8433 1.0931 1.0070 0.9677 1.0794 0.8658 0.6264 0.9619 1.1341 0.7718 0.9090 1.3177 1.1296 1.0961 1.3177 0.8113 0.1427'
# draw_ori_perturbed(original_data, perturbed_data,
# filename='论文插图2/figure3_ECGFiveDays随机区间成功.pdf',
# loc_sample=loc_sample,
# loc_sub=loc_sub,
# dashed_lists=scale)
#
# # 原区间成功
# scale = [(3, 14), (27, 52), (74,84)]
# perturbed_data = '0.7105 0.6894 0.6551 1.2224 1.8428 2.0472 1.7260 1.6045 1.3185 0.5770 0.1076 -0.2949 -0.1636 0.0517 -0.2392 -0.5039 -0.6020 -0.4257 -0.3627 -0.6225 -0.8194 -0.7298 -0.6382 -0.7202 -0.9134 -1.0540 -1.0283 -0.9722 -1.4386 -1.2600 -1.1366 -1.6790 -1.5343 -1.2766 -1.6165 -1.9023 -1.5843 -1.6212 -1.9980 -1.7463 -1.5317 -1.8412 -1.7552 -1.5399 -1.3920 -1.4149 -1.2649 -0.6781 -0.4535 -0.7282 -0.3204 -0.0391 0.0010 -0.0685 0.0609 0.2248 0.3061 0.3292 0.3028 0.3230 0.3998 0.4567 0.5148 0.5269 0.4515 0.4403 0.5410 0.5968 0.5534 0.4987 0.4910 0.5554 0.6822 0.7272 0.6277 0.6284 0.7937 0.6874 0.7385 0.7790 1.0495 1.1863 0.9164 1.0463 0.8658 0.6264 0.9619 1.1341 0.7718 0.9090 1.3177 1.1296 1.0961 1.3177 0.8113 0.1427'
# draw_ori_perturbed(original_data, perturbed_data,
# filename='论文插图2/figure3_ECGFiveDays原区间成功.pdf',
# loc_sample=loc_sample,
# loc_sub=loc_sub,
# dashed_lists=scale)
#
# # 随机区间失败12
# scale = [(100,130)]
# perturbed_data = original_data
# draw_ori_perturbed(original_data, perturbed_data,
# filename='论文插图2/figure3_ECGFiveDays随机区间失败1.pdf',
# loc_sample=loc_sample,
# loc_sub=loc_sub,
# dashed_lists=scale)
# scale = [(80, 110)]
# draw_ori_perturbed(original_data, perturbed_data,
# filename='论文插图2/figure3_ECGFiveDays随机区间失败2.pdf',
# loc_sample=loc_sample,
# loc_sub=loc_sub,
# dashed_lists=scale)
# # 扰动因子和成功率
# data1 = [52, 81, 81, 81, 81, 81] # Car*
# data2 = [1, 8, 8, 19, 18, 29] # ItalyPowerDemand*
# data3 = [3, 12, 17, 42, 59, 77] # SonyAIBORobotSurface2
# data4 = [0, 4, 65, 78, 78, 78] # Plane
# data5 = [17, 22, 82, 87, 88, 88] # ECG200*
# data6 = [23, 43, 81.5, 100, 100, 100] # Ligning7*
# labels = ['0.01', '0.02', '0.04', '0.06', '0.08', '0.1'] # x轴扰乱因子标记
#
# draw_diff_pert_info(data1, data2, data5, data6, labels, marker='o', linewidth=3,
# filename='./论文插图2/SR3.pdf')
#
# 种群倍数
# car_data_ani = [1, 1, 1, 1, 1]
# ecg200_data_ani = [13.8, 9.4, 11.8, 13.5, 13]
# italy_data_ani = [6.7, 4.8, 3.9, 5.2, 4.5]
# ligning_ani = [8.78, 8.3, 8.2, 8.16, 8.2]
# # car_data_mse = [0.0031, 0.003, 0.00315, 0.0032, 0.00325]
# # ecg200_data_mse = [0.0066, 0.00655, 0.00652, 0.0068, 0.0067]
# # italy_data_mse = [0.0024, 0.00245, 0.0024, 0.0026, 0.0027]
# # ligning_mse = [0.0144, 0.0144, 0.0147, 0.0146, 0.0145]
#
# car_data_q = [544.00, 544.00, 544.00, 544.00, 544.00]
# ecg200_data_q = [423, 469.5, 544, 693, 592]
# italy_data_q = [39, 42.75, 49.05, 42.75, 48]
# ligning_q = [380, 400, 400, 400, 400]
# draw_times_diff_bar(car_data_ani, ecg200_data_ani, italy_data_ani, ligning_ani,
# car_data_q, ecg200_data_q, italy_data_q, ligning_q,
# 'Car', 'ECG200', 'Italy', 'Ligning7',
# filename='./论文插图2/GT-ANI-bar.pdf',
# rightLabel='Queries', leftLabel='ANI', times=1)
# 扰动因子2
car_data_sr = [8.63,
2,
2,
2,
2]
ecg200_data_sr = [7.25,
16.591176470588238,
12.325,
5.8884375,
3.8646153846153846]
italy_data_sr = [6.75,
4.715714285714285,
9.205416666666666,
10.055915492957746,
9.667916666666667]
ligning_sr = [15.417499999999999,
15.142857142857142,
7.199666666666667,
3.9983333333333335,
2.5326666666666666]
car_data_mse = [431.5810526,
100,
100,
100,
100]
ecg200_data_mse = [362.5,
829.4088235294118,
616.1317741935484,
294.53125,
193.07507692307695]
italy_data_mse = [337.5,
235.71285714285713,
460.41625000000005,
502.8149295774648,
483.33214285714286]
ligning_mse = [770.8325000000001,
757.1428571428571,
359.99899999999997,
200.001,
126.66633333333333]
draw_times_diff_bar(car_data_mse, ecg200_data_mse, italy_data_mse, ligning_mse,
car_data_sr, ecg200_data_sr, italy_data_sr, ligning_sr,
'Car', 'ECG200', 'Italy', 'Ligning7',
filename='扰动因子.pdf', rightLabel='ANI', xlabel='$\\beta$',
x_value=['0.01', '0.02', '0.04', '0.06', '0.08'], leftLabel='Queries',times=1)
# 热力图
# data1 = generate_heat_maps_array(count_classes_samples('/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/热力图/Lightning7', select_colum='Success'),
# classes_size=7)
# data2 = generate_heat_maps_array(count_classes_samples('/Users/catb/Library/CloudStorage/CloudMounter-B40-4/home/BJTU/project/CPadv/CCPP实验结果/热力图/Plane', select_colum='Success'),
# classes_size=7)
# heat_maps_of_classes(data1, data2,
# '',
# cbar_ticks1=[0, 1, 2, 3, 4], cbar_ticks2=[0, 1, 2, 3, 4], filename='热力图.pdf')

565
drawing_tool.py Normal file
View File

@ -0,0 +1,565 @@
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import patches
from matplotlib.font_manager import FontProperties
from matplotlib.ticker import FuncFormatter
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
import matplotlib.patheffects as pe
# 设置字体为 Times New Roman并调整字体大小
plt.rcParams['font.family'] = 'Times New Roman'
plt.rcParams['font.size'] = 22 # 设置默认字体大小
plt.rcParams['axes.titlesize'] = 26 # 设置标题字体大小
plt.rcParams['axes.labelsize'] = 26 # 设置轴标签字体大小
plt.rcParams['xtick.labelsize'] = 26 # 设置x轴刻度字体大小
plt.rcParams['ytick.labelsize'] = 26 # 设置y轴刻度字体大小
plt.rcParams['legend.fontsize'] = 20 # 设置图例字体大小
import matplotlib
from matplotlib.patches import FancyBboxPatch
from mpl_toolkits.axes_grid1 import make_axes_locatable
from analyzeTool import generate_heat_maps_array, count_classes_samples
matplotlib.use('MacOSX') # 使用MacOSX后端以兼容Mac
# 绘制原始和扰动时间序列的函数
def draw_ori_perturbed(ori_data, pert_data, dashed_lists=None, title=None, filename='comp_ori_pert_result.pdf',
loc_sample='upper left', loc_sub='upper left', inset_range=None, xy=(0, 0), xytext=(0, 0)):
color_1 = '#4B0082'
color_2 = '#FF8C00'
# 将字符串数据转换为浮点数列表
ori_ts = list(map(float, ori_data.split()))
perturbed_ts = list(map(float, pert_data.split()))
length = len(ori_ts)
x = np.arange(0, length, 1) # 生成从0到数据长度的x值
# 绘制数据
plt.figure(figsize=(10, 5))
plt.plot(x, ori_ts, label='Original', color=color_1, linewidth=5)
plt.plot(x, perturbed_ts, label='Perturbed', color=color_2, linewidth=5)
# 添加虚线框
if dashed_lists is None:
dashed_lists = []
if len(dashed_lists) > 0:
for start, end in dashed_lists:
max_len = max(max(ori_ts[start:end]), max(perturbed_ts[start:end]))
min_len = min(min(ori_ts[start:end]), min(perturbed_ts[start:end]))
plt.plot(
[start, start, end, end, start],
[min_len, max_len, max_len, min_len, min_len],
linestyle='--', # 使用linestyle来指定虚线样式
linewidth=4, # 线宽
color='black'
)
plt.xlim(-10, length + 10) # 设置x轴范围
plt.legend(loc=loc_sample)
plt.grid(True)
# 获取当前轴并设置边框宽度
ax = plt.gca()
for spine in ax.spines.values():
spine.set_linewidth(2) # 设置边框线宽
# 添加局部放大
if inset_range is not None:
plt.annotate('', xy=xy, xytext=xytext,
arrowprops=dict(arrowstyle='->', color='black', lw=3))
inset_start, inset_end = inset_range
ax_inset = inset_axes(plt.gca(), width="30%", height="30%", loc=loc_sub, borderpad=1) # 调整宽度和高度
ax_inset.plot(x[inset_start:inset_end], ori_ts[inset_start:inset_end], label='Original', color=color_1,
linewidth=4)
ax_inset.plot(x[inset_start:inset_end], perturbed_ts[inset_start:inset_end], label='Perturbed', color=color_2,
linewidth=4)
ax_inset.set_xlim(inset_start, inset_end)
ax_inset.grid(True)
# 移除插入图的坐标轴刻度
ax_inset.set_xticks([])
ax_inset.set_yticks([])
for spine in ax_inset.spines.values():
spine.set_linewidth(2) # 设置边框线宽
if title is not None:
# 使用 tight_layout 和 subplots_adjust 调整布局
plt.tight_layout()
plt.subplots_adjust(bottom=0.15) # 调整底部边距
# 在下方添加标题
plt.figtext(0.5, 0.02, title, ha='center', fontsize=12)
plt.savefig(filename)
plt.show()
# 绘制原始和扰动时间序列的函数,带有放大视图
def draw_ori_perturbed_with_inset(ori_data, pert_data, inset_start, inset_end):
# 将字符串数据转换为浮点数列表
ori_ts = list(map(float, ori_data.split()))
perturbed_ts = list(map(float, pert_data.split()))
length = len(ori_ts)
x = np.arange(0, length, 1) # 生成从0到数据长度的x值
# 创建主图
fig, ax = plt.subplots(figsize=(10, 5))
ax.plot(x, ori_ts, label='Original: Class 0', color='royalblue', linewidth=2)
ax.plot(x, perturbed_ts, label='Perturbed: Class 1', color='tomato', linewidth=2)
ax.set_xlim(-20, length + 20) # 设置x轴范围
ax.grid(True)
# 创建放大视图
from mpl_toolkits.axes_grid1.inset_locator import inset_axes, mark_inset
# 定义放大区域
inset_axes_params = {
'width': '40%', # 放大视图的宽度
'height': '40%', # 放大视图的高度
'bbox_to_anchor': (-0.2, -0.1, 0.8, 0.8), # 偏移,尺寸
'bbox_transform': ax.transAxes # 使用轴的变换
}
# 创建放大视图轴
ax_inset = inset_axes(ax, **inset_axes_params)
# 设置放大视图的范围
ax_inset.plot(x, ori_ts, color='royalblue', linewidth=2)
ax_inset.plot(x, perturbed_ts, color='tomato', linewidth=2)
ax_inset.set_xlim(inset_start, inset_end)
ax_inset.set_ylim(min(ori_ts[inset_start:inset_end]) - 0.5, max(ori_ts[inset_start:inset_end]) + 0.5)
# 移除放大视图中的刻度
ax_inset.set_xticks([])
ax_inset.set_yticks([])
# 标记放大区域并设置边框粗细和zorder(层次位置,越大越靠前)避免线条重叠在数据线上loc1和loc2代表引导线的起始角
mark_inset(ax, ax_inset, loc1=3, loc2=1, fc="none", ec="0.5", lw=2, zorder=10)
# 添加阴影效果到原图的标记框
bbox_shadow = FancyBboxPatch((inset_start, min(ori_ts[inset_start:inset_end]) - 0.5),
inset_end - inset_start,
max(ori_ts[inset_start:inset_end]) - min(ori_ts[inset_start:inset_end]) + 1,
boxstyle="round,pad=0.1",
ec="none", fc="black", alpha=0.2,
transform=ax.transData, zorder=2)
ax.add_patch(bbox_shadow)
# 保存并展示图像
plt.savefig('comp_ori_pert_inset_result.pdf')
plt.show()
def draw_times_diff(data1, data2, data3, data1_label, data2_label, data3_label):
x = np.arange(1, 6)
# 创建图表
plt.figure(figsize=(10, 5))
plt.plot(x, data1, label=data1_label, color='royalblue', marker='o')
plt.plot(x, data2, label=data2_label, color='tomato', marker='o')
plt.plot(x, data3, label=data3_label, color='sandybrown', marker='o')
# 添加标签和图例
plt.xlabel('Times of population size')
plt.ylabel('MSE')
plt.legend()
plt.grid(True)
# 调整布局以防止标签被裁剪
plt.tight_layout()
plt.legend(loc='center right')
# 保存为PDF格式矢量图
plt.savefig('line_chart_result.pdf', format='pdf')
plt.show()
def draw_times_diff_bar(data1, data2, data3, data4,
line_data1, line_data2, line_data3, line_data4,
data1_label, data2_label, data3_label, data4_label,
filename='bar_chart_with_lines_and_legend_above.pdf', leftLabel='MSE (10^-3)', rightLabel='ANI',
xlabel='Times of population size', x_value=None, times=1000):
if x_value is None:
x_value = ['1', '2', '3', '4', '5']
x = np.arange(1, 6) # 假设有5个数据点
# 设置柱状图的宽度
bar_width = 0.15
# 创建图表
fig, ax1 = plt.subplots(figsize=(8, 5))
color1 = '#05B9E2'
color2 = '#54B345'
color3 = '#F27970'
color4 = '#8983BF'
# 为每组数据创建柱状图,并添加黑色边框
bars1 = ax1.bar(x - bar_width * 1.5, data1, width=bar_width, label=data1_label, color=color1, alpha=0.6,
edgecolor='black')
bars2 = ax1.bar(x - bar_width * 0.5, data2, width=bar_width, label=data2_label, color=color2, alpha=0.6,
edgecolor='black')
bars3 = ax1.bar(x + bar_width * 0.5, data3, width=bar_width, label=data3_label, color=color3, alpha=0.6,
edgecolor='black')
bars4 = ax1.bar(x + bar_width * 1.5, data4, width=bar_width, label=data4_label, color=color4, alpha=0.6,
edgecolor='black')
# 设置左侧Y轴标签和格式
ax1.set_xlabel(xlabel)
ax1.set_ylabel(leftLabel)
ax1.set_xticks(x)
ax1.set_xticklabels(x_value)
ax1.tick_params(axis='y')
ax1.grid(axis='y') # 只显示y轴的网格线
for spine in ax1.spines.values():
spine.set_linewidth(2) # 设置边框线宽
# 格式化y轴刻度为指数形式
def to_exponential(x, _):
return f'{x * times:.0f}'
ax1.yaxis.set_major_formatter(FuncFormatter(to_exponential))
# 创建右侧Y轴
ax2 = ax1.twinx()
ax2.plot(x, line_data1, color=color1, marker='o', linestyle='-', linewidth=2, markersize=8)
ax2.plot(x, line_data2, color=color2, marker='o', linestyle='-', linewidth=2, markersize=8)
ax2.plot(x, line_data3, color=color3, marker='o', linestyle='-', linewidth=2, markersize=8)
ax2.plot(x, line_data4, color=color4, marker='o', linestyle='-', linewidth=2, markersize=8)
ax2.set_ylabel(rightLabel)
ax2.tick_params(axis='y')
# 将柱状图的图例放在图的上方,并设置字体大小
bars_legend = ax1.legend(loc='upper center', bbox_to_anchor=(0.5, 1.2), ncol=4, frameon=False)
# 添加图例到图中
ax1.add_artist(bars_legend)
# 调整布局以防止标签被裁剪
plt.tight_layout(rect=[0, 0, 1, 0.95])
# 保存为PDF格式矢量图
plt.savefig(filename, format='pdf')
plt.show()
def draw_diff_pert_info(data1, data2, data5, data6, labels, marker=None, linewidth=2, filename='line_chart_result.pdf'):
x = np.arange(len(labels))
color1 = '#F27970'
color2 = '#54B345'
color3 = '#05B9E2'
color4 = '#8983BF'
# 创建图表
plt.figure(figsize=(7, 5))
plt.plot(x, data1, label='Car', color=color1, marker=marker, linewidth=linewidth, markersize=8)
plt.plot(x, data5, label='ECG200', color=color2, marker=marker, linewidth=linewidth, markersize=8)
plt.plot(x, data2, label='Italy', color=color3, marker=marker, linewidth=linewidth, markersize=8)
plt.plot(x, data6, label='Ligning7', color=color4, marker=marker, linewidth=linewidth, markersize=8)
# 添加标签和图例
plt.xlabel('$\\beta$')
plt.ylabel('Success Rate')
plt.xticks(x, labels, rotation=0, ha='center')
# plt.legend(loc='center right') # 图例位置和字体大小
plt.grid(True) # 网格线
# 调整子图布局以防止重叠
plt.tight_layout(rect=[0, 0.03, 1, 0.95])
# 获取当前坐标轴对象
ax = plt.gca()
for spine in ax.spines.values():
spine.set_linewidth(2) # 设置边框线宽
# 保存为PDF格式矢量图
plt.savefig(filename, format='pdf')
plt.show()
# 画大表
def draw_all_data_set_info(data1, data2, data3, data4, data5, labels):
def replace_neg_ones_with_nan(data):
"""
将数据中的所有-1替换为np.nan
参数:
data (array-like): 输入数据数组
返回:
numpy.ndarray: -1替换为np.nan后的数据数组
"""
return np.array([np.nan if x == -1 else x for x in data])
def move_neg_ones_to_end(arrays):
for i in range(len(arrays)):
# 跳过所有非数字数组
if not isinstance(arrays[i][0], (int, float)):
continue
# 记录每个数组中的元素和对应的索引
elements = [(val, idx) for idx, val in enumerate(arrays[i])]
# 将-1移动到末尾
sorted_elements = sorted(elements, key=lambda x: (x[0] == -1, 0))
# 重新排列每个数组
for array in arrays:
sorted_array = [array[elem[1]] for elem in sorted_elements]
array[:] = sorted_array
# 修正数组
move_neg_ones_to_end([labels, data1, data2, data3, data4, data5])
# 将数据集中的-1替换为NaN
data1 = replace_neg_ones_with_nan(data1)
data2 = replace_neg_ones_with_nan(data2)
data3 = replace_neg_ones_with_nan(data3)
data4 = replace_neg_ones_with_nan(data4)
data5 = replace_neg_ones_with_nan(data5)
# 创建x轴的值
x = np.arange(len(labels))
# 创建折线图
plt.figure(figsize=(10, 5))
plt.plot(x, data1, label='GATN MSE', color='black')
plt.plot(x, data2, label='advGAN MSE', color='royalblue')
plt.plot(x, data3, label='TSadv MSE $\\beta=0.04$', color='tomato')
plt.plot(x, data4, label='CPadv MSE $\\beta=0.04$', color='sandybrown')
plt.plot(x, data5, label='CPadv MSE $\\beta=0.02$', color='firebrick')
# 添加标签和图例
plt.xlabel('')
plt.ylabel('MSE')
plt.xticks(x, labels, rotation=30, ha='right', fontsize=5, fontweight='bold')
plt.legend(loc='upper right') # 标签位置
plt.grid(False) # 网格线
# 调整布局以防止重叠
plt.tight_layout(rect=[0, 0.03, 1, 0.95])
# 添加标题
plt.figtext(0.5, 0.01, 'Fig. 9. MSE results of TSadv over different $\\beta$ and GATN on 42 UCR datasets',
ha='center', fontsize=12)
# 保存为PDF文件
plt.savefig('line_chart_result.pdf', format='pdf')
plt.show()
def heat_maps_of_classes(ori_data1, ori_data2, title, labels=None, cbar_ticks1=None, cbar_ticks2=None,
cmap_color='Blues', filename='heatmap.pdf'):
"""
生成两个数据集的并排热图并将其保存为PDF文件
参数:
ori_data1 (list of int/float): 第一个数据集将其可视化为热图
ori_data2 (list of int/float): 第二个数据集将其可视化为热图
title (str): 热图的标题
labels (list of tuple of str, optional): 两个热图的x轴和y轴标签列表默认值为[('', ''), ('', '')]
cbar_ticks1 (list of float, optional): 自定义color bar1的刻度列表默认值为None
cbar_ticks2 (list of float, optional): 自定义color bar2的刻度列表默认值为None
cmap_color (str): 热力图颜色默认Blues
"""
# 设置字体
# 设置颜色条的字体
font = FontProperties()
font.set_family('serif')
font.set_name('Times New Roman')
font.set_size(20) # 设置字体大小
# 数据
if labels is None:
labels = [('', ''), ('', '')]
data1 = np.array(ori_data1)
data2 = np.array(ori_data2)
fig, axs = plt.subplots(1, 2, figsize=(8, 3), gridspec_kw={'wspace': 0.4})
# 第一个子图
cax1 = axs[0].matshow(data1, cmap=cmap_color, alpha=0.8, vmin=min(cbar_ticks1), vmax=max(cbar_ticks1))
# 添加网格
axs[0].set_xticks(np.arange(data1.shape[1] + 1) - 0.5, minor=True)
axs[0].set_yticks(np.arange(data1.shape[0] + 1) - 0.5, minor=True)
axs[0].grid(which='minor', color='gray', linestyle='-', linewidth=0.5)
# 创建第一个子图的颜色条
divider1 = make_axes_locatable(axs[0])
cax1_cb = divider1.append_axes("right", size="5%", pad=0.1)
cb1 = fig.colorbar(cax1, cax=cax1_cb)
if cbar_ticks1:
cb1.set_ticks(cbar_ticks1)
# 应用字体设置到颜色条的标签
cb1.ax.yaxis.set_tick_params(labelsize=12)
for label in cb1.ax.get_yticklabels():
label.set_fontproperties(font)
# 第二个子图
cax2 = axs[1].matshow(data2, cmap=cmap_color, alpha=0.8, vmin=min(cbar_ticks2), vmax=max(cbar_ticks2))
# 添加网格
axs[1].set_xticks(np.arange(data2.shape[1] + 1) - 0.5, minor=True)
axs[1].set_yticks(np.arange(data2.shape[0] + 1) - 0.5, minor=True)
axs[1].grid(which='minor', color='gray', linestyle='-', linewidth=0.5)
# 创建第二个子图的颜色条
divider2 = make_axes_locatable(axs[1])
cax2_cb = divider2.append_axes("right", size="5%", pad=0.1)
cb2 = fig.colorbar(cax2, cax=cax2_cb)
if cbar_ticks2:
cb2.set_ticks(cbar_ticks2)
cb2.ax.yaxis.set_tick_params(labelsize=12)
for label in cb2.ax.get_yticklabels():
label.set_fontproperties(font)
for i in range(2):
axs[i].tick_params(axis='both', which='major', labelsize=12)
axs[i].xaxis.set_ticks_position('bottom')
axs[i].xaxis.set_label_position('bottom')
axs[i].invert_yaxis()
for label in (axs[i].get_xticklabels() + axs[i].get_yticklabels()):
label.set_fontproperties(font)
# 设置xy轴刻度间隔为1
axs[0].set_xticks(np.arange(data1.shape[1]))
axs[0].set_yticks(np.arange(data1.shape[0]))
axs[1].set_xticks(np.arange(data2.shape[1]))
axs[1].set_yticks(np.arange(data2.shape[0]))
# 添加描述文字
plt.figtext(0.5, 0.01, title, ha='center', va='center', fontsize=10, fontname='Times New Roman')
# 保存为矢量图PDF格式
plt.savefig(filename, format='pdf', bbox_inches='tight')
# 显示图像
plt.show()
if __name__ == '__main__':
# 攻击样本对比
# original_data = "0.95110175 0.03860069 0.001077176 0.001077176 0.001077176 -0.028107779 0.0052464556 -0.036446338 -0.040615617 -0.036446338 -0.028107779 -0.078139131 -0.08647769 -0.044784896 -0.078139131 -0.057292734 -0.057292734 -0.094816249 -0.08647769 -0.069800573 -0.069800573 -0.08647769 -0.1240012 -0.11566264 -0.078139131 -0.094816249 -0.094816249 -0.14067832 -0.14067832 -0.090646969 -0.14901688 -0.16986328 -0.098985528 -0.15735544 -0.1240012 -0.061462014 -0.0072613824 -0.0072613824 0.071954926 0.096970602 -0.032277059 -0.13233976 -0.19070967 -0.27826454 -0.21572535 -0.27409526 -0.26992598 -0.28660309 -0.25741814 -0.28243382 -0.24907958 -0.24907958 -0.24907958 -0.2240639 -0.098985528 1.0600742 1.7771901 -0.82027086 -3.8930297 -5.3647854 -4.0431238 -2.2294872 -1.0287348 -0.44920499 -0.23240247 -0.1240012 -0.08647769 -0.015599941 0.017754294 0.03860069 0.063616366 0.10530916 0.10530916 0.18869474 0.18035619 0.28458817 0.40549727 0.46803646 0.60979196 0.75988602 0.93499575 1.2018296 1.5312027 1.8522372 2.1565946 2.4943062 2.7402937 2.9445884 2.9154034 2.5443376 2.0148391 1.3811086 0.85161016 0.45135934 0.21371042 0.071954926 -0.0239385 -0.078139131 -0.10315481 -0.08647769 -0.13233976 -0.094816249 -0.090646969 -0.044784896 -0.053123455 -0.044784896 -0.057292734 -0.10315481 -0.08647769 -0.08647769 -0.11566264 -0.15735544 -0.165694 -0.20321751 -0.21572535 -0.28243382 -0.28243382 -0.26992598 -0.29077238 -0.3074495 -0.34914228 -0.34080373 -0.33246517 -0.34914228 -0.32829589 -0.34080373 -0.3658194 -0.3658194 -0.37832724 -0.38249653 -0.39083508 -0.39917364 -0.39500436 -0.39083508 -0.43252788 -0.40334292"
# perturbed_data = "0.9546 0.0387 0.0011 0.0011 0.0011 -0.0282 0.0053 -0.0366 -0.0408 -0.0366 -0.0282 -0.0784 -0.0868 -0.0450 -0.0784 -0.0575 -0.0575 -0.0952 -0.0868 -0.0701 -0.0701 -0.0868 -0.1245 -0.1161 -0.0784 -0.0952 -0.0952 -0.1412 -0.1412 -0.0910 -0.1496 -0.1705 -0.0994 -0.1579 -0.1245 -0.0617 -0.0073 -0.0073 0.0722 0.0973 -0.0324 -0.1328 -0.1914 -0.2793 -0.2165 -0.2751 -0.2709 -0.2877 -0.2584 -0.1592 -0.2146 0.0321 -0.0189 0.0241 0.1806 1.3527 1.6821 -1.0405 -3.7122 -5.2477 -4.2234 -2.4362 -1.3062 -0.6095 -0.2333 -0.1245 -0.0868 -0.0157 0.0178 0.0387 0.0639 0.1057 0.1057 0.1894 0.1810 0.4762 0.2598 0.1544 0.2773 0.8633 0.8632 1.0042 1.3689 1.9531 2.3896 2.7358 2.7239 2.8305 2.7696 2.5007 2.0223 1.3862 0.8548 0.4530 0.2145 0.0722 -0.0240 -0.0784 -0.1035 -0.0868 -0.1328 -0.0952 -0.0910 -0.0450 -0.0533 -0.0450 -0.0575 -0.1035 -0.0868 -0.0868 -0.1161 -0.1579 -0.1663 -0.2040 -0.2165 -0.2835 -0.2835 -0.2709 -0.2918 -0.3086 -0.3504 -0.3421 -0.3337 -0.3504 -0.3295 -0.3421 -0.3672 -0.3672 -0.3797 -0.3839 -0.3923 -0.4006 -0.3965 -0.3923 -0.4341 -0.4048"
# # # 样本4成功
# # -0.4898 -0.4707 -0.4611 -0.4323 -0.4898 -0.4515 -0.4036 -0.4228 -0.4898 -0.4707 -0.3461 -0.4132 -0.4898 -0.3173 -0.4707 -0.2982 -0.3653 -0.2886 -0.3461 -0.2694 -0.3844 -0.3077 -0.3365 -0.3269 -0.2119 -0.2598 -0.2694 -0.2311 -0.3269 -0.2215 -0.2694 -0.1640 -0.1256 0.0660 0.0564 -0.0202 -0.1927 -0.4803 -0.5569 -0.3077 -0.3557 -0.2119 -0.2502 -0.2694 -0.2311 -0.2790 -0.0969 -0.0011 -0.0969 0.1653 0.2051 0.2683 0.8980 -0.2241 -4.2003 -6.0178 -4.5483 -3.0059 -1.3216 -0.5447 -0.2506 0.1809 -0.1301 0.4711 0.2481 0.2673 0.2385 0.2865 0.2673 0.3631 0.3823 0.3056 0.3823 0.4877 0.5261 0.9649 0.6908 0.7372 0.6360 0.8578 1.0912 1.5034 1.6566 1.7832 2.1861 2.5592 2.3825 1.6257 1.4009 0.9878 0.4590 0.3248 0.2194 0.2290 0.1906 0.1906 0.1715 0.1906 0.1906 0.1906 0.3344 0.1715 0.2290 0.2098 0.2481 0.2098 0.2194 0.2385 0.1715 0.2673 0.2290 0.2098 0.2098 0.2769 0.1715 0.2002 0.1810 0.1715 0.1906 0.1810 0.2098 0.1715 0.1906 0.1140 0.2290 0.1906 0.1619 0.2290 0.2481 0.2290 0.2481 0.2290 0.1715 0.1906 0.2002 0.2481
# draw_ori_perturbed(original_data, perturbed_data,
# [(49, 64), (75, 90)],
# '') # 可以添加多个虚线框
# draw_ori_perturbed_with_inset(original_data, perturbed_data, 220, 230)
# draw_ori_perturbed(original_data, perturbed_data)
# 种群倍数
# car_data = [1, 1, 1, 1, 1]
# ecg200_data = [10.2, 9.2, 8.3, 10, 8.7]
# italy_data = [6.7, 5.8, 4.2, 6.2, 6.2]
# car_data = [0.0031, 0.003, 0.00315, 0.0032, 0.00325]
# ecg200_data = [0.0066, 0.00655, 0.00652, 0.0068, 0.0067]
# italy_data = [0.0024, 0.00245, 0.0024, 0.0026, 0.0027]
# draw_times_diff_bar(car_data, ecg200_data, italy_data, 'Car', 'ECG200', 'ItalyPowerDemand')
# 大表MSE
# labels = [
# "Car", "Chlorine", "CinCECGTorso", "Earthquakes", "ECG200",
# "ECG5000", "ECGFiveDays", "FordA", "FordB", "InsectWngSnd",
# "ItalyPowerDemand", "Lightning2", "Lightning7", "MoteStrain", "NonIFECGTho1",
# "NonIFECGTho2", "Phoneme", "Plane", "SonyAIBOSurf1", "SonyAIBOSurf2",
# "StarLightCurves", "Trace", "TwoLeadECG", "Wafer", "AllGestureWiimoteX",
# "AllGestureWiimoteY", "AllGestureWiimoteZ", "FreezerRegularTrain", "FreezerSmallTrain", "PickupGestureZ",
# "PigAirwayPressure", "PigArtPressure", "PigCVP", "ShakeGestureZ", "Fungi",
# "GesturePebbleZ1", "GesturePebbleZ2", "DodgerLoopDay", "DodgerLoopWeekend", "DodgerLoopGame",
# "EOGHorizontalSignal", "EOGVerticalSignal"
# ]
#
# GATN = [
# 0.1130, 0.2690, 0.0490, 0.1220, 0.1380,
# 0.1530, 0.0830, 0.1130, 0.1190, 0.1580,
# 0.0800, 0.1330, 0.1320, 0.1430, 0.0840,
# 0.0870, 0.0750, 0.2730, 0.1680, 0.1790,
# 0.0640, 0.0780, 0.1080, 0.1330, 0.1200,
# 0.1220, 0.1090, 0.1490, 0.1310, 0.1350,
# 0.0400, 0.0380, 0.0410, 0.1220, 0.2050,
# 0.1290, 0.1300, 0.0950, 0.1370, 0.0260,
# 0.0580, 0.0640
# ]
#
# advGAN = [
# 0.246, 0.1223, 0.138, -1, 0.1257,
# 0.1796, 0.0331, 0.2281, 0.2466, 0.1306,
# 0.2473, 0.2102, 0.1856, 0.2194, 0.1587,
# 0.2434, 0.1778, 0.1774, 0.1924, 0.2033,
# 0.1479, 0.0406, 0.1169, 0.0743, 0.2397,
# 0.1447, 0.1936, 0.0533, 0.0624, 0.1253,
# -1, -1, -1, 0.1421, 0.1388,
# 0.124, 0.1386, -1, -1, -1,
# -1, -1
# ]
#
# TS_adv4 = [
# 0.0013, 0.0111, 0.017, 0.0052, 0.0079,
# 0.0062, 0.0139, 0.0067, 0.0079, 0.0063,
# 0.0036, 0.0383, 0.0138, 0.0048, 0.0085,
# 0.0049, 0.0048, 0.0068, 0.0063, 0.0073,
# 0.0022, 0.0024, 0.0034, 0.0031, 0.0201,
# 0.0096, 0.0019, 0.0012, 0.001, 0.006,
# 0.0022, 0.0014, 0.0052, 0.0087, 0.0086,
# 0.0345, 0.0204, 0.003, 0.003, 0.0044,
# 0.0023, 0.0043
# ]
#
# CP_adv4 = [
# 0.0029, 0.0042, 0.0179, 0.0042, 0.0065,
# 0.0085, 0.0092, 0.0091, 0.0094, 0.0064,
# 0.0042, 0.0208, 0.0143, 0.004, 0.0112,
# 0.0097, 0.0186, 0.0055, 0.0051, 0.0069,
# 0.0032, 0.0013, 0.0039, 0.0032, 0.0203,
# 0.0126, 0.0057, 0.0011, 0.0017, 0.005,
# 0.0045, 0.0044, 0.0058, 0.0097, 0.0066,
# 0.0281, 0.0226, 0.0036, 0.0038, 0.0057,
# 0.0043, 0.0051
# ]
#
# CP_adv2 = [
# 0.0008, 0.0011, 0.0046, 0.0011, 0.0018,
# 0.0022, 0.0027, 0.0023, 0.0024, 0.0016,
# 0.0008, 0.006, 0.0038, 0.0011, 0.0029,
# 0.0026, 0.0046, 0.0006, 0.0014, 0.0016,
# 0.0008, -1, 0.0012, 0.0008, 0.0052,
# 0.0031, 0.0014, 0.0003, 0.0004, 0.0013,
# 0.0011, 0.0011, 0.0013, 0.0023, 0.0022,
# 0.0067, 0.0053, 0.0009, 0.001, 0.0014,
# 0.0011, 0.0013
# ]
#
# draw_all_data_set_info(GATN, advGAN, TS_adv4, CP_adv4, CP_adv2, labels)
# 画不同扰乱因子下mse/ani对比图
# 扰动因子和成功率
# data1 = [52, 81, 81, 81, 81, 81] # Car
# # data2 = [1, 8, 8, 19, 18, 29] # ItalyPowerDemand
# data3 = [3, 12, 17, 42, 59, 77] # SonyAIBORobotSurface2
# data4 = [0, 4, 65, 78, 78, 78] # Plane
# data5 = [17, 22, 82, 87, 88, 88] # ECG200
# data6 = [23, 43, 81.5, 100, 100, 100] # Ligning7
# labels = ['0.01', '0.02', '0.04', '0.06', '0.08', '0.1'] # x轴扰乱因子标记
#
# draw_diff_pert_info(data1, data3, data4, data5, data6, labels,marker='o',linewidth=3)
# 热力图
# data1 = generate_heat_maps_array(count_classes_samples('result_0.08_6_f/Lightning7', select_colum='Success'),
# classes_size=7)
#
# data2 = generate_heat_maps_array(count_classes_samples('result_0.08_8_f/Plane', select_colum='Success'),
# classes_size=7)
#
# heat_maps_of_classes(data1, data2, '', cbar_ticks1=[2,4,6,8,10], cbar_ticks2=[3,6,9,12,15,18])
pass

375
ex.py Normal file
View File

@ -0,0 +1,375 @@
import warnings
import matplotlib
# matplotlib.use('Agg')
import networkx as nx
import matplotlib.pyplot as plt
matplotlib.use('Agg')
import numpy as np
import torch
import pandas as pd
import ruptures as rpt
from scipy.optimize import differential_evolution
from sklearn.metrics import mean_squared_error
from query_probability import query_one, load_ucr
warnings.filterwarnings('ignore')
def detect_change_points(data, model="l2", pen=1):
algo = rpt.Pelt(model=model,min_size=1,jump=1).fit(data)
#algo = rpt.Binseg(model=model, min_size=1, jump=1).fit(data)
bkps = algo.predict(pen=pen)
#print('=======',bkps)
return bkps
def build_local_graph(data, center_index, window_size):
"""构建局部图"""
start = max(0, center_index - window_size // 2)
end = min(len(data), center_index + window_size // 2)
G = nx.Graph()
for i in range(start, end):
for j in range(i + 1, end):
weight = np.linalg.norm(data[i] - data[j])
G.add_edge(i, j, weight=weight)
return G
def find_important_nodes_via_components(G):
"""使用连通分量动态确定次要变点的数量"""
components = list(nx.connected_components(G))
important_nodes = []
for component in components:
if len(component) > 1: # 考虑大于一个节点的组件
important_nodes.extend(component)
return list(important_nodes)
def process_change_points(data, change_points, window_size):
all_important_nodes = set()
for cp in change_points:
G = build_local_graph(data, cp, window_size)
important_nodes = find_important_nodes_via_components(G)
print(cp, '------', important_nodes)
all_important_nodes.update(important_nodes)
all_important_nodes.update((change_points))
return all_important_nodes
def get_magnitude(run_tag, factor, normalize,gpu):
'''
:param run_tag:
:param factor:
:return: Perturbed Magnitude
'''
data = load_ucr('data/' + run_tag + '/' + run_tag + '_attack'+gpu+'.txt', normalize=normalize)
X = data[:, 1:]
max_magnitude = X.max(1)
min_magnitude = X.min(1)
mean_magnitude = np.mean(max_magnitude - min_magnitude)
perturbed_mag = mean_magnitude * factor
print('Perturbed Magnitude:', perturbed_mag)
return perturbed_mag
class Attacker:
def __init__(self, run_tag, model_type, cuda, normalize, e,device,gpu):
self.run_tag = run_tag
self.model_type = model_type
self.cuda = cuda
#self.intervals = get_attack_position(self.run_tag, self.top_k)
self.normalize = normalize
self.e = e
self.device = device
self.gpu = gpu
def perturb_ts(self, perturbations, ts, attack_pos):
'''
:param perturbations:formalized as a tuplex,e),x(int) is the x-coordinatee(float) is the epsilon,e.g.,(2,0.01)
:param ts: time series
:return: perturbed ts
'''
# first we copy a ts
ts_tmp = np.copy(ts)
coordinate = 0 # 初始化perturbations数组的索引
for i in range(len(attack_pos)):
if attack_pos[i] == 1:
ts_tmp[i] += perturbations[coordinate]
coordinate += 1
# for interval in self.intervals:
# for i in range(int(interval[0]), int(interval[1])):
# ts_tmp[i] += perturbations[coordinate]
# coordinate += 1
return ts_tmp
def plot_per(self, perturbations, ts, target_class, sample_idx,attack_pos, prior_probs, attack_probs, factor):
# Obtain the perturbed ts
ts_tmp = np.copy(ts)
ts_perturbed = self.perturb_ts(perturbations=perturbations, ts=ts, attack_pos=attack_pos)
# Start to plot
plt.figure(figsize=(6, 4))
plt.plot(ts_tmp, color='b', label='Original %.2f' % prior_probs)
plt.plot(ts_perturbed, color='r', label='Perturbed %.2f' % attack_probs)
plt.xlabel('Time', fontsize=12)
if target_class == -1:
plt.title('Untargeted: Sample %d, eps_factor=%.3f' %
(sample_idx, factor), fontsize=14)
else:
plt.title('Targeted(%d): Sample %d, eps_factor=%.3f' %
(target_class, sample_idx, factor), fontsize=14)
plt.legend(loc='upper right', fontsize=8)
plt.savefig('result_' + str(factor) + '_' + str(self.model_type) + '/'
+ self.run_tag + '/figures'+self.gpu+'/' + self.run_tag +'_' + str(sample_idx) + '.png')
# plt.show()
def fitness(self, device,perturbations, ts, sample_idx, queries,attack_pos, target_class=-1):
#device = torch.device("cuda:0" if self.cuda else "cpu")
perturbations = torch.tensor(perturbations).to(device)
#ts = torch.tensor(ts, device='cuda')
queries[0] += 1
ts_perturbed = self.perturb_ts(perturbations, ts,attack_pos = attack_pos)
prob, _, _, _, _ = query_one(run_tag=self.run_tag,device=device, idx=sample_idx, attack_ts=ts_perturbed,
target_class=target_class, normalize=self.normalize,
cuda=self.cuda, model_type=self.model_type, e=self.e,gpu=self.gpu)
prob = torch.tensor(prob)
if target_class != -1:
prob = 1 - prob
return prob # The fitness function is to minimize the fitness value
def attack_success(self,device,perturbations, ts, sample_idx, attack_pos, iterations, target_class=-1, verbose=True):
iterations[0] += 1
print('The %d iteration' % iterations[0])
ts_perturbed = self.perturb_ts(perturbations, ts, attack_pos)
#ts_perturbed = torch.tensor(ts_perturbed, device='cuda')
# Obtain the perturbed probability vector and the prior probability vector
prob, prob_vector, prior_prob, prior_prob_vec, real_label = query_one(self.run_tag, device,idx=sample_idx,
attack_ts=ts_perturbed,
target_class=target_class,
normalize=self.normalize,
verbose=verbose, cuda=self.cuda,
model_type=self.model_type,
e=self.e,gpu=self.gpu)
predict_class = torch.argmax(prob_vector).to(device)
prior_class = torch.argmax(prior_prob_vec).to(device)
real_label = real_label.to(device)
# Conditions for early termination(empirical-based estimation), leading to save the attacking time
# But it may judge incorrectly that this may decrease the success rate of the attack.
if (iterations[0] > 5 and prob > 0.99) or \
(iterations[0] > 20 and prob > 0.9):
print('The %d sample is not expected to successfully attack.' % sample_idx)
print('prob: ',prob)
return True
if prior_class != real_label:
print('The %d sample cannot be classified correctly, no need to attack' % sample_idx)
return True
if prior_class == target_class:
print(
'The true label of %d sample equals to target label, no need to attack' % sample_idx)
return True
if verbose:
print('The Confidence of current iteration: %.4f' % prob)
print('########################################################')
# The criterion of attacking successfully:
# Untargeted attack: predicted label is not equal to the original label.
# Targeted attack: predicted label is equal to the target label.
if ((target_class == -1 and predict_class != prior_class) or
(target_class != -1 and predict_class == target_class)):
print('##################### Attack Successfully! ##########################')
return True
def attack(self, sample_idx,device, target_class=-1, factor=0.04,
max_iteration=50, popsize=200, verbose=True):
test = load_ucr('data/' + self.run_tag + '/' + self.run_tag + '_attack'+self.gpu+'.txt'
, normalize=self.normalize)
#attack_poses = np.loadtxt('data/' + self.run_tag + '/' + self.run_tag + '_attackPos'+self.gpu+'.txt')
ori_ts = test[sample_idx][1:]
#变点检测找区间
length = ori_ts.shape
result = detect_change_points(ori_ts)
sampled_indices = np.zeros(len(ori_ts), dtype=int)
if length[0] > 500 or len(result) > 0.4 * length[0]:
# 设置基本窗口大小和基本采样密度
base_window_size = 0
base_density_factor = 0.01
else:
# 设置基本窗口大小和基本采样密度
base_window_size = int(0.1 * length[0])
base_density_factor = 0.5
# 计算变点的重要性并调整窗口大小和采样密度
for i, cp in enumerate(result[:-1]):
# 计算变点前后的统计差异
if i == 0:
pre_mean = np.mean(ori_ts[:cp])
else:
pre_mean = np.mean(ori_ts[result[i - 1]:cp])
post_mean = np.mean(ori_ts[cp:result[i + 1]])
# 重要性评估:差异的绝对值
importance = abs(post_mean - pre_mean)
# 动态调整窗口大小和采样密度
if length[0] > 500 or len(result) > 0.1 * length[0]:
window_size = int(base_window_size + int(importance * 5)) # 重要性越大,窗口越大
density_factor = base_density_factor + importance * 0.1 # 重要性越大,采样密度越高
else:
window_size = int(base_window_size + int(importance * 10)) # 重要性越大,窗口越大
density_factor = base_density_factor + importance * 0.3 # 重要性越大,采样密度越高
# 设置窗口的开始和结束位置
start = max(cp - window_size // 2, 0)
end = min(cp + window_size // 2, len(ori_ts))
# 在窗口内随机采样
sample_count = int((end - start) * density_factor)
if sample_count > 0:
samples = np.random.choice(range(start, end), sample_count, replace=True)
sampled_indices[samples] = 1
attack_pos = sampled_indices
#attack_pos = attack_poses[sample_idx,:]
# attack_pos = attack_poses.head(sample_idx)
# attack_pos = attack_pos.apply(pd.to_numeric, errors='coerce').fillna(0)
#ori_ts = torch.tensor(ori_ts).to(device)
attacked_probs, attacked_vec, prior_probs, prior_vec, real_label = query_one(self.run_tag,device,idx=sample_idx,
attack_ts=ori_ts,
target_class=target_class,
normalize=self.normalize,
verbose=False,
cuda=self.cuda, e=self.e,
model_type=self.model_type,gpu=self.gpu)
prior_class = torch.argmax(prior_vec).to(device)
if prior_class != real_label:
print('The %d sample cannot be classified correctly, no need to attack' % sample_idx)
return ori_ts,ori_ts, [prior_probs, attacked_probs, 0, 0, 0, 0, 0, 'WrongSample']
# Get the maximum perturbed magnitude
perturbed_magnitude = get_magnitude(self.run_tag, factor, normalize=self.normalize,gpu=self.gpu)
bounds = []
# for interval in self.intervals:
# steps_count += int(interval[1]) - int(interval[0])
# for i in range(int(interval[0]), int(interval[1])):
# bounds.append((-1 * perturbed_magnitude, perturbed_magnitude))
steps_count = attack_pos.sum()
for i in range(len(attack_pos)):
if attack_pos[i] == 1:
bounds.append((-1 * perturbed_magnitude, perturbed_magnitude))
print('The length of shapelet interval', steps_count)
#print('The length of bounds', len(bounds))
popmul = max(1, popsize // len(bounds))
# Record of the number of iterations
iterations = [0]
queries = [0]
def fitness_fn(perturbations):
return self.fitness(perturbations=perturbations, ts=ori_ts, queries=queries,
sample_idx=sample_idx, attack_pos=attack_pos,target_class=target_class,device=device)
def callback_fn(x, convergence):
return self.attack_success(perturbations=x, ts=ori_ts,
sample_idx=sample_idx,
attack_pos = attack_pos,
iterations=iterations,
target_class=target_class,
verbose=verbose,device=device)
attack_result = differential_evolution(func=fitness_fn, bounds=bounds
, maxiter=max_iteration, popsize=popmul
, recombination=0.7, callback=callback_fn,
atol=-1, polish=False)
attack_ts = self.perturb_ts(attack_result.x, ori_ts, attack_pos)
mse = mean_squared_error(ori_ts, attack_ts)
attacked_probs, attacked_vec, prior_probs, prior_vec, real_label = query_one(self.run_tag,device, idx=sample_idx,
attack_ts=attack_ts,
target_class=target_class,
normalize=self.normalize,
verbose=False,
cuda=self.cuda, e=self.e,
model_type=self.model_type,gpu=self.gpu)
predicted_class = torch.argmax(attacked_vec).to(device)
prior_class = torch.argmax(prior_vec).to(device)
if prior_class != real_label:
success = 'WrongSample'
elif prior_class == target_class:
success = 'NoNeedAttack'
else:
if (predicted_class.item() != prior_class.item() and target_class == -1) \
or (predicted_class.item() == target_class and target_class != -1):
success = 'Success'
else:
success = 'Fail'
if success == 'Success':
self.plot_per(perturbations=attack_result.x, ts=ori_ts, target_class=target_class,
sample_idx=sample_idx, attack_pos=attack_pos, prior_probs=prior_probs, attack_probs=attacked_probs, factor=factor)
return ori_ts, attack_ts, [prior_probs, attacked_probs, prior_class.item(),
predicted_class.item(), queries[0], mse, iterations[0], success]
if __name__ == '__main__':
idx = [1]
attacker = Attacker(run_tag='ECG200', top_k=3, model_type='f', e=1499,
cuda=True, normalize=False)
for idx in idx:
attack_ts, info = attacker.attack(sample_idx=idx, target_class=-1, factor=0.01,
max_iteration=200, popsize=1, verbose=True)
#这里是生成对抗样本
if info[-1] == 'Success':
file = open('attack_time_series.txt', 'w+')
file.write('%d %d ' % (idx, info[3])) # save the sample index and the perturbed label
for i in attack_ts:
file.write('%.4f ' % i)
file.write('\n')
file.close()
print(info)
file = open('info.txt', 'w+')
file.write('%d ' % idx)
for i in info:
if isinstance(i, int):
file.write('%d ' % i)
elif isinstance(i, float):
file.write('%.4f ' % i)
else:
file.write(i + ' ')
file.write('\n')
file.close()

53
filter_figures_folder.py Normal file
View File

@ -0,0 +1,53 @@
import os
import shutil
from pathlib import Path
def copy_with_filtered_figures(source_root, target_root):
"""
Copy the directory structure from source_root to target_root,
excluding all folders that start with 'figures' directly under each dataset folder.
Args:
source_root: Path to the source directory (/Users/catb/Downloads/result_0.04_r)
target_root: Path to the target directory (/Users/catb/Downloads/result_0.04_r_filtered)
"""
# Create target root directory if it doesn't exist
if not os.path.exists(target_root):
os.makedirs(target_root)
# First level: Get all dataset directories
for dataset_name in os.listdir(source_root):
dataset_path = os.path.join(source_root, dataset_name)
# Skip if not a directory
if not os.path.isdir(dataset_path):
continue
# Create corresponding dataset directory in target
target_dataset_path = os.path.join(target_root, dataset_name)
if not os.path.exists(target_dataset_path):
os.makedirs(target_dataset_path)
# Process contents of each dataset directory
for item in os.listdir(dataset_path):
item_path = os.path.join(dataset_path, item)
target_item_path = os.path.join(target_dataset_path, item)
# Skip folders that start with 'figures'
if os.path.isdir(item_path) and item.startswith('figures'):
continue
# Copy directories (recursively) or files
if os.path.isdir(item_path):
shutil.copytree(item_path, target_item_path)
else:
shutil.copy2(item_path, target_item_path)
# Define source and target directories with absolute paths
source_directory = "/Users/catb/Downloads/result_0.04_f"
target_directory = source_directory + "_filtered"
# Run the filtering and copying process
copy_with_filtered_figures(source_directory, target_directory)
print(f"完成! 已创建筛选后的目录结构: {target_directory}")

120
main.py Normal file
View File

@ -0,0 +1,120 @@
import argparse
import numpy as np
import os
import time
import torch
from attacker import Attacker
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--cuda', action='store_false', help='it is unnecessary')
parser.add_argument('--gpu', type=str, default='0', help='the index of test sample ')
parser.add_argument('--target_class', type=int, default=-1, help='-1:untargeted')
parser.add_argument('--popsize', type=int, default=1, help='the popsuze of DE')
parser.add_argument('--magnitude_factor', type=float, default=0.04, help='the value of beta')
parser.add_argument('--maxitr', type=int, default=50, help='max iterations of DE')
parser.add_argument('--run_tag', default='ItalyPowerDemand', help='the name of dataset e.g.ECG200')
parser.add_argument('--model', default='f', help='the model type(ResNet,FCN),f:FCN r:Resnet')
parser.add_argument('--topk', type=int, default=4, help='employ the top k shapelets, maxima value is 5')
parser.add_argument('--normalize', action='store_true', help='it is unnecessary in our project, we have '
'normalized the data')
parser.add_argument('--e', type=int, default=1499, help='epochs of model')
opt = parser.parse_args()
device = "cpu"
# device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(device)
# device = 'cuda' if torch.cuda.is_available() else 'cpu'
os.makedirs('result_%s_%s/%s/figures%s' % (str(opt.magnitude_factor),
opt.model, opt.run_tag, opt.gpu), exist_ok=True)
data_path = 'data/' + opt.run_tag + '/' + opt.run_tag + '_attack' + opt.gpu + '.txt'
test_data = np.loadtxt(data_path)
size = test_data.shape[0]
idx_array = np.arange(size)
attacker = Attacker(run_tag=opt.run_tag, e=opt.e,
model_type=opt.model, cuda=opt.cuda, normalize=opt.normalize, device=device, gpu=opt.gpu)
# record of the running time
start_time = time.time()
# count the number of the successful instances, mse,iterations,queries
success_cnt = 0
right_cnt = 0
total_mse = 0
total_iterations = 0
total_quries = 0
for idx in idx_array:
print('###Start %s : generating adversarial example of the %d sample ###' % (opt.run_tag, idx))
ori_ts, attack_ts, info = attacker.attack(sample_idx=idx, target_class=opt.target_class,
factor=opt.magnitude_factor, max_iteration=opt.maxitr,
popsize=opt.popsize, device=device)
# only save the successful adversarial example
if info[-1] == 'Success':
success_cnt = success_cnt + 1
total_iterations += info[-2]
total_mse += info[-3]
total_quries += info[-4]
file0 = open('result_' + str(opt.magnitude_factor) + '_' + opt.model
+ '/' + opt.run_tag + '/ori_time_series' + str(opt.gpu) + '.txt', 'a+')
file0.write('%d %d ' % (idx, info[3]))
for i in ori_ts:
file0.write('%.4f ' % i)
file0.write('\n')
file0.close()
file = open('result_' + str(opt.magnitude_factor) + '_' + opt.model
+ '/' + opt.run_tag + '/attack_time_series' + str(opt.gpu) + '.txt', 'a+')
file.write('%d %d ' % (idx, info[3]))
for i in attack_ts:
file.write('%.4f ' % i)
file.write('\n')
file.close()
if info[-1] != 'WrongSample':
right_cnt += 1
# Save the returned information, whether the attack was successful or not
file = open('result_' + str(opt.magnitude_factor) + '_' + opt.model
+ '/' + opt.run_tag + '/information' + opt.gpu + '.txt', 'a+')
file.write('%d ' % idx)
for i in info:
if isinstance(i, int):
file.write('%d ' % i)
elif isinstance(i, float):
file.write('%.4f ' % i)
else:
file.write(str(i) + ' ')
file.write('\n')
file.close()
endtime = time.time()
total = endtime - start_time
# print useful information
print('Running time: %.4f ' % total)
print('Correctly-classified samples: %d' % right_cnt)
print('Successful samples: %d' % success_cnt)
print('Success rate%.2f%%' % (success_cnt / right_cnt * 100))
print('Misclassification rate%.2f%%' % (success_cnt / size * 100))
print('ANI: %.2f' % (total_iterations / success_cnt))
print('MSE: %.4f' % (total_mse / success_cnt))
print('Mean queries%.2f\n' % (total_quries / success_cnt))
# save the useful information
file = open('result_' + str(opt.magnitude_factor) + '_' + opt.model
+ '/' + opt.run_tag + '/information' + opt.gpu + '.txt', 'a+')
file.write('Running time:%.4f\n' % total)
file.write('Correctly-classified samples: %d' % right_cnt)
file.write('Successful samples:%d\n' % success_cnt)
file.write('Success rate%.2f%%' % (success_cnt / right_cnt * 100))
file.write('Misclassification rate%.2f%%\n' % (success_cnt / size * 100))
file.write('ANI:%.2f\n' % (total_iterations / success_cnt))
file.write('MSE:%.4f\n' % (total_mse / success_cnt))
file.write('Mean queries%.2f\n' % (total_quries / success_cnt))
file.close()

97
models.py Normal file
View File

@ -0,0 +1,97 @@
import torch.nn as nn
import torch.nn.functional as F
import torch
class ResNet(nn.Module):
def __init__(self, n_in, n_classes):
super(ResNet, self).__init__()
self.n_in = n_in
self.n_classes = n_classes
blocks = [1, 64, 128, 128]
self.blocks = nn.ModuleList()
for b, _ in enumerate(blocks[:-1]):
self.blocks.append(ResidualBlock(*blocks[b:b + 2], self.n_in))
self.fc1 = nn.Linear(blocks[-1], self.n_classes)
def forward(self, x: torch.Tensor):
for block in self.blocks:
x = block(x)
x = F.adaptive_avg_pool2d(x, 1)
x = x.view(-1, 1, 128)
x = self.fc1(x)
# x = F.log_softmax(x,1)
return x.view(-1, self.n_classes)
class ResidualBlock(nn.Module):
def __init__(self, in_maps, out_maps, time_steps):
super(ResidualBlock, self).__init__()
self.in_maps = in_maps
self.out_maps = out_maps
self.time_steps = time_steps
self.conv1 = nn.Conv2d(self.in_maps, self.out_maps, (7, 1), 1, (3, 0))
self.bn1 = nn.BatchNorm2d(self.out_maps)
self.conv2 = nn.Conv2d(self.out_maps, self.out_maps, (5, 1), 1, (2, 0))
self.bn2 = nn.BatchNorm2d(self.out_maps)
self.conv3 = nn.Conv2d(self.out_maps, self.out_maps, (3, 1), 1, (1, 0))
self.bn3 = nn.BatchNorm2d(self.out_maps)
def forward(self, x):
x = x.view(-1, self.in_maps, self.time_steps, 1)
x = F.relu(self.bn1(self.conv1(x)))
inx = x
x = F.relu(self.bn2(self.conv2(x)))
x = F.relu(self.bn3(self.conv3(x)) + inx)
return x
# FCN model
class ConvNet(nn.Module):
def __init__(self, n_in, n_classes):
super(ConvNet, self).__init__()
self.n_in = n_in
self.n_classes = n_classes
self.conv1 = nn.Conv2d(1, 128, (7, 1), 1, (3, 0))
self.bn1 = nn.BatchNorm2d(128)
self.conv2 = nn.Conv2d(128, 256, (5, 1), 1, (2, 0))
self.bn2 = nn.BatchNorm2d(256)
self.conv3 = nn.Conv2d(256, 128, (3, 1), 1, (1, 0))
self.bn3 = nn.BatchNorm2d(128)
self.fc4 = nn.Linear(128, self.n_classes)
def forward(self, x: torch.Tensor):
x = x.view(-1, 1, self.n_in, 1)
x = F.relu(self.bn1(self.conv1(x)))
x = F.relu(self.bn2(self.conv2(x)))
x = F.relu(self.bn3(self.conv3(x)))
x = F.adaptive_avg_pool2d(x, 1)
x = x.view(-1, 128)
x = self.fc4(x)
# return F.log_softmax(x,1)
return x
if __name__ == '__main__':
# resNet = ResNet(n_in=96, n_classes=3)
# input = torch.randn(32, 96, 1)
# out = resNet(input)
# print(out.shape)
torch.manual_seed(3)
fcn = ConvNet(n_in=112, n_classes=3)
input = torch.randn(32, 112, 1)
out = fcn(input)
print(out.size())

0
print_results_path.py Normal file
View File

78
query_probability.py Normal file
View File

@ -0,0 +1,78 @@
'''
This script use pre-trained model(e.g. FCN)
as the target model. We can query the probability
from it to decide attacks whether efficient or not.
'''
import numpy as np
import torch
import torch.nn as nn
device = torch.device("cuda:0" if 'store_true' else "cpu")
def load_ucr(path, normalize=False):
data = np.loadtxt(path)
data[:, 0] -= 1
# limit label to [0,num_classes-1]
num_classes = len(np.unique(data[:, 0]))
for i in range(data.shape[0]):
if data[i, 0] < 0:
data[i, 0] = num_classes - 1
# Normalize some datasets without normalization
if normalize:
mean = data[:, 1:].mean(axis=1, keepdims=True)
std = data[:, 1:].std(axis=1, keepdims=True)
data[:, 1:] = (data[:, 1:] - mean) / (std + 1e-8)
return data
def query_one(run_tag, device, idx, attack_ts, target_class=-1, normalize=False,
e=1499, verbose=False, cuda=True, model_type='r', gpu='0',n_class=1024):
ts = torch.from_numpy(attack_ts).float().to(device)
data_path = 'data/' + run_tag + '/' + run_tag + '_attack' + gpu + '.txt'
test_data = load_ucr(path=data_path, normalize=normalize)
test_data = torch.from_numpy(test_data).to(device)
Y = test_data[:, 0]
test_one = test_data[idx]
X = test_one[1:].float()
y = test_one[0].long()
y = y.to(device)
real_label = y
if target_class != -1:
y = target_class
ts = ts.to(device)
X = X.to(device)
model_path = 'model_checkpoints/' + run_tag + '/pre_'+model_type+'Trained.pth'
#print(device)
model = torch.load(model_path, map_location=device, weights_only=False)
with torch.no_grad():
model.eval()
softmax = nn.Softmax(dim=-1)
out = model(X)
prob_vector = softmax(out)
prob = prob_vector.view(n_class)[y].item()
out2 = model(ts)
prob_vector2 = softmax(out2)
prob2 = prob_vector2.view(n_class)[y].item()
if verbose:
print('Target_Class', target_class)
print('Prior Confidence of the %d sample is %.4f ' % (idx, prob))
return prob2, prob_vector2, prob, prob_vector, real_label
if __name__ == '__main__':
query_one('ECG200', 2)

5
requirements.txt Normal file
View File

@ -0,0 +1,5 @@
matplotlib
pandas
ruptures
scikit-learn
pymoo

203
run_all_datasets.py Normal file
View File

@ -0,0 +1,203 @@
import os
import csv
import pandas as pd
import concurrent.futures
from argparse import Namespace
from attack import attack_process
def create_datasets_csv(datasets_dir, output_csv="datasets_config.csv"):
"""
创建包含所有数据集及其参数的CSV文件
Args:
datasets_dir: 包含所有数据集文件夹的目录
output_csv: 输出CSV文件的路径
"""
# 检查目录是否存在
if not os.path.exists(datasets_dir):
raise FileNotFoundError(f"数据集目录 {datasets_dir} 不存在")
# 获取所有数据集文件夹
datasets = [d for d in os.listdir(datasets_dir) if os.path.isdir(os.path.join(datasets_dir, d))]
# 创建CSV文件
with open(output_csv, 'w', newline='') as csvfile:
fieldnames = [
'dataset_name',
'cuda',
'total_gpus',
'classes',
'target_class',
'pop_size',
'magnitude_factor',
'max_itr',
'run_tag',
'model',
'normalize',
'e',
'done'
]
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
# 为每个数据集添加一行,使用默认参数
for dataset in datasets:
writer.writerow({
'dataset_name': dataset,
'cuda': 'store_true',
'total_gpus': 1,
'target_class': -1,
'classes': 0,
'pop_size': 1,
'magnitude_factor': 0.04,
'max_itr': 50,
'run_tag': dataset,
'model': 'r',
'normalize': 'store_true',
'e': 1499,
'done': '0' # 初始状态为未完成
})
print(f"已创建数据集配置文件: {output_csv}")
return output_csv
def validate_dataset(dataset_path):
"""验证数据集路径是否有效"""
if not os.path.exists(dataset_path):
return False
# 可以添加更多的验证逻辑,如检查必要的文件是否存在
return True
def process_dataset(row, datasets_base_dir):
"""处理单个数据集利用多个GPU并行处理"""
dataset_name = row['dataset_name']
dataset_path = os.path.join(datasets_base_dir, dataset_name)
# 验证数据集
if not validate_dataset(dataset_path):
print(f"警告: 数据集 '{dataset_name}' 路径无效或格式不正确")
return False
# 获取总GPU数量
total_gpus = int(row['total_gpus'])
# 为每个GPU创建一个配置
configurations = []
for i in range(total_gpus):
config = {
'cuda': row['cuda'] == 'store_true',
'gpu': str(i), # 分配不同的GPU
'target_class': int(row['target_class']),
'classes':int(row['classes']),
'popsize': int(row['pop_size']),
'magnitude_factor': float(row['magnitude_factor']),
'maxitr': int(row['max_itr']),
'run_tag': row['run_tag'],
'model': row['model'],
'normalize': row['normalize'] == 'store_true',
'e': int(row['e']),
'dataset': dataset_name # 添加数据集名称
}
configurations.append(config)
# 并行处理同一个数据集的多个任务
success = True
with concurrent.futures.ProcessPoolExecutor() as executor:
futures = []
for config in configurations:
arg = Namespace(**config)
future = executor.submit(attack_process, arg)
futures.append(future)
# 等待所有进程完成
for future in concurrent.futures.as_completed(futures):
try:
result = future.result()
# 如果任何一个进程失败,标记整个数据集处理为失败
if not result:
success = False
except Exception as e:
import traceback
print(f"处理数据集 '{dataset_name}' 时出错: {str(e)}")
print(traceback.format_exc())
success = False
return success
def main(csv_file, datasets_base_dir, max_workers=4):
"""
主程序顺序遍历CSV文件中的数据集并执行任务
每个数据集内部可能有并行处理由attack_process内部实现
Args:
csv_file: 包含数据集和参数的CSV文件
datasets_base_dir: 数据集根目录
max_workers: 数据集内部并行的最大工作进程数
"""
# 验证CSV文件
if not os.path.exists(csv_file):
raise FileNotFoundError(f"CSV文件 {csv_file} 不存在")
# 读取CSV文件
df = pd.read_csv(csv_file)
# 检查CSV格式是否正确
required_columns = [
'dataset_name',
'cuda',
'total_gpus',
'target_class',
'classes',
'pop_size',
'magnitude_factor',
'max_itr',
'run_tag',
'model',
'normalize',
'e',
'done'
]
missing_columns = [col for col in required_columns if col not in df.columns]
if missing_columns:
raise ValueError(f"CSV文件缺少必要的列: {', '.join(missing_columns)}")
# 只处理未完成的数据集
pending_datasets = df[df['done'] == 0]
total_pending = len(pending_datasets)
print(f"发现 {total_pending} 个未处理的数据集")
# 顺序处理数据集
for index, row in pending_datasets.iterrows():
dataset_name = row['dataset_name']
print(f"开始处理数据集: {dataset_name} ({pending_datasets.index[pending_datasets.index == index].item() + 1}/{total_pending})")
try:
# 处理单个数据集(内部可能有并行)
success = process_dataset(row, datasets_base_dir)
if success:
# 更新CSV中的done状态
df.at[index, 'done'] = 1
df.to_csv(csv_file, index=False)
print(f"完成数据集: {dataset_name}")
else:
print(f"处理数据集失败: {dataset_name}")
except Exception as e:
print(f"处理数据集 '{dataset_name}' 时出现异常: {str(e)}")
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description='批量处理数据集')
parser.add_argument('--csv', type=str, default='datasets_config.csv', help='数据集配置CSV文件')
parser.add_argument('--datasets_dir',default='data' , type=str, help='数据集根目录')
parser.add_argument('--create_csv', action='store_true', help='是否创建新的CSV文件')
parser.add_argument('--max_workers', type=int, default=4, help='最大并行工作进程数')
args = parser.parse_args()
if args.create_csv:
create_datasets_csv(args.datasets_dir, args.csv)
main(args.csv, args.datasets_dir, args.max_workers)

18
run_parallel_config.ini Normal file
View File

@ -0,0 +1,18 @@
[GLOBAL]
# mac win
#machine = mac
[GPU]
cuda=store_true
total_gpus=5
[MODEL]
run_tag=Car
classes=5
target_class=-1
pop_size=1
magnitude_factor=0.04
max_itr=50
model=f
normalize=store_true
e=1499

42
run_parallel_main.py Normal file
View File

@ -0,0 +1,42 @@
import concurrent
from argparse import Namespace
from attack import attack_process
from utils import read_config
def create_configurations(config):
# 基于配置文件生成配置列表
total_gpus = int(config['GPU']['total_gpus'])
configurations = []
for i in range(total_gpus):
conf_dict = {
'cuda': config['GPU']['cuda'],
'gpu': str(i),
'target_class': int(config['MODEL']['target_class']),
'popsize': int(config['MODEL']['pop_size']),
'magnitude_factor': float(config['MODEL']['magnitude_factor']),
'maxitr': int(config['MODEL']['max_itr']),
'run_tag': config['MODEL']['run_tag'],
'model': config['MODEL']['model'],
'normalize': config['MODEL']['normalize'],
'e': int(config['MODEL']['e'])
}
configurations.append(conf_dict)
return configurations
if __name__ == "__main__":
config_file = read_config("run_parallel_config.ini")
configurations = create_configurations(config_file)
with concurrent.futures.ProcessPoolExecutor() as executor:
futures = []
for config in configurations:
arg = Namespace(**config)
future = executor.submit(attack_process, arg)
# attack_process(arg)
futures.append(future)
for future in concurrent.futures.as_completed(futures):
# 处理结果,如果需要的话
pass

58
test.py Normal file
View File

@ -0,0 +1,58 @@
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import matplotlib as mpl
# 设置全局字体为 Times New Roman
plt.rcParams['font.family'] = 'Times New Roman'
plt.rcParams['mathtext.fontset'] = 'stix' # 数学文本也使用与 Times New Roman 兼容的字体
# 读取Excel文件
file_path = "实验结果.xlsx" # 请替换为你的文件路径
sheet_name = "Sheet1"
df = pd.read_excel(file_path, sheet_name=sheet_name)
# 提取所需数据
# 注意: Excel范围F2:F42对应pandas的索引1:41
# 同样L2:L43对应索引1:42A2:A43对应索引1:42
dataset_names = df.iloc[1:42, 0].values # A2:A43 数据集名称
cp_adv = df.iloc[1:41, 5].values # F2:F42 CPadv数据
cp_soadv = df.iloc[1:42, 12].values # L2:L43 CPsoadv数据
# 计算均值
cp_adv_mean = np.mean(cp_adv)
cp_soadv_mean = np.mean(cp_soadv)
# 创建图表 - 减小图片尺寸
plt.figure(figsize=(10, 5)) # 从 (12, 6) 减小到 (10, 5)
# 绘制CPadv折线
plt.plot(dataset_names[:len(cp_adv)], cp_adv, 'b-', marker='o', label='CPadv')
# 绘制CPadv均值线
plt.axhline(y=cp_adv_mean, color='b', linestyle='--', alpha=0.7, label='Mean of CPadv')
# 绘制CPsoadv折线
plt.plot(dataset_names[:len(cp_soadv)], cp_soadv, 'r-', marker='s', label='CPsoadv')
# 绘制CPsoadv均值线
plt.axhline(y=cp_soadv_mean, color='r', linestyle='--', alpha=0.7, label='Mean of CPsoadv')
# 设置图表标题和标签
plt.ylabel('Queries', fontsize=12)
plt.grid(True, linestyle='--', alpha=0.7)
plt.legend()
# 调整x轴标签
plt.xticks(rotation=45, ha='right')
plt.tight_layout()
# 保存为PDF矢量图
plt.savefig('CCPP_comparison.pdf', bbox_inches='tight')
# 同时也保存一份PNG格式如果需要
plt.savefig('CCPP_comparison.png', dpi=300, bbox_inches='tight')
plt.show()
# 打印均值结果
print(f"CPadv 均值: {cp_adv_mean:.2f}")
print(f"CPsoadv 均值: {cp_soadv_mean:.2f}")

70
utils.py Normal file
View File

@ -0,0 +1,70 @@
import configparser
import torch
import numpy as np
from torch.utils.data import Dataset
from query_probability import load_ucr
import warnings
warnings.filterwarnings('ignore')
class UcrDataset(Dataset):
def __init__(self, txt_file, channel_last, normalize):
'''
:param txt_file: path of file
:param channel_last
'''
# self.data = np.loadtxt(txt_file)
self.data = load_ucr(txt_file, normalize)
self.channel_last = channel_last
if self.channel_last:
self.data = np.reshape(self.data, [self.data.shape[0], self.data.shape[1], 1])
else:
self.data = np.reshape(self.data, [self.data.shape[0], 1, self.data.shape[1]])
def __len__(self):
return len(self.data)
def __getitem__(self, idx):
if not self.channel_last:
return self.data[idx, :, 1:], self.data[idx, :, 0]
else:
return self.data[idx, 1:, :], self.data[idx, 0, :]
def get_seq_len(self):
if self.channel_last:
return self.data.shape[1] - 1
else:
return self.data.shape[2] - 1
class AdvDataset(Dataset):
def __init__(self, txt_file):
self.data = np.loadtxt(txt_file)
self.data = np.reshape(self.data, [self.data.shape[0], self.data.shape[1], 1])
def __len__(self):
return len(self.data)
def __getitem__(self, idx):
return self.data[idx, 2:, :], self.data[idx, 1, :]
def get_seq_len(self):
return self.data.shape[1] - 2
def UCR_dataloader(dataset, batch_size):
data_loader = torch.utils.data.DataLoader(dataset, batch_size=batch_size, shuffle=True, num_workers=0)
return data_loader
def read_config(file_name):
# 创建一个配置解析器
config = configparser.ConfigParser()
# 从INI文件读取配置
config.read(file_name)
return config