Глава 4: Сверточные нейронные сети для распознавания изображений и звука (том 2)

TensorFlow

Глава 4: Сверточные нейронные сети для распознавания изображений и звука (том 1)

4.3 Вне браузера: быстрее обучайте модели с помощью Node.js

В предыдущем разделе мы обучили коннет в браузере, и точность теста достигла 99,0%. В этом разделе мы создадим более мощную сверточную сеть, которая даст нам более высокую точность теста, около 99,5%. Однако за повышение точности приходится платить: модель потребляет много памяти и вычислений во время обучения и логического вывода. Увеличение стоимости более заметно во время обучения, потому что обучение включает в себя обратное распространение, которое требует больше вычислительных ресурсов, чем прямое прогон, необходимый для вывода. Большие консети слишком тяжелы и медленны для обучения в большинстве сред веб-браузера.

4.3.1 Использование зависимостей tfjs-node и импорта

Введите версию TensorFlow.js для Node.js! Он работает в серверной среде и не зависит от каких-либо ограничений ресурсов (например, ограничений вкладок браузера). Версия Node.js TensorFlow для ЦП (далее именуемая tfjs-node) напрямую использует многопоточные математические операции, написанные на C++ и используемые основной версией TensorFlow для Python. Если на вашем компьютере установлен графический процессор с поддержкой CUDA, tfjs-node также может использовать математические ядра с ускорением на графическом процессоре, написанные на CUDA, для еще большего прироста скорости.

Код расширенной сверточной сети MNIST находится в каталоге mnist-node tfjs-examples. Как мы видели в примере, вы можете получить доступ к коду с помощью:

git clone https://github.com/tensorflow/tfjs-examples.git
cd tfjs-examples / mnist-node

Отличие от предыдущего примера в том, что пример mnist-node будет работать в терминале, а не в веб-браузере. Чтобы загрузить зависимости, используйте команду yarn.

Зависимость @tensorflow/tfjs-node можно увидеть в файле package.json. После объявления @tensorflow/tfjs-node в качестве зависимости, yarn автоматически загрузит разделяемую библиотеку C++ (с именем libtensorflow.so, libtensorflw.dylib или libtensorflow.dll в системах Linux, Mac или Windows соответственно) в каталог node_modules для использования TensorFlow. .js.

После запуска команды yarn вы можете начать обучение модели с помощью:

node main.js

После установки пряжи бинарные файлы узла доступны по вашему пути к файлу (дополнительную информацию см. в Приложении A3). Приведенный выше рабочий процесс позволит вам обучить усиленную сеть на ЦП. Если на ваших рабочих станциях и ноутбуках установлены графические процессоры с поддержкой CUDA, вы также можете обучать модели на графических процессорах. Необходимые шаги:

  1. Установите правильную версию драйверов NVIDIA для вашего графического процессора.
  2. Установите набор инструментов NVIDIA CUDA. Эта библиотека обеспечивает параллельные вычисления общего назначения на семействе графических процессоров NVIDIA.
  3. Установите CuDNN, библиотеку NVIDIA, построенную на основе CUDA, для высокопроизводительных алгоритмов глубокого обучения (подробнее о шагах 1–3 см. Приложение A3).
  4. В package.json замените зависимость @tensorflow/tfjs-node на @tensorflow/tfjs-node-gpu, но сохраните тот же номер версии, поскольку два пакета выпускаются синхронно.
  5. Повторный запуск пряжи загрузит общую библиотеку, содержащую математические операции CUDA, используемые TensorFlow.js.
  6. В main.js замените require('@tensorflow/tfjs-node'); на require('@tensorflow/tfjs-node-gpu');
  7. Снова запустите тренировочный узел main.js Если эти шаги выполнены правильно, ваша модель будет работать на графическом процессоре CUDA, обычно обучаясь в пять раз быстрее, чем может достичь версия с процессором (tfjs-node). Обучение с версией tfjs-node для процессора или графического процессора выполняется намного быстрее, чем обучение той же модели в браузере.

4.3.2 Обучающий расширенный коннет для MNIST в узле tfjs

Как только обучение будет завершено за 20 эпох, модель должна показать точность окончательного теста (т.е. оценки) около 99,6%, что лучше, чем 99,0% наших результатов в разделе 4.2. Итак, в чем разница между такой моделью на основе узлов и моделью на основе браузера и почему это приводит к увеличению точности? Если вы обучаете одну и ту же модель в tfjs-узле и браузерной версии TensorFlow.js, используя данные для обучения данных, вы должны получить одинаковые результаты (за исключением эффектов или инициализации случайных весов). Чтобы ответить на этот вопрос, давайте посмотрим на определение модели на основе узлов. Модель построена в файле model.js, который импортируется main.js.

