Я использую macOS на своем MacBook Pro (Retina, 15-дюймовый, середина 2015 г.), в котором есть два графических процессора, в соответствии с пунктом «Об этом Ма c» в меню Apple. Один графический процессор - AMD Radeon R9 M370X 2 ГБ, другой - Intel Iris Pro 1536 МБ - стандартные чипы, я полагаю? Это чипы, которые были там, когда я его купил, я ничего себе не добавил.
Я использую библиотеку Swift MPS для матричных вычислений; он отлично работает на графическом процессоре Intel, но когда я выбираю Radeon, я получаю только нули обратно от каждой операции, без сообщений об ошибках. Я искал документацию, но ничего не могу найти. Единственная подсказка, которую я имею до сих пор, заключается в том, что Radeon сообщает, что он «не интегрирован» (или, по крайней мере, я думаю, что так и есть, основываясь на примере кода на Поиск графических процессоров на macOS , что примерно так же полезно, как на Apple do c когда-либо есть, что означает не очень ). Если я правильно прочитал эту страницу, это то, что мне говорят мои два графических процессора.
Device Intel Iris Pro Graphics; caps: headful, not discrete, integrated, not external
Device AMD Radeon R9 M370X; caps: headful, discrete, not integrated, not external
Я не могу найти ничего c это подсказало бы, что я делаю неправильно. Я проверил документацию Apple MPS, но безрезультатно. И, как я уже сказал, код прекрасно работает на Intel GPU, поэтому я думаю, что он будет работать и на Radeon. Я запустил некоторые загружаемые инструменты диагностики c, чтобы проверить Radeon, но он не отображается в меню этих инструментов. Поэтому я даже не знаю, что я делаю неправильно в коде, или сам чип сломан.
Ниже приведен код, который вы можете создать как консольное приложение, вставив в него код. main.swift
. Найдите следующую строку:
let device = MTLCopyAllDevices()[1]
Я использую [0]
для Intel, [1]
для Radeon, и вы можете видеть, что вывод отличается, то есть все нули для Radeon. Я полагаю, ваш пробег может варьироваться в зависимости от вашей машины. Я приветствую любой вклад, ура
import MetalPerformanceShaders
typealias MPSNumber = Float32
let MPSNumberSize = MemoryLayout<MPSNumber>.size
let MPSNumberTypeInGPU = MPSDataType.float32
class MPSNet {
let commandBuffer: MTLCommandBuffer
let commandQueue: MTLCommandQueue
let device = MTLCopyAllDevices()[1]
var neuronsInMatrix1: MPSMatrix?
var neuronsInMatrix2: MPSMatrix?
var neuronsOutMatrix: MPSMatrix?
init() {
guard let cq = device.makeCommandQueue() else { fatalError() }
guard let cb = cq.makeCommandBuffer() else { fatalError() }
commandQueue = cq
commandBuffer = cb
let cMatrices = 2
let cRows = 1
let cColumns = 3
let sensoryInputs1: [MPSNumber] = [1, 2, 3]
let sensoryInputs2: [MPSNumber] = [4, 5, 6]
neuronsInMatrix1 = makeMatrix(device, sensoryInputs1)
neuronsInMatrix2 = makeMatrix(device, sensoryInputs2)
let rowStride = MPSMatrixDescriptor.rowBytes(fromColumns: cColumns, dataType: MPSNumberTypeInGPU)
neuronsOutMatrix = makeMatrix(device, cRows, cColumnsOut: cColumns, rowStride: rowStride)
let adder = MPSMatrixSum(
device: device, count: cMatrices, rows: cRows, columns: cColumns, transpose: false
)
adder.encode(
to: commandBuffer,
sourceMatrices: [neuronsInMatrix1!, neuronsInMatrix2!],
resultMatrix: neuronsOutMatrix!, scale: nil, offsetVector: nil,
biasVector: nil, start: 0
)
commandBuffer.addCompletedHandler { _ in
let motorOutputs = self.getComputeOutput(self.neuronsOutMatrix!)
let discrete = !self.device.isLowPower && !self.device.isRemovable
let caps = "\(self.device.isHeadless ? " headless" : " headful")" +
"\(discrete ? ", discrete" : ", not discrete")" +
"\(self.device.isLowPower ? ", integrated" : ", not integrated")" +
"\(self.device.isRemovable ? ", external" : ", not external")"
print("Device \(self.device.name); caps:\(caps); motor outputs \(motorOutputs)")
}
}
func compute() {
commandBuffer.commit()
commandBuffer.waitUntilCompleted()
}
}
extension MPSNet {
func getComputeOutput(_ matrix: MPSMatrix) -> [Double] {
let rc = matrix.data.contents()
return stride(from: 0, to: matrix.columns * MPSNumberSize, by: MPSNumberSize).map {
offset in
let rr = rc.load(fromByteOffset: offset, as: MPSNumber.self)
return Double(rr)
}
}
func loadMatrix(_ data: MTLBuffer, _ rawValues: [MPSNumber]) {
let dContents = data.contents()
zip(stride(from: 0, to: rawValues.count * MPSNumberSize, by: MPSNumberSize), rawValues).forEach { z in
let (byteOffset, rawValue) = (z.0, MPSNumber(z.1))
dContents.storeBytes(of: rawValue, toByteOffset: byteOffset, as: MPSNumber.self)
}
}
func makeMatrix(_ device: MTLDevice, _ rawValues: [MPSNumber]) -> MPSMatrix {
let rowStride = MPSMatrixDescriptor.rowBytes(
fromColumns: rawValues.count, dataType: MPSNumberTypeInGPU
)
let descriptor = MPSMatrixDescriptor(
dimensions: 1, columns: rawValues.count, rowBytes: rowStride,
dataType: MPSNumberTypeInGPU
)
guard let inputBuffer = device.makeBuffer(
length: descriptor.matrixBytes, options: MTLResourceOptions.storageModeManaged
) else { fatalError() }
loadMatrix(inputBuffer, rawValues)
return MPSMatrix(buffer: inputBuffer, descriptor: descriptor)
}
func makeMatrix(_ device: MTLDevice, _ cRowsOut: Int, cColumnsOut: Int, rowStride: Int) -> MPSMatrix {
let matrixDescriptor = MPSMatrixDescriptor(
dimensions: cRowsOut, columns: cColumnsOut,
rowBytes: rowStride, dataType: MPSNumberTypeInGPU
)
return MPSMatrix(device: device, descriptor: matrixDescriptor)
}
}
let net = MPSNet()
net.compute()