ai声音模拟软件 AI教程工具箱系列|使用AI构建声音分类iOS应用

AI资讯1年前 (2024)发布 fengdao
49 0

假设您要制作一个可以实时识别音频信号,并有触发动作的iOS应用-这需要探索机器学习与移动开发的交叉路口。

为了识别声音信号,首先必须收集用于训练机器学习模型的数据。幸运的是,我发现了一个非常相关的数据集:50种环境声音的集合(//ESC-50)

对于每种类别或类型的声音,都有40条记录,每条记录5秒。结果,2000条有分类标记的数据记录,可用来训练我们的模型。数据合格(即,数据所属类别清晰)这一事实非常重要。该模型将基于此,并将学习区分不同的类别。

但是,在训练模型之前,我们必须经历“特征工程阶段”。此步骤涉及转换数据以简化数据并删除冗余信息。这以及随后的模型结构,使得归纳学习结果成为可能。

的确,目标不是要拥有一个能够完全了解训练数据的模型,而是要拥有一个与训练数据充分独立,能够识别出从未听过的声音的模型。“特征工程”通常是成功完成这项工作的关键。

在信号处理领域中,并且特别是在声音信号处理领域中,通常的做法是使用频率变换进行特征提取。该频率使,例如可以将以低频为特征的低音与以高频为特征的锐音区分开。

对我们来说幸运的是,为我们完成了所有繁重的工作。

步骤1:资料准备

出于本文的目的,我将专注于四种明显不同的声音,所使用的数据来自ESC-10数据集,并按原样使用:

狗的声音波形

公鸡声音波形

直升机声波

打喷嚏的声音波形

我确保选择的声音彼此截然不同。

步骤2:训练模型

在开始编写分类器之前,我们需要确保数据平衡,这意味着该模型将为每个类获取相同数量的数据。

图说:训练数据的分布(仅限四个类别)

现在我们知道我们的数据是干净且平衡的,我们可以开始训练模型了。

这是所有步骤:

ai声音模拟软件_模拟声音软件下载_模拟声音下载

GPU的使用:我正在使用计算机中所有的GPU,但是您可以将使用率更改为(0),如果不使用或(n)更改您要使用的GPU的数量。加载数据:加载包含所有音频数据的文件夹。加载元数据:加载概述文件名和相应标签的.csv文件。仅使用ESC-10:由于我的计算机不是很强大,因此我只使用了ESC-10,并排除了不属于它的所有记录。您绝对可以使用过滤器功能跳过这一部分。拆分数据:仅使用一小部分数据进行训练(折1仅为ESC-10)和进行测试(折1)。创建模型:Turi 将为我们完成工作-我们只需要训练数据和迭代次数(允许通过数据的最大次数)。我选择了100次迭代,因为默认值只有10次,但这不够。保存预测:这些预测将用于评估模型的性能。评估模型:模型将尝试预测测试数据并将其与真实数据进行比较。保存模型:保存模型,以便以后以其他格式导出时可以使用它。导出一个.文件:这个文件格式,可以作为Xcode为我们的iOS应用程序解析。

import turicreate as tc
from os.path import basename
tc.config.set_num_gpus(-1)
# Load the audio data and meta data.
data = tc.load_audio('/ESC-50/audio/')
meta_data = tc.SFrame.read_csv('/ESC-50/meta/esc50.csv')
# Join the audio data and the meta data.
data['filename'] = data['path'].apply(lambda p: basename(p))
data = data.join(meta_data)
# Drop all records which are not part of the ESC-10.
data = data.filter_by('True', 'esc10')
# Make a train-test split, just use the first fold as our test set.
test_set = data.filter_by(1, 'fold')
train_set = data.filter_by(1, 'fold', exclude=True)
# Create the model.
model = tc.sound_classifier.create(train_set,
                                   target='category',
                                   feature='audio',
                                   max_iterations=100,
                                   custom_layer_sizes=[200, 200])
# Generate an SArray of predictions from the test set.
predictions = model.predict(test_set)
# Evaluate the model and print the results
metrics = model.evaluate(test_set)
print(metrics)
# Save the model for later use in Turi Create
model.save('SoundClassification.model')
# Export for use in Core ML
model.export_coreml('SoundClassification.mlmodel')

怎么运行的:

预处理以975毫秒的音频形式的音频数据作为输入(确切的输入长度取决于采样率),并生成形状数组(96,64)。声音工程领域的人可能会熟悉这一部分。

在这个阶段还没有学习。

在这里,我们使用VGG特征提取。 VGG是提供的用于图像分类和识别的预训练卷积神经网络。我强烈建议您阅读的文章,以更好地了解这种架构。(文章下载附后)

Turi 使用三层,前两层是密集层(每个神经元都简单地连接到上一层的所有神经元。我们也可以将该层称为“完全连接”),具有100个单元测试(我已经将其更改为200,可以提高准确性)。

第三个是层。 将十进制概率分配给多类问题的每个类。这些十进制概率的总和必须等于1。这种额外的限制使学习收敛比以前更快。

iOS应用

首先,我们需要使用单个视图应用程序创建一个iOS项目:

图说:创建一个单视图应用程序

现在,我们的项目已准备就绪。我不喜欢自己使用情节提要,因此本教程中的应用程序是通过编程方式构建的,这意味着没有按钮或开关可切换-只是纯代码 。

要采用这种方法,您必须删除main.,并按以下方式设置.swift文件:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        window = UIWindow(frame: UIScreen.main.bounds)
        let controller = ViewController()
        window?.makeKeyAndVisible()
        window?.rootViewController = controller
        return true
    }