Листинг 4.5. Определение большей сети для MNIST в Node.js
const model = tf.sequential();
 model.add(tf.layers.conv2d({
   inputShape: [28, 28, 1],
   filters: 32,
   kernelSize: 3,
   activation: 'relu',
 }));
 model.add(tf.layers.conv2d({
   filters: 32,
   kernelSize: 3,
   activation: 'relu',
 }));
 model.add(tf.layers.maxPooling2d({poolSize: [2, 2]}));
 model.add(tf.layers.conv2d({
   filters: 64,
   kernelSize: 3,
   activation: 'relu',
 }));
 model.add(tf.layers.conv2d({
   filters: 64,
   kernelSize: 3,
   activation: 'relu',
 }));
 model.add(tf.layers.maxPooling2d({poolSize: [2, 2]}));
 model.add(tf.layers.flatten());
 model.add(tf.layers.dropout({rate: 0.25}));
 model.add(tf.layers.dense({units: 512, activation: 'relu'}));
 model.add(tf.layers.dropout({rate: 0.5}));
 model.add(tf.layers.dense({units: 10, activation: 'softmax'}));
  
 model.summary();
 model.compile({
   optimizer: 'rmsprop',
   loss: 'categoricalCrossentropy',
   metrics: ['accuracy'],
 });

Резюме модели выглядит следующим образом:

_________________________________________________________________
 Layer (type)                 Output shape              Param #  
 =================================================================
 conv2d_Conv2D1 (Conv2D)      [null,26,26,32]           320      
 _________________________________________________________________
 conv2d_Conv2D2 (Conv2D)      [null,24,24,32]           9248     
 _________________________________________________________________
 max_pooling2d_MaxPooling2D1  [null,12,12,32]           0        
 _________________________________________________________________
 conv2d_Conv2D3 (Conv2D)      [null,10,10,64]           18496    
 _________________________________________________________________
 conv2d_Conv2D4 (Conv2D)      [null,8,8,64]             36928    
 _________________________________________________________________
 max_pooling2d_MaxPooling2D2  [null,4,4,64]             0        
 _________________________________________________________________
 flatten_Flatten1 (Flatten)   [null,1024]               0        
 _________________________________________________________________
 dropout_Dropout1 (Dropout)   [null,1024]               0        
 _________________________________________________________________
 dense_Dense1 (Dense)         [null,512]                524800   
 _________________________________________________________________
 dropout_Dropout2 (Dropout)   [null,512]                0         
 _________________________________________________________________
 dense_Dense2 (Dense)         [null,10]                 5130     
 =================================================================
 Total params: 594922
 Trainable params: 594922
 Non-trainable params: 0
 _________________________________________________________________

Основное различие между нашей моделью TFJS-NODE и моделями на основе браузера заключается в следующем:

  1. Модель на основе узлов имеет четыре слоя conv2d, на один больше, чем модель на основе браузера.
  2. Скрытые плотные слои в модели на основе узлов содержат больше единиц (512), чем соответствующие слои в модели на основе браузера (100).
  3. В целом модель на основе узлов примерно в 18 раз превышает весовые параметры модели на основе браузера.
  4. Модель на основе узлов вставляет два выпадающих слоя между плоским и плотным слоями.
    Различия 1-3, перечисленные выше, дают моделям на основе узлов более высокую пропускную способность, чем модели на основе браузера. Они также делают модели на основе узлов слишком требовательными к памяти и вычислительным ресурсам для обучения в браузере. Как мы узнали из главы 3, большая емкость модели сопряжена с большим риском переобучения. Отличие 4 (т. е. включение выпадающих слоев) снижает риск переобучения.

Использование выпадающих слоев для уменьшения переобучения

Выпадающие слои — это еще один новый тип слоя TensorFlow.js, с которым вы столкнетесь в этой главе. Это один из наиболее эффективных и широко используемых методов уменьшения переобучения в глубоких нейронных сетях. Его функции можно кратко описать:

  • На этапе обучения (т. е. во время вызова Model.fit()) он случайным образом устанавливает часть элементов входного тензора в ноль (т. е. «отбрасывает»), а результатом является выходной тензор. В этом примере слой сброса имеет только один параметр конфигурации: скорость сброса (например, два поля скорости, показанные в листинге 4.5). Например, если предположить, что уровень отсева настроен на коэффициент отсева 0,25, а входной тензор является одномерным тензором со значениями [0,7, -0,3, 0,8, -0,4], выходной тензор может быть [0,7, -0,3, 0,0 , например 0,4], то есть 25% входного тензора выбирается случайным образом и устанавливается в значение 0. Во время обратного распространения это случайное обнуление аналогичным образом влияет на тензор градиента на капельном слое.
  • Во время логического вывода (т. е. вызовов Model.predict() и Model.evaluate) уровень исключения не изменяется случайным образом до нуля на входных элементах тензора. Вместо этого ввод просто передается для вывода без изменений (т. е. отображения).
    На рис. 4.11 ниже показано, как слой отсева с двумерными входными тензорами работает во время обучения и тестирования.
