Нейронные сети с параллелью и вычислением графического процессора

Глубокое обучение

Можно обучить сверточную нейронную сеть (CNN, ConvNet) или длинные краткосрочные сети памяти (сети LSTM или BiLSTM) использование функции trainNetwork. Можно выбрать среду выполнения (центральный процессор, графический процессор, мультиграфический процессор и параллель) использование trainingOptions.

Обучение параллельно, или на графическом процессоре, требует Parallel Computing Toolbox™. Для получения дополнительной информации о глубоком обучении для графических процессоров и параллельно, смотрите Глубокое обучение для Больших данных на центральных процессорах, графических процессорах, параллельно, и на Облаке.

Режимы параллелизма

Нейронные сети являются по сути параллельными алгоритмами. Многожильные центральные процессоры, графические блоки обработки (графические процессоры) и кластеры компьютеров с несколькими центральными процессорами и графических процессоров могут использовать в своих интересах этот параллелизм.

Parallel Computing Toolbox, когда используется в сочетании с Deep Learning Toolbox™, позволяет обучению нейронной сети и симуляции использовать в своих интересах каждый режим параллелизма.

Например, следующее показывает стандартный однопоточный сеанс обучения и симуляции:

[x, t] = bodyfat_dataset;
net1 = feedforwardnet(10);
net2 = train(net1, x, t);
y = net2(x);

Два шага, которые можно параллелизировать на этом сеансе, являются вызовом train и неявным вызовом sim (где сеть net2 называется как функция).

В Deep Learning Toolbox можно разделить любые данные, такие как x и t в коде предыдущего примера, через выборки. Если x и t содержат только одну выборку каждый, нет никакого параллелизма. Но если x и t содержат сотни или тысячи выборок, параллелизм может обеспечить и скорость и проблемные преимущества размера.

Распределенные вычисления

Parallel Computing Toolbox позволяет обучению нейронной сети и симуляции натыкаться на несколько ядер процессора на одном PC, или через несколько центральных процессоров на нескольких компьютерах в сети с помощью MATLAB® Parallel Server™.

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

Чтобы управлять кластерными конфигурациями, используйте Кластерного менеджера по Профилю из меню Environment вкладки MATLAB Home Parallel > Manage Cluster Profiles.

Чтобы открыть пул работников MATLAB, использующих кластерный профиль по умолчанию, который обычно является локальными ядрами процессора, используют эту команду:

pool = parpool
Starting parallel pool (parpool) using the 'local' profile ... connected to 4 workers.

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

pool.NumWorkers
   4

Теперь можно обучить и моделировать нейронную сеть с данными, разделенными выборкой через всех рабочих. Для этого установите train и параметр sim 'useParallel' к 'yes'.

net2 = train(net1,x,t,'useParallel','yes')
y = net2(x,'useParallel','yes')

Используйте аргумент 'showResources', чтобы проверить, что вычисления натыкались на несколько рабочих.

net2 = train(net1,x,t,'useParallel','yes','showResources','yes');
y = net2(x,'useParallel','yes','showResources','yes');

MATLAB указывает, какие ресурсы использовались. Например:

Computing Resources:
Parallel Workers
  Worker 1 on MyComputer, MEX on PCWIN64
  Worker 2 on MyComputer, MEX on PCWIN64
  Worker 3 on MyComputer, MEX on PCWIN64
  Worker 4 on MyComputer, MEX on PCWIN64

Когда train и sim называются, они делят входные данные о матрице или массиве ячеек на распределенные Составные значения перед обучением и симуляцией. Когда sim вычислил Составной объект, этот вывод преобразован назад в ту же форму матричного или массива ячеек, прежде чем это будет возвращено.

Однако вы можете хотеть выполнить это деление данных вручную если:

  • Проблемный размер является слишком большим для хоста - компьютера. Вручную определение элементов Составных значений последовательно позволяет намного большим проблемам быть заданными.

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

Следующий код последовательно создает серию случайных наборов данных и сохраняет их, чтобы разделить файлы:

pool = gcp;
for i=1:pool.NumWorkers
  x = rand(2,1000);
  save(['inputs' num2str(i)],'x');
  t = x(1,:) .* x(2,:) + 2 * (x(1,:) + x(2,:));
  save(['targets' num2str(i)],'t');
  clear x t
