POPLAR TUTORIAL 5: MATRIX-VECTOR MULTIPLICATION

Sungho Kim·2023년 11월 3일

IPU Programming

목록 보기
6/7

2.5. poplar tutorial 5: 행렬-벡터 곱셈

이 튜토리얼에서는 다음을 수행합니다. 소스코드는 여기

  • 행렬에 벡터를 곱하는 포플러 함수와 정점을 구축하려면 이 작업을 시도하기 전에 자습서 3을 완료하는 것이 좋습니다.
  • 주어진 두 벡터 사이의 내적을 계산하는 정점 코드를 작성합니다.
  • 그래프에 여러 정점을 추가하는 호스트 코드를 작성하고 이를 적절한 텐서 및 텐서 슬라이스에 연결합니다.
  • 선택적으로 IPU 하드웨어에서 실행되는 이 프로그램의 버전을 생성합니다.

이 튜토리얼의 마지막 부분에 간략한 요약이 포함되어 있습니다. 이 튜토리얼을 보완하려면 주저하지 말고 Poplar 및 PopLibs 사용자 가이드를 읽어보세요 . tut5_matrix_vector/start_here작업 디렉터리로 사용하세요 .

설정

IPU에서 이 튜토리얼을 실행하려면 Poplar SDK 환경을 활성화해야 합니다(IPU 시스템 시작 안내서 참조).

또한 C++11 표준과 호환되는 C++ 도구 체인이 필요합니다. 이 튜토리얼의 빌드 ​​명령은 GCC를 사용합니다.

vertex code

파일에는 matrix-mul-codelets.cpp내적을 수행하는 정점 코드에 대한 개요가 포함되어 있습니다. 입력 및 출력 필드는 이미 정의되어 있습니다.

class DotProductVertex : public Vertex {
public:
  Input<Vector<float>> a;
  Input<Vector<float>> b;
  Output<float> out;
}

TO DO (1): vertex code 작성

정점이 포플러에 계산을 제공하려면 compute방법이 DotProductVertex완료되어야 합니다. 이 메서드는 두 입력 벡터 의 내적을 계산 a하고 b스칼라 결과를 에 저장 해야 합니다 out.

대수적으로 두 벡터 a=[a0,a1,,an]a = [a_0, a_1, …, a_n]b=[b0,b1,,bn]b = [b_0, b_1, …, b_n]의 dot product은 다음과 같이 계산됩니다.

a0b0+a1b1++anbna_0 * b_0 + a_1 * b_1 + … + a_n * b_n

튜토리얼 3의 코드렛을 다시 살펴보는 것도 유용할 수 있습니다 . 팁: compute코드렛의 메소드 내에서 를 사용하여 벡터의 요소 수를 찾을 수 a있습니다 a.size().

호스트 코드

호스트 코드는 이전 자습서의 호스트 코드와 유사한 패턴을 따릅니다.

입력 행렬, 입력 벡터 및 출력 벡터에 대해 정의된 세 가지 텐서가 있습니다.

Tensor matrix = graph.addVariable(FLOAT, {numRows, numCols}, "matrix");
Tensor inputVector = graph.addVariable(FLOAT, {numCols}, "inputVector");
Tensor outputVector = graph.addVariable(FLOAT, {numRows}, "outputVector");

이 함수는 buildMultiplyProgram곱셈을 수행하기 위한 그래프와 제어 프로그램을 생성합니다. 제어 프로그램은 이라는 단일 계산 세트를 실행합니다 mulCS. 이 컴퓨팅 세트는 출력 벡터의 각 출력 요소에 대한 꼭짓점(즉, 입력 행렬의 각 행에 대한 하나의 꼭짓점)으로 구성됩니다.

TO DO (2): 그래프에 정점을 추가합니다.

이 자습서의 다음 작업은 호스트 코드를 작성하여 컴퓨팅 세트에 정점을 추가하는 것입니다.

  • 반복을 수행하는 루프를 생성합니다 numRows. 각 반복은 그래프에 정점을 추가합니다. t힌트: 모양이 인 포플러 텐서가 주어지면 를 사용하여 i번째 차원의 크기를 얻을 수 있습니다 . 예를 들면 .{numRows, numCols}t.dim(i)numRows == t.dim(0)

  • 그래프 개체의 기능을 사용하여 컴퓨팅 세트 에 addVertex정점 유형을 추가합니다 . 튜토리얼 3 에서 정점을 추가한 방법을 다시 살펴보는 것이 도움이 될 수 있습니다 .DotProductVertexmulCS

  • addVertex의 마지막 인수를 사용하여 정점의 필드를 해당 행의 관련 텐서 슬라이스에 연결합니다. v예를 들어, 입력 in과 출력이 있는 꼭지점을 만들고 싶고 out그래프에서 이미 동일한 이름을 가진 두 개의 텐서를 정의했다고 가정하면 다음과 같이 꼭지점을 만들 수 있습니다.

VertexRef v = graph.addVertex(computeSet, "v", {{"in", in}, {"out", out}});

