0%

2025年要结束了。此刻是2025年12月30日的上午8点52,我正坐在家里客厅的垫子上,赵老师和乖乖还在睡。外面阴天,窗户那边传来扫地的机器的声音。我拿着笔记本,来记录和总结一下我们的2025年。
如果用一个词总结2025年的话,我会用“幸福”。生活上,一切顺遂,父母,家人身体都好,女儿也健康成长,没有大的坎。工作上,也是是比较稳定的一年。每天能见到家人,能一起吃饭,一起活动,一起记录,就是最大的幸福。

说到记录,今年我开始写个人日常记录的公众号,将值得记录的事情写下来,像每次出去玩的游记,女儿的身上发生的好玩的事情。

很有趣的是,现在女儿每天还要听我的公众号的内容,拿着手机找过来,说自己要”听爸爸以前写的“。当听到手机念出来“王云峰的记录”这几个字时,乖乖就笑起来,自己也奶声奶气地模仿。

更有意思的是,乖乖听的次数多了,竟然能将之前写的内容背下来,怎么发现的呢?有一次赵老师听见乖乖在自言自语,一听,是我之前写的公众号的内容,太好玩了。

有一天,乖乖说”爸爸你很厉害了“,我很好奇她为什么这么说,就问她,“爸爸为什么厉害呀?”,她回答道,“爸爸一个人写了那么多字”,真的很温暖。记录这一件小事,无心插柳,却真真切切地给小孩带来了影响。

今年我们带乖乖去玩了很多地方。清明节,去了南通。五一,我们回老家。6月份,去了南浔。今年九月份,带乖乖去海边玩了一次,她很喜欢,现在还经常提起要去海边玩。我们说好明年夏天再带她去。国庆节,去了绍兴,乖乖也记住了柯桥古镇这个地方。后面又去了宜兴,冬天的周末去杭州的各个公园玩了很多次。

孩子长得真快,一转眼快三岁了,真想让时间永远停留在现在,永远陪着这个调皮的小女孩。

后面记录一下这一年去了哪,见了谁,玩了什么,把值得记录的都按时间顺序列出来。

年度轨迹

1月12日,带乖乖去玉鸟集玩,在大草坪玩了会,去可莎蜜儿买了面包
1月18日,带乖乖去大运河附近桥西历史文化街区,去伞博物馆玩了玩,然后带她吃了麦当劳
1月19日,一起去公司玩,拍了落日,然后去菲住不渴吃了自助螃蟹
1月25日,去办了身份证,中午吃了猪脚饭发现了虫子……晚上带乖乖去藤集玩,吃了烤肉
1月30日到1月31日,去南京玩,去了鸡鸣寺,江南贡院。
2月1日,去西溪天街玩,吃了西贝。
2月2日, 去西溪湿地玩,看了越剧表演
2月3日,去西湖文化中心自然博物馆玩
2月5日,去西溪天街玩,赵老师去看电影哪吒2,我陪乖乖玩,直到商场关门
2月16日,去浙大紫金港校区玩
2月23日,去韬光寺参加义工活动,认识了几个甘肃老乡
2月28日,去植物园玩,梅花整得正盛
3月1日,去天空体育馆打羽毛
3月2日,我们带乖乖去浙大紫金港校区玩
3月9日,带乖乖去玉鸟集玩
3月13日,小雨来杭州出差,我们聊了好久
3月16日,和华哥家去西溪天街吃了绿茶餐厅
3月29日,本来打算去后面的草莓园摘草莓,结果半路被两条狗追赶,只得返回
3月30日,去藤集吃了必胜客
4月4日到4月5日,去南通找彩虹玩
4月13日,去西溪湿地大草坪放风筝,我们的风筝飞起来很高,结果断掉了飞走了
4月20日,去西湖边玩,看了松鼠,然后回来去弄堂里吃饭
4月26日,去移动公司外面拍了蔷薇花
5月1日到5月5日,回了老家,去了贵清山,去秦安县城走了走
5月10日,去爬了老和山,到北高峰,沿着韬光寺下去
5月11日,去杭师大仓前校区逛了逛,吃了食堂的饭菜
5月16日坐飞机去咸阳,17日在咸阳城逛了逛,然后坐火车去秦安,再坐出租到庄浪,18日返回,在咸阳吃了好吃的马蜚面馆,咸菜太好吃了,至今难忘
5月31日,去杭州动物园玩
6月12日到6月14日,团队去桂林outing
6月27日到6月28日,我们去南浔玩了两天
7月4日,团队给我和蜇锋举办了五周年聚餐,我们去吃了余白
7月27日,参加公司的净山活动,老和山出发,到北高峰结束
8月1日-8月3日,田明来杭州玩,我们晚上去了西湖边,刚好看了音乐喷泉。2日和田明去了灵隐寺,中午吃了鱼,下午去杭州博物馆,晚上去吃了绿茶餐厅。8月3日去公司转了转。
8月9日,我们去径山镇的进贤村玩水,在溪流旁露营,抓鱼,最后居然还抓了几条刀鳅,在家里养着,直到12月底
8月16日,和大学同学旸哥,潇哥,杨珈蒙聚餐,在西湖边吃了烧烤
8月23日,带乖乖去西溪天街,在肯德基,给乖乖吃了好吃的冰激凌
9月3日到9月6日,我们和彩虹去台州玩了几天。
9月17日,团队聚餐
10月4日,去绍兴玩,重游了黄酒小镇,新去了柯桥古镇
10月6日,去合肥,去科大走了走
10月8日,我带乖乖去玉鸟集露营
10月12日,我们去西溪湿地,在北门发现了一家书店,进去之后发现非常棒,玩了很久
10月19日,我带乖乖去自然科学博物馆玩,吃完肯德基回来
10月24日到10月25日,去丹阳参加大学同学张凯婚礼,和栾京,航航,劼博,段哥,郭哥聚了聚
10月26日,我们去良渚古城遗址公园玩
10月31日,去吃了万通里烧烤,味道很棒
11月2日,再次来西溪湿地大草坪露营
11月8日-9日,我们去宜兴玩
11月16日,我们去杭州植物园玩,看菊花展,拾了很多的榛过
11月22日,我们去杭钢公园玩
11月29日,我们去公司玩,捞了很多鳑鲏鱼
11月30日,我们去了青山湖公园
12月7日,我带乖乖去南湖公园露营,公园很大,任何多,露营很棒
12月13日,我带乖乖去西湖边看西湖边音乐喷泉
12月14日,我带乖乖去滨水公园露营,风有点大,地方有点小
12月24日,团队去羊锅村吃羊肉
12月27日,再次去西溪湿地玩,结束这个暖和的冬天