end

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

Теперь можно загрузить наборы данных последовательно через параллельных рабочих, и обучить и моделировать сеть на Составных данных. Когда train или sim вызваны Составными данными, аргумент 'useParallel' автоматически установлен в 'yes'. При использовании Составных данных сконфигурируйте вход сети и выходные параметры, чтобы совпадать с одним из наборов данных вручную с помощью функции configure перед обучением.

xc = Composite;
tc = Composite;
for i=1:pool.NumWorkers
  data = load(['inputs' num2str(i)],'x');
  xc{i} = data.x;
  data = load(['targets' num2str(i)],'t');
  tc{i} = data.t;
  clear data
end
net2 = configure(net1,xc{1},tc{1});
net2 = train(net2,xc,tc);
yc = net2(xc);

Чтобы преобразовать Composite выходной параметр, возвращенный sim, можно получить доступ к каждому из его элементов, отдельно, если затронуто ограничениями памяти.

for i=1:pool.NumWorkers
  yi = yc{i}
end

Объединенный Составное значение в одно локальное значение, если вы не обеспокоены ограничениями памяти.

y = {yc{:}};

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

Не требуется, что у каждого рабочего есть данные. Если элемент, i Составного значения не определен, рабочий i, не будет использоваться в вычислении.

Одно вычисление графического процессора

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

Для последних требований графического процессора смотрите веб-страницу для Parallel Computing Toolbox; или запросите MATLAB, чтобы определить, имеет ли ваш PC поддерживаемый графический процессор. Эта функция возвращает количество графических процессоров в вашей системе:

count = gpuDeviceCount
count =

    1

Если результат - один или несколько, можно запросить каждый графический процессор индексом для его характеристик. Это включает его имя, количество многопроцессорных систем, SIMDWidth каждой многопроцессорной системы и общую память.

gpu1 = gpuDevice(1)
gpu1 = 

  CUDADevice with properties:

                      Name: 'GeForce GTX 470'
                     Index: 1
         ComputeCapability: '2.0'
            SupportsDouble: 1
             DriverVersion: 4.1000
        MaxThreadsPerBlock: 1024
          MaxShmemPerBlock: 49152
        MaxThreadBlockSize: [1024 1024 64]
               MaxGridSize: [65535 65535 1]
                 SIMDWidth: 32
               TotalMemory: 1.3422e+09
           AvailableMemory: 1.1056e+09
       MultiprocessorCount: 14
              ClockRateKHz: 1215000
               ComputeMode: 'Default'
      GPUOverlapsTransfers: 1
    KernelExecutionTimeout: 1
          CanMapHostMemory: 1
           DeviceSupported: 1
            DeviceSelected: 1

Самый простой способ использовать в своих интересах графический процессор состоит в том, чтобы задать, вызывают train, и sim с набором аргумента 'useGPU' параметра к 'yes' ('no' является значением по умолчанию).

net2 = train(net1,x,t,'useGPU','yes')
y = net2(x,'useGPU','yes')

Если net1 имеет учебный функциональный trainlm по умолчанию, вы видите предупреждение, что вычисления графического процессора не поддерживают якобиевское обучение, только обучение градиента. Таким образом, учебная функция автоматически изменяется на функцию обучения градиента trainscg. Чтобы избежать уведомления, можно задать функцию перед обучением:

net1.trainFcn = 'trainscg';

Чтобы проверить, что обучение и симуляция происходят на устройстве графического процессора, запросите, чтобы ресурсы компьютера показали:

net2 = train(net1,x,t,'useGPU','yes','showResources','yes')
y = net2(x,'useGPU','yes','showResources','yes')

Каждая из вышеупомянутых строк кода выводит следующие сводные данные ресурсов:

Computing Resources:
GPU device #1, GeForce GTX 470

Много функций MATLAB автоматически выполняются на графическом процессоре, когда любой из входных параметров является gpuArray. Обычно вы перемещаете массивы в и от графического процессора с функциями gpuArray и gather. Однако для вычислений нейронной сети на графическом процессоре, чтобы быть эффективными, матрицы должны быть транспонированы, и столбцы дополнены так, чтобы первый элемент в каждом столбце выровнялся правильно в памяти графического процессора. Deep Learning Toolbox обеспечивает специальную функцию под названием nndata2gpu, чтобы переместить массив в графический процессор и правильно организовать его:

