Highlight
iOS 17 的 Speech 框架允许开发者用自定义词汇和模板定制设备端语音识别的语言模型,让专业术语、人名和领域短语获得更高的识别准确率,所有处理均在本地完成。
核心内容
通用语言模型的局限
从 iOS 10 开始,Speech 框架封装了声学模型和语言模型的完整流程,提供了简单易用的接口。但这个接口对所有应用一视同仁,强迫每个应用使用相同的语言模型。
问题在于:不同领域需要不同的语言模型行为。一个象棋应用想让用户口述棋步,比如”Play the Albin counter gambit”。通用语言模型在训练时见过大量音乐请求(“Play the album…”),所以把这句话误识别为音乐播放请求。象棋术语从未出现在训练数据中。
(00:29)
构建训练数据
iOS 17 引入了 SFLanguageModel 类,用 result builder DSL 构建训练数据容器。
import Speech
// 定义精确短语及其权重
let trainingData = SFLanguageModel.CustomData {
PhraseCount(phrase: "Albin counter gambit", count: 50)
PhraseCount(phrase: "Queen's Gambit", count: 100)
PhraseCount(phrase: "Winawer variation", count: 30)
}
关键点:
PhraseCount描述短语在最终数据集中的出现次数,用于给特定短语更高权重- 系统接受的数据量有限,要在提升短语和总体预算之间取得平衡
(02:57)
用模板批量生成样本
import Speech
// 定义词类
let pieces = ["pawn", "knight", "bishop", "rook", "queen", "king"]
let files = ["a", "b", "c", "d", "e", "f", "g", "h"]
let ranks = ["1", "2", "3", "4", "5", "6", "7", "8"]
// 用模板生成所有可能的棋步组合
let chessMoves = SFLanguageModel.CustomData {
TemplateCount(
pattern: "\(pieces) to \(files)\(ranks)",
count: 10000
)
}
关键点:
TemplateCount将多个词类组合成模式,批量生成样本- 计数应用于整个模板,10000 个样本会均匀分配给所有生成的数据
- 模板适合组合空间大的场景,比如棋步、医学术语组合
(03:47)
自定义发音
import Speech
// 为专业术语定义拼写和发音
let medicalTerms = SFLanguageModel.CustomData {
PhraseCount(
phrase: "amoxicillin",
pronunciation: "@.mO.k.sI."lI.nIn",
count: 20
)
}
关键点:
- 发音使用 X-SAMPA 字符串格式
- 每个 locale 支持不同的发音符号子集
- 适合医学、法律等专业领域的外来词或特殊发音
(04:28)
运行时训练数据
import Speech
// 基于用户数据动态生成训练数据
func generateUserSpecificTrainingData(contacts: [Contact]) -> SFLanguageModel.CustomData {
SFLanguageModel.CustomData {
for contact in contacts.prefix(50) {
PhraseCount(phrase: "call \(contact.name)", count: 10)
}
}
}
// 将数据写入文件
try trainingData.export(to: fileURL)
关键点:
- 运行时生成的数据可以基于用户特定信息,如通讯录人名、通话记录频率
- 隐私敏感信息始终留在设备上,不发送到网络
- 训练数据绑定到单个 locale,多语言场景用
NSLocalizedString
(05:09)
部署自定义模型
import Speech
// 准备自定义语言模型(耗时操作,应在后台执行)
let customModelURL = try await SFLanguageModel.prepareCustomLanguageModel(
for: fileURL,
clientIdentifier: "com.example.chessapp",
locale: Locale(identifier: "en_US")
)
// 配置识别请求
let request = SFSpeechAudioBufferRecognitionRequest()
request.requiresOnDeviceRecognition = true
request.customizedLanguageModel = customModelURL
// 开始识别
let recognizer = SFSpeechRecognizer(locale: Locale(identifier: "en_US"))!
let task = recognizer.recognitionTask(with: request) { result, error in
if let result = result {
print(result.bestTranscription.formattedString)
}
}
关键点:
prepareCustomLanguageModel有显著延迟,必须在后台线程调用- 识别请求必须设置
requiresOnDeviceRecognition = true,否则定制不生效 - 所有定制化请求严格在设备端处理,数据不离开设备
(06:08)
详细内容
语音识别的工作原理
语音识别的流程分为两步:
- 声学模型:将音频数据转换为音素表示
- 语言模型:从多个候选转录中选出最可能的句子
当多个音素表示匹配音频数据,或单个音素对应多个转录时,语言模型负责消歧。它基于训练期间接触到的使用模式,预测给定词在序列中出现的概率。
(00:37)
数据预算与平衡
系统对训练数据有总量限制。PhraseCount 的 count 参数决定了短语在最终数据集中的权重。给高频短语更高的 count,给低频短语更低的 count。但要注意整体预算,避免过度侧重某些短语而忽略其他重要词汇。
(03:30)
隐私保护机制
语言模型定制的核心设计原则是数据不离开设备:
- 训练数据文件在本地生成和存储
prepareCustomLanguageModel完全在本地执行- 识别请求在设备端处理,不发送到云端
这适合处理通讯录人名、通话记录、个人播放列表等隐私敏感数据。
(05:33)
核心启发
-
做什么:为专业领域应用添加语音输入支持
- 为什么值得做:通用语音识别在专业术语上准确率很低,定制语言模型可以将医学术语、法律词汇、工程名词的识别率提升到可用水平
- 怎么开始:用
SFLanguageModel.CustomData收集领域高频短语,用PhraseCount设置权重,导出后通过prepareCustomLanguageModel部署
-
做什么:实现基于用户数据的个性化语音识别
- 为什么值得做:通讯录人名、个人播放列表、常用联系人等用户特定数据无法被通用模型覆盖
- 怎么开始:在应用启动时读取通讯录或用户历史数据,生成
PhraseCount列表,定期更新训练数据文件
-
做什么:为复杂组合场景使用模板生成训练数据
- 为什么值得做:手动列举所有可能的短语组合不现实,模板可以批量覆盖整个组合空间
- 怎么开始:定义词类数组,用
TemplateCount组合成模式,设置合适的总样本数让系统均匀分配
-
做什么:为语音控制游戏设计专用识别模型
- 为什么值得做:游戏指令通常有固定语法结构,模板可以完美覆盖所有可能的指令组合
- 怎么开始:分析游戏的所有可语音控制操作,定义动作词、目标词、方位词等词类,用模板生成完整指令集
-
做什么:构建离线语音笔记应用
- 为什么值得做:设备端识别 + 语言模型定制意味着完全离线可用,适合隐私敏感场景
- 怎么开始:设置
requiresOnDeviceRecognition = true,用用户的历史笔记内容生成训练数据,让常用词汇获得更高识别权重
关联 Session
- Spotlight your app with App Shortcuts — 通过 App Shortcuts 让用户用语音触发应用功能
- Explore enhancements to App Intents — App Intents 框架的最新增强
- Integrate your media app with HomePod — 将媒体应用与 HomePod 集成,支持语音控制播放
评论
GitHub Issues · utterances