Играем с TensorflowJS — первый взгляд на машинное обучение

искусственный интеллект внешний интерфейс
Играем с TensorflowJS — первый взгляд на машинное обучение

Предисловие/Основное введение

  • Чтобы изучить принципы машинного обучения, очень важно иметь немного математической основы (исчисление, линейная генерация, статистическая вероятность). Я не буду здесь вдаваться в вывод математических формул. Этот контент должен быть изучен в автономном режиме всеми. Это в основном объяснит концепции и приложения. Сначала я расскажу о некоторых основных вещах и попытаюсь объяснить их в простой для понимания форме. В настоящее время я нашел несколько руководств по машинному обучению. Студенты с плохой базой исключены. Мне не нравится этот путь.
  • Конечно, в начале я не буду рассказывать о коде и приложении, связанном с tensorflow, но мне все же нужно понять некоторые предварительные концепции и основы. В противном случае это будет запутывать новичков. Поскольку знания о машинном обучении связны и линейно возрастают, если вы не понимаете фронт, вы не сможете изучить его позже, и это будет становиться все сложнее и сложнее.
  • Пока я не буду говорить о глубоком обучении, начну с самых простых алгоритмов обучения и постепенно перейду к глубокому обучению.
  • Подводя итог, машинное обучение можно разделить на две категории: обучение с учителем и обучение без учителя.
  • Существует два типа задач обучения с учителем: проблемы регрессии и проблемы классификации. Итак, давайте начнем с проблемы регрессии.
  • Мы поговорим о неконтролируемом обучении и глубоком обучении позже.

Линейная регрессия

Я решил начать с проблемы регрессии, потому что это основа основ машинного обучения, и ее можно взять отсюда. Функция потерь, градиентный спуск, скорость обучения. начнется здесь. Итак, давайте начнем с самой простой одномерной линейной регрессии.

Существует два способа реализации линейной регрессии. Здесь обсуждается только линейная регрессия машинного обучения, и может быть проще использовать математические формулы для наклона и точки пересечения. Но не наша цель. Глубокое обучение — это систематическая дисциплина, и одни формулы не могут решить все проблемы.

Прогнозирование цен на жилье

Это классическая регрессионная задача, например, у нас есть два набора данных, один — размер дома, а другой — площадь дома. Затем, чтобы предсказать цену дома в определенном районе, нужно знать x, чтобы найти y. Графически представим данные следующим образом:

image.png

Ось X — это площадь дома, а ось Y — цена дома. PS: ручная роспись немного уродлива, пожалуйста, не обращайте внимания.

1. Первый шаг – определить модель расчета цены

Пусть площадь дома равна х, а цена продажи равна у. Нам нужно создать выражение, которое вычисляет выход y на основе входа x, который является моделью. Как следует из названия, линейная регрессия предполагает линейную зависимость между выходом и каждым входом, а затем следующую формулу:

y = x * w + b

В линейной регрессии w — это наклон, а b — точка пересечения. Но в машинном обучении нам нравится определять, что w — это вес, а b — смещение. (Поэтому, когда мы будем смотреть разные учебники, мы снова запутаемся, я объясню здесь) Наша цель найти w и b.

Позвольте мне рассказать немного больше: если это множественная линейная регрессия, какой она должна быть? Например, расположение дома также является фактором, влияющим на цену. Тогда может быть несколько x. Также будет несколько соответствующих весов w, определенных следующим образом: y = x1 * w1 + x2*w2 + b. Я расскажу об этом позже, просто упомяну еще одну вещь здесь. Подробнее об этом позже.

2. Второй шаг — определить функцию потерь.

Почему понятие функции потерь нам не нужно? Наша цель — найти w и b, но сначала мы не знаем значений w и b. Таким образом, машинное обучение часто начинается со случайной инициализации w и b, но это определенно неправильный результат. Так как же нам оптимизировать w и b? Пусть их значения приближаются к правильному результату. Следовательно, только найдя сравнительный метод измерения качества параметров, мы можем определить. Функция Loss делает именно это. Нам нужно измерить убыток между прогнозируемой ценой и истинным значением. Таким образом, он будет сравнивать убыток.Чем меньше результат, возвращаемый убытком, тем меньше убыток. Это доказывает, что наша оценка верна. Но как определить этот алгоритм?

Пожалуйста, смотрите картинку

test1.png

