В этом примере показано, как использовать сверточную нейронную сеть (CNN) для классификации модуляций. Вы генерируете синтетический продукт, поврежденные каналом формы волны. Используя сгенерированные формы волны как обучающие данные, вы обучаете CNN классификации модуляций. Вы затем тестируете CNN с оборудованием программно определяемого радио (SDR) и беспроводными сигналами.
Обученный CNN в этом примере распознает эти цифровые восемь и три аналоговых типа модуляции:
Бинарное манипулирование сдвига фазы (BPSK)
Манипулирование сдвига фазы Quadrature (QPSK)
8-ary сдвиг фазы, включающий (8-PSK)
16-ary квадратурная амплитудная (16-QAM) модуляция
64-ary квадратурная амплитудная (64-QAM) модуляция
4-ary импульсная амплитудная модуляция (PAM4)
Гауссово манипулирование сдвига частоты (GFSK)
Непрерывное манипулирование сдвига частоты фазы (CPFSK)
Широковещательно передайте FM (B-FM)
Двойная амплитудная модуляция боковой полосы (DSB-AM)
Однополосная амплитудная модуляция (SSB-AM)
modulationTypes = categorical(["BPSK", "QPSK", "8PSK", ... "16QAM", "64QAM", "PAM4", "GFSK", "CPFSK", ... "B-FM", "DSB-AM", "SSB-AM"]);
Во-первых, загрузите обучивший сеть. Для получения дополнительной информации на сетевом обучении, смотрите раздел Training a CNN.
load trainedModulationClassificationNetwork
trainedNet
trainedNet = SeriesNetwork with properties: Layers: [28x1 nnet.cnn.layer.Layer] InputNames: {'Input Layer'} OutputNames: {'Output'}
Обученный CNN берет 1 024 поврежденных каналом выборки и предсказывает тип модуляции каждой системы координат. Сгенерируйте несколько систем координат PAM4, которым повреждают с Rician многопутевое исчезновение, центральная частота и дрейф времени выборки и AWGN. Используйте следующую функцию, чтобы сгенерировать синтетические сигналы протестировать CNN. Затем используйте CNN, чтобы предсказать тип модуляции систем координат.
randi
: Сгенерируйте случайные биты
pammod
(Communications Toolbox) PAM4-модулирует биты
rcosdesign
(Signal Processing Toolbox): Спроектируйте повышенный формирующий фильтр импульса косинуса квадратного корня
filter
: Импульс формирует символы
comm.RicianChannel
(Communications Toolbox): Примените многопутевой канал Rician
comm.PhaseFrequencyOffset
(Communications Toolbox): Примените фазу, и/или частота переключают должный синхронизировать смещение
interp1
: Примените дрейф синхронизации, должный синхронизировать смещение
awgn
(Communications Toolbox): добавьте AWGN
% Set the random number generator to a known state to be able to regenerate % the same frames every time the simulation is run rng(123456) % Random bits d = randi([0 3], 1024, 1); % PAM4 modulation syms = pammod(d,4); % Square-root raised cosine filter filterCoeffs = rcosdesign(0.35,4,8); tx = filter(filterCoeffs,1,upsample(syms,8)); % Channel SNR = 30; maxOffset = 5; fc = 902e6; fs = 200e3; multipathChannel = comm.RicianChannel(... 'SampleRate', fs, ... 'PathDelays', [0 1.8 3.4] / 200e3, ... 'AveragePathGains', [0 -2 -10], ... 'KFactor', 4, ... 'MaximumDopplerShift', 4); frequencyShifter = comm.PhaseFrequencyOffset(... 'SampleRate', fs); % Apply an independent multipath channel reset(multipathChannel) outMultipathChan = multipathChannel(tx); % Determine clock offset factor clockOffset = (rand() * 2*maxOffset) - maxOffset; C = 1 + clockOffset / 1e6; % Add frequency offset frequencyShifter.FrequencyOffset = -(C-1)*fc; outFreqShifter = frequencyShifter(outMultipathChan); % Add sampling time drift t = (0:length(tx)-1)' / fs; newFs = fs * C; tp = (0:length(tx)-1)' / newFs; outTimeDrift = interp1(t, outFreqShifter, tp); % Add noise rx = awgn(outTimeDrift,SNR,0); % Frame generation for classification unknownFrames = helperModClassGetNNFrames(rx); % Classification [prediction1,score1] = classify(trainedNet,unknownFrames);
Возвратите предсказания классификатора, которые походят на трудные решения. Сеть правильно идентифицирует системы координат как системы координат PAM4. Для получения дополнительной информации на генерации модулируемых сигналов, см., что helperModClassGetModulator функционирует.
prediction1
prediction1 = 7x1 categorical
PAM4
PAM4
PAM4
PAM4
PAM4
PAM4
PAM4
Классификатор также возвращает вектор из музыки к каждой системе координат. Счет соответствует вероятности, что каждая система координат имеет предсказанный тип модуляции. Постройте баллы.
helperModClassPlotScores(score1,modulationTypes)
Прежде чем мы сможем использовать CNN для классификации модуляций или любую другую задачу, мы сначала должны обучить сеть с известным (или помеченный) данные. Первая часть этого примера показывает, как использовать функции Communications Toolbox, такие как модуляторы, фильтры, и нарушения канала, чтобы сгенерировать синтетические обучающие данные. Вторая часть фокусируется на определении, обучении и тестировании CNN для задачи классификации модуляций. Третья часть проверяет производительность сети с беспроводными сигналами с помощью платформ программно определяемого радио (SDR).
Сгенерируйте 10 000 систем координат для каждого типа модуляции, где 80% используются для обучения, 10% используется для валидации, и 10% используется для тестирования. Мы используем системы координат обучения и валидации во время сетевой учебной фазы. Итоговая точность классификации получена с помощью тестовых систем координат. Каждая система координат является 1 024 выборками долго и имеет частоту дискретизации 200 кГц. Для цифровых типов модуляции восемь выборок представляют символ. Сеть принимает каждое решение на основе одной систем координат, а не на нескольких последовательных системах координат (как в видео). Примите центральную частоту 902 МГц и 100 МГц для цифровых и аналоговых типов модуляции, соответственно.
Чтобы запустить этот пример быстро, используйте обучивший сеть и сгенерируйте небольшое количество учебных систем координат. Чтобы обучить сеть на вашем компьютере, выберите опцию "Train network now" (i.e. установите trainNow на истину).
trainNow = false; if trainNow == верный numFramesPerModType = 10000; else numFramesPerModType = 500; end percentTrainingSamples = 80; percentValidationSamples = 10; percentTestSamples = 10; SPS = 8; % Samples per symbol солнцезащитный фактор = 1024; % Samples per frame symbolsPerFrame = солнцезащитный фактор / SPS; фс = 200e3; % Sample rate ФК = [902e6 100e6]; % Center frequencies
Передайте каждый кадр через канал с
AWGN
Rician многопутевое исчезновение
Смещение часов, приводящее к центральному смещению частоты и дрейфу времени выборки
Поскольку сеть в этом примере принимает решения на основе одной систем координат, каждая система координат должна пройти через независимый канал.
Канал добавляет AWGN с ОСШ 30 дБ. Реализуйте канал с помощью awgn
(Communications Toolbox) функция.
Канал передает сигналы через Rician многопутевой исчезающий канал с помощью comm.RicianChannel
(Communications Toolbox) Системный объект. Примите профиль задержки [0 1.8 3.4] выборки с соответствующими средними усилениями пути [0 - 2 - 10] дБ. K-фактор равняется 4, и максимальный эффект Доплера составляет 4 Гц, который эквивалентен скорости обхода на уровне 902 МГц. Реализуйте канал со следующими настройками.
Смещение часов происходит из-за погрешностей внутренних источников часов передатчиков и приемников. Синхронизируйте причины смещения центральная частота, которая используется к downconvert сигнал к основной полосе и частота дискретизации цифро-аналогового преобразователя, чтобы отличаться от идеальных значений. Средство моделирования канала использует фактор смещения часов , описанный как , где смещение часов. Для каждой системы координат канал генерирует случайное значение от равномерно распределенного множества значений в области значений [ ], где максимальное смещение часов. Смещение часов измеряется в частях на миллион (ppm). В данном примере примите максимальное смещение часов 5 страниц в минуту.
maxDeltaOff = 5; deltaOff = (rand()*2*maxDeltaOff) - maxDeltaOff; C = 1 + (deltaOff/1e6);
Смещение частоты
Подвергните каждую систему координат смещению частоты на основе фактора смещения часов и центральная частота. Реализуйте канал с помощью comm.PhaseFrequencyOffset
(Communications Toolbox).
Смещение частоты дискретизации
Подвергните каждую систему координат смещению частоты дискретизации на основе фактора смещения часов . Реализуйте канал с помощью interp1
функция, чтобы передискретизировать систему координат на новом уровне .
Используйте объект helperModClassTestChannel применить все три нарушения канала к системам координат.
channel = helperModClassTestChannel(... 'SampleRate', fs, ... 'SNR', SNR, ... 'PathDelays', [0 1.8 3.4] / fs, ... 'AveragePathGains', [0 -2 -10], ... 'KFactor', 4, ... 'MaximumDopplerShift', 4, ... 'MaximumClockOffset', 5, ... 'CenterFrequency', 902e6)
channel = helperModClassTestChannel with properties: SNR: 30 CenterFrequency: 902000000 SampleRate: 200000 PathDelays: [0 9.0000e-06 1.7000e-05] AveragePathGains: [0 -2 -10] KFactor: 4 MaximumDopplerShift: 4 MaximumClockOffset: 5
Можно просмотреть основную информацию о канале с помощью функции объекта info.
chInfo = info(channel)
chInfo = struct with fields:
ChannelDelay: 6
MaximumFrequencyOffset: 4510
MaximumSampleRateOffset: 1
Создайте цикл, который генерирует поврежденные каналом системы координат для каждого типа модуляции и хранит системы координат их соответствующими метками в файлах MAT. Путем сохранения данных в файлы вы избавляете от необходимости генерировать данные каждый раз, когда вы запускаете этот пример. Можно также совместно использовать данные эффективнее.
Удалите случайное число выборок с начала каждой системы координат удалить переходные процессы и убедиться, что системы координат имеют случайную начальную точку относительно контуров символа.
% Set the random number generator to a known state to be able to regenerate % the same frames every time the simulation is run rng(1235) tic numModulationTypes = length(modulationTypes); channelInfo = info(channel); transDelay = 50; dataDirectory = fullfile(tempdir,"ModClassDataFiles"); disp("Data file directory is " + dataDirectory)
Data file directory is /tmp/BR2020bd_1490193_5188/mlx_to_docbook3/ModClassDataFiles
fileNameRoot = "frame"; % Check if data files exist dataFilesExist = false; if exist(dataDirectory,'dir') files = dir(fullfile(dataDirectory,sprintf("%s*",fileNameRoot))); if length(files) == numModulationTypes*numFramesPerModType dataFilesExist = true; end end if ~dataFilesExist disp("Generating data and saving in data files...") [success,msg,msgID] = mkdir(dataDirectory); if ~success error(msgID,msg) end for modType = 1:numModulationTypes fprintf('%s - Generating %s frames\n', ... datestr(toc/86400,'HH:MM:SS'), modulationTypes(modType)) label = modulationTypes(modType); numSymbols = (numFramesPerModType / sps); dataSrc = helperModClassGetSource(modulationTypes(modType), sps, 2*spf, fs); modulator = helperModClassGetModulator(modulationTypes(modType), sps, fs); if contains(char(modulationTypes(modType)), {'B-FM','DSB-AM','SSB-AM'}) % Analog modulation types use a center frequency of 100 MHz channel.CenterFrequency = 100e6; else % Digital modulation types use a center frequency of 902 MHz channel.CenterFrequency = 902e6; end for p=1:numFramesPerModType % Generate random data x = dataSrc(); % Modulate y = modulator(x); % Pass through independent channels rxSamples = channel(y); % Remove transients from the beginning, trim to size, and normalize frame = helperModClassFrameGenerator(rxSamples, spf, spf, transDelay, sps); % Save data file fileName = fullfile(dataDirectory,... sprintf("%s%s%03d",fileNameRoot,modulationTypes(modType),p)); save(fileName,"frame","label") end end else disp("Data files exist. Skip data generation.") end
Generating data and saving in data files...
00:00:00 - Generating BPSK frames 00:00:03 - Generating QPSK frames 00:00:05 - Generating 8PSK frames 00:00:08 - Generating 16QAM frames 00:00:11 - Generating 64QAM frames 00:00:13 - Generating PAM4 frames 00:00:16 - Generating GFSK frames 00:00:19 - Generating CPFSK frames 00:00:22 - Generating B-FM frames 00:00:35 - Generating DSB-AM frames 00:00:37 - Generating SSB-AM frames
% Plot the amplitude of the real and imaginary parts of the example frames % against the sample number helperModClassPlotTimeDomain(dataDirectory,modulationTypes,fs)
% Plot the spectrogram of the example frames
helperModClassPlotSpectrogram(dataDirectory,modulationTypes,fs,sps)
Используйте signalDatastore
объект управлять файлами, которые содержат сгенерированные комплексные формы волны. Хранилища данных особенно полезны, когда каждый отдельный файл умещается в памяти, но целый набор не обязательно соответствует.
frameDS = signalDatastore(dataDirectory,'SignalVariableNames',["frame","label"]);
Нейронная сеть для глубокого обучения в этом примере ожидает действительные входные параметры, в то время как полученный сигнал имеет комплексные основополосные выборки. Преобразуйте комплексные сигналы в действительные оцененные 4-D массивы. Выходные системы координат имеют размер 1 солнцезащитным фактором 2 N, где первая страница (3-я размерность) является синфазными выборками, и вторая страница является квадратурными выборками. Когда сверточные фильтры имеют размер 1 солнцезащитным фактором, этот подход гарантирует, что информация во мне и Q смешана даже в сверточных слоях и лучше использует информацию о фазе. См. helperModClassIQAsPages для деталей.
frameDSTrans = transform(frameDS,@helperModClassIQAsPages);
Затем разделите системы координат на обучение, валидацию и тестовые данные. См. helperModClassSplitData для деталей.
splitPercentages = [percentTrainingSamples,percentValidationSamples,percentTestSamples]; [trainDSTrans,validDSTrans,testDSTrans] = helperModClassSplitData(frameDSTrans,splitPercentages);
Starting parallel pool (parpool) using the 'local' profile ... Connected to the parallel pool (number of workers: 12). Evaluating tall expression using the Parallel Pool 'local': - Pass 1 of 2: 0% complete Evaluation 0% complete
- Pass 1 of 2: Completed in 6.1 sec - Pass 2 of 2: Completed in 5.8 sec Evaluation completed in 13 sec
Обучение нейронной сети является итеративным. В каждой итерации datastore считывает данные из файлов и преобразовывает данные прежде, чем обновить сетевые коэффициенты. Если совпадения данных в память о вашем компьютере, импортируя данные из файлов в память включают более быстрое обучение путем устранения этого повторного чтения из файла, и преобразуйте процесс. Вместо этого данные считаны из файлов и преобразованы однажды. Обучение эта сеть с помощью файлов данных на диске занимает приблизительно 110 минут, в то время как обучение с помощью данных в оперативной памяти занимает приблизительно 50 min.
Импортируйте все данные в файлах в память. Файлы имеют две переменные: frame
и label
и каждый read
вызов datastore возвращает массив ячеек, где первым элементом является frame
и вторым элементом является label
. Используйте transform
функции helperModClassReadFrame и helperModClassReadLabel, чтобы считать системы координат и метки. Используйте tall
массивы, чтобы включить параллельную обработку функций преобразования, в случае, если у вас есть лицензия Parallel Computing Toolbox. Начиная с gather
функция, по умолчанию, конкатенирует выход read
функционируйте по первой размерности, возвратите системы координат в массиве ячеек и вручную конкатенируйте по 4-й размерности.
% Gather the training and validation frames into the memory
trainFramesTall = tall(transform(trainDSTrans, @helperModClassReadFrame));
rxTrainFrames = gather(trainFramesTall);
Evaluating tall expression using the Parallel Pool 'local': - Pass 1 of 1: Completed in 3.7 sec Evaluation completed in 3.7 sec
rxTrainFrames = cat(4, rxTrainFrames{:}); validFramesTall = tall(transform(validDSTrans, @helperModClassReadFrame)); rxValidFrames = gather(validFramesTall);
Evaluating tall expression using the Parallel Pool 'local': - Pass 1 of 1: Completed in 0.89 sec Evaluation completed in 0.91 sec
rxValidFrames = cat(4, rxValidFrames{:});
% Gather the training and validation labels into the memory
trainLabelsTall = tall(transform(trainDSTrans, @helperModClassReadLabel));
rxTrainLabels = gather(trainLabelsTall);
Evaluating tall expression using the Parallel Pool 'local': - Pass 1 of 2: Completed in 2.8 sec - Pass 2 of 2: Completed in 4.2 sec Evaluation completed in 8 sec
validLabelsTall = tall(transform(validDSTrans, @helperModClassReadLabel)); rxValidLabels = gather(validLabelsTall);
Evaluating tall expression using the Parallel Pool 'local': - Pass 1 of 2: Completed in 0.68 sec - Pass 2 of 2: Completed in 0.89 sec Evaluation completed in 1.9 sec
Этот пример использует CNN, который состоит из шести слоев свертки и одного полносвязного слоя. Каждый слой свертки кроме последнего сопровождается слоем нормализации партии., исправил линейный модуль (ReLU) слой активации и макс. объединение слоя. В последнем слое свертки макс. слой объединения заменяется средним слоем объединения. Выходной слой имеет softmax активацию. Для руководства проектирования сети смотрите Советы Глубокого обучения и Приемы.
modClassNet = helperModClassCNN(modulationTypes,sps,spf);
Затем сконфигурируйте TrainingOptionsSGDM
использовать решатель SGDM с мини-пакетным размером 256. Определите максимальный номер эпох к 12, поскольку большее число эпох не обеспечивает дальнейшего учебного преимущества. По умолчанию, 'ExecutionEnvironment'
свойство установлено в 'auto'
, где trainNetwork
функционируйте использует графический процессор, если вы доступны или используете центральный процессор, если нет. Чтобы использовать графический процессор, у вас должна быть лицензия Parallel Computing Toolbox. Установите начальную скорость обучения на . Уменьшайте скорость обучения на коэффициент 10 каждых 9 эпох. Установите 'Plots'
к 'training-progress'
построить процесс обучения. На Титане NVIDIA Xp графический процессор сеть занимает приблизительно 25 минут, чтобы обучаться..
maxEpochs = 12;
miniBatchSize = 256;
options = helperModClassTrainingOptions(maxEpochs,miniBatchSize,...
numel(rxTrainLabels),rxValidFrames,rxValidLabels);
Или обучите сеть или используйте, уже обучил сеть. По умолчанию этот пример использует обучивший сеть.
if trainNow == true fprintf('%s - Training the network\n', datestr(toc/86400,'HH:MM:SS')) trainedNet = trainNetwork(rxTrainFrames,rxTrainLabels,modClassNet,options); else load trainedModulationClassificationNetwork end
Когда график процесса обучения показывает, сеть сходится приблизительно в 12 эпох больше чем с 95%-й точностью.
Оцените обучивший сеть путем получения точности классификации для тестовых систем координат. Результаты показывают, что сеть достигает приблизительно 94%-й точности для этой группы форм волны.
fprintf('%s - Classifying test frames\n', datestr(toc/86400,'HH:MM:SS'))
00:02:03 - Classifying test frames
% Gather the test frames into the memory
testFramesTall = tall(transform(testDSTrans, @helperModClassReadFrame));
rxTestFrames = gather(testFramesTall);
Evaluating tall expression using the Parallel Pool 'local': - Pass 1 of 1: Completed in 0.68 sec Evaluation completed in 0.69 sec
rxTestFrames = cat(4, rxTestFrames{:});
% Gather the test labels into the memory
testLabelsTall = tall(transform(testDSTrans, @helperModClassReadLabel));
rxTestLabels = gather(testLabelsTall);
Evaluating tall expression using the Parallel Pool 'local': - Pass 1 of 2: Completed in 0.68 sec - Pass 2 of 2: Completed in 0.92 sec Evaluation completed in 2 sec
rxTestPred = classify(trainedNet,rxTestFrames); testAccuracy = mean(rxTestPred == rxTestLabels); disp("Test accuracy: " + testAccuracy*100 + "%")
Test accuracy: 95.4545%
Постройте матрицу беспорядка для тестовых систем координат. Когда матрица показывает, сеть путает 16-QAM и 64-QAM системы координат. Эта проблема ожидается, поскольку каждая система координат несет только 128 символов, и 16-QAM подмножество 64-QAM. Сеть также путает QPSK и системы координат 8-PSK, поскольку созвездия этих типов модуляции выглядят подобными когда-то вращаемый фазой из-за исчезающего канала и смещения частоты.
figure cm = confusionchart(rxTestLabels, rxTestPred); cm.Title = 'Confusion Matrix for Test Data'; cm.RowSummary = 'row-normalized'; cm.Parent.Position = [cm.Parent.Position(1:2) 740 424];
Проверьте производительность обучившего сеть с беспроводными сигналами с помощью функции helperModClassSDRTest. Чтобы выполнить этот тест, вы, должно быть, выделили SDRs для передачи и приема. Можно использовать два радио ADALM-PLUTO, или одно радио ADALM-PLUTO для передачи и один радио USRP® для приема. Необходимо установить Пакет Поддержки Communications Toolbox для Радио ADALM-PLUTO. Если вы используете радио USRP®, необходимо также установить Пакет Поддержки Communications Toolbox для Радио USRP®. helperModClassSDRTest
функционируйте использует те же функции модуляции, как используется для генерации учебных сигналов, и затем передает их использующий радио ADALM-PLUTO. Вместо того, чтобы симулировать канал, получите поврежденные каналом сигналы с помощью SDR, который сконфигурирован для приема сигнала (ADALM-PLUTO или радио USRP®). Используйте обучивший сеть с тем же classify
функция раньше ранее предсказывала тип модуляции. Выполнение следующего сегмента кода производит матрицу беспорядка и распечатывает тестовую точность.
radioPlatform = "ADALM-PLUTO"; switch radioPlatform case "ADALM-PLUTO" if helperIsPlutoSDRInstalled () == верный радио = findPlutoRadio (); if длина (радио)> = 2 helperModClassSDRTest (радио); else disp'Selected radios not found. Skipping over-the-air test.') end end case {"USRP B2xx","USRP X3xx","USRP N2xx"} if (helperIsUSRPInstalled () == верный) && (helperIsPlutoSDRInstalled () == верный) txRadio = findPlutoRadio (); rxRadio = findsdru (); switch radioPlatform case "USRP B2xx" idx = содержит ({rxRadio.Platform}, {'B200','B210'}); case "USRP X3xx" idx = содержит ({rxRadio.Platform}, {'X300','X310'}); case "USRP N2xx" idx = содержит ({rxRadio.Platform}, 'N200/N210/USRP2'); end rxRadio = rxRadio (idx); if (длина (txRadio)> = 1) && (длина (rxRadio)> = 1) helperModClassSDRTest (rxRadio); else disp'Selected radios not found. Skipping over-the-air test.') end end end
При использовании двух стационарных радио ADALM-PLUTO, разделенных приблизительно на 2 фута, сеть достигает 99%-й общей точности со следующей матрицей беспорядка. Результаты будут варьироваться на основе экспериментальной настройки.
Возможно оптимизировать параметры гиперпараметров, такие как количество фильтров, размера фильтра, или оптимизировать структуру сети, такую как добавление большего количества слоев, использование различных слоев активации, и т.д. улучшить точность.
Коммуникационный Тулбокс обеспечивает намного больше типов модуляции и нарушений канала. Для получения дополнительной информации смотрите Модуляцию (Communications Toolbox) и Модели Распространения и Канала (Communications Toolbox) разделы. Можно также добавить стандартные определенные сигналы с LTE Toolbox, WLAN Toolbox и 5G Toolbox. Можно также добавить радарные сигналы с Phased Array System Toolbox.
функция helperModClassGetModulator обеспечивает, функции MATLAB раньше генерировали модулируемые сигналы. Можно также исследовать следующие функции и Системные объекты для получения дополнительной информации:
О'Ши, T. J. Дж. Коргэн и Т. К. Клэнси. "Сверточные Радио-Сети Распознавания Модуляции". Предварительно распечатайте, представленный 10 июня 2016. https://arxiv.org/abs/1602.04105
О'Ши, T. J. Т. Рой и Т. К. Клэнси. "Беспроводная основанная на глубоком обучении Радио-Классификация Сигнала". Журнал IEEE Выбранных Тем в Обработке сигналов. Издание 12, Номер 1, 2018, стр 168–179.
Лю, X., Д. Янг и А. Э. Джамаль. "Архитектуры глубоких нейронных сетей для Классификации Модуляций". Предварительно распечатайте, представленный 5 января 2018. https://arxiv.org/abs/1712.00443v3
trainingOptions
| trainNetwork