当前位置:   article > 正文

【更新】cyのMemo(20240609~)

【更新】cyのMemo(20240609~)

序言

节后首日,中期结束,接下来一切即将如期而至,时光像道皮鞭在赶鸭子上架,但似乎还并没有准备好一切。

最近几日,休息得不是很好,状态跌落,但总之手头事情告一段落,可以好好休整几日,韬光养晦。

安静了许多,大家都很忙碌。

筵席终散。然,命运的交点,将于未来邂逅。

有感,且歌一场。

《五月初五登高赋》 囚生
端午登高祈福佑,轻语绕梁疾未休。
花开叶落人渐朽,日没月升活似囚。
丛木泥径盘峰秀,远岫倩影碧空游。
君不见月圆常有,空太息圆月难留。



20240611

第一层和第一个头的值权重矩阵如下所示。

v_layer0_head0 = v_layer0 [0] v_layer0_head0.shape
# torch.Size ([128, 4096])
  • 1
  • 2

现在使用值权重来获取每个 token 的注意力值,其大小为 [17x128],其中 17 为提示中的 token 数,128 为每个 token 的值向量维数。

v_per_token = torch.matmul (token_embeddings, v_layer0_head0.T)v_per_token.shape
# torch.Size ([17, 128])
  • 1
  • 2

与每个 token 的值相乘后得到的注意力向量的形状为 [17*128]。

qkv_attention = torch.matmul (qk_per_token_after_masking_after_softmax, v_per_token) qkv_attention.shape
# torch.Size ([17, 128])
  • 1
  • 2

现在有了第一层和第一个头的注意力值。

接下来运行一个循环并执行与上面单元完全相同的数学运算,不过第一层中的每个头除外。