看书

空闲时间基本都是在陪娃,看书的也少了,微信读书上只有24个小时的阅读时间,下面是今年看过的一些书籍:

  • 说不尽的外交
  • 王兴传
  • 可爱的中国
  • 科技群星闪耀时
  • 万物皆计算

影视

今年看剧看电影的时间也更少了,这里列一些看过部分的影视剧

  • 南京照相馆
  • 浪浪山小妖怪
  • 哪吒之魔童闹海
  • 少年谢尔顿
  • 片场风云 第一季
  • 匹兹堡医护前线 第一季

说明

最近有个工作需要一个宣传视频,我希望将声音转换为黑白背景的视频,并且将声音对应的文字通过字幕形式显示出来,但没找到合适的工具。剪映语音识别字幕当然做的很好,但是要开VIP;必剪语音识别时候卡死……而刚好最近AI Coding工具越来越强,我在想,何不自己做一个顺手的工具呢,于是就有了这个极简的Python 命令行工具lyrichroma,一键音频转视频,可以设置背景,可以调整字幕位置,可以手动修改ASR识别的字幕错误,等等功能。

代码仓库: https://github.com/vra/lyrichroma

主要功能一览

在详细介绍如何使用之前,让我们先来看看 lyrichroma 的主要特性:

自动语音识别(ASR):基于 faster-whisper 引擎,支持多种语言(包括中文),并提供词级别的时间戳,支持切换ASR模型
动态背景效果:内置多种炫酷的动态背景,比如极光、日落、海洋、赛博朋克和森林主题
卡拉OK样式字幕:实时高亮当前朗读的单词,营造卡拉OK效果
高度可定制化:支持调整字体大小、颜色、高亮颜色和字幕位置
字幕编辑功能:可导出字幕为 JSON 文件进行人工校对,再重新导入生成视频

安装步骤

最简单的安装方式是使用pip:

1
pip install lyrichroma

另外,如果想想源码使用也是可以的,lyrichroma 使用 uv 进行管理,因此使用非常方便

1
2
3
4
5
6
7
8
9
# 首先安装 uv(如果尚未安装)
pip install uv

# clone 代码
git clone https://github.com/vra/lyrichroma
cd lyrichroma

#同步依赖
uv sync

就是这么简单!接下来我们就可以开始使用了。

基础使用方法

最基本的用法只需要一行命令:

1
lyrichroma --input audio.mp3 --output video.mp4

这条命令会将 audio.mp3 转换为 video.mp4,并配有黑色背景和白色字幕。

进阶使用技巧

  1. 动态背景效果
    如果你觉得纯色背景太单调,lyrichroma 内置了几种炫酷的动态背景:
    1
    lyrichroma --input audio.mp3 --output video.mp4 --bg-type dynamic --bg-value aurora
    目前支持的调色板包括:
    1
    2
    3
    4
    5
    aurora(极光效果,默认)
    sunset(日落效果)
    ocean(海洋效果)
    cyberpunk(赛博朋克效果)
    forest(森林效果)

    2. 自定义静态背景

    除了动态背景,你还可以使用纯色或图片作为背景:
1
2
3
4
5
# 使用纯色背景
lyrichroma --input audio.mp3 --output video.mp4 --bg-type color --bg-value "#FF5733"

# 使用图片背景
lyrichroma --input audio.mp3 --output video.mp4 --bg-type image --bg-value background.jpg

3. 字幕样式定制

lyrichroma 提供了样式定制选项:

1
2
3
4
5
6
7
lyrichroma \
--input audio.mp3 \
--output video.mp4 \
--font-size 60 \
--font-color "#FFFFFF" \
--highlight-color "#FF0000" \
--text-y 0.8

