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


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


Коротко:


Предполагаем, что на достаточно коротком отрезке траектория полёта укладывается в кривую Безьe, по нескольким точкам догадываемся о характеристиках кривой и используем её для предсказаний.


  1. Один процесс собирает датасет с координатами и обучает нейросеть
  2. Второй процесс имея предыдущие координаты, собственно, делает предсказание, выдаёт координаты в будущем.

Для простоты считаем, что у нас есть 5 координат в прошлом: T-4, T-3, T-2, T-1, и T-0 и расстояние по времени между ними одинаковое. Если говорить строго, то в реальной жизни так не бывает, потому что кадры с видео приходят с разной задержкой, не на всех кадрах можно распознать объект и т.д., потому кроме координат по-хорошему надо обрабатывать и временную метку. Выносим это за пределы статьи и будем оперировать только с плоскими координатами.


Итак, считаем что у нас есть координаты пикселей для каждой из T.


Датасет в CSV выглядит вот так:


filename, x_t+1, y_t+1, x_t-0, y_t-0, x_t-1, y_t-1, x_t-2, y_t-2, x_t-3, y_t-3, x_t-4, y_t-4 

kxs2ut1j, -0.003441, -0.006477,  0.000000,  0.000000, -0.076425,  0.012893, -0.232717,  0.032203, -0.468875,  0.057928, -0.784900,  0.090070

Это координаты относительные к точке T-0. То есть мы считаем что T-0 всегда находится ровно в середине кадра с координатами 0,0; при этом -0.5, -0.5 это левый-верхний угол кадра, +0.5, +0.5 это правый-нижний угол кадра.


В качестве инструментов используем JavaScript и библиотеку brain.js


Но почему JavaScript?

Я пробовал идентичный код в питоне+tensorflow, JavaScript+tensorflow.js и выяснилось, что JavaScript+brain.js запускается существенно быстрее, отрабатывает быстрее, потребляет существенно меньше памяти и при этом ещё и в обычном браузере на клиенте отлично работает.
Цифр замеров у меня не сохранилось, но разница — в разы.
В общем, для этой конкретной задачи brain.js подходит замечательно.


Объявим зависимости


const brain = require("brain.js");
const fs = require("fs");

Проинициализируем примитивную fully-connected нейросеть в один слой и три нейрона. Если есть пред-тренированные веса, загружаем их


const config = {
  binaryThresh: 0.5,
  hiddenLayers: [3], // array of ints for the sizes of the hidden layers in the network
  activation: "sigmoid", //supported activation types: ["sigmoid", "relu", "leaky-relu", "tanh"],
  learningRate: 0.000003, // scales with delta to effect training rate --> number between 0 and 1
  momentum: 0.01,
  log: true,
  logPeriod: 1,
  iterations: 1000, //number of iterations per epoch
  errorThresh: 0.0000005,
};

const net = new brain.NeuralNetwork(config);

//if there are weights saved from the previous run, fetch them
if (fs.existsSync("brain")) { 
  let json = JSON.parse(fs.readFileSync("brain"));
  net.fromJSON(json);
  console.log("Reused the weights from the brain trained last time");
}

Прочитаем наш датасет из csv файла


const data = fs.readFileSync("./dataset/data.csv", "UTF-8");

// split the contents by new line
let lines = data.split(/\r?\n/);

Создадим два массива с датасетом: в input пойдут координаты T-4… T-0, в output пойдут координаты T+1


let dataset = [];

lines.forEach((line) => {
  let raw = line.split(",");
  let rec = {
    input: [],
    output: []
  };

  for (let i = 1; i < raw.length; i++)
    raw[i] = (parseFloat(raw[i]) +1) / 2;

  rec.input.push(raw[3]); //present coordinates T-0
  rec.input.push(raw[4]);
  rec.input.push(raw[5]); //past coordinates T-1
  rec.input.push(raw[6]);
  rec.input.push(raw[7]); //past coordinates T-2
  rec.input.push(raw[8]);
  rec.input.push(raw[9]); //past coordinates T-3
  rec.input.push(raw[10]);
  rec.input.push(raw[11]); //past coordinates T-4
  rec.input.push(raw[12]);

  rec.output.push(raw[1]); //future coordinates T+1
  rec.output.push(raw[2]);

  dataset.push(rec);
});

Запускаем обучение. На моём лаптопе обучение в тысячу итераций с сотней датапоинтов занимает всего 38ms без использования GPU.
Для объектов летящих по баллистической траектории достаточно данных со ста кадров. Для активно маневрирующих объектов — чуть больше.


console.time("training");
net.train(dataset);
console.timeEnd("training");
fs.writeFileSync("brain", JSON.stringify(net.toJSON())); //save the weights

Результат налицо:


imageimageimage


Тут зелёным показаны прошлые точки, жёлтым реальная координата в будущем, красным — предсказанная координата.


То есть за всего 38 несчастных миллисекунд и с помощью данных со ста кадров мы научили нейросетку предсказывать координату со вполне себе достаточной точностью. Если вы можете позволить себе потратить ещё 38мс то можно прогнать ещё цикл, предсказание станет ещё точнее.


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


Весь код и синтетический датасет для иллюстрации, конечно, на гитхабе.