Рисунок 4.11 Схематическая диаграмма того, как работает выпадающий слой. В этом примере входной тензор является двумерным с формой [4, 2]. Скорость отсева слоя настроена на 0,25, что приводит к случайному выбору 25% (т.е. двух из восьми) входных тензоров на этапе обучения и установке их на ноль. На этапе логического вывода этот слой действует как обычный сквозной слой.

Кажется странным, что такой простой алгоритм является одним из самых эффективных способов борьбы с переоснащением. Почему это работает? Джефф Хинтон, изобретатель алгоритма сброса, типа алгоритма нейронной сети, сказал, что его вдохновили механизмы, которые некоторые банки используют для предотвращения мошенничества со стороны сотрудников. По его собственным словам:

«Я пошел в банк. Кассиры постоянно менялись, и я спросил одного из них, почему. Он сказал, что не знает, но они менялись. Это заставило меня понять, что случайное удаление разных подмножеств нейронов в каждом примере предотвратит сговор и, таким образом, уменьшит переобучение».

Чтобы выразить это в терминологии глубокого обучения, введение шума в выходные значения слоя разрушает шаблоны непредвиденных обстоятельств, которые не важны для истинного шаблона данных (то, что Хинтон называет «заговорами»). В упражнении 3 в конце этой главы вы должны попробовать удалить два выпадающих слоя из консети на основе узлов в model.js, снова обучить модель и посмотреть, как изменится ее точность обучения, проверки и оценки.

В листинге 4.6 ниже показан ключевой код, который мы использовали для обучения и оценки усиленной сети. Если вы сравните приведенный здесь код с кодом в листинге 4.2, то сможете понять сходство между двумя блоками кода. Оба сосредоточены на вызовах Model.fit() и Model.evaluate(). Синтаксис и стиль одинаковы, разница заключается в том, как значения потерь, значения точности и прогресс обучения визуализируются или отображаются в разных пользовательских интерфейсах (т. е. терминал или браузер).

Это показывает важные особенности TensorFlow.js, среды глубокого обучения JavaScript, которая охватывает интерфейс и серверную часть: С точки зрения создания и обучения модели код, написанный в TensorFlow.js, одинаков независимо от того, используете ли вы веб-браузер или Node.js.

Листинг 4.6. Обучение и оценка расширенной сети в узле tfjs
await model.fit(trainImages, trainLabels, {
    epochs,
    batchSize,
    validationSplit
});

const {images: testImages, labels: testLabels} = data.getTestData();
const evalOutput = model.evaluate(testImages, testLabels);
console.log('\nEvaluation result:');
console.log(
    `  Loss = ${evalOutput[0].dataSync()[0].toFixed(3)}; `+
    `Accuracy = ${evalOutput[1].dataSync()[0].toFixed(3)}`);

4.3.3 Сохраните модель из Node.js и загрузите модель в браузере

Обучение модели потребляет ресурсы процессора и графического процессора и занимает некоторое время. Вы же не хотите потерять плоды своего обучения. Если вы не сохраните модель, вам придется начинать с нуля при следующем запуске main.js. В этом разделе показано, как сохранить модель после обучения и как экспортировать сохраненную модель в виде файла на диск (называемого «контрольной точкой» или «артефактом»). Мы также покажем, как импортировать контрольные точки в браузере, преобразовать их в модели и использовать их для логических выводов.

Последняя часть функции main() в main.js состоит из кода, который сохраняет модель:

Листинг 4.7 сохраняет обученную модель в файловой системе tfjs-node.
if (modelSavePath != null) {
    await model.save(`file://${modelSavePath}`);
    console.log(`Saved model to path: ${modelSavePath}`);
}

Каталог в файловой системе. Метод принимает единственный параметр, представляющий собой строку URL, начинающуюся с файла схемы://. Обратите внимание: поскольку мы используем tfjs-node, можно сохранить модель в файловой системе. Браузерная версия TensorFlow.js также предоставляет API model.save(), но не имеет прямого доступа к собственной файловой системе машины, так как это запрещено браузерами по соображениям безопасности. Если мы используем TensorFlow.js в браузере, мы должны использовать цель сохранения, отличную от файловой системы (например, локальное хранилище браузера и IndexedDB). Они соответствуют схемам URL, отличным от file://.

