Представяме AnySpeechRecognizer и AnyDecisionModel: отворени модели за реч и вземане на решения на платформите на Apple
Езиковите модели могат много. Те пишат, обобщават, превеждат и използват инструменти. Но са само малка част от това, което машинното обучение може да прави.
Представете си, че клиент се обажда на линията ви за поддръжка. Първо искате да разберете какво е казал (разпознаване на реч). След това трябва да решите къде да го насочите (решение). Бихте могли да поверите и двете задачи на езиков модел, но за всяка от тях има модели, които са по-добри, по-бързи и по-евтини.
В нашия преглед на AnyLanguageModel 1.0 разгледахме една година локални и хоствани модели в Swift. Сега, когато AnyLanguageModel и swift-huggingface вече са с издания 1.x, разширяваме същия подход към речта и решенията: познати Swift API с възможност за избор на модел.
Днес обявяваме два пакета:
- AnySpeechRecognizer реализира новия API на Apple за преобразуване на реч в текст с възможност за избор на двигател за разпознаване, включително Parakeet на NVIDIA и Qwen3-ASR на Alibaba, работещи локално с Core ML, и добавя диаризация на говорителите, за да проследява кой кога говори.
- AnyDecisionModel отговаря на въпроси с отговор „да“ или „не“, въпроси с множество възможности и въпроси със скала за оценка с типизирани резултати и вероятности. Той извежда всеки отговор от вероятностите на модела, вместо да генерира текст, като използва модел на устройството ви с MLX, Core AI или llama.cpp, или модел за вземане на решения от Jev или Ollama.
И двата пакета могат да изтеглят отворени модели от Hugging Face Hub и да ги изпълняват на устройството.
AnySpeechRecognizer
Компютрите транскрибират реч от десетилетия,
а през последните няколко години станаха много добри в това.
Платформите на Apple вече имат API за тази цел.
macOS 26 и iOS 26 представиха SpeechAnalyzer,
новия API на Apple за преобразуване на реч в текст.
Добавяте модули като SpeechTranscriber и SpeechDetector към анализатор,
подавате му файл или поток от аудиобуфери
и четете резултатите от асинхронни последователности, докато пристигат.
AssetInventory инсталира моделите,
така че приложението ви решава кога да се извършват изтеглянията.
Това е добре проектиран API, но единственият двигател зад него е този на Apple. AnySpeechRecognizer запазва API и ви позволява да изберете двигателя:
- import Speech
+ import AnySpeechRecognizer
Пакетът отразява SpeechAnalyzer, SpeechTranscriber, DictationTranscriber,
SpeechDetector и AssetInventory,
като рамката Speech на Apple е двигателят по подразбиране.
Ако кодът ви използва този споделен API, достатъчно е да промените импорта.
За да използвате Parakeet,
променете само начина, по който създавате транскрибатора:
let transcriber = SpeechTranscriber(
model: ParakeetSpeechModel(variant: .v3),
transcriptionOptions: [],
reportingOptions: [.volatileResults],
attributeOptions: [.audioTimeRange]
)
Стъпките за инсталиране на ресурсите, изпълнение на анализатора и четене на резултатите остават същите. README съдържа пълен пример и описва разликите спрямо рамката на Apple.
Запознайте се с моделите
Parakeet v3 е Parakeet TDT 0.6B v3 на NVIDIA. Той е полиглот: разпознава 25 европейски езика и сам определя кой от тях чува, така че не е необходимо да подавате локал.
Parakeet Ultra е дообучена версия на v3 на Moondream. При повечето ни измервания той беше по-точен.
Parakeet Unified е Parakeet само за английски език на NVIDIA.
И трите модела Parakeet работят със собствения Core ML runtime на пакета, който поддържа файлов и поточен вход, променливи резултати, времеви обозначения на думите и увереност за думите.
Qwen3-ASR е моделът за реч на Alibaba, в размери 0.6B и 1.7B. Той разпознава 30 езика и 22 китайски диалекта, включително мандарин, кантонски, японски и корейски, които Parakeet не поддържа. Езикът се открива автоматично или можете да зададете такъв:
let transcriber = SpeechTranscriber(
model: QwenSpeechModel(variant: .large, language: Locale.Language(identifier: "yue")),
transcriptionOptions: [],
reportingOptions: [],
attributeOptions: []
)
Qwen3-ASR дава един краен резултат за всеки сегмент с продължителност до 40 секунди, без променливи резултати, времеви обозначения на думите или увереност. Той работи с GPU и е по-бавен от Parakeet, затова е по-подходящ за транскрибиране на файлове, отколкото за поточен вход.
За да добавите друг двигател, реализирайте SpeechRecognitionModel за неговата конфигурация
и SpeechRecognitionExecutor за сесията на един модул.
README включва малък доставчик,
който отчита примерен текст, за да ви помогне да започнете.
Core ML модели в Hub
За да работят тези модели в приложения, ги преобразувахме в Core ML и ги публикувахме в Hub:
| Модел | Core ML преобразуване | Оригинален checkpoint | Лиценз |
|---|---|---|---|
| Parakeet TDT 0.6B v3 | mattt/parakeet-tdt-0.6b-v3-coreml | nvidia/parakeet-tdt-0.6b-v3 | CC BY 4.0 |
| Parakeet Ultra | mattt/parakeet-ultra-coreml | moondream/parakeet-ultra | CC BY 4.0 |
| Parakeet Unified EN 0.6B | mattt/parakeet-unified-en-0.6b-coreml | nvidia/parakeet-unified-en-0.6b | Лиценз за отворени модели на NVIDIA |
| Qwen3-ASR 0.6B | mattt/qwen3-asr-0.6b-coreml | Qwen/Qwen3-ASR-0.6B-hf | Apache 2.0 |
| Qwen3-ASR 1.7B | mattt/qwen3-asr-1.7b-coreml | Qwen/Qwen3-ASR-1.7B-hf | Apache 2.0 |
| Streaming Sortformer 4spk v2 | mattt/diar-streaming-sortformer-4spk-v2-coreml | nvidia/diar_streaming_sortformer_4spk-v2 | CC BY 4.0 |
| Streaming Sortformer 4spk v2.1 | mattt/diar-streaming-sortformer-4spk-v2.1-coreml | nvidia/diar_streaming_sortformer_4spk-v2.1 | Лиценз за отворени модели на NVIDIA |
Всеки репозиторий посочва своя изходен checkpoint и контролна сума за всеки файл, а пакетът го фиксира към определена ревизия. Репозиториите на Parakeet добавят енкодер за 8 секунди за поточен вход, което съкращава времето за анализ на живо с около една трета, но води до малко по-висок процент грешки при думите. Репозиторият съдържа и работните процеси за преобразуване, повечето от които следват скриптовете mobius на FluidInference, и проверява всяко преобразуване спрямо оригиналния модел.
Изтеглянията се извършват само когато приложението ви ги поиска: около 600 MB за всеки Parakeet плюс около 590 MB за енкодера за поточен вход, от 0,9 до 2,4 GB за Qwen3-ASR и около 250 MB за Sortformer. Файловете се съхраняват в стандартния кеш на Hugging Face, така че приложение за Mac извън sandbox споделя файловете с Python и други инструменти на Hugging Face.
Диаризация на говорителите
Когато транскрибирате разговор,
често искате да знаете кой какво е казал.
Това е диаризация на говорителите,
а рамката Speech на Apple няма модул за нея,
затова AnySpeechRecognizer добавя такъв.
SpeakerDiarizer изпълнява
Streaming Sortformer на NVIDIA
с Core ML наред с транскрибатор на Apple или Parakeet,
в една и съща времева линия:
let diarizer = SpeakerDiarizer(model: SortformerDiarizationModel())
if let request = try await AssetInventory.assetInstallationRequest(
supporting: [transcriber, diarizer]
) {
try await request.downloadAndInstall()
}
let analyzer = SpeechAnalyzer(modules: [transcriber, diarizer])
Диаризаторът проследява до четирима говорители,
дори когато говорят едновременно.
SpeakerTimeline събира резултатите му
и приписва всяка дума с времево обозначение на говорител,
така че можете да отпечатате транскрипция по ред на говорителите.
Подобно на поддръжката на изображения в AnyLanguageModel,
това надхвърля възможностите на API на Apple днес.
По подразбиране диаризаторът използва Sortformer v2. Можете да изберете и v2.1, който NVIDIA е обучила с повече данни от срещи и който според нашите измервания също беше по-точен при срещи.
Колко добре работи?
Измерихме пакета с неговия инструмент от командния ред hear
на Mac Studio с M4 Max и macOS 27.0.1.
Ето процентите грешки при думите за файлове от LibriSpeech с продължителност от 3 до 8 минути:
| Транскрибатор | test-clean | test-other |
|---|---|---|
| Parakeet v3, файл | 1.55% | 2.78% |
| Parakeet v3, на живо | 4.73% | 4.29% |
| Parakeet Ultra, файл | 1.66% | 2.55% |
| Parakeet Ultra, на живо | 2.65% | 3.28% |
| Parakeet Unified, файл | 1.43% | 2.19% |
| Parakeet Unified, на живо | 1.45% | 2.42% |
| Транскрибаторът на Apple, файл | 2.12% | 3.97% |
Parakeet транскрибира един час аудио за около 20 до 40 секунди от файл или за около 1,5 до 2,5 минути на живо, като използва около 100 MB памет, след като Core ML компилира модела. Qwen3-ASR е значително по-бавен и се нуждае от няколко гигабайта памет. Срещите са трудни за всички: при записите от AMI, където хората говорят едновременно, всеки тестван от нас двигател имаше процент грешки при думите над 23%.
Тези числа идват от една машина и няколко набора от данни,
затова измерете резултатите със собствения си хардуер и аудио.
hear evaluate работи със собствените ви файлове,
а инструментът natural-speech-eval.py на репозитория
възпроизвежда тези измервания.
Досега сме тествали само на macOS 27, а не на iPhone.
Следващата ни цел е да добавим още двигатели, включително Core AI в macOS 27 и iOS 27.
AnyDecisionModel
AnyDecisionModel е друга история. Няма рамка на Apple, към която да се адаптира, а моделите за вземане на решения не са точно нещо ново.
Това е модел за решения само ако идва от региона Décision във Франция; в противен случай е просто блестяща класификация с нулев изстрел.
Новото е името, многото шум около тях и появата на модели, обучени да вземат решения. Смятаме, че натам вървят нещата, затова искахме Swift API, който да е готов за тях.
Приложенията често карат езикови модели да вземат решения. Спешно ли е това съобщение? Кой екип трябва да обработи този тикет? Колко разочарован е този клиент? Обичайният подход е да подадете подкана към езиков модел и да анализирате генерирания от него текст. Това ви дава един отговор, но не показва вероятностите, които е присвоил на алтернативите.
Ето как изглежда едно решение в Swift:
import AnyDecisionModel
enum Department: String, Choosable {
case billing, technical, sales
}
let ticket = "Бях таксуван два пъти за поръчката си, а сега приложението ме изхвърля, когато се опитам да поискам възстановяване на сумата."
let model = MLXDecisionModel(modelID: "mlx-community/Qwen3-4B-Instruct-2507-4bit")
let session = DecisionSession(model: model, state: .text(ticket))
let urgent = try await session.probability(of: "Изразява ли това спешност?")
let team = try await session.choice("Кой екип?", from: Department.self)
let anger = try await session.score(
"Колко е разочарован?",
levels: ["Спокоен", "Разочарован", "Много ядосан"]
)
urgent е Double.
team е Choice<Department>, съдържащ избрания случай,
вероятност за всяка възможност и стойност на увереността.
anger е Score, съдържащ очакваното ниво,
вероятност за всяко ниво и стойност на увереността.
Тъй като Department съответства на Choosable,
team.value е Department, който можете да използвате в изчерпателен switch.
Ако сте използвали Foundation Models или AnyLanguageModel,
моделът и шаблонът със сесии ще ви бъдат познати.
DecisionSession съдържа едно състояние, което може да бъде текст или JSON,
и всеки въпрос се отнася до това състояние.
Въпросите са независими:
отговорът никога не става вход за следващ въпрос.
За да зададете няколко въпроса едновременно,
предайте ги на decide(_:) като пакет.
За всеки въпрос бекендът MLX изгражда подкана с еднотокенов етикет за всеки разрешен отговор, след което прочита вероятността на всеки етикет от едно предно подаване.
Изпробвайте го: Emoji Magnet
Emoji Magnet е приложение за macOS с текстово поле над купчина от 343 емоджита. Въведете фраза, например „неща, които носите“, и съответстващите емоджита се издигат от купчината. Уточнете я до „неща, които носите през зимата“, и емоджитата, които вече не съответстват, падат обратно.
Приложението няма вградени правила за ключови думи; моделът решава всичко по време на извеждането. Когато спрете да пишете, то задава на модела по един въпрос с отговор „да“ или „не“ за всяко емоджи, например:
Твърдение: дебело зимно палто съответства на описанието „неща, които носите“. Вярно ли е това твърдение?
Състоянието на сесията съдържа фразата.
Демонстрацията по-горе използва хоствания бекенд Jev,
който отговаря на всичките 343 въпроса в една заявка,
така че емоджитата се подреждат за около половин секунда за всяка фраза.
Без TYPESAFE_AI_API_KEY приложението изпълнява Qwen3 4B на вашия Mac с бекенда MLX.
Този бекенд използва кеширане на префикса, за да оцени състоянието веднъж,
след което отговаря на 16 въпроса при едно предно подаване.
На M4 Max група от 16 въпроса отнема около 0,45 секунди след зареждането на модела.
Пълното преминаване през всичките 343 емоджита отнема около 10 секунди,
а резултатите от всяка група се показват веднага след пристигането им.
Emoji Magnet се намира в репозитория AnyDecisionModel-Examples.
Глави за решения и Clef
Четенето на вероятностите за следващия токен работи с езикови модели с общо предназначение, но тези модели не са обучени да вземат решения. Моделите Clef на Cloudflare са пример за по-нов подход: модел с обучена глава за решения, която превръща състояние и схема от типизирани въпроси в решения, като връща вероятности за всички разрешени възможности по въпросите при едно предно подаване. Clef-Flash е вариантът с 9B.
AnyDecisionModel изпълнява Clef-Flash на Mac с MLX:
let model = MLXHeadDecisionModel(
modelID: "mlx-community/clef-flash-4bit",
head: .jointSchema
)
Използвате същите сесии и въпроси,
но MLXHeadDecisionModel прочита всяко решение от обучената глава за решения на Clef,
вместо от вероятностите за следващия токен.
4-битовият модел е изтегляне от 6,2 GB,
а картата на модела препоръчва Mac с поне 16 GB памет.
Clef може да чете изображения и видео,
но този бекенд приема само текстови и JSON състояния.
Калибриране и проверка на вероятностите
Необработените вероятности от езиковите модели често са прекалено уверени.
Локалните бекендове приемат Calibration,
който прилага температура към всеки отговор и отместване към отговорите „да“ или „не“.
Използвайте отделни набори от данни, за да настроите калибрирането и да оцените резултатите.
Езиковите модели могат също да предпочетат дадена възможност заради позицията ѝ в списъка.
При бекендовете за следващ токен MLX, Core AI и llama.cpp
активирайте rotationDebiasing, за да зададете въпроса за избор
по веднъж за всяка ротация на възможностите и да осредните вероятностите.
Това струва по една оценка на подкана за всяка ротация.
Всеки локален избор и оценка включва и стойност на увереността, основана на ентропията на вероятностите. Тя измерва колко концентрирани са вероятностите, а не дали отговорът е правилен, затова проверете процента грешки върху собствените си данни, преди да изберете праг. Диагностиката на бекендовете за следващ токен показва каква част от вероятността моделът е присвоил на разрешените отговори. Ниска стойност означава, че е присвоил по-голямата част от вероятността другаде.
Бекендове
AnyDecisionModel има шест бекенда:
- MLX изпълнява малък езиков модел върху Apple silicon с mlx-swift-lm и го изтегля от Hub.
- MLX decision heads изпълнява модел със собствена обучена глава за решения, като Clef.
- Core AI прави същото като MLX с модел Core AI в macOS 27 и iOS 27.
- llama.cpp прочита решения от локален GGUF модел чрез llama.swift.
- Jev извиква Jev на TypeSafe чрез System One API, или всеки сървър, който го реализира, като Kev.
- Ollama извиква модел за решения System One на локален сървър Ollama или в облака на Ollama. Изисква Ollama 0.35.0 или по-нова версия, или 0.40.5 или по-нова за облачни модели.
Бекендовете за следващ токен обозначават отговорите с „yes“ и „no“, A до Z или 0 до 9, така че един избор може да има най-много 26 възможности, а една оценка — най-много 10 нива. Главите за решения нямат такова ограничение.
Подобно на AnyLanguageModel, пакетът използва характеристики на Swift пакетите.
Без характеристики той няма зависимости от трети страни.
Получавате основните типове и бекендовете Jev и Ollama,
които се компилират и под Linux.
Активирайте характеристиката MLX, CoreAI или Llama за локалните бекендове.
Първи стъпки
И двата пакета изискват Swift 6.2 или по-нова версия и macOS 26 или iOS 26 или по-нова версия. Средите за изпълнение на Parakeet и Sortformer и бекендът MLX изискват Apple silicon. Задачите за компилация на MLX на AnyDecisionModel използват Xcode Swift 6.4 или по-нова версия и инструментариума Metal; Core AI изисква Xcode 27 и runtime на операционна система 27.
Добавете пакетите към своя Package.swift:
dependencies: [
.package(url: "https://github.com/mattt/AnySpeechRecognizer", from: "0.1.0"),
.package(
url: "https://github.com/mattt/AnyDecisionModel",
from: "0.6.0",
traits: ["MLX"]
),
]
Засега характеристиката CoreAI на AnyDecisionModel не може да се комбинира с AnySpeechRecognizer,
защото coreai-kit 0.7.3 изисква swift-huggingface под 1.0,
а AnySpeechRecognizer изисква 1.x.
Всеки README съдържа още примери и подробности за изискванията и бекендовете.
AnySpeechRecognizer включва и инструмент от командния ред, hear,
който транскрибира локални файлове, обозначава говорителите им и оценява резултатите.
Всяка команда hear изисква --backend apple, --backend parakeet или --backend qwen;
изпълнете hear prepare със същия бекенд и опциите за модела преди анализа,
за да инсталирате необходимите ресурси.
Изпробвайте ги в приложенията си и ни кажете кое работи и кое не. Сигнали за проблеми и pull request-и са добре дошли и в двата репозитория.
Връзки
- AnySpeechRecognizer в GitHub
- AnyDecisionModel в GitHub
- AnyDecisionModel-Examples в GitHub
- AnyLanguageModel в GitHub
- swift-huggingface в GitHub
Благодарим на NVIDIA за Parakeet, Sortformer и NeMo, на Moondream за Parakeet Ultra, на FluidInference, чиито проекти FluidAudio и mobius документираха конвенциите, следвани от runtime-а на Parakeet и преобразуванията към Core ML, на Cloudflare за Clef и на всички, допринесли за AnyLanguageModel, чиито шаблони двата пакета заимстват.
Модели, споменати в тази статия 10
Общност
· Регистрирайте се или влезте, за да коментирате
Модели, споменати в тази статия 10
Преведено автоматично от английски. Оригиналната статия е на връзката по-долу.

