介绍

Lofter的网页端没有原生的划线评论查看功能,体验不如使用移动端APP,因此本人在Deepseek指导下写了一份能让Lofter网页版也显示划线评论的脚本

效果展示

划线评论显示效果

下载地址

Github仓库地址:点我
GreasyFork脚本安装地址:点我

安装方法

  1. 首先安装篡改猴(TamperMonkey):

注意:如果使用的是Edge浏览器,则需要开启开发者模式才能正常启用,可以参照这篇文章操作

  1. 接下来点我前往GreasyFork网站安装本脚本

  2. 安装完成!

原理

Lofter上的文章每一段都有对应的id,如

1
<p id='xxxxxx'>你好</p>

手机端获取评论时也会同时获取其对应的pid(非划线评论则为null),并根据pid将其显示到对应段落后面。

而经过浏览器抓包分析,发现网页版Lofter虽然不显示划线评论,但其评论请求的响应中也带有每条评论对应pid位置,如:

1
2
var s1={};
s1.content="yyy"; ...; s1.pid="xxxxxx";

因此,本脚本用ajax-hook拦截评论请求,并根据响应内容,将评论显示到其pid对应的位置后,实现了划线评论的显示。具体逻辑参见Github仓库(点我)

存在问题

  1. 目前不能显示划线评论中的回复评论
  2. 不支持GreaseMonkey
  3. 按钮有待美化
  4. 尚不能显示划线的具体是一段中的哪些字

发现其他问题可以来Github仓库上提Issue

问题描述

在使pytorch/pytorchnvidia-cuda的Docker镜像下使用Paddle或者Onnxruntime-gpu可能会出现找不到CUDA或者CUDNN文件的报错。

