数据来自github,https://github.com/yingdajun/SpeechEmotionAndPeopleAnalyse
数据的目录结构如下,按录音人分为4个文件夹,每个文件夹下按情绪氛围6个子文件夹,生气(angry)、害怕(fear)、高兴(happy)、中性(neutral)、悲伤(sad)和惊讶(surprise)。每个子文件夹下包括50个wav格式的音频文件。

本节将介绍如何从数据根目录下,提取出各音频文件列表,每个文件记录为相对路径。由于下载数据存放在本地电脑上,可以直接使用File的相关操作,具体代码如下:
static String[] listWavFiles_Local(String dirPath) throws Exception {
List<String> paths = new ArrayList<>();
subListWavFiles(new File(dirPath), paths);
List<String> relativePaths = paths.stream()
.map(x -> x.substring(dirPath.length()))
.collect(Collectors.toList());
for (int i = 0; i < 5; i++) {
System.out.println(relativePaths.get(i));
}
return relativePaths.toArray(new String[0]);
}
static private void subListWavFiles(File dir, List<String> relativePaths) throws IOException {
for (File file : dir.listFiles()) {
if (file.isDirectory()) {
subListWavFiles(file, relativePaths);
} else {
if (file.getName().toLowerCase().endsWith(".wav")) {
relativePaths.add(file.getCanonicalPath());
}
}
}
}执行该函数,获取 DATA_DIR 文件夹下所有音频文件列表
listWavFiles_Local(DATA_DIR);
执行结果如下,打印输出了前5个相对路径。
wangzhe/happy/249.wav wangzhe/happy/248.wav wangzhe/happy/216.wav wangzhe/happy/202.wav wangzhe/happy/203.wav
考虑到该功能的扩展性,如果文件存储在Hadoop、OSS或S3等文件系统,可以使用Alink FileSystem相应接口实现,将下面代码中变量fs定义为相应文件系统即可。具体代码如下:
static String[] listWavFiles_FileSystem(String dirPath) throws Exception {
LocalFileSystem fs = new LocalFileSystem();
FilePath rootFolder = new FilePath(dirPath, fs);
URI rootUri = rootFolder.getPath().makeQualified(fs).toUri();
List<String> relativePaths = FileSystemUtils.listFilesRecursive(rootFolder, true)
.stream()
.filter(new Predicate<FilePath>() {
@Override
public boolean test(FilePath filePath) {
return filePath.getPathStr().toLowerCase().endsWith(".wav");
}
})
.map(x -> rootUri
.relativize(x.getPath().makeQualified(fs).toUri())
.getPath()
)
.collect(Collectors.toList());
for (int i = 0; i < 5; i++) {
System.out.println(relativePaths.get(i));
}
return relativePaths.toArray(new String[0]);
}执行该函数,获取 DATA_DIR 文件夹下所有音频文件列表
listWavFiles_FileSystem(DATA_DIR);
执行结果如下,打印输出了前5个相对路径,与前面使用File操作得到的结果相同。
wangzhe/happy/249.wav wangzhe/happy/248.wav wangzhe/happy/216.wav wangzhe/happy/202.wav wangzhe/happy/203.wav
因为音频文件相对路径的子文件夹名称包含情绪和录音人姓名,我们可以从中提取出情绪标签和录音人,具体步骤和代码如下:
new MemSourceBatchOp(listWavFiles_Local(DATA_DIR), "relative_path")
.select("relative_path, "
+ "REGEXP_EXTRACT(relative_path, '(angry|fear|happy|neutral|sad|surprise)') AS emotion, "
+ "REGEXP_EXTRACT(relative_path, '(liuchanhg|wangzhe|zhaoquanyin|ZhaoZuoxiang)') AS speaker"
)
.link(
new AkSinkBatchOp()
.setFilePath(DATA_DIR + "temp.ak")
.setOverwriteSink(true)
);
BatchOperator.execute();定义几个常量如下:
static final String TEST_FILE = "test.ak";
static final String TRAIN_FILE = "train.ak";
static final int AUDIO_SAMPLE_RATE = 16000;使用ReadAudioToTensorBatchOp组件从音频文件中读取数据,该组件读取的音频数据会保存为张量格式。具体代码如下。
BatchOperator<?> data_set = new AkSourceBatchOp()
.setFilePath(DATA_DIR + "temp.ak")
.link(
new ReadAudioToTensorBatchOp()
.setRelativeFilePathCol("relative_path")
.setRootFilePath(DATA_DIR)
.setSampleRate(AUDIO_SAMPLE_RATE)
.setDuration(3.0)
.setOutputCol("audio_data")
);参数SampleRate指定了读取结果数据中对应的音频采样频率,如果原始文件中的音频频率与SampleRate不同,会进行相应的转换。参数Duration为读取音频的时长(单位:秒),如果音频文件的时长小于Duration,会进行补0操作;如果不指定该参数,将读取全部数据;根据当前录音数据大部分在3秒以内,这里设置参数Duration为3.0秒。
前面三个小节,我们获得实验所需的全部音频数据及标签。接下来,将此数据集分为训练集和测试集,具体代码如下:
Utils.splitTrainTestIfNotExist(
data_set, DATA_DIR + TRAIN_FILE, DATA_DIR + TEST_FILE, 0.9
);