首先我想说我在 ML 方面完全是新手,特别是在 .NET ML 方面。 我在 ONNX 和 .NET 8 API 应用程序中有本地 phi-3 模型
// Program.cs
var builder = WebApplication.CreateBuilder(args);
var modelDirectory = @"path-to-local-model-directory";
builder
.Services
.AddSingleton(new Model(modelDirectory))
.AddSingleton<Tokenizer>();
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
以及从模型返回响应的控制器:
//TestController.cs
[ApiController]
[Route("[controller]")]
public class TestController(Model model, Tokenizer tokenizer) : ControllerBase
{
[HttpPost("generate")]
public string Generate([FromBody] Dto dto)
{
using var tokens = tokenizer.Encode(dto.test);
using var generatorParams = new GeneratorParams(model);
generatorParams.SetSearchOption("max_length", 2048);
generatorParams.SetInputSequences(tokens);
var result = new StringBuilder();
using var generator = new Generator(model, generatorParams);
while (!generator.IsDone())
{
generator.ComputeLogits();
generator.GenerateNextToken();
var outputTokens = generator.GetSequence(0);
var newToken = outputTokens.Slice(outputTokens.Length - 1, 1);
result.Append(tokenizer.Decode(newToken));
}
return result.ToString();
}
}
public class Dto
{
public string test { get; set; }
}
这段代码运行良好,但我感兴趣的是这个应用程序如何处理并行请求,我得到了这个结果:
并行请求数 | 完成所有请求的总时间 | 平均请求完成时间 | 内存使用 | 处理器使用 |
---|---|---|---|---|
1 | 00:01:50.30 | 00:01:50.18 | 4.3GB | < 20% |
2 | 00:03:07.82 | 00:03:07.64 | 5.4GB | ~25% |
3 | 00:04:19.06 | 00:04:18.73 | 6.6GB | ~30% |
4 | 00:05:36.74 | 00:05:35.96 | 7.8 GB | ~50% |
我们看到,请求确实是并行执行的,因为完成的总时间等于平均请求时间。我还了解到,当并行请求数量增加时,RAM 和 CPU 使用率也会增加。但我不明白为什么每个请求的时间增加了?
也许还可以以不同的方式使用 Microsoft.ML.OnnxRuntimeGenAI 来提高并行请求的性能?
我想我在这里找到答案https://www.databricks.com/blog/llm-inference-performance-engineering-best-practices
在本文中,我发现对于 LLM 来说内存带宽是关键,这解释了为什么并行请求会增加每个请求的持续时间而无需 CPU 限制。在这种情况下,内存带宽成为瓶颈,并行进程会竞争对 RAM 的访问