各参数含义:
–font-size:设置字幕字体大小(默认40)
–font-color:设置字幕颜色(默认白色)
–highlight-color:设置当前朗读词的高亮颜色(默认黄色)
–text-y:设置字幕垂直位置,范围0.0(顶部)到1.0(底部)(默认0.8)

4. 字幕编辑工作流

对于需要精确控制字幕内容的场景,lyrichroma 提供了字幕编辑工作流,这是该工具的一大亮点。由于自动语音识别技术并非完美,有时会出现识别错误,这时就需要人工干预。

LyriChroma 的字幕编辑工作流分为三步:

第一步:只生成字幕文件(不生成视频):

lyrichroma –input audio.mp3 –save-transcript transcript.json
执行这个命令后,你会得到一个名为 transcript.json 的文件,它包含了所有的识别结果和时间戳信息。

第二步:手动编辑生成的 transcript.json 文件

打开这个 JSON 文件,你会发现它的结构类似于:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[
{
"start": 0.0,
"end": 3.0,
"text": "你好世界",
"words": [
{
"start": 0.0,
"end": 1.5,
"word": "你好",
"probability": 0.9
},
{
"start": 1.5,
"end": 3.0,
"word": "世界",
"probability": 0.85
}
]
}
]

在这个文件中,你可以:

更正识别错误的文字内容
调整时间戳以改善同步效果
删除不必要的段落
添加遗漏的内容
例如,如果某个词被错误识别,你可以直接修改对应的 word 或 text 字段。如果你发现某个时间段的字幕时间不对,可以调整 start 和 end 时间戳。

第三步:使用编辑后的字幕生成视频:

1
lyrichroma --input audio.mp3 --output video.mp4 --load-transcript transcript.json

这样就能生成带有经过人工修正的高质量字幕的视频了。

这种方式特别适合需要对自动识别结果进行校正的场景,比如:

专业术语识别不准确
人名、地名识别错误
方言口音导致的识别偏差
背景噪音影响识别准确性

细节

前几天在GitHub上看到点赞了JiT的代码仓库,进去看了下,发现是kaiming he的新论文,这几天看完后,发现是一篇非常极简,优雅,结论清晰的论文,这里记录一下笔者的阅读笔记。

论文提出了一个非常核心的观点:在流假设里面,自然图像是在低维度空间的,而噪声是在高维度空间,现有的一些方法通过预测高维度的噪声来去噪,本身提高了任务的难度,而如果在自然图像维度来学习的话,难度会下降很多,因此不需要太大的模型参数。
另一方面,高维度的噪声学习难度大,为了不断提高拟合这些维度的精度,就需要不断增大网络的尺寸,可能不是一个合理的方向。
由于Diffusion模型和Flow Matching模型都可以归纳成ODE(Ordinary Differential Equation, 常微分方程)形式,因此论文从flow-based的角度出发,系统地总结了 三个预测空间v, x, or ϵ.和三个loss空间,并通过实验证明,在x预测空间,不管什么loss设计,都能比较好地学习降噪效果;而在v预测空间和ϵ预测空间,则不管什么loss,网络学习到误差都比较大。

论文通过一个toy实验先验证低的x空间被融合在高维度的噪声空间中的时候,采用v, x, 和 ϵ预测,哪个能恢复原始的数据,最后实验发现,在噪声维度本身比较低的时候,几种方案都可以,但维度过高,超过模型的能力的时候,只有x预测才work。

当然论文中的x-Prediction之前的人也研究过,只不过这里作者给出了一个更系统的验证,部分结论跟之前论文是一致的。

虽然论文前面部分对现有的swiGLU, RSNNorm, RopE,CFG等现有Diffusion的标配组件没有太多涉及,但在后续部分也指出了论文中的实验也采用了这些标配组件。

疑问

论文中的方法能否用来做生图?
论文的这种方法是用来降噪的,且一个前提是自然图像在流假设中是低维度的,但AI生成的图像未必跟自然图像一样,都是低维度的,所以是不是不能用来生图?笔者对这块没想清楚,希望懂的朋友们多赐教。

感受

读下来几点感受:

  • 思路非常清晰,行文的逻辑非常通畅,跟之前作者的一些论文风格很一致
  • 专门标注了筛选的结果和非筛选过的结果,对实验用到的trick都进行了脚注说明,非常坦诚,值得科研工作者学习

2023年11月份的时候,我写过一篇介绍贾扬清创业项目LeptonAI的文章,当时的感受是,项目对应的python包leptonai API设计优雅,对应的云端平台体验也很丝滑。后面看到团队又更新了叫gupd的一个仓库,这是一个轻量级、生产级的 GPU 监控与管理工具,为保障 GPU 在 AI和机器学习环境下的可靠性和高效性设计的。整体看起来,团队做的事情是AI Infra的基建构建。

2025年4月份的时候,有消息说英伟达收购LeptonAI。而在4月17日,我收到一份Lepton AI发的邮件:

简单翻译如下:

尊敬的客户:
我们谨此通知您,Lepton 服务将停止运营,并将于 2025 年 5 月 20 日正式终止。
自该日起,您将无法再访问 Lepton AI 平台提供的任何服务,也无法获取您提交至该平台的数据。我们建议您务必在此日期前下载并保存所有必要数据,因为 5 月 20 日之后将无法再访问任何内容。
此外,服务终止时您账户中剩余的未使用积分将在服务关闭后予以退还。
感谢您一直以来对 Lepton 的支持与信任。
Lepton AI 团队
可见在2025年4月17日的时间节点,LeptonAI 已经确定收购意向,并且决定关停服务了。