На самом деле наша цель с помощью линейной регрессии — получить эту синюю линию, но мы не можем нарисовать ее интуитивно, нам нужно использовать машину для ее расчета. Итак, мы хотим вычислить значение каждой опорной точки для сегмента синей линии (сегмент зеленой линии на изображении ниже представляет ошибку).

image.pngКак вычислить ошибку, на этот раз нужно ввести среднеквадратичную ошибку (MSE), о которой я расскажу ниже. Итак, существует следующая формула. Среднеквадратическая ошибка может использоваться в качестве индикатора для измерения результатов прогноза.

image.png

Y(X1) представляет значение результата расчета модели, а Yi представляет фактическое значение, также называемое эталонным значением. Проще говоря, разница между прогнозом и эталоном возводится в квадрат и суммируется, а затем делится на количество выборок, чтобы получить потерю одного стандартного отклонения. Как правило, мы изначально будем генерировать w и b случайным образом. О том, хороши ли w и b, будет судить функция потерь. Если нет, то как мы можем ее оптимизировать? Далее мы предложим наиболее важный алгоритм оптимизации для машинного обучения. , градиентный спуск.

3. Градиентный спуск

Приведенный выше метод наименьших квадратов просто решает наши исходные значения w и b, независимо от того, хороши они или нет, и выполняет расчет потерь. Итак, что мы должны сделать, чтобы найти оптимальные w и b? Ранее мы упоминали, что функция функции Loss состоит в том, чтобы найти разрыв между фактическим значением и идеальным значением, Если разрыв найден, как мы можем сократить этот разрыв? Мы превращаем функцию Loss в графическое отображение, как показано на следующем рисунке. Алгоритм градиентного спуска — это задача спуска, приближающаяся к подножию горы (экстремальное значение) шаг за шагом по самому крутому направлению.

20190121201301798.pngМатематическое объяснение, позаимствуйте следующую картинку, чтобы проиллюстрировать

20190121203434245.pngJ является функцией Θ.Наша текущая позиция Θ0, и нам нужно пройти от этой точки до точки минимума J, которая является подножием горы. Прежде всего, мы сначала определяем направление прогресса, которое является обратным градиенту, а затем делаем шаг расстояния, который равен α (скорость обучения), После этого шага мы достигаем точки Θ1.

α называется скорость обучения или размер шага валгоритм градиентного спуска, Это гиперпараметр, что означает, что мы можем контролировать расстояние каждого шага через α, чтобы гарантировать, что шаги не слишком велики, слишком велики и пропущены самые низкие точка. . В то же время следите за тем, чтобы не ходить слишком медленно, слишком медленная походка может привести к длительной тренировке. Таким образом, выбор α часто очень важен в методе градиентного спуска. Нужно продолжать попытки. Но позже я упомяну некоторые алгоритмы оптимизации для градиентного спуска. Для решения этой проблемы.

Тогда вы можете задать вопрос, что такое J(θ)? J(θ) — самое быстрое нисходящее направление Как получить J(θ)? J(θ) — частная производная двух параметров w и b соответственно в соответствии с функцией потерь. Конкретная математическая формула выглядит следующим образом:

image.png

image.png

Я не буду объяснять, как получена или выведена формула, иначе она окажется вне поля нашего исследования. В этой части вы можете взглянуть на знания, связанные с цепным правилом, наедине.

4. Обратное распространение

Кстати, еще одна концепция, о которой стоит упомянуть, — это обратное распространение. Этот алгоритм часто упоминается в области глубокого обучения. Когда мы снова делаем градиент, наши w и b должны быть переданы обратно в обратном направлении в соответствии со значениями, полученными из последнего частичного вывода. Обновите последние параметры, а затем выполните обновление градиента. В противном случае это вызовет проблему исчезновения градиента. Грубо говоря, параметры w и b сохраняются, и следующее обновление градиента будет обновлено из последних параметров. Посмотрите на мой демонстрационный код позже, и все станет ясно.

Линейная регрессия с нативным JS

Используя упомянутые выше принципы, давайте сначала рассмотрим пример реализации линейной регрессии в машинном обучении с помощью собственного javascript.

  1. Определить обучающий набор данных и гиперпараметры

Сначала нам нужно определить набор данных x и y Это данные, соответствующие нормальному распределению, поскольку в js нет метода случайного нормального распределения. Давайте сначала определим набор жестко закодированных данных для демонстрации. Конечно, вы можете использовать случайный диапазон данных. Просто данные очень дискретны. Недостаточно интуитивно понятно.