标签

我们需要一个标签,通过适当的预测来更新视图:

lazy var label = UILabel()
    ///////////////////////////////////////////////////////////
    // MARK: - Setup the label layout and add it to the subview
    ///////////////////////////////////////////////////////////
    private func setupLabel() {
        label.translatesAutoresizingMaskIntoConstraints = false
        label.font = UIFont(name: "Avenir-Heavy", size: 100)
        view.addSubview(label)
        label.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        label.topAnchor.constraint(equalTo: view.topAnchor, constant: 120).isActive = true
    }

获取推断并更新视图:

为了获得预测并更新视图,我们需要执行一些步骤:使用()实例化模型。出于本教程的目的,我添加了一个计时器来检查不同的声音类型。获取音频文件(请记住,它必须大于975ms)。读取音频文件。创建一个(这是我们输入的多维数组),并设置为Core ML模型。获取所有预测。获得具有最大预测的标签。更改视图颜色,并用最佳预测标记文本。

/////////////////////////////////////////////////////////////////////////////
// MARK: - Get the inference for each sound and change the layout accordingly
    private func getInference() {
        //200 layers 100 iterations
        let model = SoundClassification()
 
        var count = 0
        _ = Timer.scheduledTimer(withTimeInterval: 5, repeats: true) { t in
 
            var wav_file: AVAudioFile!
            do {
                let fileUrl = URL(fileReferenceLiteralResourceName: "(self.output[count])_1_converted.wav")
                wav_file = try AVAudioFile(forReading:fileUrl)
            } catch {
                fatalError("Could not open wav file.")
            }
 
            print("wav file length: (wav_file.length)")
            assert(wav_file.fileFormat.sampleRate==16000.0, "Sample rate is not right!")
 
            let buffer = AVAudioPCMBuffer(pcmFormat: wav_file.processingFormat,
                                          frameCapacity: UInt32(wav_file.length))
            do {
                try wav_file.read(into:buffer!)
            } catch{
                fatalError("Error reading buffer.")
            }
            guard let bufferData = buffer?.floatChannelData else { return }
 
            // Chunk data and set to CoreML model
            let windowSize = 15600
            guard let audioData = try? MLMultiArray(shape:[windowSize as NSNumber],
                                                    dataType:MLMultiArrayDataType.float32)
                else {
                    fatalError("Can not create MLMultiArray")
            }
 
            // Ignore any partial window at the end.
            var results = [Dictionary]()
            let windowNumber = wav_file.length / Int64(windowSize)
            for windowIndex in 0..<Int(windowNumber) {
                let offset = windowIndex * windowSize
                for i in 0...windowSize {
                    audioData[i] = NSNumber.init(value: bufferData[0][offset + i])
                }
                let modelInput = SoundClassificationInput(audio: audioData)
 
                guard let modelOutput = try? model.prediction(input: modelInput) else {
                    fatalError("Error calling predict")
                }
                results.append(modelOutput.categoryProbability)
            }
 
            var prob_sums = Dictionary()
            for r in results {
                for (label, prob) in r {
                    prob_sums[label] = (prob_sums[label] ?? 0) + prob
                }
            }
 
            var max_sum = 0.0
            var max_sum_label = ""
            for (label, sum) in prob_sums {
                if sum > max_sum {
                    max_sum = sum
                    max_sum_label = label
                }
            }
 
            let most_probable_label = max_sum_label
            let probability = max_sum / Double(results.count)
            print("(most_probable_label) predicted, with probability: (probability)")
 
            let prediction: classes = classes.init(rawValue: most_probable_label)!
 
            switch prediction {
            case .dog:
                self.label.text = most_probable_label
                self.view.backgroundColor = #colorLiteral(red: 0.2392156869, green: 0.6745098233, blue: 0.9686274529, alpha: 1)
            case .helicopter:
                self.label.text = most_probable_label
                self.view.backgroundColor = #colorLiteral(red: 0.8078431487, green: 0.02745098062, blue: 0.3333333433, alpha: 1)
            case .rooster:
                self.label.text = most_probable_label
                self.view.backgroundColor = #colorLiteral(red: 0.9529411793, green: 0.6862745285, blue: 0.1333333403, alpha: 1)
            case .sneezing:
                self.label.text = most_probable_label
                self.view.backgroundColor = #colorLiteral(red: 0.3411764801, green: 0.6235294342, blue: 0.1686274558, alpha: 1)
            }
            print(count)
            if count >= 3 {
                t.invalidate()
            }
            count += 1
        }
    }