这个有个小细节,Lepton AI发邮件的时候,貌似给所有用户一起发或者按批次发的邮件,所以能看到所有收件人的邮箱,我统计了一下,总共50个收件人,我不知道这是LeptonAI总的客户数,还是他们按照50个人,50个人来发邮件的。

团队貌似没有真正官宣过这起收购事件(没有上X看过),但现在看贾扬清的领英介绍,已经显示最新工作单位是英伟达了。

现在有半年过去了,我好奇LeptonAI的那套SDK和别的工程的东西现在发展怎么样了,还在更新吗,于是最近去看了一下,简单研究后我认为,LeptonAI团队虽然被收购了,但做的事情跟LeptonAI独立公司阶段没有大的区别。

首先是官方网站,访问原始域名lepton.ai,会跳转到https://www.nvidia.com/en-us/data-center/dgx-cloud-lepton/,介绍内容改变比较大,风格也从极简风改成英伟达绿色配色为主。

互联网博物馆看到的LeptonAI 2024年11月的网站

Nvidia DGX Cloud Lepton 网站
可以看到,LeptonAI现在变成了Nvidia DGX Cloud的一部分,名字就叫 NVDIA DGX Cloud Lepton。DGX Cloud是英伟达2023年推出的云托管的AI超级计算服务,不光提供月租的GPU卡,还包括模型训练、部署等一套软件设施。这样一看,Lepton被集成进DGX Cloud,是非常合理的。

技术文档在这个地址:https://docs.nvidia.com/dgx-cloud/lepton,可以看到相比GitHub的README,介绍内容还是发生了不少变化,从DGX Cloud的组件角度来看整个工具了:

使用方式没什么变化,还是同一个包名

然后项目也是正常迭代,包括代码提交,版本发布,以及更新的节奏:

所以总结来说,做的事情没什么大的变化,只不过由创业公司的高不确定性到大公司的高确定性的变化而已。

我觉得这个是好事,因为不需要作为乙方,买英伟达的卡,再提供给客户来使用,毕竟自家的卡用起来又不花钱。

而且LeptonAI的这套基建,在英伟达显卡一家独大的情况下,服务好了英伟达,也就是服务好了大部分GPU市场,从这个角度讲,他们在里面做跟在外面做没什么区别。

总之LeptonAI的故事告一段落了。

这是去年9月份受两个实习生小伙伴讨论代码启发而做的一个小项目,这周五他们回学校了,我也把这个在草稿箱躺了11个月的文章改了改,发出来作为纪念。

背景介绍

为了找出开源代码仓库存在的问题(缺少证书,缺少文档,缺少测试,代码质量不高)并加以改进,我搭建了一个基于 LLM 来自动分析代码仓库并打分的网站,可以在这里体验

实现细节

Clone 仓库
将仓库中的代码、文档、证书、测试例子等按照固定的格式,写成一个总结文档
设计给大模型的 PROMPT 提示词规范
将 PROMPT+总结文档喂给大模型(这里用的是智谱的免费模型 GLM-4-Flash),大模型返回 json 格式的打分结果
网页渲染 json 结果,得到最终的输出

Features

打分维度考虑全面,包括代码质量、仓库大小、Git Commit 规范、文档、测试、开源证书等方面
基于大模型的打分并给出了建议,可以根据建议来改进代码质量
有结果保存成图片的功能,方便记录
代码开源,源代码地址: https://github.com/vra/llm-code-scorer
下面是这个网站制作的详细说明,希望能给想做简单好玩AI应用的朋友们提供一个参考。

起因

有一次想到某个仓库的代码,逻辑非常绕,很不直观。要是有办法能让作者意识到这里的问题,进行优化改进,对使用者也是极好的。

然后联想到有一次团队的一个小伙伴提到某个开源代码,评价其是“一坨狗屎”,突然灵光一现:能不能做一个大模型来对代码进行分析的工具,给出0-10分的打分,最差的0分,锐评就是“一坨狗屎”,把这个梗用上去。

然后整体评估了下,整体上是可行的,大模型见过了那么多的代码,肯定知道哪些代码是好的,哪些代码是烂的。

方案设计

然后一个核心问题出现了:GitHub上的开源代码仓库有大有小,包含文档、配置、测试和真正的有用源代码,如何将这么多东西喂给大模型输出一个总体的评分呢?想起了之前看过的LLM的项目,我设计了一个模板,将内容按照源码、配置项、README、证书,是否有测试等情况进行分类,按照一个模板,汇总成输入给到大模型。

打分的时候,也是设计了Prompt,根据不同的维度进行考察,Prompt如下:

1
2
3
4
5
6