const x= [13,18,23,36,42,48,58,72,85,94] //x轴 对应房子的平方
const y =[18,25,39,47,32,59,73,87,83,94] //y轴 对应房子的价格
const LEARNING_RATE = 0.0003; //学习率
let w = 0; //权重
let b = 0; //偏置
  1. определить линейную модель
const hypothesis = x => w * x + b;
  1. Определим функцию потерь и получим следующий код по формуле MSE
const LossFuc = () => {
  let sum = 0;

  for (let i = 0; i < M; i++) {
    //MSE
    sum += Math.pow(hypothesis(x[i]) - y[i], 2);
  }
  return sum / (2 * M);
}
  1. Определите метод вычисления градиента
const gradient=(arg,deriv)=>arg - LEARNING_RATE * (deriv / M)

5. Определите метод обучения

const training = () => {
  let bSum = 0;
  let wSum = 0;
  //计算loss并求偏导
  for (let i = 0; i < M; i++) {
    //对w求偏导
    wSum += (hypothesis(x[i]) - y[i]) * x[i];
    //对b求偏导
    bSum += hypothesis(x[i]) - y[i];
  }
  //计算梯度,更新参数,并反向传播数据
  w = gradient(w,wSum);
  b = gradient(b,bSum);
}

image.png

в заключении:Мы говорили обо всем процессе машинного обучения выше и нарисовали блок-схему следующим образом:

截屏2021-08-01下午4.52.46.png

Пожалуйста, имейте в виду весь описанный выше процесс, который будет часто использоваться в будущем, который может становиться все более и более сложным, но он также основан на этой основе.

Код загружен в codeandboxдемонстрационный адрес

Мы обнаружили, что код машинного обучения написан на нативном js. Необходимость инкапсулировать эти математические формулы самостоятельно — это просто резать и сжигать. Если в будущем потребуется глубокое обучение с использованием нейронных сетей, этих CNN или RNN, GAN и других алгоритмов, код будет очень сложным и трудным для понимания. Поэтому нам нужны фреймворки для решения таких проблем. Для фронтенд-людей давайте посмотрим, есть ли в javascript фреймворк для машинного обучения. Здесь я думаю о TensorflowJS. Далее давайте посмотрим, сможет ли TensorflowJS хорошо решить нашу проблему.

Линейная регрессия с TensorflowJs

Теперь давайте преобразуем приведенный выше код и используем TensorflowJs для линейной регрессии, чтобы посмотреть, улучшится ли он. Первым делом я отправился изучать официальную документацию. Прежде всего, я нашел более сложную задачу. Все типы в TensorflowJs относятся к тензорному типу, как нам преобразовать тензорный тип в обычный нативный тип js. Это не похоже на то, что python может играть с типами numpy. В это время я обнаружил, что у тензорного типа есть метод dataSync, который может нам помочь.

Чтобы решить эту проблему, давайте установим нашу первоначальную идею написания js. Сначала определите обучающие данные и гиперпараметры, инициализируйте w и b случайным образом

const trainX= [13,18,23,36,42,48,58,72,85,94]
const trainY =[18,25,39,47,32,59,73,87,83,94]
const LEARNING_RATE = 0.0003;
const w = tf.variable(tf.scalar(Math.random()));//使用tf.variable代表可训练的参数
const b = tf.variable(tf.scalar(Math.random()));

Здесь, возможно, потребуется объяснить некоторые предварительные знания, потому что машинное обучение имеет матричные операции, включающие некоторые преобразования данных, что такое скаляры, тензоры, векторы, матрицы, сложение матриц, вычитание, умножение и деление, транспонирование, трансляция и другие оперативные знания. Если вы не понимаете эти знания, вы можете рассказать об этом в отдельной статье позже.

Определение расчетов линейной модели

function predict(x) {
  return tf.tidy(function() { //使用tidy会执行CG动作
    return w.mul(x).add(b); //tensor类型默认提供一些计算方法。
  });
}

Мы обнаружили, что tensorflowjs — это функциональный стиль программирования.

Определите функцию потерь MSE (среднеквадратичная ошибка) вычисления

//损失函数,MSE
function loss(prediction, labels) {
    const error = prediction
      .sub(labels)
      .square()
      .mean();
    return error;
}

Наконец определитесь с основным методом тренировки

