数据来自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 );