Возникли проблемы с MPSMatrixMultiplication encodeToBuffer
Я использую MPSMatrixMultiplication, и когда я вызываю encodeToCommandBuffer, появляется сообщение об ошибке "Начальная матрица должна содержаться в каждом из объектов MPSMatrix". Я не уверен, что это значит.
Я просто пытаюсь сделать простое вычисление, и кажется, что если я применяю подобный код и шаблон в swift, это работает отлично, но в Objective-c это дает мне ошибку.
#import <Foundation/Foundation.h>
#import <Metal/Metal.h>
#import <MetalKit/MetalKit.h>
#import <MetalPerformanceShaders/MetalPerformanceShaders.h>
NS_ASSUME_NONNULL_BEGIN
//Interface
@interface KernelCalculator: NSObject
///Properties
@property id<MTLDevice> device;
@property id<MTLBuffer> bufferA;
@property id<MTLBuffer> bufferB;
@property id<MTLBuffer> bufferC;
@property MTKView *view;
@property id<MTLCommandQueue> commandQueue;
@property id<MTLCommandBuffer> commandBuffer;
@property MPSMatrixMultiplication *mmKernel;
@end
NS_ASSUME_NONNULL_END
#import "KernelCalculator.h"
@implementation KernelCalculator
- (instancetype)init
{
self = [super init];
if (self)
{
_view = [[MTKView alloc] init];
_view.device = MTLCreateSystemDefaultDevice();
if(!_view.device){
NSLog(@"Metal is not supported on this device");
return self;
}
_device = _view.device;
_commandQueue = [_device newCommandQueue];
_commandBuffer = [_commandQueue commandBuffer];
//Float array A
float _matrix_A[] = {
2.0, 3.0, 4.0
};
//Float array B
float _matrix_B[] = {
2.0, 2.0, 2.0
};
//size of each array
int matrix_A_length= sizeof(_matrix_A)/sizeof(float);
int matrix_B_length= sizeof(_matrix_B)/sizeof(float);
///<A>
int totalBytesA = sizeof(_matrix_A);
_bufferA = [_device newBufferWithBytes:_matrix_A length:totalBytesA options: MTLResourceCPUCacheModeDefaultCache];
MPSMatrixDescriptor *descriptionA = [[MPSMatrixDescriptor alloc] init];
[descriptionA setRows:3];
[descriptionA setColumns:1];
[descriptionA setRowBytes:totalBytesA/3];
[descriptionA setDataType:MPSDataTypeFloat32];
MPSMatrix *A = [[MPSMatrix alloc] initWithBuffer:_bufferA descriptor:descriptionA];
printf("\n A row: %lu ", (unsigned long)A.rows);
printf("\n A columns: %lu ", (unsigned long)A.columns);
printf("\n A rowBytes: %lu", (unsigned long)A.rowBytes);
printf("\n A totalBytes: %lu \n\n", (unsigned long)totalBytesA);
///</A>
///<B>
int totalBytesB = sizeof(_matrix_B);
_bufferB = [_device newBufferWithBytes:_matrix_B length:totalBytesB options: MTLResourceCPUCacheModeDefaultCache];
MPSMatrixDescriptor *descriptionB = [[MPSMatrixDescriptor alloc] init];
[descriptionB setRows:1];
[descriptionB setColumns:3];
[descriptionB setRowBytes:totalBytesB/1];
[descriptionB setDataType: MPSDataTypeFloat32];
MPSMatrix *B = [[MPSMatrix alloc] initWithBuffer:_bufferB descriptor:descriptionB];
printf("\n B row: %lu ", (unsigned long)B.rows);
printf("\n B columns: %lu ", (unsigned long)B.columns);
printf("\n B rowBytes: %lu", (unsigned long)B.rowBytes);
printf("\n B totalBytes: %lu \n\n", (unsigned long)totalBytesB);
///</B>
///<C>
int totalBytesC = matrix_A_length* matrix_B_length*sizeof(float);
_bufferC = [_device newBufferWithLength:totalBytesC options:MTLResourceCPUCacheModeDefaultCache];
MPSMatrixDescriptor *descriptionC = [[MPSMatrixDescriptor alloc] init];
[descriptionC setRows:A.rows];
[descriptionC setColumns:B.columns];
[descriptionC setRowBytes:totalBytesC/A.rows];
[descriptionC setDataType: MPSDataTypeFloat32];
MPSMatrix *C = [[MPSMatrix alloc] initWithBuffer:_bufferC descriptor:descriptionC];
printf("\n C row: %lu ", (unsigned long)C.rows);
printf("\n C columns: %lu ", (unsigned long)C.columns);
printf("\n C rowBytes: %lu", (unsigned long)C.rowBytes);
printf("\n C totalBytes: %lu \n\n", (unsigned long)totalBytesC);
///</C>
_mmKernel = [[MPSMatrixMultiplication alloc]
initWithDevice:_device
transposeLeft:false
transposeRight:false
resultRows:3
resultColumns:1
interiorColumns:1
alpha:1.0
beta:0.0];
[_mmKernel encodeToCommandBuffer: _commandBuffer leftMatrix:B rightMatrix:A resultMatrix:C];
[_commandBuffer commit];
[_commandBuffer waitUntilCompleted];
}
return self;
}
@end
Я был бы признателен, если бы просто указал на проблему, которая у меня есть в моем коде.
1 ответ
Это странное сообщение об ошибке, и оно само по себе заслуживает сообщения об ошибке.
Проблема в том, что вы вручную заполняете свои матричные дескрипторы, но не инициализируете все необходимые поля. В частности, каждый из ваших матричных дескрипторов matrices
а также matrixBytes
свойства установлены в 0, что является недопустимой конфигурацией.
Хотя эти свойства, кажется, не проверяются во время создания матрицы, они, похоже, проверяются во время кодирования, что приводит к этой ошибке. На мой взгляд, во время создания матрицы должна быть более строгая проверка, но потому что MPSMatrix
такая легкая обертка вокруг буфера, это, вероятно, не было сочтено необходимым.
В любом случае, лучший способ избежать этого - использовать метод фабрики матричных дескрипторов, чтобы заполнить оставшиеся поля. Это меньше кода, и это более стильно. Например:
MPSMatrixDescriptor * descriptionA =
[MPSMatrixDescriptor matrixDescriptorWithRows:3
columns:1
rowBytes:totalBytesA/3
dataType:MPSDataTypeFloat32];
Кроме того, у вас, похоже, есть ошибка при создании ядра и вызовах кодирования: resultColumns
должно быть 3, а не 1; leftMatrix
должно быть A
; а также rightMatrix
должно быть B, чтобы получить матрицу результата 3x3.