hxy published on included in 趣味项目 技巧 Web智能乐谱播放器实现 简介 在上一篇博客中,我实现了智能钢琴Web项目,仅需上传midi或musicxml可自动弹奏,同时支持更换音源。作为音乐爱好者,笔者在思索如何渲染乐谱,和钢琴曲一同播放。
技术流程 乐谱播放器的研发流程分为
读取乐谱 渲染乐谱 与midi同步,动态更新播放进度 musicXML是一种标准的乐谱记录格式,能够还原谱子全貌。市面上有许多读取musicxml的库,包括VexFlow、OpenSheetMusicDisplay等。
受用VUE实现一个乐谱播放器启发,笔者选用OpenSheetMusicDisplay库作为musicxml的渲染工具。
核心原理 乐谱渲染 首先安装opensheetmusicdisplay库
1 "opensheetmusicdisplay": "^1.8.4" 接着初始化osmd库
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 import { OpenSheetMusicDisplay as OSMD } from 'opensheetmusicdisplay' mounted() { this.setupOsmd() }, methods: { async setupOsmd() { if (this.$refs.container) { this.osmd = new OSMD(this.
hxy published on included in 趣味项目 技巧 Web智能钢琴实现 简介 笔者热爱音乐,擅长钢琴,最近想做一个自动播放乐谱的功能。诸如此类自动演奏的软件有不少,弹琴吧、虫虫钢琴均可实现钢琴模拟和乐谱同步,但都收取会员费。 因此,借助Web技术手动实现一个是非常实用且有趣的事情。
参考项目 全部手搓太耗时间,笔者在github上找到一个很棒的项目。 自动钢琴
运行也非常简单
1 2 yarn install yarn start 这是一个Vue项目,用CSS模拟了钢琴的黑白键。不过仔细一看,这个钢琴缺少了低音域和高音域。
笔者决定做一个88键 “满血版”。经过一个多小时,大功告成! 布局技巧 所有白键直接均匀排开,麻烦的是黑键布局。可将每五个黑键分成一个组,组里采用绝对定位,组与组之间间隔相等。
项目原理 按键 事实上,这个“钢琴”是通过一个json来实现的,每个键都对应一个mp3。 88个键范围: 白键从A0-C8 黑键从A#0-A#7。
如果要更换音源,需要修改这88个音的MP3。人工对钢琴的每个键录音非常麻烦。 事实上,玩音乐的人都知道,musescore软件中音源是通过sf2格式存储的。那么有无办法将sf2文件转成所有音的MP3文件呢?
笔者查询百度和DS未果,一筹莫展之际,偶然间在github中找到一个读取sf2的库。
1 2 3 4 5 6 7 8 9 import sf2_loader as sf loader = sf.sf2_loader(r"you-path.sf2") music_list = [ 'A0', 'B0', 'C1', ..., 'A7', 'B7', 'C8' ] for note in music_list: loader.export_note(note, format='mp3', name=f'{note}.mp3') 一波操作,导出所有白键的音源(黑键同理)。这样就实现了钢琴换音源工作。可以将钢琴换成施坦威等高级音质。
hxy published on included in 代码技巧 机器学习——numpy手搓神经网络 引言 笔者近期给数学系学生讲授机器学习课程。讲解BP神经网络的反向传播、梯度下降等操作时,较难理解。 因此,写一篇博客记录一下numpy手搓神经网络的过程。
BP神经网络 手搓实现 导包 首先导入numpy库和画图的matplotlib库。只需要这两个!
1 2 import numpy as np import matplotlib.pyplot as plt 定义激活函数及其导数 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 # 设置随机种子 np.random.seed(42) class ReLU: def __init__(self): pass def __call__(self, x): self.original_x = x return np.maximum(0, x) def derivative(self): return np.where(self.original_x > 0, 1, 0) class Sigmoid: def __init__(self): pass def __call__(self, x): self.
hxy published on included in 代码技巧 机器学习——RNN系列网络 引言 授课过程中,对于RNN、GRU和LSTM,发现有一些难点需要梳理。调用pytorch中的torch.nn库尽管方便,但没法深刻理解公式和代码的对应关系。因此,写一篇博客记录一下这些网络的原理和手搓实现过程。
RNN 简单的MLP网络没法利用序列前后的信息,并且参数量很大。 RNN 通过引入“循环”结构,使得网络能够在处理当前输入时,利用之前步骤的信息。这种特性使其非常适合处理时间序列、文本、语音等具有顺序关系的数据,让模型具有短期记忆能力。
公式 隐藏层在时间t的更新公式: $$ h_t = \sigma(W_{hx}\cdot x_t+W_{hh}\cdot h_{t-1} + b_h) $$
其中$\sigma$是激活函数,tanh或ReLU。$x_t$是t时刻的输入,$h_t$是当前的隐藏状态 $h_{t−1}$是上一时刻的隐藏状态
输出层公式: $$ y_t = W_{hy} \cdot h_t + b_y $$ $y_t$是当前时刻的输出
RNN的隐藏状态$h_t$起到了记忆的作用。 对于一整个序列,图示如下: pytorch实现 调库 可使用pytorch封装的nn.RNN模块。
1 2 3 4 5 6 7 8 9 10 11 class RNNModel(nn.Module): def __init__(self, input_dim, hidden_dim, output_dim=1, num_layers=1): super(RNNModel, self).__init__() self.rnn = nn.RNN(input_dim, hidden_dim, num_layers, batch_first=True) self.fc = nn.Linear(hidden_dim, output_dim) def forward(self, x): x, _ = self.
llm decoder的研究 引入 对于大模型来说,常见的是decoder-only transformer架构。因此,研究解码器的原理至关重要。 笔者通过实践,实践了默认解码方法的调用和自己重写解码器。
如何调用开源LLM LLM可分为开源和闭源两种。其中闭源的LLM会提供api,如gpt4等模型。 可使用requests库发送请求并接收信息。部分llm支持openai库
1 2 3 4 5 6 7 8 9 10 11 12 13 from openai import OpenAI client = OpenAI(api_key=api_key, base_url=base_url) # 调用API检索 response = client.chat.completions.create( model=model_name, messages=[ {"role": "user", "content": prompt}, ], stream=False ) # 获取优化后的代码结果 result = response.choices[0].message.content stream=True代表流式输出。反之直接输出最终的文本。
对于开源llm,可使用transformers库来调用
在科研中,尽管开源的llm调用起来十分方便,但也没有那么自由。因此,当我们需要访问llm的logits、attention权重等参数时,需选择开源llm进行研究。
常见的有llama系列(llama2, llama3)、mistral系列等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 # 读取模型 model = AutoModelForCausalLM.
llm Agent的Tool call原理解析 引入 转眼间进入2025年,新年第一篇博客记录一下近期的发现。
笔者在实践中,探索langchain框架可以自动调用工具(tool calling)。 见 langchain 然而,众所周知,LLM是用于文本生成的工具,可以理解成func(input:str) -> str 那么工具究竟是谁在调用呢?如何判断何时调用?
回顾 我们先简单回顾一下langchain的agent调用工具的例子。
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 # # 初始化 ChatZhipuAI from langchain.tools import Tool from langchain.