Комментарии (23)


  1. S_A
    30.12.2021 07:16
    +1

    За идею применения нейросетки, да и саму сформулированную задачу в целом - спасибо :)

    В продолжение вашего интереса погуглите PredNet, MOT Challenge.


  1. Ergistael
    30.12.2021 08:56

    Довольно философский вывод. Кстати, как-то в школе на уроке физики я выразил мысль, что задача науки - предсказать (будущее, процесс, динамику, итог), но учитель поправил меня, сказав, что задача науки все-таки объяснить, а предсказать - это просто хороший дополнительный эффект (помимо проверки).


    1. haqreu
      31.12.2021 00:09
      +1

      Herbert Simon distinguished between “basic science” and “applied science”, a distinction similar to explaining versus predicting. According to Simon, basic science is aimed at knowing (“to describe the world”) and understanding (“to provide explanations of these phenomena”). In contrast, in applied science, “Laws connecting sets of variables allow inferences or predictions to be made from known values of some of the variables to unknown values of other variables.”

      https://www.stat.berkeley.edu/~aldous/157/Papers/shmueli.pdf


  1. cry_san
    30.12.2021 09:25
    +2

    Сделайте мне такой прицел на ружьё. А то устаешь целиться по уткам.

    Буду ловить их спокойно в последней точке.

    Спасибо.


    1. sappience
      31.12.2021 03:09
      +4

      Здравствуйте! Я - утка. Сделайте мне, пожалуйста, нейросетевой предсказыватель места куда будет произведен следующий выстрел. Чтоб я могла его облетать.


  1. dirijabla
    30.12.2021 09:33
    +4

    А зачем нейросеть, нельзя ли просто на каждом шаге аппроксимироваь точки теми же кривыми Безье, предварительно распознавая точку, и результат будет тем же? Или там несопоставимо будут различаться затраты на вычисления, а на сколько?


    1. Aspos Автор
      30.12.2021 14:32

      Да, и это пробовали. Код высчитывающий кривую Безье получается гораздо сложнее.


  1. Nehc
    30.12.2021 09:50

    >>> Проинициализируем примитивную fully-connected нейросеть в три скрытых слоя

    Вообще-то в один скрытый слой, размером 3 нейрона. ;)


    1. Aspos Автор
      30.12.2021 14:23

      Да, разошёлся текст с примером. Поправил. Спасибо!


  1. AlexeyALV
    30.12.2021 10:30
    +1

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


  1. Arastas
    30.12.2021 12:32
    +8

    Простейшая задача экстраполяции, и тут нейросетка. Скорее грустно.


    1. Aspos Автор
      30.12.2021 14:30
      +2

      Нет тут поводов для грусти! Экстраполяция - первое что я попробовал. Методов много, параметров тоже, код быстро превращается в монстра. Полёт теннисного шарика такой код предсказать ещё может, а зигзаг мухи - уже нет.

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

      Этот же подход -- более общее решение практически применимое во множестве случаев. И кода тут считай что нет, объяснять и значит поддерживать его намного проще.


  1. evasilenko
    30.12.2021 14:10

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

    А по моему идея класс. Просто недопилена. Нужно было сначала распознать тип обьекта отдельной нейронной сетью, а затем использоаювать отдельную нейронку чисто для этого типа. Для некоторых обьектов лучше не нейронку, а жёсткий алгоритм - так точнее будет.

    Достоинство в том, что нейронкой можно апроксимировать то, что ничем другим нельзя. Например, стрекоза - 4 крыла с отдельным асинхронным управлением творят чудеса аэродинамики, там никаких уравнений не напасешься.


    1. Arastas
      30.12.2021 14:24
      +2

      Достоинство в том, что нейронкой можно апроксимировать то, что ничем другим нельзя.

      Неправда. Существует множество универсальных аппроксиматоров.


    1. haqreu
      31.12.2021 00:14
      +1

      В нейронных сетях магии нет. Вы определяете пространство функций, и в его рамках работаете. Абсолютно всё, что можно сделать при помощи нейронных сетей, можно сделать и другими методами (внимание: я не утверждаю, что [на данный момент] это будет выгоднее).


      1. evasilenko
        31.12.2021 14:46

        И всё же нет.

        Вот представьте себе что исходный объект - это настоящая нейронная сеть. Автор в принципе указал в насекомых. Как понять как стрекоза будет шарахаться? Это как раз тот уровень, что наши нейронные сети могут осилить. Хотя там всё тоже не просто. Савельев рассказывал, что у насекомых нейроны сильно более трёхмерные чем у нас (слоёв в разы больше), поэтому гораздо меньший массив способен на сильно большее. Мы берём большой площадью коры головного мозга. Но если пытаться моделировать не всю стрекозу, а только её двигательный аппарт - то может и справимся.

        Ну и чем лучше всего натeральную нейронную сеть моделировать как не искуственной нейронной сетью? Ну очевидно же что всё другое менее эффективно.


        1. haqreu
          01.01.2022 11:02
          +1

          Нет, извините, неочевидно. Кроме того, вы уводите разговор в сторону: разговор не шёл об эффективности, но о невозможности аппроксимировать какую-то функцию чем-то иным, нежели нейронной сетью.


          1. evasilenko
            01.01.2022 19:56
            -1

            Никуда я не ухожу. С самого начала сказал, что не всё нужно моделировать нейронной сетью. Конечно полёт снаряда точнее и эффективнее моделировать несколькими дифференциальными уровнениями.

            Натуральную нейронную сеть (автор статьи заявил насекомых) таки лучше моделировать искуственной нейронной сетью.


            1. Arastas
              01.01.2022 20:59
              +1

              То, что называется нейронкой, не имеет к реальной физиологии практически никакого отношения, кроме названия.


  1. MzMz
    30.12.2021 21:07
    +1

    Тут были статьи про фильтры Калмана - они также оптимально предсказывают, если есть модель процесса.


    1. haqreu
      31.12.2021 00:15
      +2

      Осталось определить слово оптимально :)


      1. MzMz
        31.12.2021 00:55

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

        это википедия говорит - я к сожалению не совсем математик, эти фильтры пацаны синтезировали, а я просто рядом стоял.


        1. haqreu
          31.12.2021 01:03
          +2

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