qkv_attention_store = []
for head in range (n_heads):
    q_layer0_head = q_layer0 [head]
    k_layer0_head = k_layer0 [head//4] # key weights are shared across 4 heads
v_layer0_head = v_layer0 [head//4] # value weights are shared across 4 heads
q_per_token = torch.matmul (token_embeddings, q_layer0_head.T)
    k_per_token = torch.matmul (token_embeddings, k_layer0_head.T)
    v_per_token = torch.matmul (token_embeddings, v_layer0_head.T)

    q_per_token_split_into_pairs = q_per_token.float ().view (q_per_token.shape [0], -1, 2)
    q_per_token_as_complex_numbers = torch.view_as_complex (q_per_token_split_into_pairs)
    q_per_token_split_into_pairs_rotated = torch.view_as_real (q_per_token_as_complex_numbers * freqs_cis [:len (tokens)])
    q_per_token_rotated = q_per_token_split_into_pairs_rotated.view (q_per_token.shape)

    k_per_token_split_into_pairs = k_per_token.float ().view (k_per_token.shape [0], -1, 2)
    k_per_token_as_complex_numbers = torch.view_as_complex (k_per_token_split_into_pairs)
    k_per_token_split_into_pairs_rotated = torch.view_as_real (k_per_token_as_complex_numbers * freqs_cis [:len (tokens)])
    k_per_token_rotated = k_per_token_split_into_pairs_rotated.view (k_per_token.shape)

    qk_per_token = torch.matmul (q_per_token_rotated, k_per_token_rotated.T)/(128)**0.5
mask = torch.full ((len (tokens), len (tokens)), float ("-inf"), device=tokens.device)
    mask = torch.triu (mask, diagonal=1)
    qk_per_token_after_masking = qk_per_token + mask
qk_per_token_after_masking_after_softmax = torch.nn.functional.softmax (qk_per_token_after_masking, dim=1).to (torch.bfloat16)
    qkv_attention = torch.matmul (qk_per_token_after_masking_after_softmax, v_per_token)
    qkv_attention = torch.matmul (qk_per_token_after_masking_after_softmax, v_per_token)
    qkv_attention_store.append (qkv_attention)
len (qkv_attention_store)
# 32
  • 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

现在第一层上的所有 32 个头都有了 qkv_attention 矩阵,并在快结束的时候将所有注意力分数合并为一个大小为 [17x4096] 的大矩阵。

stacked_qkv_attention = torch.cat (qkv_attention_store, dim=-1) stacked_qkv_attention.shape
# torch.Size ([17, 4096])
  • 1
  • 2

20240612

  • 8号资格赛那天傍晚,补了30箭步×8组(+20kg,终于有20kg的片用了)。9号和10号很忙,都没怎么跑,到昨晚开完会已经九点半,出来操场熄灯,悻悻而归,身体也确实很累,好在终于可以睡个好觉,把状态给养回来吧。

  • 尽管近期频繁熬夜,但胃口很好,一顿能吃四个菜,吃得挺多,感觉小肚子肥了一圈,加之天气炎热,原先每晚回去例行的核心训练都懒得做,腹肌似又挥之而去,而且引体也好久不练,又回到只能硬拉一两个的程度,扎心。但好歹是尽力管住嘴,没在睡前吃太多东西,饮食相对规律,但太缺觉,睡眠质量一直不太好。

  • 今天,一言难尽的天气,阴沉大半天,闷得不行。指望赶紧下个雨,结果,下午开始出太阳,怎一个难受了得!实验室一堆咳嗽的人,感觉自己也要快热出病来,疯狂地喝水。

  • 到晚上,还是陪自己刚一波强度,毕竟好多天没有认真训练。起手三圈跑得还是很舒服,有种可以用3’50"配速顶完10km的感觉,但是很快心肺不支,跑成四段间歇(3K@3’49"+2K@3’47"+2K@4’15"+3K@3’48"),间歇心率完全恢复。坦言很吃力,浑身湿透,去年夏训被支配的恐惧跃然心头,而且今天跑完脚踝稍有不适,这种强度还是少跑,有点伤,接下来正式入梅肯定也要停跑好一阵子。

  • PS:逮到一个高手AX,统院博二,全马329,跑姿很标准,一看就是多年跑龄,万米必有40分以内的水平。拉他参加下半年的高百分站赛,他欣然应允,他长得很像我的本科室友YC,可能也是青海人。
    在这里插入图片描述
    在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

权重矩阵是最后的步骤之一。

在这里插入图片描述
第 0 层注意力要做的最后一件事是,对以下的权重矩阵进行乘法操作。

w_layer0 = model ["layers.0.attention.wo.weight"] w_layer0.shape
# torch.Size ([4096, 4096])
  • 1
  • 2

这是一个简单的线性层,所以只做矩阵乘法(matmul)。

embedding_delta = torch.matmul (stacked_qkv_attention, w_layer0.T) embedding_delta.shape
# torch.Size ([17, 4096])
  • 1
  • 2

在这里插入图片描述

现在,注意力之后的嵌入值有了变化,并应该被添加到原始 token 嵌入中。

embedding_after_edit = token_embeddings_unnormalized + embedding_delta
embedding_after_edit.shape
# torch.Size ([17, 4096])
  • 1
  • 2
  • 3

归一化并在嵌入 delta 过程中运行一个前馈神经网络。

在这里插入图片描述

embedding_after_edit_normalized = rms_norm (embedding_after_edit, model ["layers.0.ffn_norm.weight"]) embedding_after_edit_normalized.shape
# torch.Size ([17, 4096])
  • 1
  • 2

加载 ff 权重,并实现前馈网络。

在这里插入图片描述
llama3 使用 SwiGLU前馈网络,该网络架构非常擅长在模型需要时添加非线性。当前,在 LLMs 中使用这一前馈网络是非常标准的做法。


20240613

  • 今天跟腱明显疼痛,伤是还没完全好,或许不算太碍事,但接下来也不能再跑昨晚这种强度。慢点儿好。

  • 晚上计划出去放纵,遂傍晚五点多去跑了会儿,太阳还没下山,晒得很难受,5’40"的配速都显得笨重,不一会儿吴征过来了,遂陪他一起跑了半个小时,有人一起确实要舒服很多,慢慢加到4’50"以内,心率保持得很好,最终是5’08"均配的7.09km,平均心率138bpm,并无不满。就这个节奏还是很舒服的,但是没有人一起真的很无聊。

  • 可能还是得缓几天,慢慢来吧,总觉得离梦想越发遥远。
    在这里插入图片描述在这里插入图片描述

w1 = model ["layers.0.feed_forward.w1.weight"] w2 = model ["layers.0.feed_forward.w2.weight"] w3 = model ["layers.0.feed_forward.w3.weight"] output_after_feedforward = torch.matmul (torch.functional.F.silu (torch.matmul (embedding_after_edit_normalized, w1.T)) * torch.matmul (embedding_after_edit_normalized, w3.T), w2.T) output_after_feedforward.shape
torch.Size ([17, 4096])
  • 1
  • 2

现在终于在第一层之后为每个 token 提供了新的编辑后的嵌入,并且在完成之前只剩下 31 层需要处理(one for loop away)。

你可以想象这个编辑后的嵌入拥有在第一层上所有查询的信息。现在每一层将在所问问题上编码越来越复杂的查询,直到得到的嵌入了解所需的下一个 token 的一切。

layer_0_embedding = embedding_after_edit+output_after_feedforward
layer_0_embedding.shape
torch.Size ([17, 4096])
  • 1
  • 2
  • 3

之前为每一层做的所有事情,都可以一次性完成。


final_embedding = token_embeddings_unnormalized
for layer in range (n_layers):
    qkv_attention_store = []
    layer_embedding_norm = rms_norm (final_embedding, model [f"layers.{layer}.attention_norm.weight"])
    q_layer = model [f"layers.{layer}.attention.wq.weight"]
    q_layer = q_layer.view (n_heads, q_layer.shape [0] //n_heads, dim)
    k_layer = model [f"layers.{layer}.attention.wk.weight"]
    k_layer = k_layer.view (n_kv_heads, k_layer.shape [0] //n_kv_heads, dim)
    v_layer = model [f"layers.{layer}.attention.wv.weight"]
    v_layer = v_layer.view (n_kv_heads, v_layer.shape [0] //n_kv_heads, dim)
    w_layer = model [f"layers.{layer}.attention.wo.weight"]
    for head in range (n_heads):
        q_layer_head = q_layer [head]
        k_layer_head = k_layer [head//4]
        v_layer_head = v_layer [head//4]
        q_per_token = torch.matmul (layer_embedding_norm, q_layer_head.T)
        k_per_token = torch.matmul (layer_embedding_norm, k_layer_head.T)
        v_per_token = torch.matmul (layer_embedding_norm, v_layer_head.T)
        q_per_token_split_into_pairs = q_per_token.float ().view (q_per_token.shape [0], -1, 2)
        q_per_token_as_complex_numbers = torch.view_as_complex (q_per_token_split_into_pairs)
        q_per_token_split_into_pairs_rotated = torch.view_as_real (q_per_token_as_complex_numbers * freqs_cis)
        q_per_token_rotated = q_per_token_split_into_pairs_rotated.view (q_per_token.shape)
        k_per_token_split_into_pairs = k_per_token.float ().view (k_per_token.shape [0], -1, 2)
        k_per_token_as_complex_numbers = torch.view_as_complex (k_per_token_split_into_pairs)
        k_per_token_split_into_pairs_rotated = torch.view_as_real (k_per_token_as_complex_numbers * freqs_cis)
        k_per_token_rotated = k_per_token_split_into_pairs_rotated.view (k_per_token.shape)
        qk_per_token = torch.matmul (q_per_token_rotated, k_per_token_rotated.T)/(128)**0.5
        mask = torch.full ((len (token_embeddings_unnormalized), len (token_embeddings_unnormalized)), float ("-inf"))
        mask = torch.triu (mask, diagonal=1)
        qk_per_token_after_masking = qk_per_token + mask
        qk_per_token_after_masking_after_softmax = torch.nn.functional.softmax (qk_per_token_after_masking, dim=1).to (torch.bfloat16)
        qkv_attention = torch.matmul (qk_per_token_after_masking_after_softmax, v_per_token)
        qkv_attention_store.append (qkv_attention)


    stacked_qkv_attention = torch.cat (qkv_attention_store, dim=-1)
    w_layer = model [f"layers.{layer}.attention.wo.weight"]
    embedding_delta = torch.matmul (stacked_qkv_attention, w_layer.T)
    embedding_after_edit = final_embedding + embedding_delta
    embedding_after_edit_normalized = rms_norm (embedding_after_edit, model [f"layers.{layer}.ffn_norm.weight"])
    w1 = model [f"layers.{layer}.feed_forward.w1.weight"]
    w2 = model [f"layers.{layer}.feed_forward.w2.weight"]
    w3 = model [f"layers.{layer}.feed_forward.w3.weight"]
    output_after_feedforward = torch.matmul (torch.functional.F.silu (torch.matmul (embedding_after_edit_normalized, w1.T)) * torch.matmul (embedding_after_edit_normalized, w3.T), w2.T)
    final_embedding = embedding_after_edit+output_after_feedforward
  • 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

现在有了最终的嵌入,即该模型对下一个 token 的最佳猜测。该嵌入的形状与常见的 token 嵌入 [17x4096] 相同,其中 17 为 token 数,4096 为嵌入维数。

final_embedding = rms_norm (final_embedding, model ["norm.weight"]) final_embedding.shape
torch.Size ([17, 4096])
  • 1
  • 2

将该嵌入解码为 token 值。

使用该输入解码器将最终的嵌入转换为一个 token。

model ["output.weight"].shape
torch.Size ([128256, 4096])
  • 1
  • 2

使用最后 token 的嵌入来预测下一个值。在示例中,42 是「生命、宇宙和万物终极问题的答案是什么」的答案,根据《银河系漫游指南》一书,大多数现代 LLMs 都会回答 42,应该验证了整个代码。

logits = torch.matmul (final_embedding [-1], model ["output.weight"].T) logits.shape
torch.Size ([128256])
  • 1
  • 2

模型预测 token 数 2983 为下一个 token,这是 42 的 token 数吗?以下是最后的代码单元。

next_token = torch.argmax (logits, dim=-1) next_token
tensor (2983)
  • 1
  • 2

最后,启动。


20240614

  • 万米重回40分钟,只要愿意,总还是可以做到的。

  • 原计划没有打算这么快,衣服鞋子都没有换,起步只有五分配,XR中途跟来,小家伙总不肯老实地跟在后面,把我逼得越来越快。我估摸着夏天4’10"的配速对他来说应该会有些艰难,果不其然,不到3000米他就崩了,休息了会儿,他又想跟上来,不到两圈又崩,再起不能。

  • 前5000米用时20’49",13圈后我停下喝口水稍作调整。后12圈提速,把平均配速拉回4分整,体感不错,八九成力,平均心率167bpm。伤痛没有复发,甚好,作为夏天的一次训练,比较满意。
    在这里插入图片描述在这里插入图片描述

关于SQL SERVER查看数据表:

SELECT TOP(100) * FROM [DATABASE_NAME].[TABLE_NAME]
  • 1

SQL SERVER的语法和MYSQL还是有不少区别的,不能用SHOW指令,也不支持双引号包裹变量。第一次用这老东西有点吃瘪。

关于MDF文件,这是汽车工业领域常用的数据格式,配套的会有一个LDF文件作为日志,一般容量都非常大。

Python读取MDF文件的方法:

  1. 使用asammdf包:可以直接读取MDF文件,也可以读取通用的压缩包格式(zip, bz2, gzip)
>>> from asammdf import MDF
>>> mdf = MDF(version='3.30') # new MDF object with version 3.30
>>> mdf = MDF('path/to/file.mf4') # MDF loaded from file
>>> mdf = MDF(BytesIO(data)) # MDF from file contents
>>> mdf = MDF(zipfile.ZipFile('data.zip')) # MDF creating using the first valid MDF from archive
>>> mdf = MDF(bz2.BZ2File('path/to/data.bz2', 'rb')) # MDF from bz2 object
>>> mdf = MDF(gzip.GzipFile('path/to/data.gzip', 'rb')) # MDF from gzip object
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  1. 使用mdfreader
>>> import mdfreader
>>> yop=mdfreader.Mdf('NameOfFile')
>>> yop.keys() # list channels names
# list channels grouped by raster or master channel
>>> yop.masterChannelList
>>> yop.plot('channelName') or yop.plot({'channel1','channel2'})
>>> yop.resample(0.1) or yop.resample()
>>> yop.export_to_csv(sampling=0.01)
>>> yop.export_to_NetCDF()
>>> yop.export_to_hdf5()
>>> yop.export_to_matlab()
>>> yop.export_to_excel()
>>> yop.export_to_xlsx()
>>> yop.convert_to_pandas() # converts data groups into pandas dataframes
>>> yop.write() # writes mdf file
# drops all the channels except the one in argument
>>> yop.keep_channels(['channel1','channel2','channel3'])
>>> yop.get_channel_data('channelName') # returns channel numpy array
>>> yop=mdfreader.Mdf()  # create an empty Mdf object
# add channel in Mdf object
>>> yop.add_channel(channel_name, data, master_channel, master_type, unit='lumen', description='what you want')
>>> yop.write('filename') # change version with yop.MDFVersionNumber or specifically use write3/4()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

20240615~20240616

  • 周末升温,34℃,夏天真的来了。昨晚去小姨那边吃点儿好的,连吃带拿,顺了三个鲜肉蛋黄粽子回来,以及半只红烧肉鸡。最近食堂越来越不合我意,真不知道吃啥好。

  • 今天下午,跟吴征白嫖了张国际电影节的票去凑凑热闹,高仓健主演的《远山的呼唤》,说实话我根本不认识高仓健,也很少去影院看电影,但这两天也没啥急事,懒得在学校闷着。

  • 日本的电影,总觉得格局不大。不止是电影,其他文学作品也大多如此。之前有个日本文学翻译家说,日本文学要少读,因为越读越小。当然就其电影艺术而言,这种典型的学院派拍摄手法确实没有可以挑剔的地方,但是故事还是缺少那种感染力,太小了,看完似乎也就结束了,也可能是时代太过久远的缘故,我们很难去产生很强的共鸣。

  • 而且,日本文学中的一些价值观其实是有些畸形的,有些事情就很难让人理解,比如《火影忍者》里的鼬屠杀宇智波一族以防止其叛乱,一直很难理解这种事情怎么能让人称道的,再怎么牺牲小我成就大我,也不至于用这么离谱的手段,杀几个主使差不多得了,连老幼妇孺都不放过,弑父弑母这种事情无论如何也不能和正义挂钩。再比如《进击的巨人》里巨人能力继承的方式——吃人,这种就很离谱,为了继承这股力量,就需要儿子吃掉父亲,这种桥段在国内的文学中毫无疑问是不可能存在的。

  • 总之,岛国的文化就挺极端的,再举个例子就是箱根驿传,其中六区20km的下坡,选手为了守住名次,几乎需要全程冲刺,损伤极大,几乎所有的选手跑完六区都是一头攒倒在地被担架抬走,而每个高校都必须派出一个牺牲者来承担六区的重担,几乎没有学校会把王牌放在六区上场。这种事情在中国也是挺难想象的,谁家孩子不是宝呢,哪个家长愿意让自己的孩子去做这种炮灰。

  • 卷王LXY今天应该是刚回学校,就五分配跑了15km,看来回家一周没少练。晚上回来力量训练,30个正向箭步×4组+30个反向箭步×4组(+20kg),补5000米顺腿,跑得乱七八糟,心乱。

  • PS:最近童心佬在H5魔塔做出了实时弹幕系统,首次应用在《王座之上》,这个效果真的很好,极大地提升游戏体验,可惜这部作品还没完结,目前只有144层,美工顶级,剧情也超级棒,据说要到25年初才能做完,大约280层。这些人的创作热情真的可以。
    在这里插入图片描述在这里插入图片描述

亦童在集群上搭了个千问2的后端,目前外网可访问,推理速度在30秒左右,用了两张A100的卡就把72B的Qwen2给跑通了。

项目仓库在https://github.com/QwenLM/Qwen2,模型已在HUGGINGFACE上开源

from openai import OpenAI
# Set OpenAI's API key and API base to use vLLM's API server.
openai_api_key = "EMPTY"
openai_api_base = "http://10.2.170.105:43858/v1"

client = OpenAI(
    api_key=openai_api_key,
    base_url=openai_api_base,
)

chat_response = client.chat.completions.create(
    model="/gemini/data-1/Qwen2-72B-Instruct-GPTQ-Int4",
    messages=[
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "Tell me something about large language models."},
    ]
)
print(chat_response.choices[0].message.content)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

目前,OPENAI提供LLM client封装功能,方便共享,挺好用的。


20240617

  • 难得清闲的一段时期,追点前沿的事情,似乎已经很久不去深究,没有当年的热情。

  • 难得清凉的夜,偶遇嘉伟,其实他最近还是有练的,就是不怎么遇得到,我6月前15天总跑量105km,平均配速4’21",只有一两天没有跑,比不了三月巅峰期的训练质量,勉强也说得过去吧。

  • 八点下去的时候,LXY带着嘉伟,YZZ,还有国教的QSH在遛弯,她今天又是15km,属实是有点离谱了,这是准备把回家一周落下的给全补回来么。

  • 原计划今晚是带XR跑4分配节奏,看看他能顶多少,但是难得碰到嘉伟,他想跑速耐,我也不想扫他的兴,临时决定陪他进行倒金字塔间歇训练。嘉伟是1600米×1组+1200米×2组+800米×3组,我是1200米×1组+800米×1组+400米×5组,XR前两组分别被我拉爆一圈,就下了,当然我也没好到哪里去,每组也被嘉伟拉爆一圈,实在力不能及,尤其第二个800米跑到2分38秒,之后腿就完全软了,根本抬不起来,后面5个1’18"~1’20"的400米都是力竭,完全不可能多跑哪怕一圈。嘉伟还是一如既往的无敌,最后一组800米甚至跑到2分30秒,可怕,奖励他一瓶沁柠水,夏训当如此呀。

  • 可惜,或许也是最后一个夏天了,当年那个大一刚入学的嘉伟,如今也将成为大四学长,跑得再快,跑不赢时间,罢了。
    在这里插入图片描述在这里插入图片描述

目前Qwen2-72B-int4勉强可以跑通,但是还是容易挂,免费的午餐并不好吃。亦童也测试了7B版本的全量模型推理,用时大概是72B的一半,性价比角度来看还是不如72B,从理论上来讲,int4和全量版本的输出误差应该不算很大,至少对于高偏差的输出结果当如此,其实看看这些。其实这个时代对于普通人来讲,大模型的区别不算太大,所谓的好坏不过是实证的结果,缺少理论支撑。

关于K-Sparse AutoEncoder与大模型可解释性研究

这个其实是做模型压缩的操作,但是通过观察稀疏特征被激活的部分,可以粗略地解释大模型参数集合对输出的贡献情况。

LLAMA RAG Response Mode

  • https://docs.llamaindex.ai/en/latest/getting_started/concepts/
  • https://docs.llamaindex.ai/en/latest/getting_started/starter_example/
  • data => index (chunks => embedding vectors)
    • embedding model: ‘text-embedding-ada-002’
      • POST https://api.openai.com/v1/embeddings
      • from llama_index.embeddings.openai import OpenAIEmbedding
    • query => index (embedding vector)
    • retrieve similarity_top_k (default 2)
    • settings
      • embed_model: ‘text-embedding-ada-002’
      • llm: gpt-3.5-turbo
from llama_index.core.response_synthesizers.type import ResponseMode

print(ResponseMode.REFINE, ResponseMode.COMPACT, ResponseMode.SIMPLE_SUMMARIZE, ResponseMode.TREE_SUMMARIZE, ResponseMode.GENERATION)

# <ResponseMode.REFINE: 'refine'>,
# <ResponseMode.COMPACT: 'compact'>,
# <ResponseMode.SIMPLE_SUMMARIZE: 'simple_summarize'>,
# <ResponseMode.TREE_SUMMARIZE: 'tree_summarize'>,
# <ResponseMode.GENERATION: 'generation'>)

from dotenv import load_dotenv
load_dotenv('./.env')


import os
os.environ['HTTP_PROXY'] = 'http://127.0.0.1:7890'
os.environ['HTTPS_PROXY'] = 'http://127.0.0.1:7890'

# import logging
# import sys
# logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
# logging.getLogger().addHandler(logging.StreamHandler(stream=sys.stdout))


from llama_index.core import VectorStoreIndex, SimpleDirectoryReader

documents = SimpleDirectoryReader("data").load_data()
documents[0].text_template, documents[0].metadata_seperator, documents[0].metadata_template

# ('{metadata_str}\n\n{content}', '\n', '{key}: {value}')

index = VectorStoreIndex.from_documents(documents, show_progress=True)
# index.docstore.docs['9655ddd8-a3e7-46a5-b709-dca099020c81']
# index.vector_store.data.embedding_dict['9655ddd8-a3e7-46a5-b709-dca099020c81']

query_engine = index.as_query_engine()
response = query_engine.query("What did the author do growing up?")
response.response # 'The author worked on writing short stories and programming, starting with early programming experiences on an IBM 1401 using Fortran in 9th grade. Later, the author transitioned to working with microcomputers, building simple games and a word processor on a TRS-80 in the early 1980s.'

response.metadata 
"""
{'8aefc79e-2d08-4041-8f7e-294bf4f74b6a': {'file_path': '/home/whaow/workspaces/llm_aigc/tutorials/rag/data/paul_graham_essay.txt',
  'file_name': 'paul_graham_essay.txt',
  'file_type': 'text/plain',
  'file_size': 75042,
  'creation_date': '2024-06-15',
  'last_modified_date': '2024-06-15'},
 '4a01aa3a-d5ac-49f2-aed6-dbd0ad477bfe': {'file_path': '/home/whaow/workspaces/llm_aigc/tutorials/rag/data/paul_graham_essay.txt',
  'file_name': 'paul_graham_essay.txt',
  'file_type': 'text/plain',
  'file_size': 75042,
  'creation_date': '2024-06-15',
  'last_modified_date': '2024-06-15'}}
"""

len(response.source_nodes) # 2
response.response # 
'The author worked on writing short stories and programming, starting with early programming experiences on an IBM 1401 using Fortran in 9th grade. Later, the author transitioned to working with microcomputers, building simple games and a word processor on a TRS-80 in the early 1980s.'
  • 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

20240618

  • 果然不出我所料,院里是要分家,但是跟之前那个撤管科的考研点关系不大,wyl透露说是单纯觉得管科两年制的硕士没啥用,要钱没钱,要产出没产出,不如把名额划给MEM多捞点学费,好招点人进来。事实上是要新建一个新的学院,这是上面的要求,但是院里其实并不愿意分家,分家这事情在学校层面是好事,但学院层面是坏事,但小腿拗不过大腿,没辙,但这些年院里分化确实挺严重的,不如分了的好。

  • 梅雨前最后一次顶强度,3组×400米变速(3圈快2圈慢,快圈1’20"以内,慢圈2’30"以内),剩下是2000米+1200米+800米的间歇。状态不算特别好,毕竟是开完会一个人顶强度,也没去换衣服鞋子,而且昨天也刚刚进行大强度的速度训练,但就是在扯着命去顶,因为400米这个距离怎么都是能扛得下来,冬训的时候就算再累,400米变速跑个十几组都是轻轻松松,而且每次跑完都贼爽,今天终于又感觉到那种很舒服的感觉了。

  • LXY今天一共跑了19K多,三天一共跑了50K,确实猛得可怕。XR一如既往的萎靡,完全不见五月份的锐气,而我感觉自己终于要彻底摆脱伤痛的阴影,或许还会复发,但活在当下,假以时日,重回巅峰,乃至超越,亦可期。
    在这里插入图片描述

Whisper调用

import pytube
import moviepy.editor as mp
import whisper
import os
import subprocess


# 使用 yt-dlp 下载视频
def download_video(url, output_path='video.mp4'):
    subprocess.run(['yt-dlp', '-o', output_path, url])
    return output_path

# 从视频中提取音频
def extract_audio(video_path, output_path='audio.wav'):
    video = mp.VideoFileClip(video_path)
    video.audio.write_audiofile(output_path)
    return output_path

# 转录音频
def transcribe_audio_with_whisper(audio_path):
    model = whisper.load_model("large")
    # result = model.transcribe(audio_path, language='en')
    result = model.transcribe(audio_path)
    return result['text']


video_url = 'https://www.bilibili.com/video/BV12J4m1N7wU/'
video_path = './video.mp4'
audio_path = './audio.wav'

print("Downloading video...")
download_video(video_url, video_path)

print("Extracting audio...")
extract_audio(video_path, audio_path)

print("Transcribing audio with Whisper...")
transcription = transcribe_audio_with_whisper(audio_path)

print("Transcription:")
print(transcription)

# 清理临时文件
# os.remove(video_path)
# os.remove(audio_path)
  • 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

输出:

Downloading video...
[BiliBili] Extracting URL: https://www.bilibili.com/video/BV12J4m1N7wU/
[BiliBili] 12J4m1N7wU: Downloading webpage
[BiliBili] BV12J4m1N7wU: Extracting videos in anthology
[BiliBili] 1254605812: Extracting chapters
[BiliBili] Format(s) 1080P 高码率, 1080P 高清, 720P 高清 are missing; you have to login or become premium member to download them. Use --cookies-from-browser or --cookies for the authentication. See  https://github.com/yt-dlp/yt-dlp/wiki/FAQ#how-do-i-pass-cookies-to-yt-dlp  for how to manually pass cookies
[info] BV12J4m1N7wU: Downloading 1 format(s): 100110+30280
[download] Destination: ./video.f100110.mp4
[download] 100% of  425.01KiB in 00:00:00 at 7.64MiB/s     
[download] Destination: ./video.f30280.m4a
[download] 100% of  274.45KiB in 00:00:00 at 10.31MiB/s    
[Merger] Merging formats into "./video.mp4"
Deleting original file ./video.f30280.m4a (pass -k to keep)
Deleting original file ./video.f100110.mp4 (pass -k to keep)
Extracting audio...
MoviePy - Writing audio in ./audio.wav
                                                                    
MoviePy - Done.
Transcribing audio with Whisper...
Transcription:
 Saying goodbye, I don't think is ever nice, but saying goodbye without Feeling sad or feeling hurt or whatever that would that would just mean that the time we spent together was Right great and had a great time. So it was always clear that it will be tough and I know it will be tough
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

这里依赖需要安装:

!pip install pytube moviepy openai-whisper
!pip install you-get
!pip install yt-dlp
  • 1
  • 2
  • 3

尤其是这个yt-dlp,各大视频平台的视频下载都封装好了,就是更新的比较频繁。


20240619

  • 入梅首日,雨还没有下得太大,据说要一直下到七月份,但闷得不行,然而,GXJ大小姐这几天在实验室,咳嗽得厉害,搞得谁都不敢去开空调(每次她来第一件事就是关空调…),只能开窗开门通风,但还是热得不行,CHT已经开始用折扇降温,苦不堪言。

  • 晚上吃完饭本想去打球,其实今天嘉伟和XR都考完最后一门了,但去了之后还是觉得实验室要凉快点儿。八点雨停,下楼环校4圈慢跑,10km@4’26",平均心率166bpm,第三圈雨开始下得有点大,便装,穿的旧鞋子,整体节奏还行,心率维持得比较稳定,但后面T恤湿透,体感还是太吃力了。

  • 慢跑积累必不可少,但是夏天的慢跑,尤其是出梅之后,是煎熬且费时。这个夏训,除了为下半年破三做准备外,一个很重要的目标是把16km跑进一个小时,最终12月8日总决赛,形式是10人×16km的接力,而就往年情况来看,16km跑进1小时(平均配速3’45"),才能算是有竞争力的成绩,去年总决赛,50支队伍,除了前五的学校,第6~第12名都是9小时55分出头的成绩,从第15名北航开始,总用时超出10小时(平均配速3’45"),其中第12名浙江大学,160km总用时9:55:30,平均配速3’43”,他们的队长YLS就是刚好卡在这个平均值上。然而到目前为止,即便对于嘉伟,一小时跑完16km也并非易事,对其他人来说就更加困难了。我自己最接近这个指标的一次,是在三个月前的扬州半马,前16km用时62分50秒,比这个要求还是差不少。

  • 今年上海站前八的门槛,估计会在全队10km平均38分半左右,至少这个水平我们还是很有机会达到的。好想好想能进一回总决赛呀嘿,但也不是一个人就能做到,像去年一样,各种岔子。若是最后一回依然不得,总归不太圆满,还是得平常心。
    在这里插入图片描述在这里插入图片描述

https://pytorch.org/get-started/previous-versions/

2.0以前的torch最多只能用py39版本,但是很多新的加速包(accelerate,deepspeed)都要py310以后的版本。

最近回头把之前狂神的ES教程又看了一遍,我觉得其实就检索这件事情而言,老方法未必不如新方法,即稀疏检索未必不如现在这种主流的稠密检索,至少从解释性上来看,稠密检索毫无解释性可言,尤其是token级别的,所谓的product-similarity,其实效果也没有说就比sentence级别的好到哪里去。

  1. 本教程基于ElasticSearch7.6.1, 注意ES7的语法与ES6的API调用差别很大, 教程发布时最新版本为ES7.6.2(20200401更新);

  2. ES是用于全文搜索的工具:

  • SQL: 使用like %关键词%来进行模糊搜索在大数据情况下是非常慢的, 即便设置索引提升也有限;
  • ElasticSearch: 搜索引擎(baidu, github, taobao)
  • 一些ES涉及的概念:
    • 分词器 ik
    • Restful操作ES
    • CRUD
    • SpringBoot集成ES

  1. Lucene: java写成的为各种中小型应用软件加入全文检索功能;
  2. Nutch: 一个建立在Lucene核心之上的网页搜索应用程序, Nutch的应用比Lucene要更加广泛
  3. 大数据解决存储与计算(MapReduce)两个问题:
  • 2004年Doug Cutting基于GFS系统开发了分布式文件存储系统;
  • 2005年Doug Cutting基于MapReduce在Nutch搜索引擎实现了这种算法;
  • 加入Yahoo后, Doug Cutting将MapReduce和NDFS结合创建了Hadoop, 成为了Hadoop之父;
  • Doug Cutting将BigTable集成到Hadoop中
  1. 回到主题:
  • Lucene是一套信息检索工具包, jar包, 不包含搜索引擎系统;
  • Lucene包含索引结构, 读写索引的工具, 排序, 搜索规则, 工具类;
  • Lucene和ES的关系:
    • ES是基于Lucene做了一些封装和增强, 上手是比较简单的, 比Redis要简单

  1. 分布式的全文搜索引擎, 高扩展性;
  2. 接近实时更新的查询搜索;
  3. ES是基于Restful的(即用get, post, delete, put来访问);
  4. ES进行复杂的数据分析, ELK技术(elastic+logstash+kibana)

  1. 当使用索引时, solr会发生io阻塞, 查询性较差, elastic则在索引情况下的优势明显;
  2. elastic的效率在传统项目下一般有50倍的提升;
  3. elastic解压即可用, solr需要配置
  4. solr用zookeeper进行分布式管理, elastic自带分布式
  5. solr支持更多格式的数据, json, xml, csv, elastic只支持json
  6. solr比elastic的功能更强大
  7. solr查询快, 但是更新索引时慢(如插入和删除慢), elastic查询慢, 但是实时性查询快, 用于facebook新浪等搜索
  8. solr是传统搜索应用的解决方案, elastic适用于新兴的实时搜索应用
  9. solr比较成熟, elastic目前更新换代快;

  1. 要求jdk1.8以上, 这是最低要求;

  2. elastic客户端, 界面工具;

  3. springboot添加依赖时默认没有到ES7, 需要自己修改

  4. 下载链接: https://www.elastic.co/cn/downloads/elasticsearch

  5. 可以直接在windows或linux上学习, 而无需使用虚拟机或者其他配置;

  6. elastic 7.x.x的解压目录:

  • bin: 启动文件
  • config: 配置文件
    • log4j2: 日志配置
    • jvm.options: java虚拟机相关配置
    • elasticsearch.yml: ES配置文件, 默认端口是9200
  • lib: 相关jar包
  • logs: 日志
  • modules: 功能模块
  • plugins: 插件(如ik)
  1. 启动, 访问9200端口
  • 双击: bin/elasticsearch.bat
  • 访问: localhost:9200
    • 可以看到如下json字符串
      {
          "name" : "CAOYANG",
          "cluster_name" : "elasticsearch",
          "cluster_uuid" : "xEDZ4q2JSxq54mJM2UiTxQ",
          "version" : {
        	  "number" : "7.9.2",
        	  "build_flavor" : "default",
        	  "build_type" : "zip",
        	  "build_hash" : "d34da0ea4a966c4e49417f2da2f244e3e97b4e6e",
        	  "build_date" : "2020-09-23T00:45:33.626720Z",
        	  "build_snapshot" : false,
        	  "lucene_version" : "8.6.2",
         	  "minimum_wire_compatibility_version" : "6.8.0",
        	  "minimum_index_compatibility_version" : "6.0.0-beta1"
          },
          "tagline" : "You Know, for Search"
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
  1. 安装可视化插件 ES head:
  • 下载地址: https://github.com/mobz/elasticsearch-head
    • 安装步骤:
    git clone git://github.com/mobz/elasticsearch-head.git
    cd elasticsearch-head
    npm install
    npm run start
    open http://localhost:9100/
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 连接测试: 访问http://localhost:9100/
      • 会发生跨域问题, 需要在ES解压目录下的bin/elasticsearch.yml中配置跨域信息, 在配置文件末尾添加:
        • http.cors.enable: true
        • http.cors.allow-origin: "*"
    • 重新连接测试: 访问http://localhost:9100/
      • 出现可视化界面, 一些健康状况为显示在页面上

20240620

  • 时隔十个月,我又回到了129运动场。

  • 前几天嘉伟说今年还没去过129训练,得抽空去一趟。今天的课表是2000米×5组,间歇3分钟,精英组配速3’25",高级组配速3’40",肉眼可见的虐,而且天气恶劣,下午五点开始一阵一阵的暴雨,下完就出太阳,蒸得极其难受,但夏天就是这样一个冲极限的季节,事实上最近一周几乎都在速度训练,每天都在跟自己玩命。

  • 蜡烛说今晚没有精英组,我们只好一起跟跑高级组,PACER是勇哥和蜡烛。

    • 前2组,嘉伟全程在二道跟跑,明显对这个速度不是很满意,第二组最后一圈直接超越PACER,一骑绝尘。

    • 第3组开始时,我就感觉自己应该是不行了,果然1200米就崩,提前下场休息。

    • 第4组,强行跟完2000米,心肺难受到了极限,最后一圈嘉伟依然是一骑绝尘超越PACER,我也试着冲上去跟住,但最后100米还是被他拉爆,但也算是体验了一把拉爆PACER的快感。

    • 第5组,蜡烛表示不能再跑了,今天4组结束,到此为止,有个哥们儿还想跑,蜡烛就让嘉伟带他,我想想还是去跟了一段,依然是1200米崩,最后一组2000米嘉伟甚至跑到了7’10"以内,其实,对他来说前面4组根本就没有用尽全力,他现在这个状态应该是超越了之前的巅峰期,今晚如果有精英组,相信他至少也能干个三四组。

  • 整体来说,今晚是高质量的间歇训练,今年第一回赤膊上阵,操场上升腾的雾气,跑完一组,就跟从水里爬出来一样,擦完汗接着冲,不知脱了多少水,一天喝了有13杯500ml保温杯的水,怎一个痛快了得。
    在这里插入图片描述在这里插入图片描述

  1. kibana是一个针对ES的开源分析及可视化界面, 用来搜索查看和交互存储在ES索引中的数据
  2. 下载地址: https://www.elastic.co/cn/kibana
  3. 下载完毕后, 解压需要一段时间, 是一个标准的工程
  • 好处: ELK基本上都是拆箱即用;
  • 启动bin/kibana.bat, 然后访问localhost:5601即可
  • 在页面上可以直接在console里写查询语句执行, 查询结果直接显示在页面上
  1. 汉化: 直接在kibana.yml末尾添加: i18n.locale: "zh-CN", 即SpringBoot中的国际化

ES核心概念理解

  1. elasticsearch是面向文档的, 索引和搜索数据的最小单位是文档, 与关系型数据库比较:
  • 数据库(database) v.s. 索引(indices, 理解为数据库)
  • 表(tables) v.s. 类型(types, 7.x弃用, 8.x会完全丢掉)
  • 行(rows) v.s. 文档(documents)
  • 字段(columns) v.s. 字段(fields)
  • ES所有数据都是json
  1. ES在后台把索引划分成多个切片, 每份分片可以在集群中不同服务器间迁移
  2. ES一个人就是一个集群, 默认的集群名称就是elasticsearch
  3. ES文档(可以理解为json或是yml中的数据格式)的重要属性:
  • 自我包含, 一篇文档同时包含字段和对应的值, 也就是同时包含keyvalue
  • 可以是层次型的, 一个文档中包含子文档, 复杂的逻辑实体, 就是一个json对象
  • 灵活的结构, 文档不依赖预先定义的模式, 我们知道关系型数据库中, 要提前定义字段才能使用, elasticsearch中, 对于字段是灵活的, 有时可以忽略该字段, 或是动态添加一个新的字段
  1. ES索引: 就是数据库
  • ES索引是一个非常大的文档集合, 索引存储了映射类型的字段和其他设置, 然后存储到各个分片上, 一般是存在集群的不同节点上, 一旦某个节点挂了, 数据不会丢失;
  • 分片是一个Lucene索引, 一个包含==倒排索引(inverted index)==的文件目录, 倒排索引的结构使得elasticsearch在不扫描全部文档的情况下, 就可以告诉你哪些文档包含特定的关键字;
    • 通过各个关键字的权重(可以理解为score)之和来对查询结果进行排序
    • 使用倒排索引可以过滤掉完全无关的数据
  1. 总结:
  • ES中, 索引(库)这个词被频繁使用, 就是数据库, 索引被分为多个分片, 每份分片是一个Lucene的索引, 所以一个ES索引是由多个Lucene索引组成, Lucene索引是一种倒排索引;

IK分词器详解

  1. 分词: 类似python的jieba和nltk
  2. IK分词器下载地址: https://github.com/medcl/elasticsearch-analysis-ik-releases
  • 注意与ES版本对应
  1. 下载完毕后直接解压即可, 然后移动到elasticsearch7.x.x里的plugins/的ik目录下
  • IK项目的README中写道:

    拷贝和解压release下的文件: #{project_path}/elasticsearch-analysis-ik/target/releases/elasticsearch-analysis-ik-*.zip 到你的 elasticsearch 插件目录, 如: plugins/ik

  • 注意别下载错了, 解压或里面应该是一个config文件夹, 1个properties文件, 1个policy文件, 还有5个jar包
  1. 配置好后重启ES, 可以看到ik分词器被加载了;
  • 可以通过elasticsearch-plugin来查看加载的插件(把ES目录的bin文件夹添加到Path里)
  1. 开始使用IK, 在kibana的界面控制台里写:
  • 查看的不同的分词效果:
GET _analyze
{
  "analyzer": "ik_smart",
  "text": "中国人民军队"
}

GET _analyze
{
  "analyzer": "ik_max_word",
  "text": "中国人民军队"
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
+ ```ik_smart```为最少切分, 返回结果只有包含中国人民军队的结果, 就是尽可能少的切分;
+ ```ik_max_word```为最细粒度划分, 穷尽词库的可能, 如会划分中国, 人民, 军队, 及这三个分词;
+ 如果搜索```超级喜欢狂神说```, 会发现即使用最少切分, 狂神说三个字都被分开了;
+ 所以需要配置用户字典: 配置文件路径在ik/config/IKAnalyzer.cfg.xml
  * 可以新建一个kuang.dic文件, 然后在IKAnalyzer.cfg.xml中添加配置
    - ```<entry key="ext_dict">kuang.dic</entry>```
    - ```<entry key="ext_stopwords">kuang_stop.dic</entry>```
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

Rest风格操作

  1. PUT: 创建文档(指定文档id), localhost:9200/索引名称/类型名称/文档ID
  • 示例:
    PUT /test1/type1/1
    {
    	"name": "狂神说",
    	"age": 3
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 命令执行返回结果: 完成了自动增加索引, 数据也成功添加了
      {
        _index: test1,
        _type: type1,
        _id: 1,
        _score: 1,
        name: "狂神说",
        age: 3
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
  • 数据类型:
    • 字符串类型: text和keyword
    • 数值类型: long, integer, short, byte, double, float, half float, scaled float
    • 日期类型: date
    • te布尔值类型: boolean
    • 二进制类型: binary
  • 指定字段类型: 添加一个库并添加字段规则(类似mysql建表)
    PUT /test2
    {
      "mappings": {
        "properties": {
    	  "name": {
    	    "type": "text"
    	  },
    	  "age": {
    	    "type": "long"
    	  },
    	  "birthday": {
    	    "type": "date"
    	  }
    	}
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 返回结果发现acknowledged是true, 说明规则创建成功
  1. POST: 创建文档(随机文档id), localhost:9200/索引名称/类型名称
  2. POST: 修改文档, localhost:9200/索引名称/文档id/_update
  • 示例:
    POST /test3/_doc/1/_update
    {
      "doc": {
        "name": "法外狂徒张三"
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 则索引test3中的_doc类型里的name值被更新
  • 注意如果不创建文档则默认是_doc
  1. DELETE: 删除文档, localhost:9200/索引名称/类型名称/文档id
  • DELETE test1: 删除索引
  • 通过请求来判断是删除索引还是删除文档记录
  1. GET: 查询文档(通过文档id), localhost:9200/索引名称/类型名称/文档id
  • 获得索引表的规则: GET test2
    • GET 表就是拿到表的信息, GET 索引就是拿到索引的信息
  • GET _cat/health: 查看健康信息
  • GET _cat/indices?v: 索引状态
  • ge _cat可以获得es的当前的很多信息
  1. POST: 查询所有数据, localhost:9200/索引名称/类型名称/_search

20240621

  • 绿叶今天有红烧小黄鱼,已经很久没有看到食堂煮鱼了,就是个头小了些,不过才3块钱一条,难得良心。

  • 说实话,最近饿得不行,但还是尽量克制住非饭点吃东西的欲望。我有半个月没到绿叶吃砂锅,阿姨还是记得给我装两碗堆得尖尖的饭,属实是吃撑。晚上八点,慢跑10km,平均配速4’31",平均心率162bpm,配速压的比较稳,也很吃力,这种天气跑起来就肯定不会轻松。
    在这里插入图片描述在这里插入图片描述

  • PS:昨晚脱了衣服,跟别人一比自己真就一只白斩鸡(跟这些常年晒太阳的人比,还真比他们白不少),最近核心腰腹做少了,腹肌完全消失,加上胸肌又松弛得不行,侧面视角完全不能看。但体重并不算高,前两天晚饭后称毛重,67kg整,净重大约持平扬马前的水平,但就是看起来要比别人肥得多(其实我觉得自己已经不能再更轻了,净重低于65kg是肯定不行的)。
    PS:嘉伟确实跑起来是太帅了,我觉得自己练这么久,虽然比以前快了很多,但跑姿还是一塌糊涂,难绷。最后一张名场面,嘉伟:各位不会都没吃饭吧,跑这么慢?其实昨晚嘉伟还真没吃晚饭,离谱。
    在这里插入图片描述在这里插入图片描述在这里插入图片描述

把Qwen1.5和Qwen2的几个派生模型都测了一下,其实结果差不太多,目前没有看到明显的区别,但是小模型一个典型的问题就是输出的误差太大,很容易发生中英混杂的问题。大模型的输出显然是要流畅得多。

至于quantize得版本,之前在ChatGLM1和2上做测试就发现,其实输出结果真的没什么变化,我到现在

值得一提的是,Qwen2-72B-int4依然可以很好地作答比较复杂的算术问题,不容易被之前几个典型的陷阱问题误导(比如年龄问题的若干变体),最近看了K-Sparse AutoEncoder(arXiv:1312.5663,这是个很古老的理论,有点类似onthot),这个是可以用来做解释性的,就是事实上在一次推理中,大模型真正被激活的参数是很少的,海量的参数中事实上只有稀疏部分的参数是在起作用的,比如在回答法律问题,模型只会使用一部分的参数,回答物理问题,那又是另一部分的参数,这其实也是符合直觉的,人脑中或许也是不同的部分掌管不同的知识。

但是无论如何,这种解释都是缺乏理论支撑以及可复现、可迁移性的,我觉得直到目前为止,我们对LLM依然所知甚少,我们不知道它为什么这么做,也不知道它到底能做到什么地步,仅仅是依赖人类的调教经验,在无脑地增加越来越多的参数,企图使用这种“人海战术”,来穷竭量化这个世界。其实这个是挺愚蠢的一件事情,本质就是在超高维的空间,让世间一切不同的事物都是显著可分,但是时间线上的实例永远是无穷无尽的。

现在的研究无非都是在讲一个自圆其说的故事,所谓的挑战性的benchmark花样百出,甚至都不需要花费太多时间验证。除非现在能造出一个AI,让他在人类社会中生存一天、一周、一月、一年、乃至一整个生命周期,甚至不需要有实体,只需要在网络上生存一段时间,不被发现破绽,这样的图灵测试才是真正有意义的。

还有一个遐想,就是我们现在走的这套autoregressive的道路真的是正确的吗?人类在组织输出的时候,其实我觉得还是偏向于连点成线,线扩成面的,即应该是先根据问题,联想到几个点,然后想办法把他们串起来这样,如果说autoregressive是一种单向的生成,那这种就是多中心多向的生成方式,呈现在模型架构上,输出就应该是先是做“点”的生成,然后根据这些点,再进行多向的生成,这是个两步走的事情。因为目前autoregressive呈现出明显的缺陷,除了解释性不足以外,也是难以控制的,而这种多中心多向的生成,看起来似乎更合理一些。

Qwen1.5简易测试脚本

def qwen_1_5_demo():	
	import torch
	import time
	with open("cuda_avail.txt", 'w') as f:
		f.write(str(torch.cuda.is_available()))
	from transformers import AutoModelForCausalLM, AutoTokenizer
	device = "cpu" # the device to load the model onto
	model_path = r"F:\model\huggingface\Qwen\Qwen1.5-0.5B-Chat"
	model_path = "/nfsshare/home/caoyang/code/model/huggingface/Qwen/Qwen1.5-0.5B-Chat"
	model = AutoModelForCausalLM.from_pretrained(
		model_path,
		torch_dtype="auto",
		device_map="auto"
	)
	tokenizer = AutoTokenizer.from_pretrained(model_path)
	system_prompt = "你是一个数学教师,你需要对算术问题进行作答"
	user_prompt = "我今年18岁,我的妹妹的年龄是我的一半,那么当我60岁时,我的妹妹多少岁?"
	messages = [
		{"role": "system", "content": system_prompt},
		{"role": "user", "content": user_prompt}
	]
	text = tokenizer.apply_chat_template(
		messages,
		tokenize=False,
		add_generation_prompt=True
	)
	model_inputs = tokenizer([text], return_tensors="pt").to(device)
	t = time.time()
	generated_ids = model.generate(
		model_inputs.input_ids,
		max_new_tokens=512
	)
	generated_ids = [
		output_ids[len(input_ids):] for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids)
	]
	response = tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
	t = time.time() - t
	with open("resp.txt", 'w') as f:
		f.write(str(response) + '\n' + str(t))
qwen_1_5_demo()
  • 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

20240622

  • 各种校友会,以及下周的典礼,在这个并不算很好的天气里,也是多了几分生气。

  • 跑休,计划力量训练。早上没有下雨,暑气郁结,极其沉闷,即便如此依然有人不知死活地上午跑步。中午下雨,稍许改善,下午田径场一直有人踢球,看起来外面下得并不算小,五点准备去拿个壶铃做力量,但师傅想要提前下班,便也罢了,少练一回也不会死,不是么?

  • 晚上回来把许久不练的核心腰腹和俯卧撑认真练一回,真的难受,不开空调根本坚持不下来,越来越觉得地球不适合人类居住了,印象里极端的高温是从22年开始出现,那时候7月底8月初白天都不敢在外面走路,如今每年都在上演,今年出梅后肯定又是极端高温。

  1. 关于文档的基本操作(重点!)
  • 基本操作

    PUT /kuangshen/user/1
    {
    	"name": "xxx",
    	"age": 12,
    	"desc": "xxx",
    	"tags": {"a","b","c"}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • kuangshen就是_index, user就是_type, 1就是_id
    • 简单搜索GET kuangshen/user/1: 取出kuangshen库中的user表里的id为1的文档结果;
      • 有个_version字段, 表明被更新了几次
      • 可以添加条件来搜索: GET kuangshen/user/_search?q=name:狂神说Java, 注意这个是精确搜索, 少一些(比如搜索"狂神说")就找不到"狂神说Java"
      • 之前提到字符串有keyword和text的区别, keyword是不会被分词处理, text会被分词处理
    • POST kuangshen/user/1/_update {"doc":{"name": "xxxx"}}: 更新数据, 注意更新的数据放在doc键下, 是一个字典格式的, 一次可以同时更新多个字段
  • 复杂操作: select(排序, 分页, 高亮, 模糊查询, 精准查询)

    • hits字段下是所有查询结果, 如果存在多条查询出来的结果, 则每个结果有_score值返回, 指匹配度, 会降序列出;

    • 例1: 查询参数体(一个json对象), 把name字段包含"狂神"的结果都搜索出来

      GET kuangshen/user/_search
      {
        "query": {
          "match": {
            "name": "狂神"
          }
        },
        
        "_source": ["name","desc"], // 结果过滤, 只返回name和desc字段
        "sort": [ //排序
          {
            "age": {
        	  order: "asc"
        	}
          }
        ],
        
        // 分页参数: 总第from个数据开始, 返回多少条数据(当前页面)
        "from": 0,
        "size": 2
        
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
    • 例2: 多条件查询, 通过bool值字段

      • bool下的must命令, 下面的所有条件都要符合(and)
      • bool下的should命令, 下面的所有条件都要符合(or)
      • bool下的must_not命令, 下面的所有条件都不能符合
      • bool下的filter字段, 过滤条件, 包括range下的lte, lt, gt, gte字段为大于小于等等
      • match字段是包含这个字符串的结果都会被搜索出来
      GET kuangshen/user/_search
      {
        "query": {
          "bool": {
            "must": [
        	  {
        	    "match": {
        	      "name": "狂神说"
        	    }
        	  },
        	  {
        	    "match": {
        		  "age": 23
        		}
        	  }
        	],
        	"should": [
        	  {
        	    "match": 13
        	  },
        	  {
        	    "match": {
        		  "age": 12
        		}
        	  }
        	],
        	"filter": { // 过滤条件
        	  "range": {
        	    "age": {
        		  "gte": 10,
        		  "lt": 25
        		}
        	  }
        	}
          }
        }
      }	  
      
      • 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
    • 例3: 匹配多个条件

      GET kuangshen/user/_search
      {
        "query": {
          "match": {
            "tags": "a b" // 会把tag字段包含(指match)"a"和"b"的都拿出来
          }
        }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 多个条件用空格隔开, 只要满足一个结果就被查出, 会有得分结果返回, 得分越高匹配度越高
    • 精确查询!

      • term查询就是直接通过倒排索引指定的词条进程精确查找的
    • 关于分词:

      • term, 直接查询精确的, 把上面例子中的match换成term就是精确而非包含的查询
      • match, 会使用分词器解析(先分析文档, 然后再通过分析的文档进行查询)
      • text字符串会被分词解析, keyword则不会被分词解析
    • 多个值匹配的精确查询: bool.should + term

    • 高亮:

      GET kuangshen/user/_search
      {
        "query": {
          "match": {
            "tags": "a b" // 会把tag字段包含(指match)"a"和"b"的都拿出来
          }
        },
        "highlight": { // 搜索结果高亮name
          "pre_tags": "<p class='key' style='color:red'>",
          "post_tags": "</p>", // 自定义高亮的tag
          "fields": {
            "name": {}
          }
        }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15

SpringBoot集成ES详解

  1. 官方文档: https://www.elastic.co/guide/index.html
  • 找到 Java Rest Client 里的高级客户端
  • ① 引入原生依赖: sts4直接选nosql里的elasticsearch就行了, 但是有可能默认是ES6, 要改成ES7的依赖才行;
    <dependency>
    	<groupId>org.elasticsearch.client</groupId>
    	<artifactId>elasticsearch-rest-level-client</artifactId>
    	<version>7.6.2</version>
    </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
  • ② 初始化
    • 创建: 可以参数里是多个new(表示多个集群, 一般本地测试一个就行了)
    RestHighLevelClient client = new RestHighLevelClient(
    								RestClient.builder(
    									new HttpHost("localhost",9200,"http"),
    									new HttpHost("localhost",9201,"http")));
    
    • 1
    • 2
    • 3
    • 4
    • 关闭: client.close();
  • ③ ES的配置文件:
    @Configuration
    public class ElasticSearchConfig {
    	@Bean
    	public RestHighLevelClient restHighLevelClient() {
    		RestHighLevelClient client = new RestHighLevelClient(
    										RestClient.builder(
    											new HttpHost("127.0.0.1",9200,"http"),
    											));		
    		return client;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
  • ④ 测试文件:
    @SpringBootTest
    class KuangshenEsApiApplicationTests {
    	@Autowired
    	private RestHighLevelClient restHighLevelClient;
    	
    	@Test
    	void contextLoads() {
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

关于索引的API操作详解

  1. 测试文件(续)
  • 例1: 直接运行西面的测试代码, ES中创建的一个新的空索引kuang_index, 然后判断存在. 最后删除
    @SpringBootTest
    class KuangshenEsApiApplicationTests {
    	@Autowired
    	@Qualifier("restHighLevelClient")
    	private RestHighLevelClient client;
    	
    	@Test
    	void testCreateIndex() { // 测试索引创建
    		// 1. 创建索引请求
    		CreateIndexRequest request = new CreateIndexRequest("kuang_index");
    		
    		// 2. 客户端执行请求
    		CreateIndexResponse createIndexResponse = client.indices().create(request,RequestOptions.DEFAULT);
    		
    		System.out.println(createIndexResponse);
    	}
    	
    	@Test 
    	void testExistIndex() { // 测试获取索引
    		GetIndexRequest request = new GetIndexRequest("kuang_index");
    		boolean exists = client.indices.exist(request,RequestOptions.DEFAULT);
    		
    		System.out.println(exists);
    	}
    	
    	@Test
    	void testDeleteIndex() { // 测试删除索引
    		DeleteIndexRequest request = new DeleteIndexRequest("kuang_index");
    		AcknowledgedResponse delete = client.indices.delete(request,RequestOptions.DEFAULT);
    		System.out.println(delete.isAcknowledged());			
    	}
    }
    
    • 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

20240623

  • 开荤,放纵吃了一天,其实,昨晚就开始放纵地吃,而且几乎没有消耗,光吃不练,有些罪过。

  • 早上依然有些小雨,但是明天就是毕业典礼,实验楼依然在如火如荼地布置和排演,其实他们对这里又能有什么感情呢?研究生自不必说,不过是人生短暂的一站,而本科生经年种种,少些怨尤就不错了,也就我们这些呆得太久的人会有些感情。但是吧,家丑不外扬,自己人说说也则罢了,外人是没资格谈论这里的——这是个糟糕的总统,但它是我选的总统(致敬阿连德)

  • 好在这雨,总算是祛除了些暑气,晚上非常凉快,可惜九点多才到学校,去管理室拿20kg的壶铃做力量,30个正向箭步×4组+30个反向箭步×4组(+20kg),补2000米慢跑放松。XR几个人之前都已经跑完了,LXY和YZZ跑了一大圈学校,但只有6K多一点,不像是她的风格,这两天下雨不得给她憋坏了,就跑这点怎么够本。

  • 不过,我还是看到安迪和AX在跑,安迪应该跑了10K多一些,他们跑姿都很好,让我很是羡慕。尤其是AX,他肯定是跑了很久,我做完力量陪他遛了5圈以放松,4’25"的配速,他显然说起话来游刃有余,我倒觉得有些吃力。不太清楚AX的真实水平,但或许不在我之下,若果真如此,那实在太好了。

  • 休息两天也好,调整状态,晚上也算是顺了腿,明天应该不下雨,晚上也会挺凉快,顺利的话,准备测一下万米成绩,也是检测近期训练成果,可能已经恢复到巅峰期了。

K-SAE的本质是将输入映射到维度高得多的空间,然后进行一轮上采样(稀疏编码),将上采样的结果拼接成稠密的、低维的、隐层表示进行传播。

还有一个kv-cache问题,就是为什么BERT的双向注意力机制,现在不再流行,原因在于双向注意力机制无法使用kv-cache来减少计算开销。

  • KV cache 会显著地提升 inference/generate 的性能,降低时延;

  • generate 的 seq 越长,占用的显存增长得也会更多;

    • gpt 8K vs. 32k, input/output prices 是翻倍的关系
  • KV-cache Memory Usage

    2 × precision × n layers × d model × seqlen × batch 2 \times \text{precision} \times n_{\text{layers}} \times d_{\text{model}} \times \text{seqlen} \times \text{batch} 2×precision×nlayers×dmodel×seqlen×batch

    • 2 = two matrices for K and V
    • precision = bytes per parameter (e.g., 4 for fp32)
    • n layers n_{\text{layers}} nlayers = layers in the model
    • d model d_{\text{model}} dmodel = dimension of embeddings
    • seqlen = length of context in tokens
    • batch = batch size
    • OPT-30B: 2 ∗ 2 ∗ 48 ∗ 128 ∗ 1024 ∗ 7168 2*2*48*128*1024*7168 224812810247168
      • precision:2(fp16 inference)
      • 48 layers,128 batch
      • K/V shape: seqlen 1024, d_model 7168 (7*1024)
        • https://github.com/meta-llama/llama3/blob/main/llama/model.py#L129-L144
  • Bidirectional vs. Unidirectional

    • BERT:Bidirectional Encoder Representations from Transformers),双向注意力
    • GPT:Unidirectional,单向注意力;
  • 以多轮对话为例,从计算复杂度的角度探索为什么 decoder-only 更优

  • 定义

    • L L L: past sequence length
    • ℓ \ell : 新的输入的长度
    • d d d:embedding dimension
  • decoder only

    • KVcache: K p a s t , V p a s t K_{past}, V_{past} Kpast,Vpast
    • 每次新输入时,计算键值( K n e w , V n e w K_{new}, V_{new} Knew,Vnew),时间复杂度为 O ( ℓ ⋅ d ) O(\ell\cdot d) O(d),也需要计算 Query Q n e w Q_{new} Qnew
    • 计算注意力,
      • Q = Q n e w ∈ R ℓ ⋅ d Q=Q_{new}\in \mathbb R^{\ell \cdot d} Q=QnewRd
      • K = [ K p a s t , K n e w ] ∈ R ( L + ℓ ) ⋅ d K=[K_{past}, K_{new}]\in \mathbb R^{(L+\ell)\cdot d} K=[Kpast,Knew]R(L+)d
      • V = [ V p a s t , V n e w ] ∈ R ( L + ℓ ) ⋅ d V=[V_{past}, V_{new}]\in \mathbb R^{(L+\ell)\cdot d} V=[Vpast,Vnew]R(L+)d
      • A = Q K T ∈ R ℓ ⋅ ( ℓ + L ) A=QK^T\in \mathbb R^{\ell\cdot(\ell+L)} A=QKTR(+L)
        • q i q_i qi 要跟 L + i L+i L+i 的 K 计算 score vector;
      • softmax ( A ) ⋅ V ∈ R ℓ ⋅ d \text{softmax}(A)\cdot V\in \mathbb R^{\ell\cdot d} softmax(A)VRd
  • 对于 encoder-decoder

    • At every turn, the new input has to be encoded again; for unidirectional attention, only the newly added message needs to be encoded.

具体一个例子:

L, l, d = 5, 2, 3
K_past = np.random.randn(L, 3)
V_past = np.random.randn(L, 3)
Q_past = np.random.randn(L, 3)

Q_new = np.random.randn(l, 3)
K_new = np.random.randn(l, 3)
V_new = np.random.randn(l, 3)

def create_custom_matrix(n):
    # 创建一个全为负无穷的矩阵
    matrix = np.full((n, n), -np.inf)
    
    # 将下三角部分(包括对角线)设置为0
    lower_triangle_indices = np.tril_indices(n)
    matrix[lower_triangle_indices] = 0
    
    return matrix

M1 = create_custom_matrix(5)
M1
"""
array([[  0., -inf, -inf, -inf, -inf],
       [  0.,   0., -inf, -inf, -inf],
       [  0.,   0.,   0., -inf, -inf],
       [  0.,   0.,   0.,   0., -inf],
       [  0.,   0.,   0.,   0.,   0.]])"""

import scipy as sp

import scipy as sp
sp.special.softmax((Q_past.dot(K_past.T))/np.sqrt(3) + M1, axis=1)
"""array([[1.   , 0.   , 0.   , 0.   , 0.   ],
       [0.622, 0.378, 0.   , 0.   , 0.   ],
       [0.592, 0.352, 0.056, 0.   , 0.   ],
       [0.629, 0.271, 0.022, 0.079, 0.   ],
       [0.532, 0.147, 0.039, 0.079, 0.203]])"""

M2 = create_custom_matrix(7)
M2
"""array([[  0., -inf, -inf, -inf, -inf, -inf, -inf],
       [  0.,   0., -inf, -inf, -inf, -inf, -inf],
       [  0.,   0.,   0., -inf, -inf, -inf, -inf],
       [  0.,   0.,   0.,   0., -inf, -inf, -inf],
       [  0.,   0.,   0.,   0.,   0., -inf, -inf],
       [  0.,   0.,   0.,   0.,   0.,   0., -inf],
       [  0.,   0.,   0.,   0.,   0.,   0.,   0.]])"""

Q = np.concatenate([Q_past, Q_new], axis=0)
K = np.concatenate([K_past, K_new], axis=0)
sp.special.softmax((Q.dot(K.T))/np.sqrt(3) + M2, axis=1)
"""array([[1.   , 0.   , 0.   , 0.   , 0.   , 0.   , 0.   ],
       [0.622, 0.378, 0.   , 0.   , 0.   , 0.   , 0.   ],
       [0.592, 0.352, 0.056, 0.   , 0.   , 0.   , 0.   ],
       [0.629, 0.271, 0.022, 0.079, 0.   , 0.   , 0.   ],
       [0.532, 0.147, 0.039, 0.079, 0.203, 0.   , 0.   ],
       [0.245, 0.136, 0.156, 0.119, 0.122, 0.222, 0.   ],
       [0.162, 0.211, 0.233, 0.112, 0.13 , 0.079, 0.072]])"""
  • 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

可以看到两次的sp.special.softmax计算QKV注意力的结果,下三角的数值是相同的(这是decoder-only的attention),因此可以缓存,但是如果是双向:

M2 = create_custom_matrix(7)
Q = np.concatenate([Q_past, Q_new], axis=0)
K = np.concatenate([K_past, K_new], axis=0)
sp.special.softmax((Q.dot(K.T))/np.sqrt(3) + M2, axis=1)
"""array([[1.   , 0.   , 0.   , 0.   , 0.   , 0.   , 0.   ],
       [0.622, 0.378, 0.   , 0.   , 0.   , 0.   , 0.   ],
       [0.592, 0.352, 0.056, 0.   , 0.   , 0.   , 0.   ],
       [0.629, 0.271, 0.022, 0.079, 0.   , 0.   , 0.   ],
       [0.532, 0.147, 0.039, 0.079, 0.203, 0.   , 0.   ],
       [0.245, 0.136, 0.156, 0.119, 0.122, 0.222, 0.   ],
       [0.162, 0.211, 0.233, 0.112, 0.13 , 0.079, 0.072]])"""
import scipy as sp
sp.special.softmax((Q_past.dot(K_past.T))/np.sqrt(3), axis=1)
"""array([[0.353, 0.169, 0.114, 0.157, 0.206],
       [0.218, 0.132, 0.537, 0.067, 0.046],
       [0.287, 0.171, 0.027, 0.141, 0.374],
       [0.443, 0.191, 0.015, 0.055, 0.296],
       [0.532, 0.147, 0.039, 0.079, 0.203]])"""
sp.special.softmax((Q.dot(K.T))/np.sqrt(3), axis=1)
"""array([[0.227, 0.109, 0.074, 0.101, 0.132, 0.148, 0.21 ],
       [0.159, 0.097, 0.393, 0.049, 0.033, 0.188, 0.081],
       [0.229, 0.137, 0.022, 0.113, 0.3  , 0.044, 0.156],
       [0.406, 0.175, 0.014, 0.051, 0.272, 0.012, 0.07 ],
       [0.404, 0.112, 0.029, 0.06 , 0.154, 0.063, 0.178],
       [0.201, 0.112, 0.128, 0.097, 0.1  , 0.182, 0.18 ],
       [0.162, 0.211, 0.233, 0.112, 0.13 , 0.079, 0.072]])"""
  • 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

即输入的QK多加一维进来之后,结果是完全不同的,因为整个注意力权重整体都发生变化了。


20240624

  • 一个烂会注册费要两三百欧,虽然能报,但还是真的离谱,瑞士那屁大点的地方,简单吃顿饭都要四五百,但去还是得去一趟,看看风景也是好的,有人说去趟那边,就算下辈子在那儿做狗,也不回来当牛作马了。

  • 有人生来就在罗马,有人生来就是骡马。之前有段时间特别喜欢听小约翰的奇葩小国系列,看小约翰还是从硬核狠人入坑,当时也是当段子听,但是听到奇葩小国系列时,有不少都很有触动(智利的阿连德,古巴的卡斯特罗切格瓦拉,布基纳法索的桑卡拉,埃及的纳赛尔),小国的领导者也有这些正人君子,但大多数都是些独夫民贼(非洲四大仁君卡扎菲、海地的杜瓦利埃)以及井底之蛙阿尔巴尼亚冈比亚),后者当然让人唾弃,但前者往往过刚易折(除了菲律宾的杜特尔特,不过他似乎也算不得君子,只是以暴制暴,因地制宜了属于是),反而是那些中庸之辈贝宁左右横跳、苏里南傍荷兰大腿,还有泰国这种王室与军政府相制约的神奇体制)能活得更好。总之,许多烂事都深究不得,光鲜之下都是肮脏的人血馒头。

  • 晚上hmy毕业散伙饭,她最后还是去了深圳华为,wyl难得慷慨大方地请我们吃了一顿,以前聚餐他都是点一堆绿色蔬菜,虽然考虑到他老人家年纪大了,吃不了太多油腻,但还是觉得太抠搜了,今天他看我们好像没吃饱,主动又点了三四个硬菜,真的吃撑了。

  • 回来一看操场居然没关门,顿时就后悔了,赶紧消化,准备还是要认真跑一下。结果刚热身完,大雨滂沱,我跟师傅说今晚很凉快,真的想练一下,请求暂缓关门,便与XR赤膊上阵,但是毕竟雨战,操场熄灯,时间太晚,就一个人在黑暗中猛冲,而且吃太饱没完全消化完,最后只跑了5000米,19分32秒,师傅也急着在催我们,XR不到7圈就爆了,变强的路上怎能没有辣

    声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/861287
推荐阅读
相关标签