PROMPT = """
---
已将一个 Git 仓库的所有信息按照概要格式组织,请仔细阅读概要信息,尤其是一定一定要对[Code Snapshot]部分的代码风格、逻辑、规范进行仔细查阅,然后结合具体的例子,给出下面6个维度的0-10分的打分(打分标准见下): 代码质量、文档规范、配置规范、提交规范、大小规范、测试规范,最后完整全面地总结代码的优点和待改进点,给出总结和建议。

### 概要格式

[.gitignore]:
[Git Commit]:
[Code Snapshot]:
[Test Files]:
[Binary Files]:
[Repo Size]:
[Total Files]:

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

### 评分维度说明

#### 1. 代码质量(0-10)
- **0-3**: 代码不易读,逻辑混乱,缺乏注释, 命名不规范,风格不一致,难以理解,存在多个严重的潜在错误。
- **4-6**: 代码可读性一般,有部分注释,存在一些逻辑问题和不规范命名,风格混合(例如驼峰和下划线命名混用),偶尔有潜在错误。
- **7-8**: 代码整体清晰,注释较为充分,逻辑严谨通顺,命名统一规范,潜在错误较少。
- **9-10**: 代码结构良好,规范一贯,逻辑清晰,易于理解,命名准确一致,几乎没有潜在错误。
- 如果[Code Snapshot]部分内容为空,说明没有任何源代码,代码质量直接为0分,评分理由是没有任何源代码,

#### 2. 文档规范(0-10)
- **0-3**: 文档缺失(例如没有README)或只包含极少信息(README没有使用说明),无法帮助用户理解和使用。
- **4-6**: 文档不完整,有部分信息缺失,用户可能需要额外查找信息。
- **7-8**: 文档较为完整,提供了大部分所需信息,少量细节需要完善。
- **9-10**: 文档非常详尽,覆盖所有重要细节,除了README,还有BUILD,CONTRIBUTING,faq,trobuleshooting,docs等专门的文档或目录,用户能够轻松理解和上手。

#### 3. 配置规范(0-10)
- **0-3**: 项目配置混乱,缺少必要的配置文件(如 .gitignore, LICENSE)。
- **4-6**: 项目配置一般,有一些配置文件,但不充分,例如虽然有.gitignore,但是没有忽略.pyc,.DS_Store, .out,.so等中间结果。
- **7-8**: 项目配置良好,包含必要的配置文件,结构清晰,忽略了常见的非源码文件。
- **9-10**: 优化的项目配置,包含所有必要文件(如.gitignore, LICENSE, setup.cfg等),并遵循最佳实践,忽略了全部的非源码文件,已经不需要的数据目录等。
- 如果[LICENSE]部分或者[.gitignore]部分内容为空,说明没有证书或者忽略规则,配置规范直接为0分,没有证书和gitignore规则是很不专业的开源方式

#### 4. 提交规范(0-10)
- **0-3**: 提交信息极其简单,完全无法理解提交的目的(例如简单的update, upload等)。
- **4-6**: 提交信息有一定描述,但描述不够详细或含糊。
- **7-8**: 提交信息清晰,能够理解修改的内容和目的,同时有固定的格式如angular规范等。
- **9-10**: 提交信息详细且准确,充分解释每次提交的变更和背景,详细内容通过空行再详细说明的形式提交。

#### 5. 大小规范(0-10)
- **0-3**: 计算[Repo Size] / [Total Files],也就是平均每个文件的大小,超过1M,越小分值越高
- **4-6**: 平均每个文件大小超过500K,越小分值越高
- **7-8**: 平均每个文件大小超过100K,越小分值越高
- **9-10**: 平均每个文件大小小于100K,越小分值越高, 如果小于30K,则为10分
- 如果[Code Snapshot]部分内容为空,但[Size]部分超过10M,大小规范直接为0分,没有源码但size超大说明保存的是二进制文件而不是代码

#### 6. 测试规范(0-10)
- **0-3**: 没有任何的单元测试或者集成测试,也没有任何文档说明 。
- **4-6**: 有默认的mock测试文件,但没有真正代码的测试例子。
- **7-8**: 有一些实际代码的测试例子,但测试覆盖率很低,没有说明怎么进行测试。
- **9-10**: 如果[Test Files]中的测试文件数目/[Total Files] 超过10%,说明测试覆盖率高,这个占比越高分值也越高,同时有详细的说明进行如何测试。
- 如果[Test Files]部分内容为空,说明没有任何的测试,测试规范直接为0分

重要的附加说明:打分一定要有区分度,例如[Test Files],[LICENSE], [.gitignore] 或 [Code Snapshot] 如果为空,则对应的评分维度就果断打0分,这样最终的结果才有警示意义和区分度,如果做的很好就果断给10分,不要中庸地给8分或者9分.

由于智谱提供了免费的LLM API,因此打分模型基于这个免费的API来构建。

思路定了后,就想找一些网页效果比较酷炫的网站来看看,因为模仿也是写代码中很重要的一个部分(看看国内各大大模型的上传图片的UI就知道了)。 之前王登科分享过一个文字风格测试的网站(已经无法使用),想参考其做网站页面。 最后参考了之前体验的 Year in code的网站,渐变的色彩 https://year-in-code.com/

既然想做一个稍微正式点的Side Project,还是值得花点钱准备一些必须要的软硬件。

首先是申请域名时发现, 因为之前调查过,各家云厂商都有100块左右一年的低配机器,而阿里云目前在国内还是做的比较好,又是一个系统的,因此下单了99年一年的机器。

所以这个Side Project的总支出是7+99=106元,算是低成本了。

之前看过一个大佬的博客,说他50%的时间花在Coding上, 50%的时间花在Marketing,因此推广自己的作品和写代码一样重要,不要觉得推广自己的东西很羞耻,如果你做的东西很棒,那就应该让更多的人知道,毕竟在这个信息爆炸的时代,酒香也怕巷子深。

关于这个项目,我的定位还是低成本的Side Project,因此做的推广并不多。具体来说,在网站搭建好,域名还没有备案完成时,先在几个好友之间共享,收集他们的评论和反馈意见。然后网址完成备案后,在v2ex上进行了分享,源码在GitHub上开源,所有人都可以自己跑,然后修改。

它真的有用吗?

平心而论,我觉得目前这个版本用处有限,可能最大的用处是让开发者能知道格式上的问题,例如代码没有README,没有写测试,提交不规范等等,对代码逻辑是否通顺、写法是否优雅这种细致到代码实现细节的方面,它能做的不多。

那么问题在哪里呢?一方面是采用的免费模型还有改进空间,采用更强大的付费模型肯定会有提升,但按token数计算的支出可能是个无底洞,已经超出了这个Side Project的经费上限。

另一方面,Prompt可能还有改进的空间,通过几个版本Prompt的表现来看,修改Prompt是最有效的提升效果的方法,未来我可能也会优化Prompt来更新这个网站。

其实在设计评分结果展示方案的时候,还考虑过用AI生成梗图的方式,例如锐评是“你写的代码比雷军还优雅”,就生成一张类似雷军的点赞的图片,但实际尝试后发现有几个问题: 1. 首先是AI生成的图片中文字效果还做不好,例如下面采用可灵的图片, 然后考虑到AI生图与代码评分本身关系不是很大,即使做好了也只是在戏剧和传播效果有一些作用,对程序员真正地发现代码中的问题并无直接帮助,因此也就去掉了这部分比较耗时的工作。

因为我不懂前端,Vue和css的代码全部是GPT生成的,因此现在的效果展示部分还比较简单。我尝试了让Vue调用D3.js来生成蜘蛛图,显示6个考察的维度,但最终没有成功。另外想做一个生成分享页面的功能,将所有信息都展示到一张图片上,再加上网站的二维码,可以进行社交媒体的分享,因为不熟悉前端也没能搞定。后来实习的小伙伴帮忙优化了网页展示,这里也表示感谢。

其实刚开始我也想过微信或者支付宝小程序,因为它们的传播效应会很明显,万一这个东西做的出色,出圈了,小程序能够做到快速地社群传播。 但小程序也有问题,开发难度比一个网站大,而且又得专门学自有的一台编程语言和工具系统,同时不太开放,而且之前看到小程序也要备案,难度又增大了。 这里我还是考虑Side Project的短平快属性与小程序较高的学习成本与漫长的合法审核周期不契合,因此果断放弃这个思路。如果未来有个创业团队将这种AI打分App当作一个严肃的产品来对待,那小程序还是值得做的平台。

总体上,我认为代码打分这个方向未来肯定会有更专业的人做出一个合格的产品出来,这里因为各方面的原因,我目前能提供的就是这个版本了。

在音频处理领域,WavLM是一个强大的预训练模型,可以提取高质量的音频特征表示。然而,在实际应用中,我们常常面临模型体积大、推理速度慢以及部署复杂等问题。本文将详细记录我对s3prl项目中的WavLM模型进行优化,包括简化推理过程、ONNX导出以及MNN转换(包括FP16和INT8量化)的过程,用于解决上面提到的问题。

代码仓库:https://github.com/vra/s3prl, README详细记录了导出过程与使用说明

ONNX模型:https://huggingface.co/yunfengwang/wavlm-large-onnx

MNN模型:https://huggingface.co/yunfengwang/wavlm-large-mnn

Pytorch版本的问题

在开始优化之前,让我们先了解原始WavLM模型在s3prl项目中存在的几个问题:

网络依赖复杂:原始代码依赖于torch.hub加载模型,这种模式会从GitHub上拉取代码,这在国内环境中会遇到连接问题。
推理流程繁琐:需要加载完整的s3prl库和相关依赖,代码冗长且不直观。
模型体积大:原始PyTorch模型体积较大,不适合在资源受限的设备上部署。
推理速度慢:没有针对推理场景进行优化,存在不必要的计算开销。

优化过程

针对上述问题,实施了以下优化方案:

简化推理代码:创建了独立的demo.py文件,封装了一个简洁的VoiceEmbeddingExtractor类。
ONNX导出:修改了s3prl/upstream/wavlm/expert.py文件,支持将模型导出为ONNX格式。
MNN转换:将ONNX模型转换为MNN格式,并进行FP16和INT8量化。
推理示例代码:分别为PyTorch、ONNX和MNN模型提供了简洁的推理示例代码。
下面,我将详细介绍每一步的实现过程和技术细节。

简化推理代码

首先,参考UniSpeech中的代码,创建了一个利用WavLM进行音频embedding提取的demo.py文件,其中包含网络的定义,预训练权重的加载,以及一个VoiceEmbeddingExtractor类,用于封装WavLM模型的推理过程。这个类的设计非常简洁,主要包含以下功能:

初始化函数:加载预训练的WavLM模型。
extract_embedding函数:接收音频文件路径,返回提取的音频特征向量。
export_onnx函数:将PyTorch模型导出为ONNX格式。
关键代码片段如下:

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
class VoiceEmbeddingExtractor:
def __init__(self, ckpt_path, model_name="wavlm_large", device="cuda") -> None:
self.device = device
self.model = init_model(model_name, ckpt_path).to(self.device).eval()

def extract_embedding(self, audio_path):
audio = whisper.load_audio(audio_path)
audio = torch.from_numpy(audio).to(self.device).unsqueeze(0).float()
with torch.no_grad():
embed = self.model(audio)
return embed

def export_onnx(self, onnx_save_path):
dynamic_axes = {
"audio": {0: "batch_size", 1: "seq_len"},
"embed": {0: "batch_size"},
}
dummy_audio = torch.randn((1, 1024)).float().to(self.device)
torch.onnx.export(
self.model,
(dummy_audio,),
onnx_save_path,
input_names=["audio"],
output_names=["embed"],
dynamic_axes=dynamic_axes,
)

这段代码大大简化了WavLM模型的使用方式,用户只需提供预训练模型路径和音频文件路径,即可轻松提取音频特征。

ONNX导出

为了支持ONNX导出,修改s3prl/upstream/wavlm/expert.py文件,主要修改包括:

确保模型的forward函数支持ONNX导出格式。
处理动态输入尺寸,使导出的ONNX模型能够处理不同长度的音频输入。
简化模型结构,移除训练时特有的组件,只保留推理所需的部分。
在demo.py中,我实现了export_onnx方法,用于将PyTorch模型导出为ONNX格式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def export_onnx(self, onnx_save_path):
dynamic_axes = {
"audio": {0: "batch_size", 1: "seq_len"},
"embed": {0: "batch_size"},
}
dummy_audio = torch.randn((1, 1024)).float().to(self.device)
torch.onnx.export(
self.model,
(dummy_audio,),
onnx_save_path,
input_names=["audio"],
output_names=["embed"],
dynamic_axes=dynamic_axes,
)

导出ONNX模型的命令非常简单:

1
python demo.py -t export -m /path/to/wavlm_large_finetune.pth -o wavlm_large.onnx

MNN转换

将ONNX模型转换为MNN格式可以进一步优化模型体积和推理速度。MNN是阿里巴巴开源的一个轻量级深度学习推理引擎,专为移动设备设计,具有高性能、低内存占用的特点。

我使用MNN的转换工具将ONNX模型转换为MNN格式,并进行了FP16和INT8量化:

1
2
3
4
5
6
7
8
9

#安装MNN python包
pip install MNN

# FP16量化
mnnconvert -f ONNX --modelFile wavlm_large.onnx --MNNModel wavlm_large_fp16.mnn --fp16

# INT8量化
mnnconvert -f ONNX --modelFile wavlm_large.onnx --MNNModel wavlm_large_int8.mnn --weightQuantBits 8 --weightQuantAsymmetric

FP16量化将模型的权重从32位浮点数转换为16位浮点数,可以将模型体积减小约50%,同时保持较高的精度。INT8量化则将权重量化为8位整数,可以将模型体积进一步减小,但可能会导致一定的精度损失。

推理示例代码
为了方便用户使用优化后的模型,我分别为PyTorch、ONNX和MNN模型提供了简洁的推理示例代码。

PyTorch模型推理

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
# 使用demo.py中的VoiceEmbeddingExtractor类
extractor = VoiceEmbeddingExtractor(ckpt_path=args.ckpt_path)
embed = extractor.extract_embedding(args.input_audio_path)
print("embedding's mean:", embed.mean())
ONNX模型推理 (infer_onnx.py)
class ONNXModel:
def __init__(self, onnx_path):
self.onnx_session = onnxruntime.InferenceSession(onnx_path)

def process(self, x):
pred_audio = self.onnx_session.run(
None,
input_feed={
"audio": x,
},
)
embed = pred_audio[0]
return embed

# 使用示例
model = ONNXModel(onnx_path=args.onnx_path)
audio = whisper.load_audio(args.input_audio_path)[None]
embed = model.process(audio)
print("embedding's mean:", embed.mean())
MNN模型推理 (infer_mnn.py)
class MNNModel:
def __init__(self, mnn_model_path: str) -> None:
input_names = ["audio"]
output_names = ["embed"]

self.chinese_bert = MNN.nn.load_module_from_file(
mnn_model_path,
input_names,
output_names,
)

def process(self, audio):
mnn_audio = MNN.expr.placeholder(audio.shape, dtype=MNN.numpy.float32)
mnn_audio.write(audio)
output = self.chinese_bert.forward([mnn_audio])
output = MNN.expr.convert(output[0], MNN.expr.NCHW)
embed = output.read()
return embed

# 使用示例
model = MNNModel(mnn_model_path=args.mnn_model_path)
audio = whisper.load_audio(args.input_audio_path)[None]
embed = model.process(audio)
print("embedding's mean:", embed.mean())

优化效果对比

通过上述优化,我们取得了显著的效果:

代码简化:推理代码从复杂的s3prl库依赖简化为不到60行的独立代码。
模型体积:
原始PyTorch模型:约1.2GB
ONNX模型:约1.1GB
MNN FP16模型:约600MB
MNN INT8模型:约300MB
部署便捷性:不再依赖torch.hub和完整的s3prl库,只需要一个.onnx或.mnn文件和少量代码即可完成部署。

总结

通过对s3prl项目中WavLM模型的优化,我们成功地简化了推理过程,减小了模型体积,提高了推理速度,并提供了更便捷的部署方式。这些优化使得WavLM模型更适合在资源受限的环境中部署,也为其他预训练音频模型的优化提供了参考。

主要贡献包括:

修改了s3prl/upstream/wavlm/expert.py文件,支持ONNX导出。
创建了独立的demo.py文件,封装了简洁的推理接口。
提供了ONNX和MNN模型的转换方法和推理示例代码。
实现了FP16和INT8量化,大幅减小了模型体积。
这些优化不仅提高了WavLM模型的实用性,也为其他研究者和开发者提供了有价值的参考。

资源链接
优化后的模型已上传至Hugging Face:

ONNX模型:https://huggingface.co/yunfengwang/wavlm-large-onnx
MNN模型:https://huggingface.co/yunfengwang/wavlm-large-mnn

近日,Manus 在blog中分享了关于agent搭建的一些实操经验,很有用,但由于Manus本身在中国区无法访问,blog会在内容加载完成后执行额外检查,因此访问manus.im/blog子域名时,先是可以看到blog的内容,然后跳转到manus.im/unavailable。

这与Manus技术分享的初衷相悖,既然将内部技术分享出来,肯定是想让更多地人看到学习,一起进步,因此希望未来Manus能将blog子域名下的地域检查去掉。不过在此之前,有一些简单的方法可以解决此问题,下面是咨询Gemini 2.5 Pro后得到的一些解决办法。

方法一:最简单快捷的“手速流”

当页面内容一出现,立即按下键盘上的 Esc 键。

  • 原理:Esc键会停止浏览器加载页面,包括正在执行或即将执行的JavaScript脚本。因为跳转命令通常是在页面主要内容加载后由脚本触发的,所以及时按下Esc可以有效阻止它。

方法二:浏览器阅读模式

现代浏览器(如Chrome、Safari、Edge、Firefox)大多内置了“阅读模式”或“阅读器视图”。

  • 操作:在地址栏通常会有一个像书本或文章一样的图标。在页面开始跳转前,迅速点击这个图标。
  • 原理:阅读模式会提取网页的主要文本和图片,忽略掉大部分脚本和样式。它通常在跳转脚本执行前就完成了内容提取。

方法三:禁用JavaScript(诊断和访问的利器)

这是最可靠的方法之一,因为绝大多数此类跳转都是由JavaScript驱动的。

  • 操作(临时禁用):
  1. 按 F12 或 Ctrl+Shift+I (Mac: Cmd+Opt+I) 打开开发者工具。
  2. 按 Ctrl+Shift+P (Mac: Cmd+Shift+P) 打开命令菜单。
  3. 输入 “JavaScript”,然后选择 “Disable JavaScript”(禁用JavaScript)。
  4. 保持开发者工具开启状态,刷新 页面。
  5. 现在页面将不会跳转,你可以随意浏览。
  6. 看完后,重复步骤2-3,选择 “Enable JavaScript” 来恢复。

pytorch模型转换onnx的时候,遇到了下面的报错信息:

1
RuntimeError: Cannot insert a Tensor that requires grad as a constant. Consider making it a parameter or input, or detaching the gradient 

翻译过来就是不能将一个需要梯度的tensor转换为constant。

定位到报错的层,是一个Conv2D,看起来是它对应的weight设置了requires_grad为True。本以为直接修改requires_grad = False 就可以了,但比较诡异的是,实际试下来并不行。

阅读全文 »

昨天看到周舒畅老师的AI短剧 论视觉大模型 VLM 的轻量化,以讲相声的形式来表现,觉得很有意思,如果加上声音,就真的是一个技术领域的搞笑相声了。刚好最近出了一个开源的播客生成工具MOSS-TTSD,还没来得及试,正好借这个机会玩一玩。

选择了岳云鹏和孙越的几秒的参考音频,对上面AI短剧的内容进行格式化整理,然后直接跑MOSS-TTSD的开源代码,第一次跑就成功了,还是很丝滑的。

生成的效果如下:

视频

发音效果挺好,中文、英文单词发音都没明显问题,音色相似度差一些,孙越的参考声音换了几个都不太行,可能还有细节问题待定位。

总之,这个方向能玩的东西还是很多,未来可期。

之前有一次,和做投资人的高中同学聊天,他提到了投资了“小明”的创业公司,这里的小明指的是明超平。后面渐渐了解了明超平的经历。今天在B站看到张小张小珺和小明的访谈,听完后收获很大,创业者的顶级认知很有启发,这里摘录一些我觉得有收获的观点,对访谈的原文做了删减和流畅化的改写。

明超平背景:武大自动化系毕业,后转做产品经理,毕业后在One Plus 一加手机就职,后去字节做剪映产品,离职后加入MoonShot,负责海外产品Noisee。目前离职创业,做项目YouWare,一个用户分享、创造内容的社区。

下面是访谈的一些观点和访谈内容。

阅读全文 »