model.save() — это асинхронная функция, поскольку она обычно включает файловый или сетевой ввод-вывод. Поэтому мы используем await в вызове save(). Предполагая, что значение modelSavePath равно /tmp/tfjs-node-mnist, после завершения вызова model.save() вы можете проверить содержимое каталога:

ls -lh / tmp / tfjs-node-mnist

Список файлов, подобный следующему, может быть напечатан:

-rw-r--r-- 1 user group 4.6K Aug 14 10:38 model.json
-rw-r--r-- 1 user group 2.3M Aug 14 10:38 weights.bin

Там вы можете увидеть два файла:

  • model.json — это файл JSON, содержащий сохраненную топологию модели. Так называемая «топология» здесь включает типы слоев, составляющих модель, их соответствующие параметры конфигурации (например, фильтры, используемые для слоев conv2d, и скорость, используемая для удаления слоев), и способ соединения слоев с каждым. разное. Для сверточной сети MNIST соединения просты, потому что это последовательная модель. Модели с меньшим количеством подключенных схем также можно сохранить на диск с помощью model.save(). Помимо топологии модели, файл model.json также содержит список весов модели. В этом разделе перечислены имена, формы и типы данных всех весов в модели, а также место для хранения значений весов. Это подводит нас ко второму файлу: weights.bin.
  • Как следует из названия, weights.bin — это двоичный файл, в котором хранятся все значения веса для модели. Это плоский двоичный поток без разделения начального и конечного положения отдельных весов. Эта «метаинформация» доступна в разделе манифеста веса объекта JSON в model.json.

Чтобы загрузить модель с помощью tfjs-узла, вы можете использовать метод tf.loadLayersModel(), указав расположение файла model.json (не показано в примере кода)

const loadedModel = await tf.loadLayersModel('file:///tmp/tfjs-node-mnist');

tf.loadLayersModel() реконструирует модель путем десериализации данных топологии, сохраненных в model.json. Затем tf.loadLayersModel() считывает двоичные значения веса в weights.bin, используя манифест в model.json, и устанавливает веса модели в соответствии с этими значениями.

Как и model.save(), tf.loadLayersModel() является асинхронным, поэтому здесь мы вызываем await. Как только вызов возвращается, во всех смыслах и целях объект loadModel эквивалентен модели, созданной и обученной с использованием кода JavaScript в листингах 4.5 и 4.6. Вы можете распечатать производительность этой модели, вызвав ее метод summary(), использовать ее для выполнения вывода, вызвав ее метод predict(), оценить ее точность, используя метод validate(), и даже применить к ней метод fit(). Переобучить. Вы также можете сохранить модель снова, если это необходимо. Рабочий процесс переобучения и сохранения загруженных моделей будет важен, когда мы будем обсуждать трансферное обучение в главе 5.

Сказанное в предыдущем абзаце относится и к среде браузера. Сохраненный файл можно использовать для реконструкции модели на веб-странице. Реконструированная модель поддерживает полный рабочий процесс tf.LayersModel с оговоркой, что если вы переобучите всю модель, она будет особенно медленной и неэффективной из-за большого размера расширенной сверточной сети. Единственная принципиальная разница между загрузкой моделей в tfjs-node и в браузере заключается в том, что в браузере должна использоваться схема URL, отличная от file://. Как правило, вы можете разместить файлы model.json и weights.bin на HTTP-сервере в виде файлов статических активов. Предполагая, что ваше имя хоста — localhost, а файл отображается по пути сервера my/models/, вы можете загрузить модель в своем браузере с помощью следующей строки:

const loadedModel =await tf.loadLayersModel('http:///localhost/my/models/model.json');

При обработке загрузки модели на основе HTTP в браузере tf.loadLayersModel() незаметно вызывает встроенную функцию выборки браузера. Таким образом, он имеет следующие функции и возможности:

  • Поддерживаются как http:#, так и https:#.
  • Относительные пути сервера поддерживаются. На самом деле, вы можете опустить http: // или https: // часть URL, если вы используете относительные пути. Например, если ваша веб-страница находится на пути к серверу My / index.html и файл json и ваша модель json находится на my / models / model.json, вы можете использовать относительную модель / model.json, то есть.