Paddle报错:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
W1120 01:52:39.805847   549 dynamic_loader.cc:314] The third-party dynamic library (libcudnn.so) that Paddle depends on is not configured correctly. (error code is /usr/local/cuda/lib64/libcudnn.so: cannot open shared object file: No such file or directory)
Suggestions:
1. Check if the third-party dynamic library (e.g. CUDA, CUDNN) is installed correctly and its version is matched with paddlepaddle you installed.
2. Configure third-party dynamic library environment variables as follows:
- Linux: set LD_LIBRARY_PATH by `export LD_LIBRARY_PATH=...`
- Windows: set PATH by `set PATH=XXX;
Traceback (most recent call last):
File "deploy/pipeline/pipeline.py", line 1321, in <module>
main()
File "deploy/pipeline/pipeline.py", line 1308, in main
pipeline.run_multithreads()
File "deploy/pipeline/pipeline.py", line 179, in run_multithreads
self.predictor.run(self.input)
File "deploy/pipeline/pipeline.py", line 533, in run
self.predict_video(input, thread_idx=thread_idx)
File "deploy/pipeline/pipeline.py", line 993, in predict_video
classes, scores = self.video_action_predictor.predict(
File "deploy/pipeline/pphuman/video_action_infer.py", line 192, in predict
input_tensor.copy_from_cpu(inputs)
File "/usr/local/lib/python3.8/dist-packages/paddle/inference/wrapper.py", line 52, in tensor_copy_from_cpu
self._copy_from_cpu_bind(data)
RuntimeError: (PreconditionNotMet) Cannot load cudnn shared library. Cannot invoke method cudnnGetVersion.
[Hint: cudnn_dso_handle should not be null.] (at /paddle/paddle/phi/backends/dynload/cudnn.cc:64)

Onnxruntime-gpu报错:

1
2
3
2024-11-15 02:09:12.841326104 [E:onnxruntime:Default, provider_bridge_ort.cc:1480 TryGetProviderInfo_CUDA] /onnxruntime_src/onnxruntime/core/session/provider_bridge_ort.cc:1193 onnxruntime::Provider& onnxruntime::ProviderLibrary::Get() [ONNXRuntimeError] : 1 : FAIL : Failed to load library libonnxruntime_providers_cuda.so with error: libcublasLt.so.11: cannot open shared object file: No such file or directory

2024-11-15 02:09:12.841349327 [W:onnxruntime:Default, onnxruntime_pybind_state.cc:743 CreateExecutionProviderInstance] Failed to create CUDAExecutionProvider. Please reference https://onnxruntime.ai/docs/execution-providers/CUDA-ExecutionProvider.html#requirements to ensure all dependencies are met.

解决方法:

首先要确保你的使用pytorch/pytorchnvidia-cuda镜像带有CUDNN,即镜像名中应该带有cudnn字样。

在镜像环境带有CUDA与CUDNN文件,而Paddle与Onnxruntime等软件仍无法识别到时,则可以通过手动指定CUDA与CUDNN库目录的方法来解决。

nvidia/cuda:11.7.1-cudnn8-runtime-ubuntu20.04镜像为例:

定位库文件:

首先创建一个临时容器用于寻找CUDA与CUDNN库的位置

1
sudo docker run -it --gpus all --rm nvidia/cuda:11.7.1-cudnn8-runtime-ubuntu20.04 /bin/bash

其中--rm参数代表容器退出后自动删除。

执行

1
find / -name *libcudnn*

得到结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/usr/share/doc/libcudnn8
/usr/share/lintian/overrides/libcudnn8
/usr/lib/x86_64-linux-gnu/libcudnn_ops_train.so.8.5.0
/usr/lib/x86_64-linux-gnu/libcudnn_ops_train.so.8
/usr/lib/x86_64-linux-gnu/libcudnn_cnn_infer.so.8
/usr/lib/x86_64-linux-gnu/libcudnn_adv_train.so.8.5.0
/usr/lib/x86_64-linux-gnu/libcudnn_cnn_infer.so.8.5.0
/usr/lib/x86_64-linux-gnu/libcudnn_adv_infer.so.8
/usr/lib/x86_64-linux-gnu/libcudnn_ops_infer.so.8.5.0
/usr/lib/x86_64-linux-gnu/libcudnn_ops_infer.so.8
/usr/lib/x86_64-linux-gnu/libcudnn.so.8
/usr/lib/x86_64-linux-gnu/libcudnn_adv_infer.so.8.5.0
/usr/lib/x86_64-linux-gnu/libcudnn_adv_train.so.8
/usr/lib/x86_64-linux-gnu/libcudnn_cnn_train.so.8
/usr/lib/x86_64-linux-gnu/libcudnn.so.8.5.0
/usr/lib/x86_64-linux-gnu/libcudnn_cnn_train.so.8.5.0
/var/lib/dpkg/info/libcudnn8.md5sums
/var/lib/dpkg/info/libcudnn8.list

可知该镜像的CUDNN库位于/usr/lib/x86_64-linux-gnu

再执行

1
find / -name *libcublas*

得到结果

1
2
3
4
5
6
7
/usr/share/doc/libcublas-11-7
/usr/local/cuda-11.7/targets/x86_64-linux/lib/libcublasLt.so.11.10.3.66
/usr/local/cuda-11.7/targets/x86_64-linux/lib/libcublasLt.so.11
/usr/local/cuda-11.7/targets/x86_64-linux/lib/libcublas.so.11.10.3.66
/usr/local/cuda-11.7/targets/x86_64-linux/lib/libcublas.so.11
/var/lib/dpkg/info/libcublas-11-7.md5sums
/var/lib/dpkg/info/libcublas-11-7.list

可知该镜像的CUDA算子位于/usr/local/cuda-11.7/targets/x86_64-linux/lib

添加环境变量:

为了让Paddle与Onnxruntime能够找到CUDA与CUDNN的位置,需要将上面找到的两个路径添加到环境变量LD_LIBRARY_PATH,如果是临时使用容器的话,可以用该指令来临时指定(仅在当前终端有效)

1
export LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu:/usr/local/cuda-11.7/targets/x86_64-linux/lib:$LD_LIBRARY_PATH

其中/usr/lib/x86_64-linux-gnu:/usr/local/cuda-11.7/targets/x86_64-linux/lib要根据自己在前两步获得的算子路径来修改,路径间用:隔开。

而在构造镜像时,在Dockerfile中增加:

1
RUN echo export LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu:/usr/local/cuda-11.7/targets/x86_64-linux/lib:$LD_LIBRARY_PATH >> ~/.bashrc

则可在进入容器时自动指定CUDA与CUDNN算子文件位置。

Lofter的网页端不支持查看合集内容,只能用移动端设备看,对PC党很不友好。
只好通过对Lofter的安卓客户端抓包,分析API来进行合集内容的批量下载了。

用Python实现了一个简陋的批量下载合集内容并保存为markdown格式的脚本,可以保存文章中的图片。
可以不登录账户但需要手动获取合集ID,也可以在登录网页端Lofter的情况下获取当前账号订阅合集的ID(会读取Cookie信息)。

Github项目地址:
https://github.com/SrakhiuMeow/lofter-getter

使用说明

  1. 用git克隆项目:

    1
    2
    git clone https://github.com/SrakhiuMeow/lofter-getter
    cd lofter-getter

    当然也可以在浏览器打开项目地址,直接下载zip到本地后解压。

  2. 安装环境:

    1
    pip install -r requirements.txt
  3. 获取合集ID:

    下载合集需要获取其ID,有两种方法:

    1. 在Lofter App中进入合集页面,选择分享——复制链接,得到链接中CollectionId后的数字即为合集ID
    2. 在浏览器中登录Lofter,再运行本项目提供的subscription.py,即可获得合集ID
      1
      python subscription.py
  4. 爬取合集:

    此时,运行collection.py即可批量下载合集内容(默认下载到./results中)

    1
    python collection.py --collection_id 合集ID

    可选参数:

    • --save-path 保存路径 指定保存路径,默认在当前目录的results文件内
    • --save_img 将图片内容保存到本地(默认保存图片链接)
    • --rewrite 覆盖本地已下载的内容
    • --limit_once 单次抓取数 单次抓取的文章数量(默认50篇)

    会将合集内所有文章保存至保存路径/合集名
    并在保存路径下建立以合集名为文件名的目录文件,方便使用

(虽然功能真的很简陋,但是如果能帮到你的话,求求给github项目点个star吧🥹我什么都不会做的

实验室有两台同型号不同批次的8盘位硬盘柜,一台用于冷备份,一台给NAS用;二者都是通过SAS线接到主机的LSI阵列卡上来通信。

故障显现

某一天,因为要收拾实验室,就搬动了冷备用的电脑与硬盘柜。等到再次通电开机时,发现阵列卡开机自检环节就过不去,进度多次到100后又归零,然后就蜂鸣器就开始响。没办法,就只好先拔掉SAS线,先开机再插上去。

此时打开Megaraid Storage Manager,能够识别到硬盘柜,但也会报警;没办法,警报实在太吵,进Logical选项卡,右键Controller选择Disable Alarm,终于安静下来了。

右键Controller选择Scan Foreign Configuration,还好,能识别到8块盘的正常,然后选Import导入,此时问题出现:有一块盘Failed,Virtual Drive整体处于降级状态。 不过因为组的是RAID10,坏一块盘数据还能浏览,问题(应该)不大。

因为已经过保,就想办法自己解决下先。

首先尝试用MSM进行重建,然而报错如下

1
2
Controller ID:0 Rebuild failed due to target drive error: PD Port B:0:0
Controller ID:0 Diagnostivs failed on PD: Port B:0:0

在网上翻了很多资料,也没什么有价值的信息。

更换硬盘

因为尝试重建失败,而且用Diskgenius也获取不到对应盘的SMART信息,因而以为是这块硬盘坏了。(其实当时尝试把这块盘装到其他电脑上,也能获取到SMART信息,但被网上说可能是因为RAID对SMART要求更严格的信息误导了…)

求助硬盘柜的客服,也没有给出什么有用的信息(还是Scan Foreign Configuration-Rebuild那一套),因为过保、其仅能寄修不能上门,且硬盘数据不能外传,因此问对方能否直接更换硬盘,得到了可以尝试的答复。

于是买了一块同型号硬盘(¥2k+,14TB容量的硬盘真是奇葩,好难买),结果买了新的硬盘换上也没用,也不能退,寄(虽然能报销)。

此时才想到NAS用的是同型号的硬盘柜,可以试下将冷备硬盘放到NAS用硬盘柜中再接到冷备的电脑上,看下到底是不是硬盘问题。废了一番功夫装上硬盘,开机,重建,正常进入流程,并在十几个小时后重建成功了,重启后也一切正常(重建过程中数据读取灯一直为读取状态,但是硬盘确没有声音,因此认定硬盘内数据并没有损坏,这次重建只是全盘校验了一遍)……而此时再把硬盘装回冷备硬盘柜,连接电脑,开机,还是一样报错。

虽然绕了一大圈,但是退一万步,至少确定了问题不在硬盘上(而且等过几年真有硬盘坏掉就不用再临时买备用盘了(

此时又发现,有时重启冷备主机后只能识别到7块硬盘,干脆不认“故障盘”了,因此更加确信是硬盘柜出现故障。

寄修盘柜

只好寄修硬盘柜,因为认为是其自身的问题,就寄了空柜过去;

在微信联系的客服送修,结果寄出后一个星期都没有回复;只好打电话过去,得知当时跟我交接的客服已经离职了(…),对方表示会尽快帮忙维修——然而接下来又等了半个月,催了一次后终于搞定了——对面说“清灰之后就正常了”,因此不收维修费,只要我出快递费就好了。真是不错,虽然白买了硬盘,还拖了这么久,至少没再花维修钱而且修好了……吗?

当我把硬盘装上寄回的硬盘柜后,依然出现硬盘识别问题,甚至更严重了——这次只能识别5-6块盘,重启一次识别数还会变化,直接无语……这还不是最糟糕的,当我再次尝试把这些硬盘装到NAS用的硬盘柜内,再接到冷备份用的电脑上后,发现它居然只能识别slot0-3上的4块硬盘!

我的心直接凉了,不会是装硬盘时大力出“奇迹”了吧!

冷静冷静,再折腾下试试——把硬盘的上下顺序掉换一下,开机,发现识别的还是4块盘,但是识别到的是换到slot0-3盘位上的盘——原来硬盘没被搞坏。
但这台NAS用的硬盘柜分明没有问题啊?这次终于想到,问题可能出在一开始就忽略掉的LSI阵列卡上……

阵列卡!?

拔掉NAS主机上的LSI阵列卡,插到冷备主机上,连接SAS线,开机——全部硬盘均能识别。虽然还是提示有块盘Failed(就是最开始的那块“坏盘”),但是经过第一次换硬盘的经验,硬盘里面的数据应该是一切正常的,只是之前读取失败导致的Failed状态保留下来了;
理论上这次不用浪费时间进行重建了。于是,右键对应硬盘,选择Make Drive Online——一切正常了。

真是没有想到,最后居然是阵列卡的问题?但是第一次进行硬盘柜交换时就能正常识别,为什么第二次交换后就出了问题?这期间也没动过阵列卡。

本来打算再次寄修这块冷备用阵列卡,但是这次涨了教训,为了防止再白忙活一趟,干脆把它又装到了NAS主机上测试,结果竟然能正常工作。

说明这块阵列卡并没有坏掉……?

由于之前进行的互换实验并不充分,而且也不知寄修后售后方具体进行了哪些操作,故障好的莫名其妙,网上资料又太少,导致没法具体证明问题的源头……
但是这一系列问题,很可能只是因为阵列卡与主板接触不良导致的……吗?

电源线!!??

然而,没过几天,再次上电的时候又出现了掉盘情况——Slot6的盘完全识别不到了。这下是真的没办法了……难道是供电问题?但是电源和硬盘柜是一体的啊。算了,死马当活马医吧,换了一根电源线,居然又正常了……

结束(?)

这次真的是让人崩溃,真不知道问题出在了哪里……资料太少,甚至都不知道能找谁来修,只能自己折腾,至少现在暂时又能用了……

看到这篇文章的难兄难弟,遇到莫名其妙的RAID问题可以试下插拔阵列卡或者换根电源线……

省流版

如果requests返回的response是完全的乱码,而不是单纯的中文部分乱码,请尝试用pip安装brotli

1
2
# 在终端执行
pip install brotli

完整说明

问题简述

在使用python的requests对某网站发送POST请求后,发现获取到的respnse.text为乱码
乱码图片

而且保存为json时也会报错

1
2
3
4
5
6
7
8
9
10
11
12
13
Traceback (most recent call last):
File "xxx.py", line 41, in <module>
response_json = json.loads(text)['response']
^^^^^^^^^^^^^^^^
File "C:\Users\[User]]\miniconda3\envs\fastapi\Lib\json\__init__.py", line 346, in loads
return _default_decoder.decode(s)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\[User]\miniconda3\envs\fastapi\Lib\json\decoder.py", line 337, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\[User]\miniconda3\envs\fastapi\Lib\json\decoder.py", line 355, in raw_decode
raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

问题定位

首先想到的就是编码问题,然而像这样:response.encoding = 'utf-8'指定用utf-8解码后输出同样是乱码。

使用response.content.decode('utf-8')进行手动解码同样会报错:

1
2
3
4
5
Traceback (most recent call last):
File "xxx.py", line 37, in <module>
text = response.content.decode('utf-8')
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x85 in position 0: invalid start byte

与此同时,其用postman等软件发送请求后的应答则完全正常。于是认为和UTF-8的解码步骤应该无关。

此时观察返回的字节内容(response.content):\x85i\x0f\x00d\xfe_\xb7\xfa\xaf\xdf\xd9\xfb\xf5J,发现这好像也不是UTF-8对应的字节格式,是经过处理的内容。
经过排查,发现原因在于网页端的应答使用了br压缩,而python的requests库默认不支持br的解码。

解决方法也很简单,有以下两种:

  1. 如果网页端支持gzip等其他方式,则可以在去掉POST请求头中accept-encoding内的br。
    1
    2
    # 修改POST的Header
    accept-encoding: gzip
  2. 或者也可以为requests增加解码br压缩的能力,只需要安装brotli库:
    1
    2
    # 在终端执行
    pip install brotli
    此时输出一切正常。

经测试,只要安装brotli库后,request就能正常解码,不需要手动在代码中引用brotli;
如果手动使用brotli.decompress(response.content).decode('utf-8')反而会报brotli.error: BrotliDecompress failed的错误

实验室算力资源实在有限,往往是多个人共用一台机器,环境与数据都在一台机器上。如果平常用的机器(A机)被占用,又有其他机器(B机)空闲时,想要利用其他机器来训练,要么将整个目录复制过去,要么在Pytorch中调用B机的显卡,或者就用本文的方案:将A机的文件挂载到B机上,让B机来执行A机上的程序。

挂载目录

可以用sshfs将A机的环境目录与程序数据目录挂载到B机上,在B机上运行程序即可。

1
2
3
4
5
# 在B机上执行
# 挂载环境目录
sshfs [A-User]@{A-IP}:/home/[A-User]/anaconda3/envs/[your_env] /home/[B-User]/anaconda3/envs/[your_env] # 如果B机上有同名的环境,另选一个挂载目录即可

sshfs [A-User]@{A-IP}:[A-dir] [B-dir]

跨机训练

此时可以通过终端连接B机进行训练,或者用VSCode连接B机操作;

1
2
3
4
5
# 在B机上执行
conda activate [your_env] # 如果挂载到了/home/[B-User]/anaconda3/envs下的目录
python train.py
# 或者
/home/[B-User]/anaconda3/envs/[your_env] train.py

在无法直接访问B机的情况下也可以通过A机ssh来操作B机训练。

1
2
# 在A机上执行
ssh [B-User]@{B-IP} "/home/[B-User]/anaconda3/envs/[your_env]/bin/python train.py"

测速

最好提前确保两机互联速度够快,可以使用iperf3软件测试直连速度,如果是百兆网络可能会严重影响训练速度。

1
2
3
4
5
6
7
8
9
# 两台机器都需要安装iperf3
sudo apt install iperf3

# 在A机上执行
iperf3 -s
sudo ufw allow 5201 # 如果开启了防火墙需要放行5201端口

# 在B机上执行
iperf3 -c [A-IP] -b 0 -n 1G -f M

如果B机输出的测试结果中比特率(Bitrate)在100 MBytes/sec以上即说明两机之间是千兆网络,适合用来进行跨机训练。

SSH密钥设置

为了避免两机之间每次使用ssh与sshfs时都需要输入密码,建议提前将两机的公钥(id_rsa.pub内容)拷入另一台机的授权文件(authorized_keys)中。

1
ssh-copy-id [User]@[IP]

参考: https://zhuanlan.zhihu.com/p/141714106

Bash下的转义

有时在Bash下需要输入进行光标移动、改变文本颜色格式等操作,这些功能是由一些无法直接输入的特殊字符来实现的,此时就需要转义字符(escape code)与转义序列(escape sequence)的形式来实现。
反斜杠\是Bash下使用的转义标志,例如\b就代表十六进制为0x08的特殊字符,其代表退格操作。

注意,bash中的echo命令默认不解析反斜杠转义(interpretation of backslash escapes),需要加上-e参数启用转义,如:

1
2
3
echo -e '\e[33Test' # 单双引号皆可
# or
echo $'\e[33Test' # 仅能使用单引号

Bash支持C语言式的转义字符,与ANSI转义序列,详见下文:

C语言式的转义字符:

ANSI-C规定了一系列转义字符的表示方法,这些方法在Bash、Python等语言中也可使用。
而Bash中常用的转义字符如下:

转义字符 含义
\a alert (bell) 警报(响铃)
\b backspace 退格
\e \E an escape character (ESC) 转义字符, 等效于\x1b,可用于构建ANSI转义序列
\f form feed 换页
\n new line 换行
\r carriage return 回车
\t horizontal tab 水平制表符
\v vertical tab 垂直制表符
\\ backslash 反斜杠
\‘ single quote 单引号
\“ double quote 双引号
\? question mark 问号
\nnn the eight-bit character whose value is the octal value nnn (one to three octal digits) 八进制值为nnn的八位字符(一到三位八进制数字)
\xHH the eight-bit character whose value is the hexadecimal value HH (one or two hex digits) 十六进制值为HH的八位字符(一到两位十六进制数字)
\uHHHH the Unicode (ISO/IEC 10646) character whose value is the hexadecimal value HHHH (one to four hex digits) 值为HHHH的Unicode(ISO/IEC 10646)字符(一到四位的十六进制数字)
\UHHHHHHHH the Unicode (ISO/IEC 10646) character whose value is the hexadecimal value HHHHHHHH (one to eight hex digits) 值为HHHHHHHH的Unicode(ISO/IEC 10646)字符(一到八位的十六进制数字)
\cx a control-x character Ctrl+x对应的控制字符

详见Bash Manual

ANSI转义(ANSI escape code):

控制字符(C0 Control codes)

ASCII中规定了一系列单字节的控制字符,用于控制文本显示等功能。
这些控制字符本身无法显示,为了方便阅读,可以用”^G”这种脱出字符表示法来显示。在Ubuntu等系统的终端中,可以用Ctrl键来代表脱出字符”^”。

缩写 十六进制 控制字符 含义
BEL 0x07 ^G Beep 警报
BS 0x08 ^H Backspace 退格
HT 0x09 ^I Tab 水平制表符
LF 0x0A ^J Linefeed 换行
VT 0x0B ^K Vertical Tab 垂直制表符
FF 0x0C ^L Form Feed 换页
CR 0x0D ^M Carriage Return 回车
SO 0x0E ^N Activate G1 Character Set 激活G1字符集
SI 0x0F ^O Activate G0 Character Set 激活G0字符集
CAN 0x18 ^X Interrupt Escape Sequences 中断转义序列
SUB 0x1A ^Z Interrupt Escape Sequences 中断转义序列
ESC 0x1B ^[ Start Escape Sequence 开始转义序列
DEL 0x7F Ignored 忽略
CSI 0x9B Equivalent to ESC [ 等效于ESC [

要使用这些控制字符,可以利用反斜杠转义如”\xHH”、”\nnn”或”\cx”的形式输入他们。例如CR可以用”\x0E”或”\cm”表示。

注意,经过测试,Ubuntu的bash当中,ESC不能写为”\c[“,但可以用”\x1b”,”\033”或”\e”表示,而CSI应使用”ESC [“ (即”\x1b[“或”\e[“)来间接表示。

ESC控制序列 (Fe Escape sequences)

以ESC开始的一些转义序列。

ESC序列 含义
ESC c RIS - Reset 重置
ESC D IND - Linefeed 换行
ESC E NEL - Newline 新行
ESC H HTS - Set tab stop at current column 设置当前列的制表符
ESC M RI - Reverse linefeed 反向换行
ESC Z DECID - DEC private identification DEC私有标识
ESC 7 DECSC - Save current state 保存当前状态
ESC 8 DECRC - Restore state most recently saved by ESC 7 恢复最近由ESC 7保存的状态
ESC [ CSI - Control sequence introducer 控制序列引导符
ESC % Start sequence selecting character set 开始选择字符集
ESC % @ Select default (ISO 646 / ISO 8859-1) 选择默认字符集(ISO 646 / ISO 8859-1)
ESC % G Select UTF-8 选择UTF-8
ESC % 8 Select UTF-8 (obsolete) 选择UTF-8(已过时)
ESC # 8 DECALN - DEC screen alignment test DEC屏幕对齐测试
ESC ( Start sequence defining G0 character set 开始定义G0字符集
ESC ( B Select default (ISO 8859-1 mapping) 选择默认字符集(ISO 8859-1映射)
ESC ( 0 Select VT100 graphics mapping 选择VT100图形映射
ESC ( U Select null mapping - straight to character ROM 选择空映射 - 直接到字符ROM
ESC ( K Select user mapping 选择用户映射
ESC ) Start sequence defining G1 开始定义G1
ESC > DECPNM - Set numeric keypad mode 设置数字键盘模式
ESC = DECPAM - Set application keypad mode 设置应用键盘模式
ESC ] OSC - Operating system command 操作系统命令
ESC ] P Set palette 设置调色板
ESC ] R Reset palette 重置调色板

例如要使用CSI,可用”\x1b[“或”\e[“来表示

CSI (Control Sequence Introducer) sequences

以CSI即”ESC [“起始的控制序列。
在bash中使用时,需要用”\e[“或”\x1b[“来表示CSI。

CSI序列 缩写 英文名称 名称 效果
CSI n A CUU Cursor Up 光标上移 将光标向上移动n个(默认为1)个位置。如果光标已经在屏幕边缘,则不产生任何效果。
CSI n B CUD Cursor Down 光标下移
CSI n C CUF Cursor Forward 光标右移
CSI n D CUB Cursor Back 光标左移
CSI n E CNL Cursor Next Line 下一行 将光标移动到下一行开头(默认为1行)。
CSI n F CPL Cursor Previous Line 上一行 将光标移动到上一行开头(默认为1行)。
CSI n G CHA Cursor Horizontal Absolute 水平绝对定位 将光标移动到第n列(默认为第1列)。
CSI n ; m H CUP Cursor Position 光标定位 将光标移动到第n行,第m列。这些值是以1为基准的,如果省略,则默认为1(左上角)。例如,CSI ;5H是CSI 1;5H的同义词,而CSI 17;H与CSI 17H和CSI 17;1H相同。
CSI n J ED Erase in Display 清除屏幕 清除屏幕的一部分。如果n为0(或缺失),则从光标清除到屏幕末尾。如果n为1,则从光标清除到屏幕开头。如果n为2,则清除整个屏幕(并在DOS ANSI.SYS上将光标移动到左上角)。如果n为3,则清除整个屏幕并删除滚动缓冲区中保存的所有行(此功能是为xterm添加的,并受其他终端应用程序支持)。
CSI n K EL Erase in Line 清除行 清除行的一部分。如果n为0(或缺失),则从光标清除到行末尾。如果n为1,则从光标清除到行开头。如果n为2,则清除整行。光标位置不变。
CSI n S SU Scroll Up 向上滚动 将整个页面向上滚动n(默认为1)行。新行添加在底部。
CSI n T SD Scroll Down 向下滚动 将整个页面向下滚动n(默认为1)行。新行添加在顶部。
CSI n ; m f HVP Horizontal Vertical Position 水平垂直定位 与CUP相同,但被视为格式效应器函数(如CR或LF),而不是编辑器函数(如CUD或CNL)。这可能导致在某些终端模式下的不同处理。
CSI n m SGR Select Graphic Rendition 选择图形渲染 设置此代码后的字符的颜色和样式
CSI 5i AUX Port On 辅助端口打开 启用辅助串行端口,通常用于本地串行打印机
CSI 4i AUX Port Off 辅助端口关闭 禁用辅助串行端口,通常用于本地串行打印机
CSI 6n DSR Device Status Report 设备状态报告 通过传输ESC[n;mR报告光标位置(CPR),其中n是行号,m是列号。

举个例子,如果要使用CSI n T来向下滚动诶行,则应使用\e[代表CSI,n为3,于是有

1
echo -e '\e[3T'

SGR控制序列

为了调整bash终端输出的字符颜色与样式,可以使用SGR(选择图形渲染)控制序列,即CSI n m。
不同功能代码n的含义如下表所示。如果想同时实现多种功能就用分号;将功能代码隔开。
例如:

1
2
echo -e '\e[1mHello world!' # 文字加粗的Hello world!
echo -e '\e[5;31mHello world!' # 闪烁并且前景色为红色的Hello world!
代码 作用 备注
0 重置/正常 关闭所有属性。
1 粗体或增加强度
2 弱化(降低强度) 未广泛支持。
3 斜体 未广泛支持。有时视为反相显示。
4 下划线
5 缓慢闪烁 低于每分钟150次。
6 快速闪烁 MS-DOS ANSI.SYS;每分钟150以上;未广泛支持。
7 反显 前景色与背景色交换。
8 隐藏 未广泛支持。
9 划除 字符清晰,但标记为删除。未广泛支持。
10 主要(默认)字体
11–19 替代字体 选择替代字体 n − 10。
20 尖角体 几乎无支持。
21 关闭粗体或双下划线 关闭粗体未广泛支持;双下划线几乎无支持。
22 正常颜色或强度 不强不弱。
23 非斜体、非尖角体
24 关闭下划线 去掉单双下划线。
25 关闭闪烁
27 关闭反显
28 关闭隐藏
29 关闭划除
30–37 设置前景色 参见下面的颜色表。
38 设置前景色 下一个参数是5;n或2;r;g;b,见下。
39 默认前景色 由具体实现定义(按照标准)。
40–47 设置背景色 参见下面的颜色表。
48 设置背景色 下一个参数是5;n或2;r;g;b,见下。
49 默认背景色 由具体实现定义(按照标准)。
51 Framed
52 Encircled
53 上划线
54 Not framed or encircled
55 关闭上划线
60 表意文字下划线或右边线 几乎无支持。
61 表意文字双下划线或双右边线
62 表意文字上划线或左边线
63 表意文字双上划线或双左边线
64 表意文字着重标志
65 表意文字属性关闭 重置60–64的所有效果。
90–97 设置明亮的前景色 aixterm(非标准)。
100–107 设置明亮的背景色 aixterm(非标准)。

颜色表:

名称 绿 品红 亮黑(灰) 亮红 亮绿 亮黄 亮蓝 亮品红 亮青 亮白
前景色代码 30 31 32 33 34 35 36 37 90 91 92 93 94 95 96 97
背景色代码 40 41 42 43 44 45 46 47 100 101 102 103 104 105 106 107

更多关于ANSI转义的信息请看ANSI escape code

参考文章

  1. Console codes manual
  2. 维基百科: 控制字符
  3. 维基百科: ANSI转义序列
  4. Wikipedia: ANSI escape code

本文使用Copilot辅助写作。

理论上,在conda环境下安装onnx只需要一句指令:

1
pip install onnx

然而直接安装失败,报错提示:

1
2
3
4
5
6
  File "C:\Users\[User]\AppData\Local\Temp\pip-build-env-s3eshb7e\overlay\Lib\site-packages\setuptools\build_meta.py", line 295, in _get_build_requires
self.run_setup()
File "C:\Users\[User]\AppData\Local\Temp\pip-build-env-s3eshb7e\overlay\Lib\site-packages\setuptools\build_meta.py", line 311, in run_setup
exec(code, locals())
File "<string>", line 61, in <module>
AssertionError: Could not find cmake in PATH

原来是onnx安装需要CMake,那么到官网下载CMake,或者用pip安装CMake亦可。

1
conda install --upgrade cmake

然而装好CMake再次安装又出现了报错,这次的报错信息还是乱码:

1
error: could not create 'build\lib.win-amd64-cpython-312\onnx\backend\test\data\node\test_averagepool_3d_dilations_large_count_include_pad_is_0_ceil_mode_is_False\test_data_set_0': 鏂囦欢鍚嶆垨鎵╁睍鍚嶅お闀裤\x80\x82

经过查询资料,发现原来是Windows的长文件名限制导致的。参考Github上的一个issue,如果在安装Python的过程中选择了”Disable path length limit”就不会有问题。如果不想重装Python的话,按Win+R输入regedit.exe打开注册表,将“计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem”中的LongPathsEnabled的值修改为1即可。

然而继续报错…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
Traceback (most recent call last):
File "C:\Users\[User]\miniconda3\envs\ppocr\Lib\site-packages\pip\_vendor\pyproject_hooks\_in_process\*in_process.py", line 353, in <module>
main()
File "C:\Users\[User]\miniconda3\envs\ppocr\Lib\site-packages\pip\vendor\pyproject_hooks\in_process\in_process.py", line 335, in main
json_out['return_val'] = hook(**hook_input['kwargs'])
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\[User]\miniconda3\envs\ppocr\Lib\site-packages\pip\vendor\pyproject_hooks\in_process\in_process.py", line 251, in build_wheel
return build_backend().build_wheel(wheel_directory, config_settings,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\[User]\AppData\Local\Temp\pip-build-env-64ipubh\overlay\Lib\site-packages\setuptools\build_meta.py", line 410, in build_wheel
return self.build_with_temp_dir(
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\[User]\AppData\Local\Temp\pip-build-env-64ipubh\overlay\Lib\site-packages\setuptools\build_meta.py", line 395, in build_with_temp_dir
self.run_setup()
File "C:\Users\[User]\AppData\Local\Temp\pip-build-env-64ipubh\overlay\Lib\site-packages\setuptools\build_meta.py", line 311, in run_setup
exec(code, locals())
File "<string>", line 327, in <module>
File "C:\Users\[User]\AppData\Local\Temp\pip-build-env-64ipubh\overlay\Lib\site-packages\setuptools\**init**.py", line 103, in setup
return distutils.core.setup(**attrs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\[User]\AppData\Local\Temp\pip-build-env-64ipubh\overlay\Lib\site-packages\setuptools\distutils\[core.py](http://core.py/)", line 185, in setup
return run_commands(dist)
^^^^^^^^^^^^^^^^^^
File "C:\Users\[User]\AppData\Local\Temp\pip-build-env-64ipubh\overlay\Lib\site-packages\setuptools\distutils\[core.py](http://core.py/)", line 201, in run_commands
dist.run_commands()
File "C:\Users\[User]\AppData\Local\Temp\pip-build-env-64ipubh\overlay\Lib\site-packages\setuptools\distutils\[dist.py](http://dist.py/)", line 969, in run_commands
self.run_command(cmd)
File "C:\Users\[User]\AppData\Local\Temp\pip-build-env-64ipubh\overlay\Lib\site-packages\setuptools\[dist.py](http://dist.py/)", line 963, in run_command
super().run_command(command)
File "C:\Users\[User]\AppData\Local\Temp\pip-build-env-64ipubh\overlay\Lib\site-packages\setuptools\distutils\[dist.py](http://dist.py/)", line 988, in run_command
cmd_obj.run()
File "C:\Users\[User]\AppData\Local\Temp\pip-build-env-64ipubh\normal\Lib\site-packages\wheel\bdist_wheel.py", line 368, in run
self.run_command("build")
File "C:\Users\[User]\AppData\Local\Temp\pip-build-env-64ipubh\overlay\Lib\site-packages\setuptools\distutils\[cmd.py](http://cmd.py/)", line 318, in run_command
self.distribution.run_command(command)
File "C:\Users\[User]\AppData\Local\Temp\pip-build-env-64ipubh\overlay\Lib\site-packages\setuptools\[dist.py](http://dist.py/)", line 963, in run_command
super().run_command(command)
File "C:\Users\[User]\AppData\Local\Temp\pip-build-env-64ipubh\overlay\Lib\site-packages\setuptools\distutils\[dist.py](http://dist.py/)", line 988, in run_command
cmd_obj.run()
File "C:\Users\[User]\AppData\Local\Temp\pip-build-env-64ipubh\overlay\Lib\site-packages\setuptools\distutils\command\[build.py](http://build.py/)", line 131, in run
self.run_command(cmd_name)
File "C:\Users\[User]\AppData\Local\Temp\pip-build-env-64ipubh\overlay\Lib\site-packages\setuptools\distutils\[cmd.py](http://cmd.py/)", line 318, in run_command
self.distribution.run_command(command)
File "C:\Users\[User]\AppData\Local\Temp\pip-build-env-64ipubh\overlay\Lib\site-packages\setuptools\[dist.py](http://dist.py/)", line 963, in run_command
super().run_command(command)
File "C:\Users\[User]\AppData\Local\Temp\pip-build-env-64ipubh\overlay\Lib\site-packages\setuptools\distutils\[dist.py](http://dist.py/)", line 988, in run_command
cmd_obj.run()
File "<string>", line 264, in run
File "C:\Users\[User]\AppData\Local\Temp\pip-build-env-64ipubh\overlay\Lib\site-packages\setuptools\distutils\[cmd.py](http://cmd.py/)", line 318, in run_command
self.distribution.run_command(command)
File "C:\Users\[User]\AppData\Local\Temp\pip-build-env-64ipubh\overlay\Lib\site-packages\setuptools\[dist.py](http://dist.py/)", line 963, in run_command
super().run_command(command)
File "C:\Users\[User]\AppData\Local\Temp\pip-build-env-64ipubh*\overlay\Lib\site-packages\setuptools\_distutils\[dist.py](http://dist.py/)", line 988, in run_command
cmd_obj.run()
File "<string>", line 243, in run
File "C:\Users\[User]\miniconda3\envs\ppocr\Lib\[subprocess.py](http://subprocess.py/)", line 413, in check_call
raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['C:\\Program Files\\CMake\\bin\\cmake.EXE', '--build', '.', '--config', 'Release', '--', '/maxcpucount:12']' returned non-zero exit status 1.
[end of output]

note: This error originates from a subprocess, and is likely not a problem with pip.
ERROR: Failed building wheel for onnx
Failed to build onnx
ERROR: Could not build wheels for onnx, which is required to install pyproject.toml-based projects

这次没找到解决方法,放弃用pip直接安装了😭️。
于是直接从onnx源码编译安装了,详细见Github:onnx/onnx,执行:

1
2
3
4
5
6
git clone https://github.com/onnx/onnx.git
cd onnx
git submodule update --init --recursive
# prefer lite proto
set CMAKE_ARGS=-DONNX_USE_LITE_PROTO=ON
pip install -e .

在漫长的等待后终于安装成功了…

尝试在Windows安装用paddleocr时,发现在环境配置中安装lmdb的过程中会报错:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 报错提示
Collecting lmdb
Using cached lmdb-1.4.1.tar.gz (881 kB)
Preparing metadata (setup.py) ... done
Building wheels for collected packages: lmdb
Building wheel for lmdb (setup.py) ... error
error: subprocess-exited-with-error

× python setup.py bdist_wheel did not run successfully.
exit code: 1
╰─> [15 lines of output]
py-lmdb: Using bundled liblmdb with py-lmdb patches; override with LMDB_FORCE_SYSTEM=1 or LMDB_PURE=1.
py-lmdb: Using CPython extension; override with LMDB_FORCE_CFFI=1.
running bdist_wheel
running build
running build_py
creating build\lib.win-amd64-cpython-312
creating build\lib.win-amd64-cpython-312\lmdb
copying lmdb\cffi.py -> build\lib.win-amd64-cpython-312\lmdb
copying lmdb\tool.py -> build\lib.win-amd64-cpython-312\lmdb
copying lmdb\_config.py -> build\lib.win-amd64-cpython-312\lmdb
copying lmdb\__init__.py -> build\lib.win-amd64-cpython-312\lmdb
copying lmdb\__main__.py -> build\lib.win-amd64-cpython-312\lmdb
running build_ext
building 'cpython' extension
error: Microsoft Visual C++ 14.0 or greater is required. Get it with "Microsoft C++ Build Tools": https://visualstudio.microsoft.com/visual-cpp-build-tools/
[end of output]

note: This error originates from a subprocess, and is likely not a problem with pip.
ERROR: Failed building wheel for lmdb
Running setup.py clean for lmdb
Failed to build lmdb
ERROR: Could not build wheels for lmdb, which is required to install pyproject.toml-based projects

故在这里记录下解决问题的方法:

  • 下载Visual CPP build tools,下载并运行vs_BuildTools.exe。
  • 按照提示安装Visual Studio Installer,安装“Visual Studio生成工具”。
  • 安装完成后再点击“Visual Studio生成工具”的修改按钮,勾选“使用C++的桌面开发”,进行修改

此时即可正常安装lmdb。

环境冲突

The environment is inconsistent, please check the package plan carefully

Stackoverflow

1
2
3
conda activate base
conda install anaconda
conda update --all

安装特定版本torch

1
2
3
conda search pytorch | grep 2.1.2

conda install pytorch=2.1.2=py3.8_cuda11.8_cudnn8.7.0_0 torchvision=0.16.2=py38_cu118 cudatoolkit -c pytorch

安装mmcv

安装mmcv时如果没有预编译包可能会很麻烦
可以按照mmcv文档选择有预编译包的torch/cuda版本来搭建环境

mmcv中文文档

0%