确保转换文件,因为输入只能是一个通道(单声道不是立体声),并且采样率也必须是 Hz。

我已经使用该网站转换了所有音频文件(/-to-wav)。

但是不用担心,我为每个类别提供了三个示例,以便您可以测试应用程序。

模拟声音软件下载_ai声音模拟软件_模拟声音下载

最后一件事(非常重要):

使用模型之前,必须下载g.dylib。信号预处理阶段需要此文件,该文件已实现为自定义Core ML模型。可以在Turi 的版本页面(/apple////5.7/g.zip)上找到g.dylib文件。下载该文件后,将arm64文件作为文件夹引用拖放到Xcode项目中。

在 > Build 里,将g.dylib添加到“Copy “。 > 下,将g.dylib添加到 和 and 。

3. 在 > Build ,将g.dylib添加到Embed 。

重要说明:⚠️

该项目将无法在模拟器中运行-您必须在上进行测试。这是因为模拟器需要 g.dylib文件,才能在计算机的模拟器上运行。

最好的解决方案是使用您自己的手机。

最后结果:

当然,有许多改进之处。该系统适用于从训练数据集派生的测试数据集,但在实际情况下,性能仍不能令人满意。我认为在探索其他模型之后,我可以着手进行信号预处理和特征工程。

最后,我想强调两件事:

第一件事是,数据科学/机器学习项目,可以比学习型数据科学挑战走得更远。

它代表了在丰富的学习资源的帮助下,探索新领域的一种方法,但是机器学习不仅是寻找最佳预测模型性能的挑战。可以说,除了“探索和预测”范式之外,还有一些更大的项目需要走出数据科学家的舒适区。

其次,即使简化,该项目也代表了大数据项目所需的工作,其中,数据量大得多,分布在集群中(通常在Linux上运行),自动化流程投入生产后可重复运行。在这些情况下,机器学习任务的可重复性和清洁度至关重要。

在这种情况下,对于数据科学家来说,与周围的数据工程师进行互动也很重要,这样项目才能成功。在工业环境中,此类项目越来越多,其业务挑战也很大。

我还想指出,为了获得有用且接近现实的场景,您需要与声音工程领域的人们一起工作,以真正理解问题的各个方面并从整体上看待问题。

所有代码可下载://

1609.09430.pdf

1.7M

·

百度网盘

© 版权声明

相关文章

暂无评论

暂无评论...