const loadedModel = await tf.loadLayersModel('models/model.json');
  • Для указания дополнительных параметров HTTP/HTTPS-запросов вместо строковых параметров следует использовать метод tf.io.browserHTTPRequest(). Например, чтобы включить учетные данные и заголовки во время загрузки модели, вы можете сделать следующее:
const loadedModel = await tf.loadLayersModel(tf.io.browserHTTPRequest(
    'http://foo.bar/path/to/model.json',
    {credentials: 'include', headers: {'key_1': 'value_1'}}));

4.4 Распознавание речи: применение сверток к аудиоданным

До сих пор мы показали, как выполнять задачи компьютерного зрения с использованием сверточных сетей. Но человеческое восприятие — это больше, чем просто зрение. Аудио является важной формой перцептивных данных и может быть доступно через API-интерфейсы браузера. Как определить содержание и значение речи и других звуков? Стоит отметить, что свертки полезны не только для компьютерного зрения, но также могут значительно помочь машинному обучению, связанному со звуком.

В этой главе вы увидите, как решать относительно простые звуковые задачи, используя коннет, аналогичный тому, который создан для MNIST. Задача состоит в том, чтобы классифицировать короткие фрагменты речевых записей примерно по 20 категориям слов. Задача проще, чем распознавание речи, которое вы можете увидеть в таких устройствах, как Amazon Echo и Google Home. Эти системы распознавания речи имеют больший словарь, чем используемые в этом примере. Точно так же они имеют дело со связанной речью, состоящей из нескольких последовательно произносимых слов, тогда как в нашем примере речь идет об однократных словах. Таким образом, наш пример не квалифицируется как «распознаватель речи», а более точно описывается как «распознаватель слов» или «распознаватель голосовых команд». Однако наш пример по-прежнему имеет практическое применение (например, пользовательский интерфейс громкой связи и специальные возможности). Опять же, методы глубокого обучения, воплощенные в этом примере, фактически составляют основу более совершенных систем распознавания речи [70].

4.4.1 Спектрограмма: представление звука в виде изображения

Как и в любом приложении глубокого обучения, если вы хотите понять, как работает модель, вам нужно сначала понять данные. Чтобы понять, как работают аудио сверточные сети, нам сначала нужно посмотреть, как звуки представлены в виде тензоров. Если вспомнить школьную физику, звук представлял собой закономерность изменения атмосферного давления. Микрофоны улавливают изменения атмосферного давления и преобразуют их в электрические сигналы, которые затем могут быть оцифрованы звуковой картой вашего компьютера. Современные веб-браузеры имеют API WebAudio, который взаимодействует со звуковой картой и обеспечивает доступ в режиме реального времени к оцифрованному аудиосигналу (с разрешения пользователя). Итак, с точки зрения программиста на JavaScript, звуки — это массивы с действительными значениями. В глубоком обучении такие массивы чисел часто представляются как одномерные тензоры.

Некоторые читатели могут задаться вопросом: как вид свертки, которую мы видим, работает с одномерными тензорами? Разве они не должны работать с тензорами по крайней мере двух измерений? Ключевые слои convnet, включая conv2d и maxPooling2d, используют пространственные отношения в 2D-пространстве. Оказывается, звук можно представить в виде особой формы изображения, называемой спектрограммой. Спектрограммы могут не только применять свертки к звуку, но и иметь теоретические основания, выходящие за рамки глубокого обучения.
Как показано на рис. 4.12, спектрограмма представляет собой двумерный массив чисел, который можно отобразить в виде изображения в градациях серого, почти идентичного изображению MNIST. Горизонтальное измерение — это время, а вертикальное — частота. Каждый вертикальный срез спектрограммы представляет собой звуковой спектр в коротком временном окне. Спектр — это разложение звука на разные частотные составляющие, которые можно примерно понимать как разные «высоты». Точно так же, как призма может разделить свет на несколько цветов, звук можно разбить на несколько частот с помощью математической операции, называемой преобразованием Фурье. Итак, в двух словах, спектрограмма описывает, как частотный состав звука изменяется в течение ряда последовательных коротких окон времени (обычно 20 миллисекунд).

Спектрограмма является подходящим представлением звука по следующим причинам. Во-первых, это экономит место: количество поплавков в спектрограмме обычно в несколько раз меньше, чем в исходной волновой форме. Во-вторых, спектрограммы, вообще говоря, соответствуют тому, как работает слух в биологии. Анатомическая структура внутреннего уха, называемая улиткой, по существу выполняет биологическую форму преобразования Фурье. Он разбивает звук на разные частоты, которые затем улавливаются разными наборами слуховых нейронов. В-третьих, представление речи на спектрограмме облегчает различение разных типов речи друг от друга. Пример речевой спектрограммы на рис. 4.12 показывает это: гласные и согласные имеют разные определенные модели в своих спектрограммах. Десятилетия назад, до того, как машинное обучение получило широкое распространение, люди, работающие в области распознавания речи, на самом деле пытались вручную создавать правила для обнаружения различных гласных и согласных на спектрограммах. Глубокое обучение избавляет нас от хлопот ручной работы.