xg = nndata2gpu(x);
tg = nndata2gpu(t);

Теперь можно обучить и моделировать сеть с помощью конвертированных данных уже по графическому процессору, не имея необходимость задавать аргумент 'useGPU'. Затем преобразуйте и возвратите получившийся массив графического процессора назад в MATLAB с дополнительным функциональным gpu2nndata.

Перед обучением с gpuArray данными вход сети и выходные параметры должны быть вручную сконфигурированы с обычными матрицами MATLAB с помощью функции configure:

net2 = configure(net1,x,t);  % Configure with MATLAB arrays
net2 = train(net2,xg,tg);    % Execute on GPU with NNET formatted gpuArrays
yg = net2(xg);               % Execute on GPU
y = gpu2nndata(yg);          % Transfer array to local workspace

На графических процессорах и другом оборудовании, где вы можете хотеть развернуть свои нейронные сети, часто имеет место, что показательная функция exp не реализована с оборудованием, но с библиотекой программного обеспечения. Это может замедлить нейронные сети, которые используют tansig сигмоидальная передаточная функция. Альтернативной функцией является Эллиот сигмоидальная функция, выражение которой не включает вызов никаких функций высшего порядка:

(equation)	a = n / (1 + abs(n))

Перед обучением слои tansig сети могут быть преобразованы в слои elliotsig можно следующим образом:

for i=1:net.numLayers
  if strcmp(net.layers{i}.transferFcn,'tansig')
    net.layers{i}.transferFcn = 'elliotsig';
  end
end

Теперь обучение и симуляция могут быть быстрее на графическом процессоре и более простом оборудовании развертывания.

Распределенное вычисление графического процессора

Распределенный и вычисление графического процессора может быть объединен, чтобы выполнить вычисления через несколько центральных процессоров и/или графических процессоров на одиночном компьютере, или на кластере с MATLAB Parallel Server.

Самый простой способ сделать это должно задать train и sim для этого с помощью параллельного пула, определенного кластерным профилем, который вы используете. Опция 'showResources' особенно рекомендуется в этом случае, проверить, что ожидаемое оборудование используется:

net2 = train(net1,x,t,'useParallel','yes','useGPU','yes','showResources','yes')
y = net2(x,'useParallel','yes','useGPU','yes','showResources','yes')

Эти строки кода используют всех доступных рабочих в параллельном пуле. Один рабочий для каждого уникального графического процессора использует тот графический процессор, в то время как другие рабочие действуют в качестве центральных процессоров. В некоторых случаях это может быть быстрее, чтобы использовать только графические процессоры. Например, если одиночный компьютер имеет три графических процессора и четырех рабочих каждый, три рабочих, которые ускоряются этими тремя графическими процессорами, могут быть скоростью, ограниченной четвертым рабочим центрального процессора. В этих случаях можно указать, что train и sim используют только рабочих с уникальными графическими процессорами.

net2 = train(net1,x,t,'useParallel','yes','useGPU','only','showResources','yes')
y = net2(x,'useParallel','yes','useGPU','only','showResources','yes')

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

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

numSamples = [1000 1000 1000 300];
xc = Composite;
tc = Composite;
for i=1:4
  xi = rand(2,numSamples(i));
  ti = xi(1,:).^2 + 3*xi(2,:);
  xc{i} = xi;
  tc{i} = ti;
end

Можно теперь указать, что train и sim используют эти три доступные графических процессора:

net2 = configure(net1,xc{1},tc{1});
net2 = train(net2,xc,tc,'useGPU','yes','showResources','yes');
yc = net2(xc,'showResources','yes');

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

spmd
  if labindex <= 3
    xc = nndata2gpu(xc);
    tc = nndata2gpu(tc);
  end
end

Теперь данные задают, когда использовать графические процессоры, таким образом, вы не должны говорить train и sim делать так.

net2 = configure(net1,xc{1},tc{1});
net2 = train(net2,xc,tc,'showResources','yes');
yc = net2(xc,'showResources','yes');

