In one of my classes we created a program that randomly creates 10 cars with the price and star rating. Right now the program creates the 10 objects and then creates another object that it compare the 10 to. It searches by the star rating, sorts the 10 by star rating, then runs a binary search on the 10 objects. I have been trying to improve on it by adding in the car manufacturer name to each object but keep messing up the program. The program has two classes
import java.util.*;
import java.util.Scanner;
public class Sorter{
static Car [] ary; // declare
final static int NUM_CARS = 10;
public static void main() {
//Scanner rating = new Scanner(System.in);
//int r = rating.nextInt();
Car key = new Car();
ary = new Car[NUM_CARS]; // initialize
int i;
int position;
for (i=0; i<NUM_CARS; i++) {
ary [ i ] = new Car();
}
System.out.println("Unsorted:");
System.out.println(Arrays.toString(ary));
System.out.println("Sequential search for " + key);
ary[0].reset();
position = sequentialSearch(key)+1; //add one to the index position to display the position on screen that the user's desired search is first found
System.out.println("Total comparisons: "
+ ary[0].getAllCount());
System.out.println("Found a position: " +position);
System.out.println();
System.out.println("Sorted:");
ary[0].reset();
Arrays.sort(ary);
System.out.println("Total comparisons: "
+ ary[0].getAllCount());
System.out.println(Arrays.toString(ary));
System.out.println("Binary search for " + key);
ary[0].reset();
position = binarySearch(key)+1; //add one to the index position to display the position on screen that the user's desired search is first found
System.out.println("Found a position: " +position);
System.out.println("Total comparisons: "
+ ary[0].getAllCount());
}
public static int binarySearch (Car keyCar) {
return Arrays.binarySearch(ary,keyCar);
}
public static int sequentialSearch (Car keyCar) {
int pos = -1;
int i;
int answer;
for (i=0; i<ary.length; i++) {
answer = ary[i].compareTo(keyCar);
if (answer==0) {
pos = i;
break;
}
}
return pos;
}
}
Second class
import java.util.*;
/**
* in class work
*/
public class Car implements Comparable<Car> {
// instance variables - replace the example below with your own
int stars;
double price;
String name [] = {"Ford", "Dodge", "Chevrolet", "Honda", "Toyota", "VW", "Hyundai"};
int myCounter;
static int allCounter;
/**
* Constructor for objects of class Sorter
*/
public Car() {
Random generator = new Random ();
price = generator.nextDouble()*50000 + 50000;
stars = generator.nextInt(5)+1;
reset();
}
public String toString()
{
return String.format("$%,7.0f(%d stars)",price,stars);
//$ put dollar sign infront
//up to 7 digits
//, puts commas
}
/**
* Resets counter to zero
*/
public void reset(){
myCounter=0;
allCounter=0;
}
public int getMyCount() {
return myCounter;
}
public int getAllCount() {
return allCounter;
}
/**
* @param other A house to compare to.
* @return Returns 0 if they are equal
*/
public int compareTo(Car other)
{
myCounter++;
allCounter++;
if (this.stars < other.stars) {
return -1;
} else if (this.stars> other.stars) {
return +1;
}
return 0; // equals
}
}
How do I make it so that the objects will display the price, star rating, and the manufacturer?
Also, another thing I’d like to do but haven’t tried yet is making it so the user can input what star rating they want and it’ll display those cars only. This part is the next thing I’d like to try when time comes around to do so.
Виртуальные машины уже давно перестали быть каким-то отвлеченным понятием и сегодня являются доступными и понятными для любого пользователя. Одной из самых необходимых в своем роде является виртуальная машина Java (JVM), которая в Windows-системах устанавливается изначально еще при первой инсталляции самой ОС. Однако довольно часто ее бывает необходимо установить самостоятельно, дополнить или обновить компоненты уже имеющейся платформы. Далее предлагается разобраться, что это вообще такое, для чего нужно, как выполнить инсталляцию необходимых компонентов самостоятельно и решить некоторые проблемы, связанные с запуском VM в Windows-системах.
Что такое виртуальная машина Java?
Начнем с определения того, что на самом деле представляет собой эта платформа, чтобы несведущие пользователи сразу сообразили, почему требуется ее обязательная установка на собственные компьютеры. В общем смысле данная платформа и ее компоненты обычно задействуются для выполнения всевозможных скриптов и апплетов, написанных на языке программирования Java, когда вы посещаете интернет-сайты, содержащие соответствующий контент. А это могут быть элементы мультимедиа во всех проявлениях, некоторые простейшие игры, дополнения для использования банковских услуг, интерактивные карты и т. д.
Кроме того, поддержка этой платформы активно используется практически во всех мобильных телефонах, несмотря даже на наличие в них собственных операционных систем. Вы когда-нибудь обращали внимание на то, что на стареньких телефонах, в которых не было современных ОС вроде Android или iOS, можно было запросто устанавливать приложения (чаще всего игры) из файлов формата JAR и JAD? Именно поддержка Java и позволяла это сделать. И сегодня такая поддержка имеется во всех мобильных системах.
Наконец, отдельно стоит отметить, что виртуальная машина Java Virtual Machine крайне необходима многим программистам и веб-дизайнерам для разработки собственных апплетов и приложений. Таким образом, становится совершенно очевидно, что иметь ее на своем компьютере необходимо в любом случае.
Однако пользователи, не разбирающиеся в тонкостях использования виртуальной машины Java, будут удивлены тем, что просто так запустить ее окажется невозможно. Да, действительно, это так и есть, поскольку сама основная исполняемая среда графического интерфейса не имеет, а использовать ее можно только посредством интеграции в веб-обозреватели, установленные на вашем компьютере или ноутбуке, или в комплекте с IDE.
Предварительная проверка установленной версии
Для начала давайте проверим, установлена в вашей системе среда Java VM. Для проверки вызовите командную консоль (cmd) любым удобным для вас методом (необязательно от имени администратора), а затем задайте на выполнение команду java –version.
Если среда установлена, отобразится информация, показанная на изображении выше, где первостепенное внимание следует обратить на версию платформы. Поскольку ее обновление в автоматическом режиме даже при установке апдейтов для самих Windows-систем производится не всегда, настоятельно рекомендуется выполнить такое обновление вручную путем загрузки необходимого контента с официальных ресурсов и последующей самостоятельно инсталляции.
Что нужно для работы?
А вообще отдельно стоит сказать, что Java Virtual Machine представляет собой только один из множества компонентов всей платформы. Так, тем, кто занимается созданием приложений, необходимо установить специализированный пакет разработчика JDK (Java Development Kit), а обычному пользователю будет достаточно только наличия исполняемой среды JRE, где создавать собственные апплеты будет невозможно, зато появится возможность запуска и использования уже готовых программ, написанный на Java. А вот если вы хотите стать квалифицированным разработчиком, может понадобиться подобрать для себя комплект IDE (на данный момент наиболее распространенными и рекомендуемыми к установке и использованию являются Eclipse и NetBeans).
Где и что скачивать для инсталляции в Windows?
Что же касается загрузки компонентов, необходимых для установки или обновления виртуальной машины Java, можете посетить сайт java.com, где в разделе загрузок сразу будет предложено загрузить установщик, соответствующий вашей операционной системе.
Если же вам нужны дополнительные компоненты, можете обратиться к ресурсу oracle.com, где на данный момент доступен полный комплект Java SE (JDK) версии 12, некоторые более ранние модификации платформы и набор NetBeans.
Здесь стоит дать небольшое пояснение, поскольку у многих пользователей могут возникнуть сомнения по поводу того, какой именно комплект скачивать, ведь на сайте представлено целых три модификации! По всей видимости, вам понадобится только версия SE, поскольку EE представляет собой среду разработки, ориентированную на предприятия, а ME – аналогичная платформа для работы с мобильными системами.
Установка виртуальной машины Java
Итак, предполагаем, что инсталлятор загружен с одного из официальных источников на пользовательский компьютер.
Теперь установщик виртуальной машины Java для Windows 10 (как в приводимом ниже примере) необходимо запустить от имени администратора (если у вас встроенный аккаунт суперпользователя не деактивирован).
В начальном окне установки ничего можно не изменять, а просто нажать кнопку подтверждения инсталляции, после чего стартует процесс копирования файлов для интеграции всех необходимых компонентов в систему.
Когда основные компоненты будут скопированы, нужно согласиться с деинсталляцией устаревших компонентов (если таковые будут обнаружены) и нажать соответствующую кнопку (Uninstall). По окончании нужно будет еще раз нажать копку продолжения, после чего появится сообщение об удачной установке.
Примечание: имейте ввиду, что апплет, отвечающий за отслеживание обновлений, сразу же будет внесен в раздел автозагрузки системы. За ненадобностью можете его отключить, воспользовавшись соответствующим разделом либо в конфигурации (msconfig) для Windows 7, либо в «Диспетчере задач» (taskmgr) для Windows 8 и 10.
Ошибка при создании платформы
Наконец, платформа установлена. Теперь обратим внимание на некоторые сбои и ошибки, которые могут появиться по завершении интеграции компонентов в систему. Самой первой и наиболее распространенной проблемой считается невозможность запуска виртуальной машины Java (для Windows последних поколений такая проблема обычно не наблюдается, а вот в неподдерживаемых более версиях систем вроде XP могут себя проявлять).
Для устранения проблемы используйте свойства компьютера, перейдите к дополнительным параметрам, войдите в раздел переменных сред, создайте новый параметр с именем и значением, показанными на изображении ниже.
В примере указываемое значение соответствует 512 Мб выделяемого объема оперативной памяти, который машине разрешено использовать. При необходимости можете его увеличить.
Ошибка при открытии разделов реестра
Иногда виртуальная машина Java для Windows 7 и выше может выдавать ошибку доступа к реестру, особенно когда она работает посредством командной строки. В этой ситуации необходимо обратиться к каталогу System32 и удалить три исполняемых EXE-файла с такими именами: java, javaw и javaws. После этого нужно просто переустановить среду, используя ранее скачанный файл установщика.
Ошибка поиска основного класса
Еще один сбой, при котором виртуальная машина самопроизвольно и в аварийном режиме завершает работу, может быть устранен следующим способом.
Сначала запустите средство поиска и удаления вредоносных программ, вписав в консоли «Выполнить» команду mrt, нажмите кнопку продолжения, а затем выберите полное сканирование. По окончании процесса полностью перезагрузите систему, затем войдите в конфигурацию (msconfig) или в «Диспетчер задач», после чего деактивируйте в списке компонент автозагрузки под названием WJView.exe. После этого рестарт системы нужно выполнить в обязательном порядке.
Ошибка открытия JAR-файлов
Наконец, ошибка, связанная с невозможностью открытия соответствующих платформе и виртуальной машине объектов формата JAR исправляется следующим способом.
В «Панели управления» (control) войдите в раздел программ по умолчанию, кликните по ссылке сопоставления типов файлов или протоколов отдельным программам, выберите из списка расширение .jar, нажмите кнопку изменения программы и выберите виртуальную машину Java. Если проблема устранена не будет, попробуйте полностью переустановить всю платформу.
Виртуальные машины уже давно перестали быть каким-то отвлеченным понятием и сегодня являются доступными и понятными для любого пользователя. Одной из самых необходимых в своем роде является виртуальная машина Java (JVM), которая в Windows-системах устанавливается изначально еще при первой инсталляции самой ОС. Однако довольно часто ее бывает необходимо установить самостоятельно, дополнить или обновить компоненты уже имеющейся платформы. Далее предлагается разобраться, что это вообще такое, для чего нужно, как выполнить инсталляцию необходимых компонентов самостоятельно и решить некоторые проблемы, связанные с запуском VM в Windows-системах.
Что такое виртуальная машина Java?
Начнем с определения того, что на самом деле представляет собой эта платформа, чтобы несведущие пользователи сразу сообразили, почему требуется ее обязательная установка на собственные компьютеры. В общем смысле данная платформа и ее компоненты обычно задействуются для выполнения всевозможных скриптов и апплетов, написанных на языке программирования Java, когда вы посещаете интернет-сайты, содержащие соответствующий контент. А это могут быть элементы мультимедиа во всех проявлениях, некоторые простейшие игры, дополнения для использования банковских услуг, интерактивные карты и т. д.
Кроме того, поддержка этой платформы активно используется практически во всех мобильных телефонах, несмотря даже на наличие в них собственных операционных систем. Вы когда-нибудь обращали внимание на то, что на стареньких телефонах, в которых не было современных ОС вроде Android или iOS, можно было запросто устанавливать приложения (чаще всего игры) из файлов формата JAR и JAD? Именно поддержка Java и позволяла это сделать. И сегодня такая поддержка имеется во всех мобильных системах.
Наконец, отдельно стоит отметить, что виртуальная машина Java Virtual Machine крайне необходима многим программистам и веб-дизайнерам для разработки собственных апплетов и приложений. Таким образом, становится совершенно очевидно, что иметь ее на своем компьютере необходимо в любом случае.
Однако пользователи, не разбирающиеся в тонкостях использования виртуальной машины Java, будут удивлены тем, что просто так запустить ее окажется невозможно. Да, действительно, это так и есть, поскольку сама основная исполняемая среда графического интерфейса не имеет, а использовать ее можно только посредством интеграции в веб-обозреватели, установленные на вашем компьютере или ноутбуке, или в комплекте с IDE.
Предварительная проверка установленной версии
Для начала давайте проверим, установлена в вашей системе среда Java VM. Для проверки вызовите командную консоль (cmd) любым удобным для вас методом (необязательно от имени администратора), а затем задайте на выполнение команду java –version.
Если среда установлена, отобразится информация, показанная на изображении выше, где первостепенное внимание следует обратить на версию платформы. Поскольку ее обновление в автоматическом режиме даже при установке апдейтов для самих Windows-систем производится не всегда, настоятельно рекомендуется выполнить такое обновление вручную путем загрузки необходимого контента с официальных ресурсов и последующей самостоятельно инсталляции.
Что нужно для работы?
А вообще отдельно стоит сказать, что Java Virtual Machine представляет собой только один из множества компонентов всей платформы. Так, тем, кто занимается созданием приложений, необходимо установить специализированный пакет разработчика JDK (Java Development Kit), а обычному пользователю будет достаточно только наличия исполняемой среды JRE, где создавать собственные апплеты будет невозможно, зато появится возможность запуска и использования уже готовых программ, написанный на Java. А вот если вы хотите стать квалифицированным разработчиком, может понадобиться подобрать для себя комплект IDE (на данный момент наиболее распространенными и рекомендуемыми к установке и использованию являются Eclipse и NetBeans).
Где и что скачивать для инсталляции в Windows?
Что же касается загрузки компонентов, необходимых для установки или обновления виртуальной машины Java, можете посетить сайт java.com, где в разделе загрузок сразу будет предложено загрузить установщик, соответствующий вашей операционной системе.
Если же вам нужны дополнительные компоненты, можете обратиться к ресурсу oracle.com, где на данный момент доступен полный комплект Java SE (JDK) версии 12, некоторые более ранние модификации платформы и набор NetBeans.
Здесь стоит дать небольшое пояснение, поскольку у многих пользователей могут возникнуть сомнения по поводу того, какой именно комплект скачивать, ведь на сайте представлено целых три модификации! По всей видимости, вам понадобится только версия SE, поскольку EE представляет собой среду разработки, ориентированную на предприятия, а ME – аналогичная платформа для работы с мобильными системами.
Установка виртуальной машины Java
Итак, предполагаем, что инсталлятор загружен с одного из официальных источников на пользовательский компьютер.
Теперь установщик виртуальной машины Java для Windows 10 (как в приводимом ниже примере) необходимо запустить от имени администратора (если у вас встроенный аккаунт суперпользователя не деактивирован).
В начальном окне установки ничего можно не изменять, а просто нажать кнопку подтверждения инсталляции, после чего стартует процесс копирования файлов для интеграции всех необходимых компонентов в систему.
Когда основные компоненты будут скопированы, нужно согласиться с деинсталляцией устаревших компонентов (если таковые будут обнаружены) и нажать соответствующую кнопку (Uninstall). По окончании нужно будет еще раз нажать копку продолжения, после чего появится сообщение об удачной установке.
Примечание: имейте ввиду, что апплет, отвечающий за отслеживание обновлений, сразу же будет внесен в раздел автозагрузки системы. За ненадобностью можете его отключить, воспользовавшись соответствующим разделом либо в конфигурации (msconfig) для Windows 7, либо в «Диспетчере задач» (taskmgr) для Windows 8 и 10.
Ошибка при создании платформы
Наконец, платформа установлена. Теперь обратим внимание на некоторые сбои и ошибки, которые могут появиться по завершении интеграции компонентов в систему. Самой первой и наиболее распространенной проблемой считается невозможность запуска виртуальной машины Java (для Windows последних поколений такая проблема обычно не наблюдается, а вот в неподдерживаемых более версиях систем вроде XP могут себя проявлять).
Для устранения проблемы используйте свойства компьютера, перейдите к дополнительным параметрам, войдите в раздел переменных сред, создайте новый параметр с именем и значением, показанными на изображении ниже.
В примере указываемое значение соответствует 512 Мб выделяемого объема оперативной памяти, который машине разрешено использовать. При необходимости можете его увеличить.
Ошибка при открытии разделов реестра
Иногда виртуальная машина Java для Windows 7 и выше может выдавать ошибку доступа к реестру, особенно когда она работает посредством командной строки. В этой ситуации необходимо обратиться к каталогу System32 и удалить три исполняемых EXE-файла с такими именами: java, javaw и javaws. После этого нужно просто переустановить среду, используя ранее скачанный файл установщика.
Ошибка поиска основного класса
Еще один сбой, при котором виртуальная машина самопроизвольно и в аварийном режиме завершает работу, может быть устранен следующим способом.
Сначала запустите средство поиска и удаления вредоносных программ, вписав в консоли «Выполнить» команду mrt, нажмите кнопку продолжения, а затем выберите полное сканирование. По окончании процесса полностью перезагрузите систему, затем войдите в конфигурацию (msconfig) или в «Диспетчер задач», после чего деактивируйте в списке компонент автозагрузки под названием WJView.exe. После этого рестарт системы нужно выполнить в обязательном порядке.
Ошибка открытия JAR-файлов
Наконец, ошибка, связанная с невозможностью открытия соответствующих платформе и виртуальной машине объектов формата JAR исправляется следующим способом.
В «Панели управления» (control) войдите в раздел программ по умолчанию, кликните по ссылке сопоставления типов файлов или протоколов отдельным программам, выберите из списка расширение .jar, нажмите кнопку изменения программы и выберите виртуальную машину Java. Если проблема устранена не будет, попробуйте полностью переустановить всю платформу.
Независимо от того, приходилось ли вам разрабатывать на Java, вы, вероятно, слышали о виртуальной машине Java (JVM).
JVM — ядро экосистемы Java. Она позволяет программам на базе Java следовать принципу “написал один раз, запустил где угодно”. Вы можете написать Java-код на одной машине и запустить его на любой другой благодаря JVM.
JVM изначально разрабатывалась исключительно для поддержки Java. Однако со временем на платформе Java обосновались многие другие языки, такие как Scala, Kotlin и Groovy. Все они в совокупности называются языками JVM.
В этой статье мы расскажем больше о JVM: как она работает и из каких компонентов состоит.
Что такое виртуальная машина?
Прежде чем переходить к JVM, остановимся на самой концепции виртуальной машины (ВМ).
Виртуальная машина — это виртуальное представление физического компьютера. Виртуальную машину можно назвать гостевой, а физический компьютер, на котором она работает, — хост-машиной.
На одной физической машине может работать несколько виртуальных, каждая со своей собственной операционной системой и приложениями. Эти виртуальные машины изолированы друг от друга.
Что такое виртуальная машина Java?
В языках программирования, таких как C и C++, код сначала компилируется в машинный для конкретной платформы. Эти языки называются компилируемыми языками.
С другой стороны, в таких языках, как JavaScript и Python, компьютер выполняет инструкции напрямую, без необходимости компиляции. Эти языки называются интерпретируемыми.
Java использует комбинацию обоих методов. Код Java сначала компилируется в байтовый код и генерирует файл класса (.class
). Этот файл класса затем интерпретируется виртуальной машиной Java для базовой платформы. Один и тот же файл класса может выполняться на любой версии JVM, на любой платформе и операционной системе.
Подобно обычным виртуальным машинам, JVM создает изолированное пространство на хост-машине. Это пространство может использоваться для выполнения Java-программ независимо от платформы или операционной системы компьютера.
Архитектура виртуальной машины Java
JVM состоит из трех отдельных компонентов:
- загрузчик классов;
- область памяти/данных среды выполнения;
- механизм выполнения.
Рассмотрим каждый из них более подробно.
Загрузчик классов
Когда вы компилируете исходный файл .java
, он преобразуется в байт-код как файл .class
. Когда вы вызываете этот класс у себя в программе, загрузчик классов загружает его в основную память.
Как правило, первым в память загружается класс, содержащий метод main()
.
Процесс загрузки класса состоит из трех этапов: загрузка, связывание и инициализация.
Загрузка
Загрузка включает бинарную репрезентацию (байт-код) класса или интерфейса с определенным именем и создание на его основе исходного класса или интерфейса.
В Java доступны три встроенных загрузчика классов:
- Загрузчик классов начальной загрузки (Bootstrap Class Loader) — корневой загрузчик классов. Это суперкласс загрузчика классов расширений, который загружает стандартные пакеты Java, такие как
java.lang
,java.net
,java.util
,java.io
и так далее. Эти пакеты находятся внутриrt.jar
и других основных библиотек, присутствующих в каталоге$JAVA_HOME/jre/lib
. - Загрузчик классов расширений (Extension Class Loader) — подкласс загрузчика классов начальной загрузки и суперкласс загрузчика классов приложений. Он загружает расширения стандартных библиотек Java, которые присутствуют в каталоге
$JAVA_HOME/jre/lib/ext
. - Загрузчик классов приложений (Application Class Loader) — конечный загрузчик классов и подкласс загрузчика классов расширений. Он загружает файлы, которые находятся в пути к классам (classpath). По умолчанию путь к классу устанавливается как текущий каталог приложения. Путь к классу также можно изменить, добавив параметр командной строки
-classpath
или-cp
.
JVM использует метод ClassLoader.loadClass()
для загрузки класса в память. Он пытается загрузить класс на основе полного имени.
Если родительский загрузчик классов не может найти класс, он делегирует работу дочернему загрузчику классов. Если последний загрузчик также не может загрузить класс, он создает исключение NoClassDefFoundError
или ClassNotFoundException
.
Связывание
После загрузки класса в память происходит процесс связывания. Связывание класса или интерфейса предполагает объединение различных элементов и зависимостей программы.
Связывание включает следующие шаги.
- Проверка. На этом этапе проверяется структурная корректность файла
.class
путем проверки его на соответствие набору ограничений и правил. Если проверка по какой-либо причине завершается неудачей, выбрасывается исключениеVerifyException
.
Например, если код был создан на Java 11, но выполняется в системе, где установлена Java 8, этап проверки завершится неудачно.
- Подготовка. На этом этапе JVM выделяет память для статических полей класса или интерфейса и инициализирует их значениями по умолчанию.
Предположим, что вы объявили в классе следующую переменную:
private static final boolean enabled = true;
На этапе подготовки JVM выделяет память для переменной enabled
и устанавливает ее значение в значение по умолчанию для логического значения, которое равно false
.
- Решение. На этом этапе символические ссылки заменяются прямыми, присутствующими в пуле констант времени выполнения.
Например, если у вас есть ссылки на другие классы или постоянные переменные, присутствующие в других классах, они разрешаются на этом этапе и заменяются их фактическими ссылками.
Инициализация
Инициализация включает выполнение метода инициализации класса или интерфейса (известного как <clinit>
). Сюда может входить вызов конструктора класса, выполнение статического блока и присвоение значений всем статическим переменным. Это заключительный этап загрузки класса.
К примеру, ранее мы объявили следующее:
private static final boolean enabled = true;
На этапе подготовки переменной enabled
было присвоено значение по умолчанию false
. На этапе инициализации этой переменной присваивается ее фактическое значение true
.
Примечание: JVM имеет многопоточный характер. Может случиться так, что несколько потоков одновременно пытаются инициализировать один и тот же класс. Это может привести к проблемам параллелизма. Чтобы гарантировать правильную работу программы в многопоточной среде, необходимо обеспечить потокобезопасность.
Область данных среды выполнения
В области данных среды выполнения есть пять компонентов:
Рассмотрим каждый из них в отдельности.
Область метода
Здесь хранятся все данные уровня класса, такие как пул констант времени выполнения, данные полей и методов, а также код методов и конструкторов.
Если памяти, доступной в области метода, недостаточно для запуска программы, JVM выдает ошибку OutOfMemoryError
.
Например, предположим, что мы объявили следующий класс:
public class Employee { private String name;
private int age;
public Employee(String name, int age) {
this.name = name;
this.age = age;
}
}
В этом примере данные уровня поля, такие как name
и age
, а также сведения о конструкторе загружаются в область метода.
Область метода создается при запуске виртуальной машины, и на каждую виртуальную машину приходится только одна область метода.
Область кучи
Здесь хранятся все объекты и соответствующие им переменные экземпляра. Это область данных времени выполнения, из которой выделяется память для всех экземпляров классов и массивов.
Например, предположим, вы объявили следующий экземпляр:
Employee employee = new Employee();
В этом примере создается экземпляр класса Employee
и загружается в область кучи.
Куча создается при запуске виртуальной машины, и на каждую виртуальную машину приходится только одна область кучи.
Примечание: поскольку области метода и кучи совместно используют одну и ту же память для нескольких потоков, данные, хранящиеся здесь, не потокобезопасны.
Область стека
Всякий раз, когда в JVM создается новый поток, одновременно создается отдельный стек среды выполнения. Все локальные переменные, вызовы методов и частичные результаты хранятся в области стека.
Если для обработки в потоке требуется больший размер стека, чем доступно, JVM выдает ошибку StackOverflowError
.
Для каждого вызова метода в памяти стека делается одна запись, которая называется фреймом стека. Когда вызов метода завершен, фрейм стека уничтожается.
Фрейм стека разделен на три части.
- Локальные переменные. Каждый фрейм содержит массив переменных, известных как его локальные переменные. Здесь хранятся все локальные переменные и их значения. Длина этого массива определяется во время компиляции.
- Стек операндов. Каждый фрейм содержит стек последним-вошел-первым-вышел (last-in-first-out, LIFO), известный как стек операндов. Он действует как рабочая область среды выполнения для любых промежуточных операций. Максимальная глубина этого стека определяется во время компиляции.
- Данные фрейма. Здесь хранятся все символы, соответствующие методу. Здесь также хранится информация о блоке
catch
на случай исключений.
К примеру, есть следующий код:
double calculateNormalisedScore(List<Answer> answers) { double score = getScore(answers);
return normalizeScore(score);
}
double normalizeScore(double score) {
return (score – minScore) / (maxScore – minScore);
}
В этом примере кода переменные, такие как answers
и score
, помещаются в массив локальных переменных. Стек операндов содержит переменные и операторы, необходимые для выполнения математических операций вычитания и деления.
Примечание: поскольку область стека не является общей, она по своей сути потокобезопасна.
Регистры счетчика программ
JVM поддерживает многопоточность. Каждый поток имеет собственный регистр счетчика программ для хранения адреса выполняемой в данный момент инструкции JVM. Как только инструкция выполнена, регистр обновляется следующей инструкцией.
Стеки нативных методов
JVM содержит стеки, которые поддерживают нативные методы, то есть такие методы, которые написаны на языке, отличном от Java, например C или C++. Для каждого нового потока также выделяется отдельный стек нативных методов.
Система выполнения
Как только байт-код загружен в основную память, и подробная информация становится доступна в области данных среды выполнения, наступает следующий этап — запуск программы. Механизм выполнения делает это, выполняя код из каждого класса.
Однако перед выполнением программы байт-код необходимо преобразовать в инструкции машинного языка. В качестве механизма выполнения JVM может задействовать интерпретатор или JIT-компилятор.
Интерпретатор
Интерпретатор считывает и выполняет инструкции байт-кода строка за строкой. Из-за построчного выполнения интерпретатор работает сравнительно медленнее.
Еще один недостаток интерпретатора — при многократном вызове метода каждый раз требуется новая интерпретация.
JIT-компилятор
JIT-компилятор преодолевает недостаток интерпретатора. Механизм выполнения сначала использует интерпретатор для выполнения байт-кода, но когда он находит какой-то повторяющийся код, то задействует JIT-компилятор.
Затем JIT-компилятор компилирует весь байт-код и изменяет его на собственный машинный код. Этот собственный машинный код используется непосредственно для повторных вызовов методов, что повышает производительность системы.
JIT-компилятор содержит следующие компоненты.
- Генератор промежуточного кода — генерирует промежуточный код.
- Оптимизатор кода — оптимизирует промежуточный код для повышения производительности.
- Генератор целевого кода — преобразует промежуточный код в собственный машинный код.
- Профилировщик — находит горячие точки (код, который выполняется повторно).
Чтобы лучше понять разницу между интерпретатором и JIT-компилятором, предположим, что у вас есть следующий код:
int sum = 10;
for(int i = 0 ; i <= 10; i++) {
sum += i;
}
System.out.println(sum);
Интерпретатор будет извлекать из памяти значение sum
для каждой итерации в цикле, добавлять к нему значение i
и записывать обратно в память. Это дорогостоящая операция, потому что каждый раз при входе в цикл происходит обращение к памяти.
Однако JIT-компилятор распознает, что в этом коде есть “горячая точка”, и выполнит оптимизацию. Он сохранит локальную копию sum
в регистре для потока и будет продолжать добавлять значение i
в цикле. Как только цикл завершится, компилятор запишет значение sum
обратно в память.
Примечание: компилятору требуется больше времени для компиляции кода, чем интерпретатору для интерпретации кода строка за строкой. Если вы намерены запустить программу только один раз, интерпретатор будет предпочтительнее.
Сборщик мусора
Сборщик мусора (Garbage Collector, GC) собирает и удаляет объекты без ссылок из области кучи. Это процесс автоматического восстановления неиспользуемой памяти во время выполнения путем уничтожения мусорных объектов.
Сборка мусора делает память Java эффективной, потому что удаляет объекты без ссылок из памяти кучи и освобождает место для новых объектов. Она включает два этапа:
- Пометка — на этом этапе GC идентифицирует неиспользуемые объекты в памяти.
- Очистка — на этом этапе GC удаляет объекты, идентифицированные на предыдущем этапе.
Сборка мусора выполняется JVM автоматически через регулярные промежутки времени и не требует отдельной обработки. Ее также можно запустить вызовом System.gc()
, но выполнение не гарантируется.
JVM содержит три различных типа сборщиков мусора.
- Последовательная сборка мусора. Это самая простая реализация GC. Она предназначена для небольших приложений, работающих в однопоточных средах. Для сборки мусора используется один поток. Запуск приводит к событию “остановки мира”, когда все приложение приостанавливает работу. Аргумент JVM для запуск последовательного сборщика мусора:
-XX:+UseSerialGC
. - Параллельная сборка мусора. Это реализация GC по умолчанию, также известная как сборщик пропускной способности. Для сборки мусора в нем используется несколько потоков, но работа приложения все равно приостанавливается при запуске. Аргумент JVM для параллельного сборщика мусора:
-XX:+UseParallelGC
. - Garbage First (G1). G1 был разработан для многопоточных приложений с большим доступным размером кучи (более 4 ГБ). Он разбивает кучу на набор областей одинакового размера и использует несколько потоков для их сканирования. G1-сборщик определяет регионы с наибольшим количеством мусора и сначала выполняет сбор мусора в них. Аргумент JVM для этого сборщика мусора:
-XX:+UseG1GC
.
Примечание: существует другой тип сборщика мусора, называемый сборщиком параллельных меток (CMS). Однако он устарел начиная с Java 9 и полностью удален в Java 14, и его место занимает сборщик G1.
Нативный интерфейс Java (Java Native Interface, JNI)
Иногда необходимо задействовать в работе нативный (не Java) код (например, написанный на C/C++). К примеру, в тех случаях, когда нужно взаимодействовать с физическим оборудованием или преодолевать ограничения по управлению памятью и производительности в Java. Java поддерживает выполнение нативного кода через нативный интерфейс Java (JNI).
JNI действует как мост для предоставления вспомогательных пакетов другим языкам программирования, таким как C, C++ и так далее. Это особенно полезно в тех случаях, когда нужно написать код, который не полностью поддерживается Java, например, некоторые специфичные для платформы функции могут быть написаны только на C.
Вы можете воспользоваться ключевым словом native
, чтобы указать, что реализация метода будет предоставлена нативной библиотекой. Также потребуется вызвать System.LoadLibrary()
, чтобы загрузить общую нативную библиотеку в память и сделать ее функции доступными для Java.
Нативные библиотеки методов
Нативные библиотеки методов — это библиотеки, написанные на других языках программирования, таких как C, C++ и ассемблер. Эти библиотеки обычно представлены в виде файлов .dll
или .so
. Такие библиотеки можно загружать через JNI.
Распространенные ошибки JVM
ClassNotFoundException
. Происходит, когда загрузчик классов пытается загрузить классы с помощьюClass.forName()
,ClassLoader.loadClass()
илиClassLoader.findsystemclass()
, но определение класса с указанным именем не найдено.NoClassDefFoundError
. Происходит, когда компилятор успешно скомпилировал класс, но загрузчик классов не может найти файл класса во время выполнения.OutOfMemoryError
. Происходит, когда JVM не может выделить объект из-за нехватки памяти, и сборщик мусора не может предоставить больше памяти.StackOverflowError
. Происходит, если в JVM не хватает места при создании новых кадров стека во время обработки потока.
Заключение
В этой статье мы обсудили архитектуру виртуальной машины Java и ее компоненты. Часто мы не вникаем глубоко во внутреннюю механику JVM или не интересуемся, как она работает, пока работает код.
Только когда что-то идет не так, и нам нужно настроить JVM или устранить утечку памяти, мы пытаемся понять ее внутреннее устройство.
Это также очень популярный вопрос во время интервью на роль бэкенд-разработчика — как младшего, так и старшего уровня. Глубокое понимание JVM поможет вам лучше писать код и избегать подводных камней, связанных со стеком и ошибками памяти.
Читайте также:
- 9 вещей, которыми следует заняться Java программисту в 2018 году
- Превратите свой Java-код в полностью асинхронный
- Циклы Java в сторону - даешь потоки!
Читайте нас в Telegram, VK и Яндекс.Дзен
Перевод статьи Siben Nayak: JVM Tutorial — Java Virtual Machine Architecture Explained for Beginners
Java для создания беспилотных автомобилей: обнаружение объектов автомобиля
Java Autonomous Driving: Car Detection
Исходный адрес:https://dzone.com/articles/java-autonomous-driving-car-detection-1
В этой статье мы будем использовать Java для создания приложения для обнаружения видеообъектов в реальном времени для обнаружения автомобилей, которое является ключевым компонентом автономной системы вождения. В предыдущей статье мы смогли построить классификатор изображений (кошки и собаки), теперь нам нужно обнаруживать объекты (например, автомобили, пешеходов) и отмечать их границами (прямоугольниками). Не стесняйтесь загружать код или запускать приложение с собственным видео(Пример короткого видео)。
Суть обнаружения цели
Классификация объектов
Прежде всего, мы столкнулись с проблемой классификации объектов.Например, мы хотим знать, содержится ли конкретный объект в изображении, а на следующем рисунке — есть ли на изображении автомобиль.
мыПредыдущая статьяИспользование существующей архитектуры упоминается вVGG-16с участиемПередача обученияПостроить классификатор изображений.
Локализация объекта
Теперь мы можем сказать, что у нас есть высокая степень уверенности в том, чтобы судить, содержится ли конкретный объект в изображении, и мы сталкиваемся с проблемой определения местоположения объекта на изображении. Обычно это делается путем пометки объектов прямоугольниками или ограничивающими рамками.
Помимо классификации изображений, нам необходимо дополнительно определить положение объекта на изображении. Это делается путем определения ограничивающей рамки.
Ограничивающая рамка обычно отображается в центре объекта.
c
e
n
t
e
r
(
b
x
,
b
y
)
, Высота прямоугольника
h
e
i
g
h
t
(
b
h
)
, Ширина прямоугольника
w
i
d
t
h
(
b
w
)
。
Теперь нам нужно определить эти четыре переменные для каждого объекта изображения в наших обучающих данных. Кроме того, сеть будет не только выводить номер категории изображения (например, вероятность 20% кошка [1], 70% собака [2], 10% тигр [3]), но также выводит четыре значения переменных ограничивающего поле, определенное выше.
предоставляет точки ограничивающего прямоугольника (центр, ширина, высота), наша модель выводит / прогнозирует больше информации, давая нам более подробное представление о содержимом изображения.
Нетрудно представить, что добавление дополнительных точек к данным обучения изображения может дать нам более глубокое понимание изображения. Например, точки на лице человека (то есть рот, глаза) могут сказать нам, что человек улыбается, плачет и т. Д.
Обнаружение объекта
Далее мы можем найти несколько объектов на изображении.
Хотя структура сильно не изменилась, проблема здесь усложняется, поскольку нам нужно подготовить больше данных (несколько ограничивающих рамок). В принципе, мы просто разделяем изображение на меньшие прямоугольники, и для каждого прямоугольника у нас есть те же дополнительные пять переменных —
P
c
,
(
b
x
,
b
y
)
,
b
h
,
b
w
-И нормальная вероятность предсказания (20% кошка [1], 70% собака [2]). Мы увидим более подробную информацию позже, но теперь давайте предположим, что структура такая же, как и расположение объекта, разница в том, что у нас есть несколько структур.
Решение для раздвижного окна (решение для раздвижного окна)
Это очень интуитивное решение. Идея состоит не в том, чтобы использовать обычное изображение автомобиля, а в том, чтобы максимально обрезать изображение, чтобы изображение содержало только автомобили.
Мы используем обрезанное изображение для обучения сетевой структуры, подобнойVGG-16или жеДругие глубокие сетиСверточная нейронная сеть.
Результат этого метода очень хороший, но эту модель можно использовать только для определения того, содержит ли изображение автомобиль, поэтому возникнут проблемы с обнаружением изображения реальной сцены, потому что он содержит Другие объекты (например, деревья, людей, дорожные знаки и т. д.).
Кроме того, реальное изображение обычно больше, чем размер обучающих данных.
Чтобы преодолеть эти проблемы, мы можем проанализировать только часть изображения и проанализировать, содержит ли эта часть часть автомобиля. Чтобы быть более точным, мы используем скользящую прямоугольную рамку для сканирования всего изображения и используем нашу модель, чтобы определить, содержит ли эта часть автомобиль во время каждого сканирования. Давайте посмотрим на пример:
Короче говоря, мы используем обычную сверточную нейронную сеть (VGG-16) для обучения модели с обрезанными изображениями разных размеров, а затем используем прямоугольники для сканирования изображения объекта (автомобиля). . Мы видим, что, используя прямоугольники разных размеров, мы можем рассчитывать разные формы и положения транспортных средств.
Этот алгоритм не сложен и работает. Но у этого алгоритма есть два недостатка.
-
Первая проблема — это производительность. Мы должны многократно вызывать модель, чтобы предсказывать результаты. Каждый раз, когда прямоугольный прямоугольник перемещается, нам нужно вызывать модель, чтобы получить результат прогнозирования, и нам нужно использовать прямоугольные прямоугольники разных размеров, чтобы повторить это. Один из способов решения проблемы производительности — увеличить размер шага прямоугольного блока (используя большой размер шага), но таким образом мы не сможем обнаружить определенные объекты. В прошлом модели были в основном линейными и имели характеристики ручного проектирования, поэтому прогнозы были недорогими. Итак, этот алгоритм используется для хорошей работы. В настоящее время, учитывая размер сети (VGG-16 имеет параметр 138 миллионов), этот алгоритм очень медленный и почти бесполезен для обнаружения видеообъектов в реальном времени, таких как автономное вождение.
Еще одна причина низкой производительности алгоритма заключается в том, что когда мы перемещаем прямоугольный фрейм (вправо и вниз), многие общие пиксели не используются повторно, а пересчитываются. В следующей части мы воспользуемся последней сверткой, чтобы решить эту проблему.
-
Даже если мы будем использовать прямоугольные рамки разных размеров для сканирования изображения, мы все равно не сможем обнаружить объекты, содержащиеся в изображении. Модель может быть не в состоянии выводить точную информацию об ограничивающей рамке; например: этот прямоугольник содержит только часть объекта. В следующей части мы обсудим алгоритм YOLO (вы посмотрите только один раз), который решит эту проблему за нас.
Решение сверточного скользящего окна (решение сверточного скользящего окна)
Мы видим, что скользящие окна имеют проблемы с производительностью, потому что они не могут повторно использовать большое количество вычисленных значений. После каждого движения скользящего окна нам необходимо вычислить большое количество параметров в модели (возможно, миллионы параметров), чтобы получить прогнозируемое значение. На самом деле, мы можем ввести структуру свертки, чтобы повторно использовать эти результаты вычислений.
Превратите полностью связанные слои в свертку (из полностью подключенной сети в сверточную нейронную сеть)
Как мы видели в конце предыдущей статьи, структура классификации изображений, независимо от ее размера и конфигурации, обучает полностью подключенную сеть слоев с разным количеством слоев, а количество выходных данных зависит от типа объекта классификации.
Для простоты мы будем использовать модель меньшей сети в качестве примера, но та же логика действительна для любой сверточной сети. (VGG-16,AlexNet)
Для более интуитивно понятного и подробного объяснения свертки см.Предыдущая статья。
Этот простой размер использования сети составляет32 x 32 x 3
Цветное изображение в качестве входа в сеть, используйте ЖЕ3x3x64
Свертка (этот метод свертки не изменяет ширину и высоту изображения) получает размер32 x 32 x 64
Вывод (подсказка, третье измерение выходных данных равно размерности 64 суммы свертки, которая обычно используется для получения входных данных). Затем используйте максимальное объединение, чтобы уменьшить ширину и высоту, и сохранить данные в третьем измерении без изменений (16 x 16 x 64). После этого мы используем двухслойную полносвязную сеть с 256 и 128 нейронами. В конце мы выводим пять типов вероятностей (обычно soft-max).
Давайте посмотрим, как заменить полностью связанный слой сверточным слоем, сохраняя при этом тот же математический эффект (введите линейную функцию 16 X 16 X 64).
Мы просто используем ядро свертки вместо полносвязного слоя. в действительности,16x16x256
Ядро свертки на самом деле16x16x64x256
Матрица (Множественные ядра свертки), потому что третье измерение ядра свертки и третье измерение ввода всегда одинаковы. Для простоты мы будем думать об этом как о16 x 16 x 256
. Это означает, что это эквивалентно полностью связанному слою, поскольку каждый элемент вывода 1 X 1 X 256 является линейной функцией каждого элемента входа 16 X 16 X 64.
Причина, по которой мы хотим преобразовать полностью связанный (FC) слой в сверточный, заключается в том, что это даст нам больше гибкости при выборе метода вывода. С FC у вас всегда будет один и тот же размер вывода, количество классов.
Скользящее окно свертки (скользящее окно свертки)
Чтобы увидеть идею использования сверточной сети для замены полностью связанного слоя, нам нужно ввести размер изображения больше, чем размер исходного изображения —32x32x3
. Давайте использовать36x36x3
В качестве ввода.
Это изображение (с зеленым размером 36 X 36) на четыре строки и четыре столбца больше, чем исходное изображение (синее 32 X 32). Если мы используем скользящее окно с размером шага 2 и полностью подключенную сеть слоев, нам нужно 9 раз переместить исходный размер изображения, чтобы покрыть все изображение (черный прямоугольник на рисунке демонстрирует три результата перемещения). При этом модель вызывается 9 раз.
Затем давайте попробуем применить увеличенное изображение к нашей новой модели, которая использует только сверточные слои.
Как мы видели, выход полностью подключенного слоя может быть1x1x5
, Вывод из1x1x5
стал3x3x5
. Вспомните, что нам пришлось переместиться 9 раз, чтобы охватить все изображение — подождите минуту, это точно равно3x3
? Да, эти блоки размером 3×3 представляют размер каждого скользящего окна.1x1x5
Результат вывода вероятности классификации.
Это очень продвинутый метод, потому что мы можем получить все девять результатов одновременно, не выполняя модели с миллионами параметров несколько раз.
YOLO (You Only Look Once)
Хотя мы решили проблему с производительностью, введя скользящее окно свертки. Но наша модель по-прежнему не может выводить очень точные ограничивающие прямоугольники, даже если используется большое количество ограничивающих прямоугольников разных размеров. Посмотрим, как YOLO решает эту проблему.
Сначала мы обычно отмечаем объекты, которые хотим обнаружить на каждой картинке. Каждый объект будет использовать четыре переменные, отмеченные ограничивающими рамками. Помните, что эти четыре переменные являются центром объекта.
c
e
n
t
e
r
(
b
x
,
b
y
)
, Высота прямоугольника
h
e
i
g
h
t
(
b
h
)
, Ширина прямоугольника
w
i
d
t
h
(
b
w
)
. Каждое изображение разделено на меньшие прямоугольники, обычно разделенные на19x19
Прямоугольник, для простоты, здесь разделен на8x9
。
Красная ограничивающая рамка и объект состоят из частей множества синих ограничивающих рамок, поэтому мой объект Enzhijiang и ограничивающая рамка назначаются желтому прямоугольнику с центром объекта. Мы обучаем нашу модель четырьмя дополнительными переменными (помимо того, что объект указывает на то, что это машина, но также указываем центр, ширину и высоту объекта), и назначаем эти переменные ограничивающей рамке с центральной точкой. После обучения нейронной сети с использованием этого помеченного набора данных мы будем использовать модель для прогнозирования значения этих четырех переменных (кроме категории распознанного объекта), значения или ограничивающего прямоугольника.
Вместо сканирования с предопределенным размером ограничивающей рамки мы пытаемся подогнать объект. Мы позволяем модели научиться маркировать объект ограничивающей рамкой, поэтому ограничивающая рамка теперь гибкая. (от ЖЖ). Таким образом, точность ограничивающего прямоугольника намного выше и гибче.
Теперь посмотрим, как мы представляем результат. В дополнение к таким классам, как 1-автомобиль, 2-пешеход, у нас есть четыре дополнительных переменных.
(
b
x
,
b
y
,
b
h
,
b
w
)
. Фактически добавлена еще одна переменная
P
c
, Он сообщит нам, есть ли на изображении какие-либо объекты, которые мы хотим обнаружить.
P
c
=
1
(Отмечено красным) означает, что есть хотя бы один объект, который мы хотим обнаружить, поэтому стоит проверить вероятность классификации и значение ограничивающего прямоугольника распознанного объекта.
P
c
=
0
(Красная метка) означает, что любой объект, который мы хотим обнаружить, обнаружен внутри, и нам не нужно заботиться о вероятности классификации и значении ограничивающего прямоугольника, предсказанном моделью.
Спецификация ограничивающей рамки (распознавание ограничивающей рамки)
Нам нужно использовать специальные методы для маркировки наших данных, чтобы алгоритм YOLO мог работать правильно.YOLO V2
Формат требует значения размера ограничивающей рамки.
(
b
x
,
b
y
,
b
h
,
b
w
)
Это относительное значение ширины и высоты исходного изображения. Предположим, у нас есть изображение размером 300×400, а размер ограничивающей рамки равен
B
w
i
d
t
h
=
30
,
B
h
e
i
g
h
t
=
15
,
B
X
=
150
,
B
Y
=
80
. Эти значения необходимо преобразовать в
B
w
i
d
t
h
=
30
/
300
,
B
h
e
i
g
h
t
=
15
/
400
,
B
X
=
150
/
300
,
B
Y
=
80
/
400
。
Эта статьяРасскажу о том, как пользоватьсяBBox Label Tool
Инструменты для маркировки наших данных стоят небольшую цену. Ограничительный прямоугольник, отмеченный этим инструментом (он дает нам верхнюю левую точку и нижнюю правую точку) иYOLO V2
Формат немного другой. Но превратить его в нужные нам данные очень просто.
Помимо тегов, для которых YOLO требуются обучающие данные, метод прогнозирования также отличается во внутренней реализации.
Ограничивающий прямоугольник, предсказанный YOLO, определяется относительно прямоугольника (желтого) с центром объекта. Точка в верхнем левом углу желтого поля определяется как (0,0), а точка в нижнем правом углу определяется как (1,1). Итак, центр магазина
(
b
x
,
b
y
)
Должен быть в диапазоне
0
−
1
Между (функция активации сигмоида гарантирует этот результат), потому что центральная точка должна находиться в этом желтом ограничивающем прямоугольнике.
b
h
с участием
b
w
Это относительное значение, рассчитываемое по ширине и высоте желтого прямоугольника, поэтому его значение может быть больше 1. На этой картинке мы видим
b
w
Это в 1,8 раза больше ширины желтой границы, а высота в 1,6 раза больше высоты желтой границы.
После прогнозирования мы можем увидеть, насколько прямоугольник прогноза пересекается с фактическим ограничивающим прямоугольником, отмеченным в начале. По сути, мы стараемся максимизировать пересечение между ними, поэтому в идеале предсказанная ограничивающая рамка полностью пересекает помеченную ограничивающую рамку.
Это принцип в принципе! Вы обеспечиваете более профессиональное использование ограничивающих рамок
(
b
x
,
b
y
,
b
h
,
b
w
)
Помеченные обучающие данные сегментируют изображение и присваивают его блоку, содержащему центр (отвечающему за обнаружение объекта), обучают сверточную нейронную сеть со скользящим окном и предсказывают объект и положение.
Еще две проблемы (есть еще две проблемы)
Даже если мы попытаемся дать более подробное объяснение в этой статье, на самом деле у нас все еще есть две небольшие проблемы, которые необходимо решить.
Во-первых, даже если объект назначен блоку (блоку, содержащему центр объекта) во время обучения, во время тестирования (для прогнозирования) несколько блоков (желтые) могут подумать у них есть центр объекта (с красным), поэтому определите свой собственный ограничивающий прямоугольник для того же объекта. Это решается не максимальным алгоритмом подавления. В настоящее время Deeplearning4j не предоставляет реализацию, поэтому найдите простую реализацию (removeObjectsIntersectingWithMax) на GitHub. Его функция состоит в том, чтобы сначала выбрать ящик с наибольшей вероятностью Pc в качестве прогноза (он не только имеет значение 1 или 0, но может находиться в диапазоне 0-1). Затем удалите каждый прямоугольник, который пересекает прямоугольник более чем на определенный порог. Он снова запускает ту же логику, пока не кончатся ограничительные рамки.
Во-вторых, поскольку мы предсказали несколько объектов (автомобили, пешеходы, светофоры и т. д.), может случиться так, что центром двух или более объектов будет прямоугольник. Эти ситуации решаются введением якорных ящиков. Используя якорные рамки, мы выбираем несколько форм ограничивающих рамок и находим больше объектов, которые хотим обнаружить. Файл YOLO V2 реализован с помощью алгоритма k-средних, но это также можно сделать вручную. После этого мы модифицируем вывод, чтобы включить ту же структуру, которую мы видели раньше (Pc, bx, by, bh, bw, C1, C2 …), но для каждой выбранной формы якорного блока. Итак, у нас может быть что-то вроде этого:
заявка
Обучение глубокой сети требует больших усилий, значимых данных и вычислительной мощности. Как и в предыдущей статье, мы будем использовать трансферное обучение. На этот раз мы не собираемся изменять архитектуру и тренироваться с другими данными, а будем использовать сеть напрямую.
Мы планируем использоватьTiny YOLO; В Интернете цитируются следующие вопросы:
Tiny YOLO основан на эталонной сети Darknet, которая намного быстрее, чем обычная модель YOLO, но точность ниже, чем у обычной модели. Чтобы использовать обучающую версию VOC:
wget https://pjreddie.com/media/files/tiny-yolo-voc.weights
./darknet detector test cfg/voc.data cfg/tiny-yolo-voc.cfg tiny-yolo-voc.weights data/dog.jpg
Ну, это не идеально, но, черт возьми, это действительно быстро. На GPU он работает быстрее 200 FPS.
Текущая версия Deeplearning4j 0.9.1 не поддерживает TinyYOLO, но 0.9.2-SNAPSHOT поддерживает. Итак, сначала нам нужно указать Maven, где загрузить версию SNAPSHOT:
<repositories>
<repository>
<id>a</id>
<url>http://repo1.maven.org/maven2/</url>
</repository>
<repository>
<id>snapshots-repo</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
<updatePolicy>daily</updatePolicy>
</snapshots>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.deeplearning4j</groupId>
<artifactId>deeplearning4j-core</artifactId>
<version>${deeplearning4j}</version>
</dependency>
<dependency>
<groupId>org.nd4j</groupId>
<artifactId>nd4j-native-platform</artifactId>
<version>${deeplearning4j}</version>
</dependency>
Далее нам нужно загрузить модель с очень коротким кодом:
private TinyYoloPrediction() {
try {
preTrained = (ComputationGraph) new TinyYOLO().initPretrained();
prepareLabels();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
prepareLabels()
Просто используйтеPASCAL VOCМетка, используемая для обучения модели в наборе данных. ВыполнитьpreTrained.summary()
Не испытывайте давления при просмотре архитектуры модели.
Каждый кадр видеоCarVideoDetection
использоватьJavaCV
Захвачено:
FFmpegFrameGrabber grabber;
grabber = new FFmpegFrameGrabber(f);
grabber.start();
while (!stop) {
videoFrame[0] = grabber.grab();
if (videoFrame[0] == null) {
stop();
break;
}
v[0] = new OpenCVFrameConverter.ToMat().convert(videoFrame[0]);
if (v[0] == null) {
continue;
}
if (winname == null) {
winname = AUTONOMOUS_DRIVING_RAMOK_TECH + ThreadLocalRandom.current().nextInt();
}
if (thread == null) {
thread = new Thread(() -> {
while (videoFrame[0] != null && !stop) {
try {
TinyYoloPrediction.getINSTANCE().markWithBoundingBox(v[0], videoFrame[0].imageWidth, videoFrame[0].imageHeight, true, winname);
} catch (java.lang.Exception e) {
throw new RuntimeException(e);
}
}
});
thread.start();
}
TinyYoloPrediction.getINSTANCE().markWithBoundingBox(v[0], videoFrame[0].imageWidth, videoFrame[0].imageHeight, false, winname);
imshow(winname, v[0]);
Следовательно, код получает кадры из видео и передает их предварительно обученной модели TinyYOLO. Оттуда кадр изображения сначала масштабируется до 416 X 416 X 3 (RGB), а затем передается в TinyYOLO для прогнозирования и маркировки ограничивающей рамки:
public void markWithBoundingBox(Mat file, int imageWidth, int imageHeight, boolean newBoundingBOx,String winName) throws Exception {
int width = 416;
int height = 416;
int gridWidth = 13;
int gridHeight = 13;
double detectionThreshold = 0.5;
Yolo2OutputLayer outputLayer = (Yolo2OutputLayer) preTrained.getOutputLayer(0);
INDArray indArray = prepareImage(file, width, height);
INDArray results = preTrained.outputSingle(indArray);
predictedObjects = outputLayer.getPredictedObjects(results, detectionThreshold);
System.out.println("results = " + predictedObjects);
markWithBoundingBox(file, gridWidth, gridHeight, imageWidth, imageHeight);
imshow(winName, file);
}
После предсказания у нас уже должно быть предсказанное значение размера ограничивающей рамки. Мы реализовали алгоритм подавления без максимума (removeObjectsIntersectingWithMax) Потому что, как мы уже упоминали, алгоритм YOLO имеет более одного ограничивающего прямоугольника при прогнозировании каждого объекта во время тестирования. по сравнению с
(
b
x
,
b
y
,
b
h
,
b
w
)
, Мы будем использоватьtopLeft
с участиемbottomRight
Верхняя левая точка и нижняя правая точка.gridWidth
с участиемgridHeight
На сколько меньших ограничивающих прямоугольников мы собираемся разделить изображение, в нашем случае разделенное на13x13
. w и h — размеры исходного изображения.
После этого, в дополнение к потоку, который воспроизводит видео, мы запустим еще один поток, и мы обновим видео, чтобы получить прямоугольник и метку обнаруженного объекта.
Учтите, что когда мы работаем на CPU, скорость предсказания (в реальном времени) очень высока; если мы работаем на GPU, мы получим лучшие результаты обнаружения в реальном времени.
Запуск приложения
Даже если Java не установлена на вашем компьютере, этоприменениеМожет использоваться без каких-либо знаний JavaскачатьИ беги. Вы можете попробовать использовать собственное видео.
Выполнить в исходном кодеRUN
Класс можно запустить. Если вы не хотите использовать IDE для открытия этого проекта, вы можете запуститьmvn clean install exec:java
команда.
После запуска этого приложения вы увидите результат, как показано ниже:
Enjoy!
адрес кода github:https://github.com/klevis/AutonomousDriving
gitee open source адрес в Китае:https://gitee.com/sjsdfg/AutonomousDriving
Можно просмотреть больше документовhttps://github.com/sjsdfg/deeplearning4j-issues。
Ваша звезда — это моя мотивация продолжать делиться