[ggerganov/llama.cpp]控制台:修复 LC_ALL 未定义时 getwchar 失败

2024-03-22 561 views
7

修复#3638

似乎某些 Linux 发行版可能LC_ALL未定义并被LANG使用,这会导致getwchar()unicode 转换失败,但更重要的是,这会“毒害” stdin( /dev/tty) 导致任何后续无限期getwchar返回WEOF

此 PR 通过添加一个回退设置区域设置来解决此问题,LANG如果该区域设置也未定义,则将区域设置设置为C.UTF-8确保 IO 处于 unicode 兼容模式。

图像

回答

7

这并不能解决 Ctrl+C 不停止生成的问题。

另请注意,LC_ALL 环境变量和 LC_ALL 常量具有不同的含义。通常,不需要设置 LC_ALL 环境变量,对我来说,非 ASCII 输入在没有它和没有此更改的情况下也可以工作。

1

也许我们正在考虑具有相似症状的不同问题。

我可以 100% 地重现这个问题,如果 LC_ALL 未设置(setlocale(LC_ALL,"")返回 nullptr ), getwchar 会失败并且它的内部状态会被损坏,从而使其忽略所有输入。如果发生这种情况时终止进程,您的输入将在 shell 提示符中弹出,因为它没有被消耗并且累积在标准输入缓冲区中。

这也会导致无限生成,因为 getwchar 中的 weof 的解释方式与用户输入结束相同,并且当发生此问题时,控制台处理程序会从 getwchar 接收无尽的 weof 流,不断将其解释为用户输入结束。

编辑:如果您可以重现 ctrl+C 而不停止生成,如果您能帮助我重现它,我将不胜感激,因此也许可以找到解决这两个问题的更好方法。

3

好的,这也修复了非 unicode 默认语言环境,并在 debian 12 最小映像上进行了测试。

@DannyDaemonic 已经很晚了,我半睡半醒:) 所以如果你发现任何问题,我明天会处理。

7

#3638 中报告的问题是:

  1. 键入时不会出现非 ASCII 字符。
  2. 一代过早开始。
  3. 当按下 Ctrl+C 时,生成不会停止。

我可以通过使用与区域设置相关的环境变量的不正确值来重现它们。# 即使控制台代码中没有错误,也可能会出现 1。# 3 是最有力的指向错误可能性的指针。但错误可能存在于系统库中的某个位置,甚至可能是预期的行为。归根结底,这是由于配置错误造成的。

如果未设置 LC_ALL,我可以 100% 地重现此情况

这是我在没有进行此更改的情况下得到的结果。

printenv|grep -E "^(LANG|LC_)" LANG=en_US.UTF-8 echo $LC_ALL

bin/main --interactive-first --multiline-input --color -m ggml-model-Q6_K.gguf 日志开始

<...>

== 以交互模式运行。== - 按 Ctrl+C 随时插入。- 要将控制权返回给 LLaMa,请以“\”结束输入。- 要返回控制权而不开始新行,请以“/”结束输入。

F:韦尔奇字母表 hat die Buchstaben ä、Ö、Ü、ẞ?A:

一代还没有开始。当我输入 时/,它写道:Das deutsche Alphabet hat die Buchstaben ä、Ö、Ü und ẞ。迪塞·布赫斯塔本 <...>

当我按 Ctrl+C 时,它会停止,我可以再次输入绿色。所以一切都按预期进行。

由于系统/环境的不同,您可能会得到不同的结果。例如,LC_CTYPE 环境变量的错误值可能会触发该错误。然后,如果您用 LC_ALL 覆盖它,问题就会消失。此外,它可以是不同的终端或任何软件。

总的来说,在我看来,这更像是一种解决方法,而不是解决根本问题。

如果您可以重现 ctrl+C 而不停止生成,我将不胜感激,如果您能帮助我重现它,这样也许可以找到解决这两个问题的更好方法。

这需要调查。你已经比我研究得更多了。如果可以在不更改区域设置的情况下修复该行为,那么这将是正确的修复。我可能稍后会研究它,但现在我正在做别的事情。

7

即使在应用这些更改到 8396208c0025f847a8b9e8ea417a5ea029df7b8d 后,我仍然能够触发不良的控制台行为。让我重申一下我对这个问题的看法。

该问题是由系统配置错误引起的。它应该由系统的用户/操作员修复,例如通过正确设置环境变量。

我们在这里担心的可能是,在这种错误配置下,示例会以比我们希望的更糟糕的方式失败。我们可以尝试找出到底为什么getwcharCtrl+C 不起作用并考虑可能的解决方案。

只有在没有更好的解决方案的情况下,我们才应该搞乱语言环境。

5

@shibe2 我同意这可能是一个配置错误的问题。我过去通过更改配置修复了 docker 映像的类似问题。也就是说,我不认为尝试解决这个问题有什么坏处。它可能有助于警告用户他们的默认区域设置正在被覆盖,但这些区域设置不会用于格式化数字,并且我们不会调用类似 或isalpha的函数isdigit。我们唯一真正使用区域设置的是 UTF-8 编码。

0
const char * cs = nl_langinfo(CODESET);
if (strcasecmp(cs, "UTF-8") && strcasecmp(cs, "utf8")) {
     fprintf(stderr, "warning: character encodings other than UTF-8 are not supported, make sure you are using UTF-8 locale\n");
}

这需要打印在“== Running in Interactive mode.==”附近的某个地方,否则它将在默认打印的巨型转储中丢失。然后希望用户能够以适合其系统的任何方式修复区域设置。

(编辑:不区分大小写的测试)

3

@shibe2

我绝对同意根源是系统配置错误。

但对于干净默认安装的几个发行版来说,这种情况仍然会发生,我认为我们不应该鼓励用户专门为 llama.cpp 更改其系统配置(恕我直言)

6

如果它是专门针对 llama.cpp 的,我会同意。我知道容器的最小 Linux 镜像可能没有像常规发行版那样配置区域设置。如果有人想在这样的环境中运行交互式控制台生成,那么需要正确的区域设置配置来支持任何其他依赖于区域设置的应用程序是完全合理的。在其他情况下,我假设默认区域设置将使用 UTF-8,并且 llama.cpp 必须适用于任何此类区域设置。当我有时间的时候,我绝对想调查一下。

3

结果setlocale(X,"")是不一样的,setlocale(X,nullptr)前者仅在语言环境更改时返回 not nullptr,而后者返回但不更改。

另外,setlocale返回 nullptr 但getenv返回空字符串,所以我也添加了该检查。

@DannyDaemonic 让我知道现在看起来是否可以接受。

7

对上面的评论表示抱歉。当我不小心以某种方式发布它时,我正在编辑我的回复。

也就是说,我不太喜欢这组最新的更改。它使过程过于复杂。我们只需要检查是否getenv("LANG")为空。我之前的修复LANG在使用它之前检查环境结果是否为空,但也许我应该在那里更明确。我们也不需要setlocale再次调用来检查结果。您可以简单地检查返回值。

我更喜欢你之前提出的解决方案,你只需将其链接setlocales起来||即可。如果您确实想尝试这个命令(“”、LANG、“C.utf8”、“C.UTF-8”),则可以更直接地完成。