Гарантируйте, что каждый графический процессор используется только одним рабочим, так, чтобы вычисления были самыми эффективными. Если несколько рабочих присвоят gpuArray данные по тому же графическому процессору, вычисление будет все еще работать, но будет медленнее, потому что графический процессор будет работать с данными нескольких рабочих последовательно.

Параллельные временные ряды

Для сетей временных рядов просто используйте значения массива ячеек для x и t, и опционально включайте начальную входную задержку, утверждает xi, и начальная задержка слоя утверждает ai, как требуется.

net2 = train(net1,x,t,xi,ai,'useGPU','yes')
y = net2(x,xi,ai,'useParallel','yes','useGPU','yes')

net2 = train(net1,x,t,xi,ai,'useParallel','yes')
y = net2(x,xi,ai,'useParallel','yes','useGPU','only')

net2 = train(net1,x,t,xi,ai,'useParallel','yes','useGPU','only')
y = net2(x,xi,ai,'useParallel','yes','useGPU','only')

Обратите внимание на то, что параллелизм происходит через выборки, или в случае временных рядов через различный ряд. Однако, если сеть только ввела задержки без задержек слоя, задержанные входные параметры могут быть предварительно вычислены так, чтобы в целях вычисления, временные шаги стали различными выборками и могли быть параллелизированы. Дело обстоит так для сетей, таких как timedelaynet и версии разомкнутого цикла narxnet и narnet. Если сеть имеет задержки слоя, то время не может быть “сглажено” в целях вычисления, и таким образом, одни серийные данные не могут быть параллелизированы. Дело обстоит так для сетей, таких как layrecnet и версии с обратной связью narxnet и narnet. Однако, если данные состоят из нескольких последовательностей, они могут быть параллелизированы через отдельные последовательности.

Параллельная доступность, нейтрализации и обратная связь

Как упомянуто ранее, можно запросить MATLAB, чтобы обнаружить текущие параллельные ресурсы, которые доступны.

Чтобы видеть то, что графические процессоры доступны на хосте - компьютере:

gpuCount = gpuDeviceCount
for i=1:gpuCount
  gpuDevice(i)
end

Чтобы видеть, как многие рабочие запускаются в текущем параллельном пуле:

poolSize = pool.NumWorkers

Видеть графические процессоры, доступные через параллельный пул, работающий на кластере PC использование MATLAB Parallel Server:

spmd
  worker.index = labindex;
  worker.name = system('hostname');
  worker.gpuCount = gpuDeviceCount;
  try
    worker.gpuInfo = gpuDevice;
  catch
    worker.gpuInfo = [];
  end
  worker
end

Когда 'useParallel' или 'useGPU' установлены в 'yes', но параллель или рабочие графического процессора недоступны, соглашение состоит в том, что, когда ресурсы требуют, они используются при наличии. Вычисление выполняется без ошибки, даже если они не. Этот процесс отступания от требуемых ресурсов до фактических ресурсов происходит можно следующим образом:

  • Если 'useParallel' является 'yes', но Parallel Computing Toolbox недоступен, или параллельный пул не открыт, то вычисление возвращается в однопоточный MATLAB.

  • Если 'useGPU' является 'yes', но gpuDevice для текущего сеанса работы с MATLAB является неприсвоенным или не поддержан, то вычисление возвращается к центральному процессору.

  • Если 'useParallel' и 'useGPU' является 'yes', то каждый рабочий с уникальным графическим процессором использует тот графический процессор, и другие рабочие возвращаются к центральному процессору.

  • Если 'useParallel' является 'yes', и 'useGPU' является 'only', то рабочие с уникальными графическими процессорами используются. Другие рабочие не используются, если ни у каких рабочих нет графических процессоров. В случае ни с какими графическими процессорами все рабочие используют центральные процессоры.

Когда не уверенный в том, какое оборудование на самом деле используется, проверяйте gpuDeviceCount, gpuDevice и pool.NumWorkers, чтобы гарантировать, что желаемое оборудование доступно, и вызовите train и sim с набором 'showResources' к 'yes', чтобы проверить, какие ресурсы на самом деле использовались.