Научитесь создавать, обучать и оценивать модель нелинейной регрессии для нескольких функций в браузере.
Машинное обучение, благодаря своим вычислительным возможностям, теперь является ключевым фактором, способствующим новому уровню технологических прорывов. Возможности и опыт интерактивного машинного обучения могут стать областью огромных масштабов в будущем. В результате в последние несколько лет машинное обучение стало развиваться и для Интернета.
В этой статье мы обсудим Tensorflow.js, браузерную JS-библиотеку с ускорением WebGL для обучения и развертывания моделей машинного обучения. . С помощью WebGL он использует возможности видеокарты в браузере, поскольку он может обрабатывать матричные операции аналогично графическому процессору.
Теперь, зачем нам ML в браузере?
- ML в браузере будет использовать преимущества взаимодействия с пользователем
- Будет использовать такие функции устройства, как камеры
- Он использует вычислительную мощность устройства, а не что-либо размещенное в облаке, и это делает машинное обучение в браузере более безопасным.
Что такое тензоры? Тензоры подобны матрицам, как многомерному массиву.
Тензор - это то, что имеет значения, размер, форму и тип данных.
Ниже представлена документация по API для tensorflow.js, так как в этой статье мы не можем углубляться в возможности API-интерфейса tensorflow.js.
Https://js.tensorflow.org/api/latest/
Эта статья больше похожа на стартовую страницу для обычного JS-разработчика, которая может познакомиться с возможностями tensorflow.js в браузере.
Приступим,
Создание простой модели нелинейной регрессии для цены подержанного автомобиля Audi на основе заданного набора данных.
Набор данных был загружен с Kaggle, крупнейшего сообщества машинного обучения.
Ниже приводится подробная информация о наборе данных, который вы можете скачать по указанной ссылке. В этом решении мы выбрали audi.csv для создания и оценки модели.
https://www.kaggle.com/adityadesai13/used-car-dataset-ford-and-mercedes
Для модели ML нам нужно выбрать особенности входных тензоров и меток, выходных тензоров.
Прежде всего добавьте tensorflow.js через cdn или через npm, как указано ниже.
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs/dist/tf.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-vis"></script> //OR npm i @tensorflow/tfjs
Анализируя данные, мы можем увидеть, что и пробег, и миль на галлон имеют некоторую связь с ценой автомобиля, поскольку оба обратно пропорциональны цене. Чтобы потреблять данные, нам нужно их обслуживать. Этого можно добиться, установив http-сервер и запустив http-сервер из папки, в которой сохранены данные.
npm i -g http-server
Давайте построим график зависимости характеристик от цены и посмотрим на корреляцию на графике.
// Import data const audi_data = tf.data.csv(“http://127.0.0.1:8080/audi.csv"); // Extract x and y values to plot in graph const dataSet = audi_data.map(record => ({ x: record.mileage, y: record.price, })); const points = await dataSet.toArray(); plot(points, “Mileage”);
Теперь определите функцию построения графика как,
async function plot(pointsArray, featureName) { tfvis.render.scatterplot( { name: `${featureName} vs Car Price` }, { values: [pointsArray], series: [“original”] }, { xLabel: featureName, yLabel: “Price”, } ) }
Теперь давайте посмотрим, насколько эффективными могут быть обе функции и будет ли модель эффективно увеличиваться за счет объединения обеих функций.
Весь процесс можно разделить на 5 простых шагов
1. Извлечь элементы и метки
2. Нормализовать элементы и метки
3. Создать модель
4. Обучить модель
5. Оцените модель.
Случай 1: давайте оценим модель, используя пробег как функцию.
Как мы уже объяснили, как импортировать данные, мы можем сразу перейти к этапу извлечения признаков и меток. Прежде чем перейти к извлечению, нам нужно определить функцию нормализации. Это преобразует весь набор данных во что-то в диапазоне от 0 до 1, где 0 - самое низкое значение в наборе данных, а 1 - самое высокое значение. Также обратите внимание, что максимальное и минимальное значения, которые нам могут потребоваться для денормализации данных в будущем для прогноза, поскольку нам может потребоваться преобразовать данные обратно в их нормальное значение.
function normalise(tensor) { const min = tensor.min(); const max = tensor.max(); const normalisedTensor = tensor.sub(min).div(max.sub(min)); return { tensor: normalisedTensor, min, max }; }
Извлеките и нормализуйте тензоры признаков и меток, как показано ниже:
//Shuffle tf.util.shuffle(points); // Extract Features (inputs) const featureValues = points.map(p => p.x); const featureTensor = tf.tensor2d(featureValues, [featureValues.length, 1]); // Extract Labels (outputs) const labelValues = points.map(p => p.y); const labelTensor = tf.tensor2d(labelValues, [labelValues.length, 1]); // Normalise features and labels const normalisedFeature = normalise(featureTensor); const normalisedLabel = normalise(labelTensor);
Чтобы оценить модель, нам нужно разделить функции и метки на наборы для обучения и тестирования, как показано ниже.
const [trainingFeatureTensor, testingFeatureTensor] = tf.split(normalisedFeature.tensor, 2); const [trainingLabelTensor, testingLabelTensor] = tf.split(normalisedLabel.tensor, 2);
Теперь давайте создадим модель машинного обучения.
В tensorflow.js мы можем создавать собственные модели с помощью основных API для операций низкого уровня или использовать API слоев высокого уровня. В нашем примере мы используем Layers API Tensorflow.js для создания последовательной модели, как показано ниже.
function createModel() { model = tf.sequential(); model.add(tf.layers.dense({ units: 1, useBias: true, activation: 'sigmoid', inputDim: 1 })); model.compile({ loss: 'meanSquaredError', optimizer: tf.train.adam() }); return model; }
Здесь мы можем добавить столько плотных слоев и единиц, что может увеличить сложность модели и процесс обучения. Это также может замедлить процесс обучения, но может быть полезно для сложных наборов данных. Функция активации может быть линейной (линейная регрессия), сигмоидной (нелинейная регрессия) и т. Д. Для шаблонов кривых в наборе данных целесообразно использовать сигмоид с большим количеством слоев, поскольку это может обеспечить лучшее соответствие модели фактическому набору данных. После определения слоев нам нужно указать функцию потерь и оптимизатор, чтобы минимизировать потери.
Здесь мы добавили только один слой из 1 единицы. Обратите внимание на inputDim как 1, так как у нас есть только 1 функция в тензоре признаков.
В tensorflow.js доступны различные функции оптимизации, такие как Stochastic Gradient Descent, Adam и т. Д., В которых Adam является оптимизатором, не требующим скорости обучения. Он сам регулирует скорость обучения.
Теперь используйте функцию createModel, чтобы создать нашу модель в функции main.
//Create Model const model = createModel();
Теперь модель поезда 4-го шага также может быть записана в отдельной функции, как показано ниже, и использоваться в нашей основной функции.
async function trainModel(model, trainingFeatureTensor, trainingLabelTensor) { const { onBatchEnd, onEpochEnd } = tfvis.show.fitCallbacks({ name: "Training Performance" },['loss']); return model.fit(trainingFeatureTensor, trainingLabelTensor, {batchSize: 32, epochs: 20, validationSplit: 0.2, callbacks: { onEpochEnd, }}); }
Функция принимает модель, тензор признаков и тензор меток. Здесь мы указали 20% набора данных для процесса проверки, чтобы избежать переобучения.
Оптимизация происходит в конце каждого размера партии. Размер пакета - это параметр, который контролирует количество обучающих выборок, которые необходимо проработать перед обновлением внутренних параметров модели. Количество эпох - это параметр, который контролирует количество полных итераций для данного набора данных.
Теперь мы можем использовать функцию обучения для обучения набора данных, как показано ниже.
//Train Model const result = await trainModel(model, trainingFeatureTensor, trainingLabelTensor);
Давайте посмотрим на потерю обучения и потерю проверки в консоли, добавив следующие строки.
const trainingLoss = result.history.loss.pop(); console.log(`Training loss: ${trainingLoss}`); const validationLoss = result.history.val_loss.pop(); console.log(`Validation loss: ${validationLoss}`);
Наконец, мы можем оценить нашу модель с помощью
//Evaluate Model const lossTensor = model.evaluate(testingFeatureTensor, testingLabelTensor); const loss = await lossTensor.dataSync(); console.log(`Testing loss: ${loss}`);
И наша основная функция должна выглядеть примерно так, как показано ниже.
async function main() { // Import data const audi_data = tf.data.csv(“http://127.0.0.1:8080/audi.csv"); // Extract x and y values to plot in graph const dataSet = audi_data.map(record => ({ x: record.mileage, y: record.price })); const points = await dataSet.toArray(); //Shuffle tf.util.shuffle(points); // Extract Features (inputs) const featureValues = points.map(p => p.x); const featureTensor = tf.tensor2d(featureValues, [featureValues.length, 1]); // Extract Labels (outputs) const labelValues = points.map(p => p.y); const labelTensor = tf.tensor2d(labelValues, [labelValues.length, 1]); // Normalise features and labels const normalisedFeature = normalise(featureTensor); const normalisedLabel = normalise(labelTensor); //Split testing and training tensors for features and labels const [trainingFeatureTensor, testingFeatureTensor] = tf.split(normalisedFeature.tensor, 2); const [trainingLabelTensor, testingLabelTensor] = tf.split(normalisedLabel.tensor, 2); //Create Model const model = createModel(); //Train Model const result = await trainModel(model, trainingFeatureTensor, trainingLabelTensor); const trainingLoss = result.history.loss.pop(); console.log(`Training loss: ${trainingLoss}`); const validationLoss = result.history.val_loss.pop(); console.log(`Validation loss: ${validationLoss}`); //Evaluate Model const lossTensor = model.evaluate(testingFeatureTensor, testingLabelTensor); const loss = await lossTensor.dataSync(); console.log(`Testing loss: ${loss}`); }
Ниже приведены результаты обучения и тестирования модели на пробег.
Случай 2. Давайте оценим модель, используя миль на галлон в качестве функции.
Мы можем изменить функцию импорта данных, как показано ниже, и выполнить все остальные шаги или повторно использовать тот же код для миль на галлон в качестве функции.
// Import data const audi_data = tf.data.csv(“http://127.0.0.1:8080/audi.csv"); // Extract x and y values to plot in graph const dataSet = audi_data.map(record => ({ x: record.mpg, y: record.price, })); const points = await dataSet.toArray(); plot(points, “MPG”);
Выполнив те же шаги, что и при оценке модели характеристик пробега, мы можем получить результаты, как показано ниже.
Случай 3. Давайте оценим модель, используя и пробег, и миль на галлон в качестве характеристик для модели прогнозирования цен. Ниже приводится обновленная основная функция для нескольких функций, поскольку нормализация должна выполняться для каждого тензора функций. Комбинирование обеих функций и нормализации приведет к неверным результатам прогноза.
const dataSet = audi_data.map((record) => ({ x1: record.mpg, x2: record.mileage, y: record.price })); const points = await dataSet.toArray(); //Shuffle tf.util.shuffle(points); // Extract and normalise features const normalisedFeature1 = normalise(tf.tensor2d(points.map((p) => [p.x1]))).tensor.dataSync(); const normalisedFeature2 = normalise(tf.tensor2d(points.map((p) => [p.x2]))).tensor.dataSync(); const normFeatureInput = []; normalisedFeature1.forEach((item, i, self) => {normFeatureInput.push([normalisedFeature1[i], normalisedFeature2[i]])}) // Extract and normalise Labels (outputs) const labelValues = points.map(p => p.y); const labelTensor = tf.tensor2d(labelValues, [labelValues.length, 1]); const normalisedLabel = normalise(labelTensor); //Training and testing data sets const [trainingFeatureTensor, testingFeatureTensor] = tf.split(normFeatureInput, 2); const [trainingLabelTensor, testingLabelTensor] = tf.split(normalisedLabel.tensor, 2); //Create Model const model = createModel(); //Train Model const result = await trainModel(model, trainingFeatureTensor, trainingLabelTensor); const trainingLoss = result.history.loss.pop(); console.log(`Training loss: ${trainingLoss}`); const validationLoss = result.history.val_loss.pop(); console.log(`Validation loss: ${validationLoss}`); //Evaluate Model const lossTensor = model.evaluate(testingFeatureTensor, testingLabelTensor); const loss = await lossTensor.dataSync(); console.log(`Testing loss: ${loss}`);
Следует отметить одну вещь: при создании модели для количества элементов n входной размер также должен быть n. В нашем случае inputDim должен быть 2. Перепишите функцию создания модели, как показано ниже
function createModel() { model = tf.sequential(); model.add(tf.layers.dense({ units: 1, useBias: true, activation: 'sigmoid', inputDim: 2, })); model.compile({ loss: 'meanSquaredError', optimizer: tf.train.adam() }); return model; }
Ясно, что мы можем увидеть некоторое повышение эффективности, объединив две функции, а не одну. Также обратите внимание, что, используя два плотных слоя и 10 единиц во входном слое модели, как показано ниже, мы можем еще больше повысить эффективность модели. Обратите внимание, что единица выходного слоя должна соответствовать размеру метки. Поскольку у нас есть только 1 этикетка (цена), единицы второго уровня должны быть 1.
function createModel() { model = tf.sequential(); model.add(tf.layers.dense({ units: 10, useBias: true, activation: 'sigmoid', inputDim: 2, })); model.add(tf.layers.dense({ units: 1, useBias: true, activation: 'sigmoid', })); model.compile({ loss: 'meanSquaredError', optimizer:tf.train.adam() }); return model; }
Ниже приведены потери при обучении, проверке и тестировании новой модели с двумя входными характеристиками (пробег и миль на галлон) и двумя уровнями.
Надеюсь, эта статья окажется полезной для новичков в tensorflow.js. Удачного кодирования :)