Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Windows ML admite la carga y ejecución de cadenas de modelos de alto rendimiento mediante una cuidadosa optimización de la ruta GPU. Las cadenas de modelo se definen mediante dos o más modelos que se ejecutan secuencialmente, donde las salidas de un modelo se convierten en las entradas del siguiente modelo hacia abajo de la cadena.
Para explicar cómo encadenar modelos con Windows ML de forma eficaz, vamos a usar el modelo de transferencia de estilo FNS-Candy de ONNX como ejemplo. Puede encontrar este tipo de modelo en la carpeta de ejemplo de transferencia de estilo FNS-Candy en nuestro GitHub.
Supongamos que queremos ejecutar una cadena compuesta por dos instancias del mismo modelo de FNS-Candy, aquí denominada mosaic.onnx. El código de aplicación pasaría una imagen al primer modelo de la cadena, le permite calcular las salidas y, a continuación, pasar esa imagen transformada a otra instancia de FNS-Candy, lo que genera una imagen final.
En los pasos siguientes se muestra cómo hacerlo con Windows ML.
Nota:
En un escenario de palabra real, probablemente usaría dos modelos diferentes, pero esto debería ser suficiente para ilustrar los conceptos.
- En primer lugar, vamos a cargar el modelo mosaic.onnx para poder usarlo.
std::wstring filePath = L"path\\to\\mosaic.onnx";
LearningModel model = LearningModel::LoadFromFilePath(filePath);
string filePath = "path\\to\\mosaic.onnx";
LearningModel model = LearningModel.LoadFromFilePath(filePath);
- A continuación, vamos a crear dos sesiones idénticas en la GPU predeterminada del dispositivo con el mismo modelo que el parámetro de entrada.
LearningModelSession session1(model, LearningModelDevice(LearningModelDeviceKind::DirectX));
LearningModelSession session2(model, LearningModelDevice(LearningModelDeviceKind::DirectX));
LearningModelSession session1 =
new LearningModelSession(model, new LearningModelDevice(LearningModelDeviceKind.DirectX));
LearningModelSession session2 =
new LearningModelSession(model, new LearningModelDevice(LearningModelDeviceKind.DirectX));
Nota:
Para aprovechar las ventajas de rendimiento del encadenamiento, debe crear sesiones de GPU idénticas para todos los modelos. No hacerlo daría lugar a un movimiento de datos adicional fuera de la GPU y a la CPU, lo que reduciría el rendimiento.
- Las siguientes líneas de código crearán enlaces para cada sesión:
LearningModelBinding binding1(session1);
LearningModelBinding binding2(session2);
LearningModelBinding binding1 = new LearningModelBinding(session1);
LearningModelBinding binding2 = new LearningModelBinding(session2);
- A continuación, enlazaremos una entrada para nuestro primer modelo. Vamos a pasar una imagen que se encuentra en la misma ruta de acceso que nuestro modelo. En este ejemplo, la imagen se denomina "fish_720.png".
//get the input descriptor
ILearningModelFeatureDescriptor input = model.InputFeatures().GetAt(0);
//load a SoftwareBitmap
hstring imagePath = L"path\\to\\fish_720.png";
// Get the image and bind it to the model's input
try
{
StorageFile file = StorageFile::GetFileFromPathAsync(imagePath).get();
IRandomAccessStream stream = file.OpenAsync(FileAccessMode::Read).get();
BitmapDecoder decoder = BitmapDecoder::CreateAsync(stream).get();
SoftwareBitmap softwareBitmap = decoder.GetSoftwareBitmapAsync().get();
VideoFrame videoFrame = VideoFrame::CreateWithSoftwareBitmap(softwareBitmap);
ImageFeatureValue image = ImageFeatureValue::CreateFromVideoFrame(videoFrame);
binding1.Bind(input.Name(), image);
}
catch (...)
{
printf("Failed to load/bind image\n");
}
//get the input descriptor
ILearningModelFeatureDescriptor input = model.InputFeatures[0];
//load a SoftwareBitmap
string imagePath = "path\\to\\fish_720.png";
// Get the image and bind it to the model's input
try
{
StorageFile file = await StorageFile.GetFileFromPathAsync(imagePath);
IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.Read);
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
SoftwareBitmap softwareBitmap = await decoder.GetSoftwareBitmapAsync();
VideoFrame videoFrame = VideoFrame.CreateWithSoftwareBitmap(softwareBitmap);
ImageFeatureValue image = ImageFeatureValue.CreateFromVideoFrame(videoFrame);
binding1.Bind(input.Name, image);
}
catch
{
Console.WriteLine("Failed to load/bind image");
}
- Para que el siguiente modelo de la cadena use las salidas de la evaluación del primer modelo, es necesario crear un tensor de salida vacío y enlazar la salida para que tengamos un marcador para encadenar con:
//get the output descriptor
ILearningModelFeatureDescriptor output = model.OutputFeatures().GetAt(0);
//create an empty output tensor
std::vector<int64_t> shape = {1, 3, 720, 720};
TensorFloat outputValue = TensorFloat::Create(shape);
//bind the (empty) output
binding1.Bind(output.Name(), outputValue);
//get the output descriptor
ILearningModelFeatureDescriptor output = model.OutputFeatures[0];
//create an empty output tensor
List<long> shape = new List<long> { 1, 3, 720, 720 };
TensorFloat outputValue = TensorFloat.Create(shape);
//bind the (empty) output
binding1.Bind(output.Name, outputValue);
Nota:
Debe usar el tipo de datos TensorFloat al enlazar la salida. Esto impedirá que la des tensorización se produzca una vez completada la evaluación del primer modelo, por lo que también se evitará la puesta en cola de GPU adicional para las operaciones de carga y enlace para el segundo modelo.
- Ahora, ejecutamos la evaluación del primer modelo y enlazamos sus salidas a la entrada del siguiente modelo:
//run session1 evaluation
session1.EvaluateAsync(binding1, L"");
//bind the output to the next model input
binding2.Bind(input.Name(), outputValue);
//run session2 evaluation
auto session2AsyncOp = session2.EvaluateAsync(binding2, L"");
//run session1 evaluation
await session1.EvaluateAsync(binding1, "");
//bind the output to the next model input
binding2.Bind(input.Name, outputValue);
//run session2 evaluation
LearningModelEvaluationResult results = await session2.EvaluateAsync(binding2, "");
- Por último, vamos a recuperar la salida final generada después de ejecutar ambos modelos mediante la siguiente línea de código.
auto finalOutput = session2AsyncOp.get().Outputs().First().Current().Value();
var finalOutput = results.Outputs.First().Value;
Eso es todo. Ambos modelos ahora se pueden ejecutar secuencialmente aprovechando al máximo los recursos de GPU disponibles.
Nota:
Use los siguientes recursos para obtener ayuda con Windows ML:
- Para formular o responder preguntas técnicas sobre Windows ML, use la etiqueta windows-machine-learning en Stack Overflow.
- Para notificar un error, envíe un problema en nuestra GitHub.