Всем известно, что обучение нейросетей требует значительных вычислительных ресурсов. Но что делать, если у вас нет мощного оборудования? В этой статье я расскажу, как обучить нейросеть частями, но и объясню ключевые понятия вроде слоев, батчей, и функций активации. Эта статья может быть полезна начинающим разработчикам, кто только погружается в нейронки.
В качестве примера кода я приведу обработку транзакций, однако данные могут быть заменены на любые, где требуется анализ о допустимости или недопустимости результата на основе цепочки данных.
Основные понятия нейросетей
Прежде чем углубляться в процесс, кратко объясним ключевые термины, чтобы статья была понятна даже новичкам.
1. Слои нейросети
Нейросеть состоит из слоев, где каждый слой выполняет математическую обработку данных:
-
Входной слой принимает данные (например, текст или изображение).
-
Скрытые слои обрабатывают данные, выявляя паттерны и взаимосвязи.
-
Выходной слой выдает результат, например, вероятность принадлежности к какому-либо классу.
В простом многослойном перцептроне (MLP) каждый узел (нейрон) в слое соединен с узлами следующего слоя. Вот пример:
-
Входные данные: 100 чисел (например, векторы слов).
-
Первый скрытый слой: 64 нейрона. Каждый из них вычисляет взвешенную сумму входов и применяет функцию активации (например, ReLU).
-
Выходной слой: 2 нейрона (например, для предсказания «положительный» или «отрицательный»).
2. Батчи
Когда мы обучаем нейросеть, данные разбиваются на части — батчи. Вместо того чтобы подавать всю обучающую выборку сразу, модель обрабатывает один батч за раз.
-
Пример: если у нас есть 1000 текстов и размер батча — 32, то модель обработает данные в 32 итерациях (по 32 текста за итерацию).
Зачем нужны батчи?
-
Экономия памяти: мы не храним весь набор данных в оперативной памяти.
-
Ускорение обучения: обработка маленьких порций данных позволяет быстрее корректировать параметры модели.
3. Функции активации
Функции активации определяют, как выход одного нейрона преобразуется для следующего слоя. Популярные функции:
-
ReLU (Rectified Linear Unit): пропускает положительные значения, обнуляя отрицательные.
-
Softmax: преобразует выходной слой в вероятности (сумма всех значений = 1).
Как я реализовал обучение
Создадим файл transactions.csv, содержащий данные о транзакциях. Каждая строка — это одна транзакция, включающая 10 входных параметров и метку класса (0
или 1
). Вот пример содержимого файла:
0.5,0.1,0.3,0.2,0.9,0.7,0.4,0.6,0.8,0.3,1 0.6,0.2,0.4,0.1,0.8,0.5,0.3,0.5,0.7,0.2,0 0.7,0.3,0.5,0.4,0.7,0.6,0.2,0.4,0.9,0.1,1
Каждая строка состоит из 10 чисел (фичей), за которыми следует метка класса:
-
0
— нормальная транзакция, -
1
— подозрительная транзакция.
Реализация кода
1. Загрузка данных из файла
Напишем класс DataLoader, который будет загружать данные из файла и делить их на батчи. Это позволяет работать с большими файлами, обрабатывая данные частями:
import org.nd4j.linalg.dataset.DataSet; import org.nd4j.linalg.factory.Nd4j; import java.io.*; import java.util.ArrayList; import java.util.List; public class DataLoader { private final String filePath; private final int batchSize; public DataLoader(String filePath, int batchSize) { this.filePath = filePath; this.batchSize = batchSize; } public List<DataSet> loadData() throws IOException { List<DataSet> dataBatches = new ArrayList<>(); try (BufferedReader br = new BufferedReader(new FileReader(filePath))) { String line; List<double[]> features = new ArrayList<>(); List<double[]> labels = new ArrayList<>(); while ((line = br.readLine()) != null) { String[] parts = line.split(","); double[] input = new double[parts.length - 1]; for (int i = 0; i < parts.length - 1; i++) { input[i] = Double.parseDouble(parts[i]); } features.add(input); double[] label = new double[2]; label[Integer.parseInt(parts[parts.length - 1])] = 1.0; labels.add(label); if (features.size() == batchSize) { dataBatches.add(new DataSet(Nd4j.create(features.toArray(new double[0][])), Nd4j.create(labels.toArray(new double[0][])))); features.clear(); labels.clear(); } } } return dataBatches; } }
2. Создание модели нейронной сети
Для классификации данных создадим простую нейросеть с двумя скрытыми слоями. Она будет обучаться определять подозрительные транзакции:
import org.deeplearning4j.nn.conf.MultiLayerConfiguration; import org.deeplearning4j.nn.conf.NeuralNetConfiguration; import org.deeplearning4j.nn.conf.layers.DenseLayer; import org.deeplearning4j.nn.conf.layers.OutputLayer; import org.deeplearning4j.nn.multilayer.MultiLayerNetwork; import org.nd4j.linalg.activations.Activation; import org.nd4j.linalg.lossfunctions.LossFunctions; public class ModelBuilder { public static MultiLayerNetwork buildModel(int inputSize, int outputSize) { MultiLayerConfiguration config = new NeuralNetConfiguration.Builder() .learningRate(0.01) .list() .layer(new DenseLayer.Builder() .nIn(inputSize) .nOut(64) .activation(Activation.RELU) .build()) .layer(new DenseLayer.Builder() .nIn(64) .nOut(32) .activation(Activation.RELU) .build()) .layer(new OutputLayer.Builder(LossFunctions.LossFunction.NEGATIVELOGLIKELIHOOD) .nIn(32) .nOut(outputSize) .activation(Activation.SOFTMAX) .build()) .build(); MultiLayerNetwork model = new MultiLayerNetwork(config); model.init(); return model; } }
3. Обучение модели
Теперь объединим загрузку данных и модель для обучения:
import org.deeplearning4j.nn.multilayer.MultiLayerNetwork; import org.nd4j.linalg.dataset.DataSet; import java.io.IOException; import java.util.List; public class Main { public static void main(String[] args) throws IOException { String filePath = "transactions.csv"; //путь до файла int batchSize = 50; int numFeatures = 10; // Количество входных признаков int numClasses = 2; // Бинарная классификация DataLoader dataLoader = new DataLoader(filePath, batchSize); List<DataSet> trainingData = dataLoader.loadData(); MultiLayerNetwork model = ModelBuilder.buildModel(numFeatures, numClasses); int numEpochs = 10; for (int epoch = 0; epoch < numEpochs; epoch++) { for (DataSet batch : trainingData) { model.fit(batch); } System.out.println("Эпоха " + (epoch + 1) + " завершена."); } System.out.println("Обучение завершено."); } }
Почему этот подход подходит для больших данных?
-
Батчевый подход: данные загружаются порциями (батчами), что снижает нагрузку на оперативную память. Даже файлы размером в гигабайты можно обработать на обычном ПК.
-
Простота архитектуры: нейросеть оптимизирована для бинарной классификации, без избыточных слоёв. Это экономит ресурсы.
-
Масштабируемость: код можно адаптировать для других задач, включая мультиклассовую классификацию или регрессию.
-
Эффективность: благодаря библиотекам DeepLearning4j и ND4J обучение проходит быстро даже на процессоре.
С помощью этого подхода можно обучать нейронные сети на больших данных, не выходя из дома (понятно, что в разумных лимитах данных). Файл данных, простой код и понятная модель делают процесс удобным и адаптируемым.
ссылка на оригинал статьи https://habr.com/ru/articles/859866/
Добавить комментарий