ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于Matpower的IEEE14节点FDIA攻击数据集生成教程

基于Matpower的IEEE14节点FDIA攻击数据集生成教程 做电力系统方向研究的人尤其是刚接触信息物理安全、想发论文但又苦于没有数据支撑的同学应该都有过这种体验想研究FDIAFalse Data Injection Attack虚假数据注入攻击结果第一步就被“没有合适的数据集”卡住了。网上的公开数据集要么太老、要么格式不统一自己写代码又不知道从哪下手。我之前在给几个研究生做论文辅导时发现大家都在用MatlabMatpower做仿真但大部分人都只停留在跑通潮流计算对于“怎么把FDIA攻击数据生成出来”这件事几乎没有头绪。今天就手把手带大家走一遍完整的流程从Matpower的环境搭建开始到IEEE14节点系统的潮流计算再到FDIA攻击的实现原理和完整代码最后生成可以直接用于训练和实验的CSV数据集。这篇教程里的每一行代码我都实际跑过踩过的坑也会一并说清楚。1. 项目整体设计与思路拆解1.1 为什么选IEEE14节点作为研究对象IEEE14节点系统是电力系统研究里最经典的算例之一它由美国电网的某一部分简化而来包含5台发电机、11个负荷点、20条支路其中3台可调变压器。这个系统规模小但五脏俱全既能体现电力系统的主要特性——包括环网结构、变压器调节、无功补偿又不至于因为节点太多导致计算复杂、调试困难。选择IEEE14节点还有一个非常现实的原因Matpower自带的case14数据文件是官方验证过的不需要自己手动搭建电力系统参数消除了数据源不可靠的问题。对做FDIA研究的人来说这个系统恰好能展示攻击向量的构造逻辑又不会因为系统的非线性程度太高而让状态估计的线性化假设失效。我用这个系统做了接近一年的实验它还有一个隐藏优势计算速度快单次潮流计算在毫秒级批量生成几千条攻击数据也只需要几秒钟。这对做数据集的同学来说至关重要迭代实验时不用等。1.2 FDIA攻击数据集的本质需求要生成FDIA攻击数据集首先要明白这个数据集最终会被谁用、用来干什么。目前主流的FDIA研究都集中在深度学习检测方向也就是用神经网络去分辨量测数据里有没有被篡改。所以数据集的本质需求有以下几个方面需要包含正常数据这是训练的负样本即未受攻击时的状态量和量测量。需要包含攻击数据这是正样本即攻击者在量测值中注入恶意数据后的结果。需要标签0表示正常1表示攻击方便后续做监督学习。数据规模要够大单条数据没有意义至少要生成成千上万条才能支撑深度学习模型的训练。攻击方式要有多样性不能只用一种攻击向量否则模型会过拟合到特定模式。知道了这些我们就能明确代码的框架先跑潮流得到基准状态再利用状态估计模型构造可用的攻击向量最后批量生成攻击数据并打包成标准格式。1.3 方案选型为什么用手写DC潮流而不是直接用Matpower的runpfMatpower其实自带了runpf和runse这两个核心函数分别用于潮流计算和状态估计。很多教程会直接让你用runse然后在此基础上叠加攻击向量但这种做法有两个问题第一runse函数的输入输出格式相对高端对新手不友好它返回的bus和branch矩阵字段很多解析起来费劲第二我们需要的是“能自由操控代数结构”的状态估计模块而Matpower内置的状态估计器是加权最小二乘WLS实现它的雅可比矩阵和增益矩阵封在内部改起来不方便。所以我选择了自己写一个DC状态估计器基于经典的H矩阵和卡尔曼增益矩阵实现。这不仅是FDIA最常用的线性化场景还能让我们在代码层面直接验证攻击构造的核心公式a Hc * c即攻击向量等于量测雅可比矩阵乘以状态增量。这样做的好处是逻辑透明每一步都在你自己的掌控之下不会黑盒出错。2. 环境搭建与Matpower快速上手指南2.1 Matlab和Matpower版本选择的经验Matlab版本建议选R2020a及以上这倒不是说低版本不能用而是Matpower从7.0之后做了不少内部优化旧版Matlab的兼容性不太好。我在实验室的旧电脑上试过Matlab R2016b配合Matpower 7.1虽然能跑但在处理稀疏矩阵时会莫名报内存错误换成R2021b之后没再出现过。Matpower方面当前官网最新版是7.1或8.0具体看发布时间直接下载zip包解压就能用。需要注意一点Matpower 8.0开始改进了部分内部数据结构如果你用的是旧版代码有些字段的索引方式会变化比如branch矩阵的第几列代表什么最好在跑代码前先看一遍help case14。安装Matpower的步骤非常简单从官网下载压缩包并解压到任意目录我习惯放在D:\MATLAB_Tools\matpower下。打开Matlab在“设置路径”中添加该目录及其所有子文件夹。在命令行输入test_matpower如果返回All tests passed就说明安装成功。2.2 快速验证case14系统能否正常使用环境搭好后先别急着写代码先跑一下这个命令验证系统可用性mpc case14; results runpf(mpc);如果一切正常你会看到输出信息里显示“Converged in XX seconds”并且results.bus里包含各节点的电压幅值和相角。这里给大家一个经验case14的默认参数里基准功率是100MVA电压幅值是标幺值千万别习惯性当成有名值处理否则后面构造攻击向量时数值会差100倍。另外runpf的结果中results.success 1才表示潮流收敛。如果出现不收敛的情况多是因为Matpower版本冲突或者数据文件被修改过重新解压原版文件即可解决。3. 从零手写DC状态估计器搞懂FDIA的地基3.1 DC状态估计在说什么FDIA最经典的攻击模型是建立在DC状态估计之上的。所谓DC指的是直流潮流即忽略无功和电压幅值变化只考虑有功与相角之间的关系。在DC假设下量测方程非常简单z H * x e其中z是量测向量H是量测雅可比矩阵x是状态向量各节点电压相角e是量测误差。对于一个N节点的系统我们通常把平衡节点的相角设为0所以实际要估计的状态量是N-1个。DC潮流的核心关系是支路有功功率正比于两端相角差。写成矩阵就是P B * theta这里的B是节点的电纳矩阵不带电抗时是导纳矩阵的虚部theta是节点相角向量。有了这个关系我们就能通过量测的潮流值反向推断出系统状态。3.2 构造H矩阵雅可比矩阵的DCDC版在实际代码中H矩阵的构造需要遍历每条支路。每条支路连接两个节点对应的H矩阵元素是两个非零块。假设支路k连接节点i和j电抗为x那么它的有功功率对相角求偏导为对节点i的相角求偏导1/x对节点j的相角求偏导-1/x写法可以是% 计算支路电纳 b 1 ./ branch(:, 4); % 第4列是电抗x % 构建量测雅可比矩阵H for k 1:nb i branch(k, 1); j branch(k, 2); H(k, i) b(k); H(k, j) -b(k); end注意这个循环里我把所有节点都算进去了包括平衡节点因为平衡节点的相角在状态估计里虽然固定为0但我们构造攻击数据时依然可以使用完整的H。实际做状态估计时要剔除平衡节点对应的列否则矩阵奇异无法求逆。3.3 加权最小二乘估计的完整实现状态估计的目标是最小化加权残差平方和公式为x_hat (H^T * W * H)^(-1) * H^T * W * z其中W是量测权重矩阵通常取量测误差方差的倒数。在DC潮流里我们给每条支路有功量测一个权重值误差越大的传感器权重越小。Matlab代码实现% 状态估计主函数 function x_hat dc_state_estimation(z, H, W) G H * W * H; % 增益矩阵 rhs H * W * z; % 右端项 % 剔除平衡节点所在列 G(1, :) []; G(:, 1) []; rhs(1) []; x_hat G \ rhs; % 解线性方程组 end这里我把平衡节点索引固定为1因为我后面会调用Matpower的case14它的平衡节点就是1号节点。建议大家在写自己的代码时先检查一下mpc.bus(:, 2)里的状态类型字段别脑子一热直接硬编码。3.4 FDIA攻击向量的构造原理FDIA的核心思想非常经典攻击者篡改量测值使得篡改后的量测仍然能通过不良数据检测坏数据检测从而愚弄控制中心。传统坏数据检测基于残差r z - H*x_hat的L2范数小于阈值就认为是安全的。如果攻击者将量测篡改为z_a z a其中a就是攻击向量。如果a满足a Hc * c其中Hc是攻击者所能控制的量测对应的H矩阵子块c是任意非零向量那么篡改后的状态估计结果为x_hat c而残差保持不变。这就是FDIA能够完美躲过检测的原因。在我们的代码里构造攻击向量很简单% 随机生成攻击状态增量c维度可攻击的节点数 c randn(n_attack_state, 1) * attack_scale; % 攻击向量 H子矩阵 * c a H_attack * c;这里H_attack是攻击者能篡改的量测对应的H矩阵行。比如攻击者只能篡改前10条支路的量测那就取H的前10行。如果你想模拟完全完美攻击就把所有量测的行都选上。4. 完整代码IEEE14节点FDIA攻击数据集生成器4.1 代码整体结构我写的这个脚本把整个流程拆成了几个阶段方便大家按需修改初始化阶段加载case14数据提取系统的节点、支路、发电机信息。基准数据生成阶段通过潮流计算得到真实的节点相角并生成对应的正常量测。攻击数据生成阶段随机生成大量攻击向量叠加到正常量测上得到带攻击的量测数据。数据存储阶段把数据按行存储为CSV每一行对应一个样本包含量测值和标签列。验证阶段运行不良数据检测统计攻击数据的绕过率验证我们的数据真的能攻破传统检测器。4.2 完整代码逐行解释看完整代码之前先把核心变量的维度说清楚。case14系统有14个节点20条支路我们要生成的量测向量选择支路有功功率20维和节点有功注入功率14维合并成一个34维的量测向量。状态向量是除平衡节点外的13个节点相角。%% 1. 初始化并加载系统数据 clear; clc; close all; define_constants; % 引入Matpower常量定义 mpc loadcase(case14); % 加载IEEE14节点数据 baseMVA mpc.baseMVA; % 基准容量100 MVA bus mpc.bus; branch mpc.branch; nb size(bus, 1); % 节点数14 nl size(branch, 1); % 支路数20 %% 2. 提取系统的支路电抗和节点导纳矩阵 % 电抗是branch矩阵的第4列注意单位为标幺值 x_line branch(:, 4); b_line 1 ./ x_line; % 生成节点导纳矩阵B电纳矩阵 Y makeYbus(baseMVA, bus, branch); % Matpower内置函数 B full(imag(Y)); % 只取虚部得到电纳矩阵 % 平衡节点的编号case14中为1号节点 ref_node find(bus(:, 2) 3); %% 3. 运行基础潮流得到真实的节点相角 % 这里用runpf得到精确的非线性潮流解作为系统的“T贸真实状态” results runpf(mpc); theta_true results.bus(:, 9) * pi / 180; % 第9列是角度单位是度转成弧度 %% 4. 构造DC量测雅可比矩阵H34行 x 13列去掉平衡节点 % 量测包括20条支路有功 14个节点注入有功 H zeros(nl nb, nb); % 支路量测部分 for k 1:nl i branch(k, 1); j branch(k, 2); H(k, i) b_line(k); H(k, j) -b_line(k); end % 注入量测部分 for k 1:nb H(nl k, :) B(k, :); end % 剔除平衡节点对应的列 H(:, ref_node) []; %% 5. 生成正常的量测数据加上高斯噪声 % 权重矩阵量测精度越高权重越大。这里简化处理假设所有量测等精度 R 0.01^2; % 量测误差方差 W eye(nl nb) / R; noise randn(nl nb, 1) * 0.01; z_true H * (theta_true(ref_node ~ 1:end)) noise; % 这里theta需要去掉平衡节点对应元素 % 简化写法 theta_est_idx setdiff(1:nb, ref_node); z_true H * theta_true(theta_est_idx) noise;这里有个细节必须提醒我们这里的z_true是模拟的“量测表读数”它是在真实状态基础上加了噪声后得到的。在实际系统中控制中心拿到的就是这组带噪声的数据。后面的攻击向量就加在这组数据上。4.3 攻击数据生成核心代码攻击数据生成是整篇代码的灵魂。我们需要做的是随机生成攻击状态增量c然后通过H矩阵构造攻击向量a再把a叠加到正常量测上。为了让数据集“有攻击性但又不至于完全离谱”我们要给c设置合理的量级。%% 6. FDIA攻击向量构造与批量数据生成 num_samples 2000; % 生成样本总数 attack_ratio 0.5; % 攻击样本占比 attack_scale 0.05; % 攻击强度系数控制相角偏移的幅度 % 预定义存储矩阵 data zeros(num_samples, nl nb 1); % 最后一列存放标签 labels zeros(num_samples, 1); for idx 1:num_samples % 重新生成一组量测噪声 noise randn(nl nb, 1) * 0.01; z_normal H * theta_true(theta_est_idx) noise; % 确定本样本是否为攻击样本 is_attack rand() attack_ratio; labels(idx) is_attack; if is_attack % 生成攻击方向量c维度与状态量一致13维 c randn(length(theta_est_idx), 1) * attack_scale; c(1) 0; % 平衡节点相角增量固定为0否则无意义 % 构造攻击向量a H * c a H * c; % 叠加到正常量测上 z_attack z_normal a; data(idx, :) [z_attack, 1]; else data(idx, :) [z_normal, 0]; end end % 单独存一份标签 labels data(:, end);攻击强度系数attack_scale的选取有讲究。太小了比如0.001导致攻击和正常数据几乎不可区分训练出来的检测器可能过度敏感太大了比如0.5则攻击残差过于明显传统检测器就能拦下来失去FDIA的“隐蔽”特性。我测试下来0.02到0.1之间是比较合理的范围既能保持隐蔽性又能在数据层面体现出与正常数据的差异。4.4 传统不良数据检测验证证明你的攻击真的有效生成攻击数据后得先验证这些攻击数据真的能绕过传统坏数据检测。这一步如果没做后续用深度学习模型做检测别人会质疑你的数据质量。传统坏数据检测是基于残差L2范数的J(x)检测思路非常简单用状态估计得到的相角代回量测方程计算残差r z - H*x_hat如果||r||²超过阈值就认为是坏数据。%% 7. 不良数据检测绕过率验证 threshold chi2inv(0.95, nl nb); % 自由度量测数95%置信度 bypass_count 0; attack_count 0; for i 1:num_samples % 分离数据和标签 z_i data(i, 1:end-1); lbl data(i, end); if lbl 1 attack_count attack_count 1; % 对这个攻击数据做状态估计 x_hat dc_state_estimation(z_i, H, W); % 计算残差 r z_i - H * x_hat; J r * W * r; % 加权残差平方和 if J threshold bypass_count bypass_count 1; end end end bypass_rate bypass_count / attack_count; fprintf(攻击样本绕过检测率%.2f%%\n, bypass_rate * 100);如果一切正常你会看到绕过率接近100%。这验证了理论推导的结论满足a Hc * c的攻击向量确实不会改变残差。4.5 导出数据集的标准化代码生成完数据后要导出这里我会同时导出三个文件数据文件CSV、标签文件CSV、以及一个README说明文件。%% 8. 导出数据集为CSV格式 % 表头量测数据列 标签列 header cell(1, nl nb 1); for k 1:nl header{k} sprintf(branch_flow_%d, k); end for k 1:nb header{nl k} sprintf(bus_injection_%d, k); end header{end} label; % 写入CSV data_table array2table(data, VariableNames, header); writetable(data_table, ieee14_fdia_dataset.csv); fprintf(数据集已导出到 ieee14_fdia_dataset.csv\n);写完这段后大家可以打开CSV看一眼每行是一个34维量测向量加一个标签0/1。这份数据可以直接喂给Python的pandas也可以用Matlab的分类学习器做实验。5. 手把手实操演示从打开Matlab到生成数据全流程5.1 第一步新建脚本并配置路径打开Matlab后点击“新建脚本”或者按快捷键CtrlN把上面的代码分段复制进去。注意第一行的define_constants一定要有这是Matpower用来定义常量索引的脚本少了它程序里所有变量名都会变成未定义。保存时建议把文件命名为generate_fdia_dataset.m放在Matpower的安装目录下或者一个专门的实验文件夹里。我习惯新建一个FDIA_Experiment文件夹把脚本和后续生成的数据都放在里面。5.2 第二步逐段运行代码观察中间变量这是我最想强调的一点——写代码不要一键Run到底。建议逐段运行先运行初始化部分观察工作区Workspace里的mpc结构体长什么样再运行H矩阵构造看H的维度是不是34×13再看z_true确认数值大概在什么范围正常情况下有功率的支路流量应该在0.1到5之间标幺值最后运行批量生成模块同时用whos查看data矩阵的内存占用。如果某一步的结果和你预期不符立刻停下来排查不要等到最后一步才报错。我这样要求是有原因的FDIA的数值量级问题经常在中间步骤就暴露了。比如如果你忘记把角度从度转成弧度H矩阵乘出来全是错误的量测数值后面状态估计的结果也会完全不可用。5.3 第三步验证数据集质量生成CSV文件后我习惯做一个快速可视化画一下正常数据和攻击数据的分布对比。这能直观看出攻击数据是否足够与正常数据区分开。%% 9. 可视化正常数据与攻击数据的量测分布对比 figure; subplot(2,1,1); histogram(data(labels0, 1), 30, FaceColor, b, FaceAlpha, 0.5); hold on; histogram(data(labels1, 1), 30, FaceColor, r, FaceAlpha, 0.5); xlabel(第一条支路量测值 (标幺值)); ylabel(样本数); legend(正常数据, 攻击数据); title(IEEE14节点FDIA数据集量测分布); subplot(2,1,2); % 算一下两类数据的量测平均偏差 normal_mean mean(data(labels0, 1:end-1), 1); attack_mean mean(data(labels1, 1:end-1), 1); bar([normal_mean attack_mean]); xlabel(量测编号); ylabel(均值); legend(正常数据均值, 攻击数据均值);如果两类数据完全重叠不可分说明攻击强度太小需要调大attack_scale如果分得太开说明攻击太明显传统检测就能发现。找到一个中间地带既能做深度学习检测又能保证攻击的理论隐蔽性。5.4 第四步把数据集喂给Python做进一步分析很多同学做深度学习都是用的Python所以我一般还会输出一份numpy能直接读取的.npz格式不过Matlab导出需要一点额外操作。最简单的跨语言方案还是我们已经生成的CSV在Python里读取非常方便import pandas as pd df pd.read_csv(ieee14_fdia_dataset.csv) X df.iloc[:, :-1].values y df.iloc[:, -1].values这样等于打通了Matlab侧生成数据、Python侧做深度学习检测的完整链路。6. 常见问题与避坑指南6.1 H矩阵维度对不上怎么办这是最多同学会踩的坑。H矩阵的维度应该是(量测数)×(状态数)其中状态数N-1去掉平衡节点。如果H的维度不对后面的G矩阵求逆必报错。排查思路是这样的量测数 支路数20 节点数14 34。如果你发现H是40×14或者34×14说明最后一步“剔除平衡节点列”没写对。状态数 节点数14 - 1 13。可以命令行输入size(H)检查。如果H的维度正确但状态估计仍然奇异检查一下节点导纳矩阵B是否满秩。注意B的秩应该是13因为去掉平衡节点后行列式不为0。6.2 不良数据检测绕过率为0——攻击完全失效如果你发现绕过率是0%而不是接近100%大概率是攻击向量的构造方式出了问题。常见原因有两个第一a H * c中等式右侧的H用的是含平衡节点的完整矩阵但c里又把平衡节点的增量设为了非零值导致攻击向量不满足“可控”条件。解决办法是构造c时直接把平衡节点的位置置0就像我在代码里写c(1) 0那样。第二你构造攻击向量时用的是H(1:20, :)取了前20条支路但在验证提升残差时用的是全部34维的量测。攻击者只能篡改部分量测的话必然会在未篡改量测上留下残差于是被检测器揪出来。要模拟完美攻击就必须让攻击者能篡改所有量测。6.3 Matpower版本命令不兼容如果你使用的Matpower版本较旧7.0以下define_constants这一行可能报“未定义函数或变量”。这是版本兼容问题没有太好的代码绕过方案建议直接去官网下载最新版的Matpower别在老旧版本上浪费时间。另外有些教程会推荐你直接用runse函数做状态估计然后在results上叠加攻击。我试过这种方案它的问题在于runse的输出结果结构比较复杂解析runse里的雅可比矩阵很麻烦而且不同版本的字段名还有微小差异。所以如果不是特殊需求还是建议用我自己写的那套DC状态估计器从头到尾你都知道每一行在干什么。6.4 生成的CSV文件用Excel打开乱码或数据错位Matlab用writetable生成的CSV是UTF-8编码的Excel默认用本地编码GBK打开会出现中文表头乱码。但实际我们的表头都是英文的所以影响不大。如果确实遇到问题用Python的pandas读取最保险或者用Notepad转换编码。还有一个容易忽略的问题CSV里的科学计数法。Matlab默认会用类似1.2345e-05的格式输出小数值这在pandas里能正常识别但如果用Excel打开部分老版本Excel会认为这不是数字。如果遇到这种情况可以设置writetable的WriteMode属性或者干脆在输出之前把所有数值乘上一个缩放系数转成整数——不过这种做法会损失精度不推荐。6.5 内存不足或运行缓慢怎么办生成2000个样本本不慢但我见过有些同学把循环次数设到10万直接在普通笔记本上跑了一整天都没结束。这时候建议分三挡处理如果只要做基础实验500到1000个样本就完全够用如果要做深度学习5000到10000个样本够用超过5万个样本建议改写成矩阵化运算去掉循环用repmat和bsxfun批量生成速度能提升近百倍。矩阵化生成的思路是先一次性生成全部的攻击状态增量矩阵C维度是13×N然后用H乘以C得到攻击矩阵A34×N再一次性叠加到正常量测矩阵上。这里我做一个简化演示N 5000; C randn(13, N) * attack_scale; A H * C; % N个攻击向量同时生成 Z_normal repmat(z_normal_base, 1, N) randn(34, N) * 0.01; Z_attack Z_normal A;这种写法比for循环快得多而且数据处理起来也更方便。个人强烈建议实际大批量生成时用矩阵化版本。6.6 注意这只是一个仿真数据集最后必须强调一句技术边界。基于IEEE14节点加Matpower生成的FDIA数据集本质上是仿真数据集它在数学上严格满足FDIA的攻击模型但它并不等同于真实电力系统的SCADA量测数据。真实系统中还有通信延迟、量测互感器误差特性、网络拓扑动态变化等因素这些在仿真数据集里通常被简化了。我看到很多人把这个数据集直接作为“标准数据集”引用到论文里这没问题但写论文时一定要说清楚数据来源和局限性。比较规范的写法是“本文基于Matpower的IEEE14节点系统在DC潮流假设下仿真生成了FDIA攻击数据集用于验证所提检测算法的有效性。”这样评审专家不会觉得你在数据源上有夸大。7. 从数据集到论文接下来的几种拓展方向代码跑通、数据集生成完这只是起点。真正让你的研究更进一步的是如何用好这份数据集。这几种拓展方向我觉得很值得尝试引入异步攻击目前的攻击向量是一次性篡改所有量测实际中攻击者可能分批篡改间隔时间不同。你可以把单次攻击改成时间序列攻击每次只篡改一部分量测观察检测器的鲁棒性。增加拓扑攻击变体FDIA不仅攻击量测值还可以攻击拓扑信息。比如攻击者篡改支路连接状态让控制中心以为某条支路断开而实际仍连接或反之。这种情况下攻击向量构造不同检测难度也更大。接入真实数据做域适应仿真数据训练出来的模型在真实数据上往往性能下降。你可以用这份仿真数据集做预训练再用少量真实数据做微调finetune这算是目前比较热门的研究思路。与深度学习方法融合CSV导出后对接CNN/LSTM/Transformer等模型做时序侧或空间侧的检测。IEEE14节点只有34维量测适合先跑通模型结构再迁移到大系统中。我个人目前的工作方向是把这个数据集生成器做成了带参数界面的工具可以一键选择攻击方式、攻击强度、攻击位置并自动导出训练测试集。如果大家在这个基础上做了进一步的扩展欢迎分享经验。8. 最后的经验之谈做FDIA数据集不是写一个脚本那么简单它背后考验的是你对电力系统状态估计模型的理解深度。我见过太多人拿到代码就稀里糊涂跑完数据却不理解H矩阵和攻击向量之间的关系结果换一个系统结构就完全不知道如何改代码。真正常用的心法就是先搞懂a Hc * c这一句话整个数据集的构造逻辑就全通了。我还想给大家一个亲身教训别迷信网上所谓“现成的FDIA数据集”那些数据集的生成过程往往不可见攻击参数是否合理、是否满足bad data detection的绕过条件都无从考证。用我分享的这行代码十几分钟就能自己生成几千条高质量数据还全程可追溯写论文的时候也更有底气。如果你在运行过程中遇到了其他问题建议先对照着上面的避坑指南逐一排查很多问题都是参数维度或者单位的问题。祝大家都能跑出让自己满意的数据集早点发出高质量的论文。
返回列表