이 경우 각 꼭지점은 행렬의 한 행(텐서에서 인덱스 연산자를 사용할 수 있습니다 matrix. 예를 들어 i번째 행은 matrix[i])과 전체 in텐서를 가져와서 텐서의 단일 요소로 출력합니다 out.

  • 새로 생성된 정점을 타일에 매핑합니다. i가 우리가 속한 루프의 카운터라면 정점을 타일에 매핑할 수 있습니다 i. 다시 한 번 튜토리얼 3에서 이 작업을 어떻게 수행했는지 확인하는 것이 도움이 될 수 있습니다.

  • 마지막으로 graph.setPerfEstimate()이 정점을 실행하는 데 걸리는 예상 주기 수를 지정하는 데 사용합니다. 이는 장치를 사용할 때만 필요하며 IPUModel프로파일링 외에는 실제로 중요하지 않습니다. 따라서 임의의 정수를 설정할 수 있습니다.

이 코드를 추가한 후 예제를 빌드하고 실행할 수 있습니다. 프로그램을 컴파일하기 위해 makefile이 제공됩니다. 실행하여 빌드할 수 있습니다.make

호스트 프로그램 코드에서 볼 수 있듯이 행렬의 크기를 지정하는 실행 명령에 두 개의 인수를 제공해야 합니다. 예를 들어, 아래와 같이 프로그램을 실행하면 40x50 행렬에 크기 50의 벡터가 곱해집니다.

./tut5_start_here 40 50

호스트 코드에는 결과의 정확성에 대한 검사가 포함됩니다.

(Optional) IPU 사용

이 섹션에서는 IPU 하드웨어를 사용하도록 프로그램을 수정하는 방법을 설명합니다.

  • 복사 tut5.cpp하여 tut5_ipu_hardware.cpp편집기에서 엽니다.
  • 다음 포함 줄을 추가하세요.
#include <poplar/DeviceManager.hpp>
#include <algorithm>
  • IPU 모델 장치를 생성하는 다음 줄을 제거합니다.
IPUModel ipuModel;
Device device = ipuModel.createDevice();
  • 그리고 시작 부분에 다음 줄을 추가합니다 main.
// Create the DeviceManager which is used to discover devices
auto manager = DeviceManager::createDeviceManager();

// Attempt to attach to a single IPU:
auto devices = manager.getDevices(poplar::TargetType::IPU, 1);
std::cout << "Trying to attach to IPU\n";
auto it = std::find_if(devices.begin(), devices.end(), [](Device &device) {
   return device.attach();
});

if (it == devices.end()) {
  std::cerr << "Error attaching to device\n";
  return 1; //EXIT_FAILURE
}

auto device = std::move(*it);
std::cout << "Attached to IPU " << device.getId() << std::endl;

이는 호스트에 연결된 단일 IPU로 구성된 모든 장치 목록을 가져오고 성공할 때까지 각 장치에 차례로 연결을 시도합니다. 이는 호스트에 여러 사용자가 있는 경우 유용한 접근 방식입니다. 해당 기능과 함께 장치 관리자 ID를 사용하여 특정 장치를 가져오는 것도 가능합니다 getDevice.

  • setPerfEstimatein 함수 가 있는 줄을 제거합니다 buildMultiplyProgram.
graph.setPerfEstimate(v, 20);

DotProductVertex이 줄은 주어진 꼭짓점에 대해 계산이 수행되는 주기 수에 대한 추정치를 제공하며, 이 튜토리얼에서 와 같이 IPU 모델을 사용하고 사용자 정의 꼭짓점을 작성할 때만 필요합니다. IPU 하드웨어를 사용할 때 튜토리얼 4와 같이 프로그램을 프로파일링하기로 결정하면 사이클이 측정됩니다 .

  • 프로그램을 컴파일하십시오.
g++ --std=c++11 tut5_ipu_hardware.cpp -lpoplar -lpoputil -o tut5_ipu

이를 실행하기 전에 IPU에 연결하기 위해 시스템이 올바르게 구성되었는지 확인해야 합니다(IPU 시스템 시작 안내서 참조 ).

  • 프로그램을 실행하여 IPU 모델에서 실행한 것과 동일한 결과를 확인하세요.
./tut5_ipu_hardware

요약

이 튜토리얼에서는 사용자 정의 정점을 사용하여 행렬-벡터 곱셈을 수행하는 프로그램을 작성했습니다. 코드렛 자체는 두 벡터 사이의 내적을 계산합니다. 행렬과 벡터 사이의 곱셈을 계산하기 위해 우리는 이러한 정점 중 여러 개를 포플러 그래프에 추가했습니다(행렬의 각 행에 대해 하나씩). 마지막으로 이를 적절한 행과 텐서에 연결했습니다. 이러한 정점은 모두 동일한 컴퓨팅 세트에 추가되었습니다. 즉, IPU에서 병렬로 실행됩니다. 우리는 IPU 모델에서 프로그램을 실행하지만 IPU 하드웨어에서 실행하려면 어떤 변경이 필요한지 살펴보았습니다.

profile
오복, 무심

0개의 댓글