function training() {
    //sgd算法 随机梯度下降
    const optimizer = tf.train.sgd(LEARNING_RATE);
    //自动求导
    optimizer.minimize(function() {
      const predsYs = predict(tf.tensor1d(trainX));
      stepLoss = loss(predsYs, tf.tensor1d(trainY));
      return stepLoss;
    });
}

Из приведенного выше алгоритма оптимизации функции потерь и градиентного спуска мы видим, что он намного проще, чем исходная реализация, и ему не нужно зацикливаться и накапливаться самостоятельно, и его не нужно получать самостоятельно. TensorflowJS предоставляет методы и оптимизаторы для автоматического вывода. Читаемость кода лучше, чем чистый способ js. Так что это все еще обеспечивает некоторое удобство.

Окончательная реализация по-прежнему отображается с помощью реакции. Конечно, международная практика заключается в том, чтобы вставить демо-код.codesandbox

Решение задач линейной регрессии с использованием нейронных сетей

Где TensorflowJS действительно эффективен, так это в глубоком обучении с помощью нейронных сетей. Может быть, некоторые студенты не знают нейронную сеть, не беда, давайте посмотрим заранее, есть простая концепция. Если нейронная сеть используется для решения задачи линейной регрессии. Хотя это немного похоже на убийство курицы ножом мясника. Но видно, что нейронные сети могут решать не только большие задачи, но и простые задачи. Поэтому существует множество курсов глубокого обучения, которые начинаются непосредственно с нейронных сетей. Но я не люблю этот путь, я предпочитаю говорить шаг за шагом.

Без лишних слов давайте посмотрим, как использовать нейронные сети для решения задач линейной регрессии. Код станет более лаконичным. Поэтому я не буду объяснять это по частям, просто опубликую все сразу. Я буду говорить об этом медленно в следующих статьях.


const model = tf.sequential(); //定义模型,采用神经网络的顺序模型
const nr_epochs = 10;
const x = [13, 18, 23, 36, 42, 48, 58, 72, 85, 94]
const y = [18, 25, 39, 47, 32, 59, 73, 87, 83, 94]
const xs = tf.tensor2d(x,[10,1]);
const ys = tf.tensor2d(y,[10,1]);
const LEARNING_RATE = 0.0001; //学习率
let w = 0
let b = 0

function initModel(cb) {
  model.add(tf.layers.dense({ units: 1, inputShape: [1] })); //我们的问题非常简单,只需要单层神经网络即可
  model.setWeights([tf.tensor2d([w], [1, 1]), tf.tensor1d([b])]); //标记后面要跟踪的参数
  const optimizer = tf.train.sgd(LEARNING_RATE);//梯度下降优化
  model.compile({ loss: 'meanSquaredError', optimizer: optimizer });
  model.fit(xs, ys, {   //开始训练
    epochs: nr_epochs, callbacks: {
      onEpochEnd: (epoch, logs) => { //处理每个epoch的回调
        w = model.getWeights()[0].dataSync()[0];
        b = model.getWeights()[1].dataSync()[0];
        cb()
      }
    }
  });
}

Обучение этой нейронной сети непрерывное, поэтому мы не можем управлять ею через область кнопок. Обратный вызов onEpochEnd может отслеживать ход выполнения каждого пакета цикла. Пример линейной регрессии нейронной сетиcodesandbox

Вопросы для размышления каждого

  1. Что нам делать, если наши обучающие выборки имеют большую разницу в данных?
  2. Что произойдет, если скорость обучения будет слишком большой или слишком маленькой, как мы можем оптимизировать скорость обучения?
  3. Если у нас много образцов, как нам тренироваться и как оптимизировать?
  4. Как следует проводить полиномиальную регрессию?
  5. Как сделать логистическую регрессию?

Последнее, что я хочу сказать о TensorflowJS.

TensorflowJS больше подходит для трансферного обучения, он не подходит для обучения крупномасштабных моделей. По сравнению с зрелостью и сторонней поддержкой, это удобнее, чем python.С точки зрения синтаксиса, матричная работа все же более освежает. А TensorflowJS непопулярен, с меньшим количеством учебных материалов, в отличие от python, учебных материалов много. Но, основываясь на модели, делать что-то небольшое, я думаю, это нормально, и это также может работать в nodejs. Так что в целом, если вы очень хорошо знакомы с JS и модель проста, рассмотрите ее. Ладно, начнем, спасибо всем, что досмотрели до конца.