Рисунок 4.12 Пример спектрограммы для речи «ноль» и «да». Спектрограмма представляет собой совместное частотно-временное представление звука. Вы можете думать о спектрограмме как об изображении звука. Каждый срез по оси времени (т. е. столбец изображения) представляет собой небольшой момент (кадр) времени, каждый срез по оси частот (т. е. ряд изображения) соответствует определенному узкому частотному диапазону (тону). Значение в каждом пикселе изображения представляет относительную энергию звука в данном частотном бине в данный момент времени. Постройте приведенную выше спектрограмму так, чтобы более темные оттенки серого соответствовали более высокой энергии. Разные голоса имеют разные определяющие характеристики. Например, такие устойчивые согласные, как «з» и «с», характеризуются квазистационарной энергией, сосредоточенной на частотах выше 2-3 кГц. Гласные (например, «е» и «о») характеризуются горизонтальными полосами (т. е. энергетическими пиками) в нижней части (

Давайте остановимся и задумаемся на мгновение. Глядя на изображение MNIST на рис. 4.1 и спектрограмму речи на рис. 4.12, вы сможете понять сходство между двумя наборами данных. Оба набора данных содержат паттерны в двухмерном пространстве признаков, которые сможет различить пара натренированных глаз. Оба набора данных показывают некоторую случайность в подробном расположении, размере и детализации объектов. Наконец, оба являются задачами классификации нескольких классов. В то время как MNIST содержит 10 возможных классов, наш набор данных речевых команд содержит 20 (десять цифр от «0» до «9», «вверх», «вниз», «влево», «вправо», «идти», «стоп», « да", "нет" и "неизвестные" слова и категории фонового шума). Именно это сходство в природе наборов данных делает свертки подходящими для задач распознавания речевых команд.

Однако между двумя наборами данных есть и некоторые заметные различия. Во-первых, записи в наборе данных голосовых команд несколько зашумлены. В примерной спектрограмме на рис. 4.12 можно увидеть темные пиксельные пятна, не относящиеся к речи. Во-вторых, каждая спектрограмма в наборе данных голосовых команд имеет размер 43*232, что значительно больше по сравнению с размером 28*28 одного изображения MNIST. Размер спектрограммы асимметричен между временным и частотным измерениями. Эти различия будут отражены сверточной сетью, которую мы будем использовать в наборе аудиоданных.

Код для определения и обучения голосовой команды convnet находится в репозитории tfjs-models. Вы можете получить доступ к коду с помощью:

git clone https://github.com/tensorflow/tfjs-models.git
 cd speech-commands/training/browser-fft

Создание и компиляция модели инкапсулированы в функцию createModel в файле model.ts.

Листинг 4.8. Convnet для классификации спектрограмм голосовых команд
function createModel(inputShape: tf.Shape, numClasses: number) {
   const model = tf.sequential();
   model.add(tf.layers.conv2d({
     filters: 8,
     kernelSize: [2, 8],
     activation: 'relu',
     inputShape
   }));
   model.add(tf.layers.maxPooling2d({poolSize: [2, 2], strides: [2, 2]}));
   model.add(
       tf.layers.conv2d({filters: 32, kernelSize: [2, 4], activation: 'relu'}));
   model.add(tf.layers.maxPooling2d({poolSize: [2, 2], strides: [2, 2]}));
   model.add(
       tf.layers.conv2d({filters: 32, kernelSize: [2, 4], activation: 'relu'}));
   model.add(tf.layers.maxPooling2d({poolSize: [2, 2], strides: [2, 2]}));
   model.add(
       tf.layers.conv2d({filters: 32, kernelSize: [2, 4], activation: 'relu'}));
   model.add(tf.layers.maxPooling2d({poolSize: [2, 2], strides: [1, 2]}));
   model.add(tf.layers.flatten());
   model.add(tf.layers.dropout({rate: 0.25}));
   model.add(tf.layers.dense({units: 2000, activation: 'relu'}));
   model.add(tf.layers.dropout({rate: 0.5}));
   model.add(tf.layers.dense({units: numClasses, activation: 'softmax'}));
  
   model.compile({
     loss: 'categoricalCrossentropy',
     optimizer: tf.train.sgd(0.01),
     metrics: ['accuracy']
   });
   model.summary();
   return model;
}

Топология нашей аудиосети очень похожа на сеть MNIST. Последовательная модель начинается с нескольких повторяющихся модулей слоя conv2d и слоя maxPooling2d. Сверточная часть модели заканчивается выравнивающим слоем, после которого добавляется многослойный персептрон (MLP). MLP имеет два плотных слоя. Скрытые плотные слои имеют активацию relu, а последний слой (выходной) активируется softmax, подходящим для задач классификации. Скомпилируйте модель, чтобы использовать categoricalCrosssentropy в качестве функции потерь и выдавать метрики точности во время обучения и оценки. Это точно так же, как сверточная сеть MNIST, поскольку оба набора данных включают многоклассовую классификацию. Аудио сверточные сети также демонстрируют некоторые интересные отличия от MNIST. В частности, свойство kernelSize слоя conv2d представляет собой прямоугольник (например, [2, 8]) вместо квадрата. Эти значения были выбраны, чтобы соответствовать неквадратной форме спектрограмм, чья частотная размерность больше, чем временная.

Чтобы обучить модель, вам нужно сначала загрузить набор данных голосовых команд. Этот набор данных получен из набора данных голосовых команд [71], собранного Питом Варденом, инженером команды Google Brain. Он был преобразован в формат спектрограммы для конкретного браузера.

curl -fSsL https://storage.googleapis.com/learnjs-data/speech-commands/speech-commands-data-v0.02-browser.tar.gz  -o speech-commands-data-v0.02-browser.tar.gz &&
tar xzvf speech-commands-data-v0.02-browser.tar.gz

Эти команды загрузят и извлекут браузерную версию набора данных голосовых команд. После извлечения данных вы можете начать процесс обучения с помощью:

 Yarn
 yarn train speech-commands-data-browser/ /tmp/speech-commands-model/

Первый параметр команды yarn train указывает на расположение обучающих данных. Следующие параметры указывают путь к файлу JSON, в котором модель будет сохранена вместе с файлом весов и файлом метаданных JSON. Точно так же, как мы обучали расширенную сверточную сеть MNIST, обучение аудио сверточной сети происходит в узле tfjs, потенциально используя графические процессоры. Поскольку размер набора данных и модели больше, чем свертка MNIST, обучение займет больше времени (порядка часов). Если у вас есть графический процессор CUDA и вы немного измените команду, чтобы использовать tfjs-node-gpu вместо tfjs-node по умолчанию (который работает только на процессоре), вы можете значительно повысить скорость обучения. Для этого достаточно добавить флаг "--gpu" к вышеуказанной команде, т.е.

yarn train --gpu speech-commands-data-browser/ /tmp/speech-commands-model/

После обучения модель должна достичь точности конечной оценки (теста) примерно 94%. Обученная модель будет сохранена по пути, заданному указанными выше параметрами команды. Как и в нашей сверточной сети MNIST, обученной с помощью tfjs-node, сохраненная модель может быть загружена в браузер для обслуживания. Однако вам необходимо быть знакомым с WebAudio API, чтобы получать данные с микрофона и предварительно обрабатывать их в формат, который может использовать модель. Для удобства мы написали класс-оболочку, который не только загружает обученную сверточную аудиосеть, но и занимается извлечением и предварительной обработкой данных. Если вам интересна механика конвейера ввода аудиоданных, вы можете изучить базовый код в папке «speech-commands/src» в git-репозитории tfjs-model. Оболочка доступна через npm под именем «@tensorflow-models/speech-commands». В следующем листинге кода показан пример того, как можно использовать класс-оболочку для онлайн-распознавания слов голосовых команд в браузере. В папке voice-commands/demo репозитория tfjs-models вы можете найти более простые примеры использования пакета. Чтобы клонировать и запустить демонстрацию, выполните следующие команды в каталоге voice-commands:

git clone https://github.com/tensorflow/tfjs-models.git
cd tfjs-models/speech-commands
yarn && yarn publish-local
cd demo
yarn && yarn link-local && yarn watch

Команда yarn watch автоматически откроет новую вкладку в вашем веб-браузере по умолчанию. Чтобы увидеть распознаватель голосовых команд в действии, убедитесь, что на вашем компьютере есть микрофон (в большинстве ноутбуков он есть). Каждый раз, когда слово в словаре распознается, оно будет отображаться на экране в режиме реального времени вместе со спектрограммой, содержащей это слово. Итак, это браузерное распознавание слов, основанное на WebAudio API и глубоких сверточных нейронных сетях. Конечно, у него нет возможности распознавать ассоциированную речь с грамматикой. Для этого потребуется помощь других типов строительных блоков нейронных сетей, способных обрабатывать последовательную информацию. Мы познакомимся с ними в главе 8.

Листинг 4.9. Пример использования модуля @tenosrflow-models/speech-commands
import * as SpeechCommands from '@tensorflow-models/speech-commands';
  
  
 const recognizer = SpeechCommands.create('BROWSER_FFT');
  
 console.log(recognizer.wordLabels());
  
  
 recognizer.listen(result => {
   let maxIndex;
   let maxScore = -Infinity;
   result.scores.forEach((score, i) => {
     if (score > maxScore) {
       maxIndex = i;
       maxScore = score;
     }
   });
   console.log(`Detected word ${recognizer.wordLabels()[maxIndex]}`);
 }, {
   probabilityThreshold: 0.75
 });
  
 setTimeout(() => recognizer.stopStreaming(), 10e3);

4.5 Резюме

  • Сверточная нейронная сеть (convnet) извлекает двумерные пространственные объекты из входного изображения и имеет иерархию слоев conv2d и maxPooling2d.
  • Слой conv2d представляет собой многоканальный настраиваемый пространственный фильтр. Они обладают свойствами локальности и совместного использования параметров, что делает их мощными экстракторами признаков и эффективными преобразованиями представлений.
  • Слой maxPooling2d уменьшает размер тензора входного изображения, вычисляя максимальное значение в пределах окна фиксированного размера, что приводит к лучшей инвариантности положения.
  • «Башня» сверточных сетей conv2d-maxPooling2d обычно заканчивается плоским слоем, за которым следует многослойный персептрон (MLP), состоящий из плотных слоев для задач классификации или регрессии.
  • Из-за ограниченных ресурсов этот браузер подходит только для обучения небольших моделей. Для обучения более крупных моделей рекомендуется использовать tfjs-node, версию TensorFlow.js для Node.js. tfjs-node может использовать те же ядра распараллеливания ЦП и ГП, что и версия TensorFlow для Python.
  • Большая вместимость модели сопряжена с большим риском переоснащения. Переобучение можно улучшить, добавив в коннет слой отсева. Слой отсева случайным образом обнуляет заданную долю входных элементов во время обучения.
  • Свертки полезны не только для задач компьютерного зрения. Когда звуковой сигнал представлен в виде спектрограммы, к нему может быть применена свертка для достижения хорошей точности классификации.

4.6 Упражнение

  • Connet, используемый для классификации изображений MNIST в браузере (листинг 4.1), имеет два набора слоев conv2d и maxPooling2d. Измените код, чтобы уменьшить количество до одного набора. Ответьте на следующие вопросы:
    1. Как это влияет на общее количество обучаемых параметров сверточной сети?
    2. Как это влияет на скорость тренировки?
    3. Как это влияет на итоговую точность, полученную после обучения сверточной сети?
  • Это упражнение аналогично упражнению 1 выше. Однако вместо того, чтобы пытаться использовать количество групп слоев conv2d-maxPooling2d, попробуйте использовать количество плотных слоев в многослойной персептронной части консети в листинге 4.1. Как изменится общее количество параметров, скорость обучения и конечная точность, если я уберу первый плотный слой и оставлю только второй (выходной) слой?
  • Удалите отсевающий слой из сверточной сети в узле mnist (листинг 4.5) и посмотрите, насколько точны процесс обучения и окончательный тест. Почему это так? Что это значит?
  • В качестве способа использования метода tf.browser.fromPixels() для извлечения данных изображения из элементов веб-страницы, связанных с изображениями и видео, попробуйте следующее:
    1. Используйте tf.browser.fromPixels(), чтобы получить тензор, представляющий цветное изображение JPG, используя тег img.
      А. Каковы высота и ширина тензора изображения, возвращаемого tf.browser.fromPixels()? Что определяет высоту и ширину?

      б) Используйте tf.image.resizeBilinear(), чтобы изменить размер изображения до фиксированного размера 100*100 (высота*ширина).

      c. Вместо этого используйте альтернативную функцию изменения размера tf.image.resizeNearestNeighbor(). Можете ли вы найти какую-либо разницу между результатами этих двух функций изменения размера?

    2. Создайте холст HTML и используйте такие функции, как rect(), чтобы нарисовать на нем произвольные фигуры. Или, если вы предпочитаете, вы можете использовать более продвинутые библиотеки, такие как d3.js и three.js, чтобы рисовать там более сложные 2D и 3D фигуры. Затем используйте tf.browser.fromPixels(), чтобы получить данные тензора изображения с холста.