clear;
close all;
%% 固定随机数种子以确保结果可重复
rng(42); % 固定随机数种子
%% 第一部分:特征提取 - 每5000点提取一次特征
% 加载数据文件
load("2、9个负载,都去掉前面补0的值,并转置为列向量.mat");
% 定义模型
train_models = {'Diancilu_1', 'Jiashiqi_1'}; % 只使用这两个模型训练
test_models = {'Diancilu_1', 'Jiashiqi_1', 'LED_1', 'TV_1', 'bingxiang_1', 'dianfanbao_1', 'fengshan_1', 'kongtiaoguiji_1'}; % 测试这八个模型
% 定义每段数据点数
segment_size = 5000; % 每5000点作为一个样本
% 初始化特征存储矩阵
train_feature_matrix = [];
train_labels = [];
test_feature_matrix = [];
test_labels = [];
%% 处理训练数据 (Diancilu_1和Jiashiqi_1)
for model_idx = 1:length(train_models)
model_name = train_models{model_idx};
fprintf('正在处理训练模型: %s\n', model_name);
% 获取原始数据
raw_data = eval(model_name);
% 小波包分解
wpt = wpdec(raw_data, 4, 'rbio3.1');
reconstructed = wprcoef(wpt, [4, 2]);
% 计算可以提取的完整段数
num_segments = floor(length(reconstructed) / segment_size);
for seg = 1:num_segments
start_idx = (seg-1)*segment_size + 1;
end_idx = seg*segment_size;
segment_data = reconstructed(start_idx:end_idx);
% 计算能量特征(分成5段,每段1000点)
energy_features = [];
subseg_size = 1000;
for subseg = 1:5
subseg_start = (subseg-1)*subseg_size + 1;
subseg_end = subseg*subseg_size;
energy_features = [energy_features, sum(segment_data(subseg_start:subseg_end).^2)];
end
% 计算统计特征
stat_features = [mean(segment_data), std(segment_data), skewness(segment_data), kurtosis(segment_data)];
% 组合所有特征
combined_features = [energy_features, stat_features];
% 存储特征和标签
train_feature_matrix = [train_feature_matrix; combined_features];
train_labels = [train_labels; model_idx];
end
fprintf('完成 %s 的特征提取,生成 %d 个训练样本\n', model_name, num_segments);
end
%% 处理测试数据 (所有8个模型)
for model_idx = 1:length(test_models)
model_name = test_models{model_idx};
fprintf('正在处理测试模型: %s\n', model_name);
% 获取原始数据
raw_data = eval(model_name);
% 小波包分解
wpt = wpdec(raw_data, 4, 'rbio3.1');
reconstructed = wprcoef(wpt, [4, 2]);
% 计算可以提取的完整段数
num_segments = floor(length(reconstructed) / segment_size);
for seg = 1:num_segments
start_idx = (seg-1)*segment_size + 1;
end_idx = seg*segment_size;
segment_data = reconstructed(start_idx:end_idx);
% 计算能量特征(分成5段,每段1000点)
energy_features = [];
subseg_size = 1000;
for subseg = 1:5
subseg_start = (subseg-1)*subseg_size + 1;
subseg_end = subseg*subseg_size;
energy_features = [energy_features, sum(segment_data(subseg_start:subseg_end).^2)];
end
% 计算统计特征
stat_features = [mean(segment_data), std(segment_data), skewness(segment_data), kurtosis(segment_data)];
% 组合所有特征
combined_features = [energy_features, stat_features];
% 存储特征和标签
test_feature_matrix = [test_feature_matrix; combined_features];
test_labels = [test_labels; model_idx];
end
fprintf('完成 %s 的特征提取,生成 %d 个测试样本\n', model_name, num_segments);
end
%% 第二部分:数据预处理
% 数据归一化到[0,1]范围(DBN/RBM要求)
min_vals = min(train_feature_matrix);
max_vals = max(train_feature_matrix);
% 修正归一化,确保不会除以0
range_vals = max_vals - min_vals;
range_vals(range_vals == 0) = 1;
train_feature_matrix = (train_feature_matrix - min_vals) ./ range_vals;
test_feature_matrix = (test_feature_matrix - min_vals) ./ range_vals;
% 确保数据在[0,1]范围内
test_feature_matrix(test_feature_matrix < 0) = 0;
test_feature_matrix(test_feature_matrix > 1) = 1;
% 将训练标签转换为one-hot编码(只有2类)
train_label_onehot = full(ind2vec(train_labels'))';
% 随机打乱训练数据顺序
rand_order = randperm(size(train_feature_matrix, 1));
train_feature_matrix = train_feature_matrix(rand_order, :);
train_label_onehot = train_label_onehot(rand_order, :);
%% 第三部分:Transformer对比学习模型
fprintf('\n=== 开始Transformer对比学习训练 ===\n');
% 转换为序列数据格式
train_seq = permute(reshape(train_feature_matrix', size(train_feature_matrix, 2), 1, size(train_feature_matrix, 1)), [3 1 2]);
test_seq = permute(reshape(test_feature_matrix', size(test_feature_matrix, 2), 1, size(test_feature_matrix, 1)), [3 1 2]);
% 定义Transformer参数
input_size = size(train_seq, 2);
embed_dim = 64; % 确保嵌入维度是头数的整数倍
num_heads = 4;
num_layers = 2;
output_size = 32;
batch_size = 64;
num_epochs = 100;
learning_rate = 0.001;
temperature = 0.1;
% 创建基础层
layers = [
sequenceInputLayer(input_size, 'Name', 'input')
fullyConnectedLayer(embed_dim, 'Name', 'embedding')
reluLayer('Name', 'relu_embed')
];
% 初始化层图
contrastive_net = layerGraph(layers);
% 构建Transformer层
for i = 1:num_layers
layer_suffix = num2str(i);
% 添加层组
layer_group = [
sequenceFoldingLayer('Name', ['fold_' layer_suffix])
fullyConnectedLayer(embed_dim*3, 'Name', ['attention_proj_' layer_suffix])
functionLayer(@(x) customMultiheadAttention(x, num_heads, embed_dim), 'Name', ['attention_' layer_suffix])
sequenceUnfoldingLayer('Name', ['unfold_' layer_suffix])
fullyConnectedLayer(embed_dim, 'Name', ['fc_' layer_suffix])
additionLayer(2, 'Name', ['add_' layer_suffix])
batchNormalizationLayer('Name', ['bn_' layer_suffix])
];
contrastive_net = addLayers(contrastive_net, layer_group);
% 确定前一层输出
if i == 1
prev_output = 'relu_embed';
else
prev_output = ['bn_' num2str(i-1)];
end
% 定义连接关系 - 修复未连接的输入/输出问题
connection_pairs = {
{prev_output, ['fold_' layer_suffix]},
{['fold_' layer_suffix], ['attention_proj_' layer_suffix]},
{['attention_proj_' layer_suffix], ['attention_' layer_suffix]},
{['attention_' layer_suffix], ['unfold_' layer_suffix]}, % 修复unfold层的输入连接
{['unfold_' layer_suffix], ['fc_' layer_suffix]},
{['fc_' layer_suffix], ['add_' layer_suffix '/in1']},
{prev_output, ['add_' layer_suffix '/in2']}, % 残差连接
{['add_' layer_suffix], ['bn_' layer_suffix]}
};
% 添加连接
for k = 1:length(connection_pairs)
source = connection_pairs{k}{1};
target = connection_pairs{k}{2};
if ~isConnectionPresent(contrastive_net, source, target)
try
contrastive_net = connectLayers(contrastive_net, source, target);
catch e
fprintf('连接失败: %s -> %s (%s)\n', source, target, e.message);
end
end
end
end
% 添加输出层 - 修改为分类层以匹配对比学习目标
output_layers = [
globalAveragePooling1dLayer('Name', 'global_pool')
fullyConnectedLayer(output_size, 'Name', 'projection')
batchNormalizationLayer('Name', 'bn_proj')
fullyConnectedLayer(max(train_labels), 'Name', 'classifier')
softmaxLayer('Name', 'softmax')
classificationLayer('Name', 'output')
];
contrastive_net = addLayers(contrastive_net, output_layers);
% 连接输出层
output_connections = {
{['bn_' num2str(num_layers)], 'global_pool'},
{'global_pool', 'projection'},
{'projection', 'bn_proj'},
{'bn_proj', 'classifier'},
{'classifier', 'softmax'},
{'softmax', 'output'}
};
for k = 1:length(output_connections)
source = output_connections{k}{1};
target = output_connections{k}{2};
if ~isConnectionPresent(contrastive_net, source, target)
contrastive_net = connectLayers(contrastive_net, source, target);
end
end
% 验证网络结构
analyzeNetwork(contrastive_net);
% 设置训练选项
options = trainingOptions('adam', ...
'InitialLearnRate', learning_rate, ...
'MaxEpochs', num_epochs, ...
'MiniBatchSize', batch_size, ...
'Shuffle', 'every-epoch', ...
'Verbose', false, ...
'Plots', 'training-progress');
% 训练模型
fprintf('Transformer模型训练中...\n');
contrastive_net = trainNetwork(train_seq, categorical(train_labels), contrastive_net, options);
% 提取特征
fprintf('提取Transformer特征...\n');
train_features = activations(contrastive_net, single(train_seq), 'bn_proj', 'OutputAs', 'rows');
test_features = activations(contrastive_net, single(test_seq), 'bn_proj', 'OutputAs', 'rows');
% 组合特征
train_combined_features = [train_feature_matrix, train_features];
test_combined_features = [test_feature_matrix, test_features];
%% 第四部分:DBN训练
fprintf('\n=== 开始DBN训练 ===\n');
% 设置DBN参数
dbn.sizes = [100 50];
opts.numepochs = 20;
opts.batchsize = 64;
opts.momentum = 0.5;
opts.alpha = 0.1;
% 调整batchsize
total_samples = size(train_combined_features, 1);
if mod(total_samples, opts.batchsize) ~= 0
opts.batchsize = gcd(total_samples, opts.batchsize);
end
% 训练DBN
dbn = dbnsetup(dbn, train_combined_features, opts);
dbn = dbntrain(dbn, train_combined_features, opts);
% 微调神经网络
nn = dbnunfoldtonn(dbn, size(train_label_onehot, 2));
nn.activation_function = 'sigm';
nn = nntrain(nn, train_combined_features, train_label_onehot, opts);
% 测试模型
nn.testing = 1;
out_prob = nnff(nn, test_combined_features, zeros(size(test_combined_features, 1), nn.size(end)));
nn.testing = 0;
[~, predicted_labels] = max(out_prob.a{end}, [], 2);
%% 第五部分:混淆矩阵
confusion_mat = zeros(8, 8);
prediction_mapping = [1, 2];
for i = 1:length(test_labels)
true_class = test_labels(i);
pred_class_idx = predicted_labels(i);
pred_class = prediction_mapping(1);
if pred_class_idx <= length(prediction_mapping)
pred_class = prediction_mapping(pred_class_idx);
end
confusion_mat(true_class, pred_class) = confusion_mat(true_class, pred_class) + 1;
end
% 可视化
figure;
set(gcf, 'Position', [100, 100, 1000, 900]);
imagesc(confusion_mat);
colorbar;
title('混淆矩阵');
xlabel('预测类别');
ylabel('真实类别');
% 保存模型
save('trained_model.mat', 'dbn', 'nn', 'contrastive_net');
%% 函数定义
function output = customMultiheadAttention(input, num_heads, embed_dim)
% 修复reshape操作,确保元素数量匹配
[batch_size, seq_len, dim] = size(input);
% 确保维度匹配
if dim ~= embed_dim
error('输入维度与嵌入维度不匹配');
end
% 计算每个头的维度
head_dim = embed_dim / num_heads;
% 确保头维度是整数
if mod(embed_dim, num_heads) ~= 0
error('嵌入维度必须是头数的整数倍');
end
% 将输入分割为QKV
qkv = reshape(input, batch_size, seq_len, 3, num_heads, head_dim);
% 分离查询(Q)、键(K)和值(V)
q = qkv(:,:,1,:,:); % [batch, seq_len, num_heads, head_dim]
k = qkv(:,:,2,:,:);
v = qkv(:,:,3,:,:);
% 计算注意力分数
attn_scores = zeros(batch_size, seq_len, seq_len, num_heads);
for h = 1:num_heads
% 提取当前头的Q、K
q_head = squeeze(q(:,:,h,:)); % [batch, seq_len, head_dim]
k_head = squeeze(k(:,:,h,:));
% 计算注意力分数 [batch, seq_len, seq_len]
attn_scores(:,:,:,h) = pagemtimes(q_head, permute(k_head, [1,3,2])) / sqrt(head_dim);
end
% 应用softmax获取注意力权重
attn_weights = softmax(attn_scores, 3);
% 应用注意力权重到值
context = zeros(batch_size, seq_len, num_heads, head_dim);
for h = 1:num_heads
% 提取当前头的V
v_head = squeeze(v(:,:,h,:)); % [batch, seq_len, head_dim]
% 应用注意力权重 [batch, seq_len, head_dim]
context(:,:,h,:) = pagemtimes(attn_weights(:,:,:,h), v_head);
end
% 重塑并合并多头结果
context_reshaped = reshape(context, batch_size, seq_len, embed_dim);
% 确保输出维度正确
output = context_reshaped;
end
function loss = contrastiveLoss(features, labels, temperature)
sim_matrix = features * features';
sim_matrix = sim_matrix - max(sim_matrix(:));
exp_sim = exp(sim_matrix / temperature);
mask = ~eye(size(exp_sim));
pos_mask = (labels == labels') & mask;
pos_sum = sum(exp_sim .* pos_mask, 2);
neg_sum = sum(exp_sim .* mask, 2);
loss = -mean(log(pos_sum ./ neg_sum));
end
function y = softmax(x, dim)
x = x - max(x, [], dim);
ex = exp(x);
y = ex ./ sum(ex, dim);
end
function present = isConnectionPresent(net, source, target)
present = false;
connections = net.Connections;
for i = 1:height(connections)
if strcmp(connections.Source{i}, source) && contains(connections.Destination{i}, target)
present = true;
return;
end
end
end层 'fold_1': 未连接的输出。每个层输出必须连接到另一层的输入。
层 'fold_2': 未连接的输出。每个层输出必须连接到另一层的输入。
层 'unfold_1': 未连接的输入。每个层输入必须连接到另一个层的输出。
层 'unfold_2': 未连接的输入。每个层输入必须连接到另一个层的输出。修改代码实现上述功能