Мелкие нейронные сети с параллельными и GPU- Вычисления

Примечание

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

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

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

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

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 позволяет проводить обучение и симуляцию нейронных сетей через несколько центральных процессорных ядер на одном ПК или через несколько центральных процессоров на нескольких компьютерах в сети с использованием MATLAB® Parallel Server™.

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

Для управления строений кластеров используйте Диспетчер профилей кластеров на вкладке 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 вычислил Composite, этот выход преобразуется назад в ту же матрицу или форму массива ячеек перед его возвращением.

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

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

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

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

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

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

Теперь можно последовательно загружать наборы данных между параллельными рабочими, а также обучать и моделировать сеть на составных данных. Когда 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);

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

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

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

y = {yc{:}};

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

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

Вычисления на одном графическом процессоре

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

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

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. Однако, чтобы вычисления нейронной сети на графическом процессоре были эффективными, матрицы должны быть транспонированы, а столбцы заполнены так, чтобы первый элемент в каждом столбце правильно выравнивался в памяти GPU. Deep Learning Toolbox предоставляет специальную функцию под названием nndata2gpu чтобы переместить массив в графический процессор и правильно организовать его:

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

Теперь можно обучать и моделировать сеть, используя преобразованные данные уже на графическом процессоре, не задавая 'useGPU' аргумент. Затем преобразуйте и верните полученный массив GPU обратно в 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 сигмоидная передаточная функция. Альтернативной функцией является сигмоидная функция Elliot, выражение которой не включает вызов каких-либо функций более высокого порядка:

(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 для этого используйте параллельный пул, определяемый используемым профилем кластера. The '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')

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

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

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

Чтобы увидеть графические процессоры, доступные в параллельном пуле, работающем в кластере ПК с помощью 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' чтобы проверить, какие ресурсы использовались на самом деле.