RWKV系列2-ChatRWKV

注意使用最新的版本

在这里插入图片描述

提示词

##### 步骤4.1英文对话指令
    say something --> chat with bot. use \\n for new line.
    + --> alternate chat reply
    +reset --> reset chat
    
    +gen YOUR PROMPT --> free single-round generation with any prompt. use \\n for new line.
    +i YOUR INSTRUCT --> free single-round generation with any instruct. use \\n for new line.
    +++ --> continue last free generation (only for +gen / +i)
    ++ --> retry last free generation (only for +gen / +i)

##### 步骤4.1中文对话指令
    直接输入内容 --> 和机器人聊天(建议问机器人问题),用\\n代表换行,必须用 Raven 模型
    + --> 让机器人换个回答
    +reset --> 重置对话,请经常使用 +reset 重置机器人记忆
    
    +i 某某指令 --> 问独立的问题(忽略聊天上下文),用\\n代表换行,必须用 Raven 模型
    +gen 某某内容 --> 续写内容(忽略聊天上下文),用\\n代表换行,写小说用 testNovel 模型
    +++ --> 继续 +gen / +i 的回答
    ++ --> 换个 +gen / +i 的回答
    
    作者:彭博 请关注我的知乎: https://zhuanlan.zhihu.com/p/603840957
    如果喜欢,请看我们的优质护眼灯: https://withablink.taobao.com
    
    中文 Novel 模型,可以试这些续写例子(不适合 Raven 模型):
    +gen “区区
    +gen 以下是不朽的科幻史诗长篇巨著,描写细腻,刻画了数百位个性鲜明的英雄和宏大的星际文明战争。\\n第一章
    +gen 这是一个修真世界,详细世界设定如下:\\n1.

运行环境适配参考

安装包解释:https://pypi.org/project/rwkv/

运行环境适配选择,Strategy参数配置

# set these before import RWKV
os.environ['RWKV_JIT_ON'] = '1'
os.environ["RWKV_CUDA_ON"] = '0' # '1' to compile CUDA kernel (10x faster), requires c++ compiler & cuda libraries

########################################################################################################
#
# Use '/' in model path, instead of '\'. Use ctx4096 models if you need long ctx.
#
# fp16 = good for GPU (!!! DOES NOT support CPU !!!)
# fp32 = good for CPU
# bf16 = worse accuracy, supports CPU
# xxxi8 (example: fp16i8, fp32i8) = xxx with int8 quantization to save 50% VRAM/RAM, slower, slightly less accuracy
#
# We consider [ln_out+head] to be an extra layer, so L12-D768 (169M) has "13" layers, L24-D2048 (1.5B) has "25" layers, etc.
# Strategy Examples: (device = cpu/cuda/cuda:0/cuda:1/...)
# 'cpu fp32' = all layers cpu fp32
# 'cuda fp16' = all layers cuda fp16
# 'cuda fp16i8' = all layers cuda fp16 with int8 quantization
# 'cuda fp16i8 *10 -> cpu fp32' = first 10 layers cuda fp16i8, then cpu fp32 (increase 10 for better speed)
# 'cuda:0 fp16 *10 -> cuda:1 fp16 *8 -> cpu fp32' = first 10 layers cuda:0 fp16, then 8 layers cuda:1 fp16, then cpu fp32
#
# Basic Strategy Guide: (fp16i8 works for any GPU)
# 100% VRAM = 'cuda fp16'                   # all layers cuda fp16
#  98% VRAM = 'cuda fp16i8 *1 -> cuda fp16' # first 1 layer  cuda fp16i8, then cuda fp16
#  96% VRAM = 'cuda fp16i8 *2 -> cuda fp16' # first 2 layers cuda fp16i8, then cuda fp16
#  94% VRAM = 'cuda fp16i8 *3 -> cuda fp16' # first 3 layers cuda fp16i8, then cuda fp16
#  ...
#  50% VRAM = 'cuda fp16i8'                 # all layers cuda fp16i8
#  48% VRAM = 'cuda fp16i8 -> cpu fp32 *1'  # most layers cuda fp16i8, last 1 layer  cpu fp32
#  46% VRAM = 'cuda fp16i8 -> cpu fp32 *2'  # most layers cuda fp16i8, last 2 layers cpu fp32
#  44% VRAM = 'cuda fp16i8 -> cpu fp32 *3'  # most layers cuda fp16i8, last 3 layers cpu fp32
#  ...
#   0% VRAM = 'cpu fp32'                    # all layers cpu fp32
#
# Use '+' for STREAM mode, which can save VRAM too, and it is sometimes faster
# 'cuda fp16i8 *10+' = first 10 layers cuda fp16i8, then fp16i8 stream the rest to it (increase 10 for better speed)
#
# Extreme STREAM: 3G VRAM is enough to run RWKV 14B (slow. will be faster in future)
# 'cuda fp16i8 *0+ -> cpu fp32 *1' = stream all layers cuda fp16i8, last 1 layer [ln_out+head] cpu fp32
#
# ########################################################################################################

from rwkv.model import RWKV
from rwkv.utils import PIPELINE, PIPELINE_ARGS

# download models: https://huggingface.co/BlinkDL
model = RWKV(model='/fsx/BlinkDL/HF-MODEL/rwkv-4-pile-169m/RWKV-4-Pile-169M-20220807-8023', strategy='cpu fp32')
pipeline = PIPELINE(model, "20B_tokenizer.json") # 20B_tokenizer.json is in https://github.com/BlinkDL/ChatRWKV

ctx = "\nIn a shocking finding, scientist discovered a herd of dragons living in a remote, previously unexplored valley, in Tibet. Even more surprising to the researchers was the fact that the dragons spoke perfect Chinese."
print(ctx, end='')

def my_print(s):
    print(s, end='', flush=True)

# For alpha_frequency and alpha_presence, see "Frequency and presence penalties":
# https://platform.openai.com/docs/api-reference/parameter-details

args = PIPELINE_ARGS(temperature = 1.0, top_p = 0.7, top_k = 100, # top_k = 0 then ignore
                     alpha_frequency = 0.25,
                     alpha_presence = 0.25,
                     alpha_decay=0.996, # gradually decay the penalty
                     token_ban = [0], # ban the generation of some tokens
                     token_stop = [], # stop generation whenever you see any token here
                     chunk_len = 256) # split input into chunks to save VRAM (shorter -> slower)

pipeline.generate(ctx, token_count=200, args=args, callback=my_print)
print('\n')

out, state = model.forward([187, 510, 1563, 310, 247], None)
print(out.detach().cpu().numpy())                   # get logits
out, state = model.forward([187, 510], None)
out, state = model.forward([1563], state)           # RNN has state (use deepcopy to clone states)
out, state = model.forward([310, 247], state)
print(out.detach().cpu().numpy())                   # same result as above
print('\n')

张量分离的理解

out, state = model.forward([187, 510, 1563, 310, 247], None)
print(out.detach().cpu().numpy())      解释下这里的detach()函数和cpu函数

在这个代码片段中,out 是一个 PyTorch 张量(tensor)。detach 和 cpu 是 PyTorch 张量的两个方法,作用如下:

detach() 方法用于创建一个新的 Tensor,这个新的 Tensor 不再是原始 Tensor 的一个视图,并且与计算图(Computation Graph)断开连接。使用 detach() 方法可以将张量从计算图中分离出来,使得修改这个分离的张量不会对计算图中的其他张量产生影响,也不会更新梯度。

cpu() 方法用于将 PyTorch 张量从 GPU 上移动到 CPU 上,并返回一个新的 CPU 张量。如果需要将训练模型的中间结果打印出来或进行其他 CPU 计算,就需要使用 cpu() 方法。在上面的代码中,在张量 out 上调用了 detach() 方法,然后再使用 cpu() 方法将结果转移到 CPU 上打印出来。

因此,这段代码的作用是,将输入序列 [187, 510, 1563, 310, 247] 通过模型进行前向计算,得到输出张量 out 和状态张量 state,然后将 out 张量从计算图中分离出来,并将其移动到 CPU 上作为 Numpy 数组打印出来。

numy的打印格式设置

np.set_printoptions(precision=4, suppress=True, linewidth=200)这个函数是干嘛的?

np.set_printoptions() 函数是 Numpy 库中的一个函数,用于设置 Numpy 数组在输出时的格式和打印选项。在本例中,该函数的作用是将 Numpy 数组的打印选项进行格式化。

precision 参数指定 Numpy 打印时保留的小数点位数。在本例中,指定小数点后保留的位数为4位。

suppress 参数控制是否关闭科学计数法。当 suppress 设置为 True 时, Numpy 数组将以固定的小数格式进行打印,而不是科学计数法。在本例中,设置 suppress=True 可以避免对数据进行科学计数法的转换。

linewidth 参数指定输出行的宽度。在本例中,设置为 200 可以保证一行中尽量多的显示数据,方便查看和分析。

因此,使用这个函数可以将符合一定格式的 NumPy 数组进行格式化的输出,使其更加易读易懂。

types.SimpleNamespace()

在这个代码片段中,`types` 是 Python 内置库中的一个模块,包含了一些用于动态创建、修改和查询 Python 类和对象的工具。在这里,我们使用 `types.SimpleNamespace()` 方法创建了一个简单的命名空间对象,在其中存储了不同字段的数据,具体有什么字段需要根据实际需求而定。

在这里,使用 `types.SimpleNamespace()` 方法相当于创建一个简单的、只有属性的类,这个类中包含了一个或多个参数。我们可以将这个类的实例作为参数传递给其他 Python 函数或对象,方便地进行数据传递和处理。在这个代码片段中,我们将 `args` 对象作为参数传递给了其他对象或函数,包括 `torch.nn.Module` 模块、`tokenizers` 模块等等。

例如,`args.MODEL_NAME` 存储了训练好的模型的名称和路径,`args.n_layer` 存储了模型的网络层数,`args.n_embd` 存储了模型的嵌入层维度。这些参数可以在程序中被引用,方便地控制程序的行为并进行相应的处理。

总之,`types.SimpleNamespace()` 是 Python 内置库中的一个工具,用于创建一个简单的、只有属性的类,它的主要作用是方便地传递和处理参数和数据。

types.SimpleNamespace() 创建的对象实际上是一个具有属性的特殊对象。它本质上是一个类,也就是说,它可以像类一样定义属性,这些属性可以用于存储不同类型的数据。

所以,在一个types.SimpleNamespace() 对象中,可以使用点(.)操作符来访问和设置不同属性,属性的名称即为点操作符前面的名称。这些属性可以包含数字、字符串、元组、列表、字典、函数等类型的数据。例如,可以按照以下方式定义:

import types

args = types.SimpleNamespace()
args.MODEL_NAME = '../models/rwkv-4-pile-430m/RWKV-4-Pile-430M-20220808-8066'
args.n_layer = 24
args.n_embd = 1024
args.batch_size = 16
args.dropout = 0.2
args.learning_rate = 1e-4
在上面的代码中,我们首先导入 types 模块,然后使用 types.SimpleNamespace() 方法创建了一个新的命名空间对象 args。接着,我们为这个对象添加了一些属性,如 MODEL_NAME、n_layer、n_embd、batch_size 等等,这些属性分别关联了值 '../models/rwkv-4-pile-430m/RWKV-4-Pile-430M-20220808-8066'、241024160.21e-4 等等。

这些属性的设置方式和访问方式都类似于 Python 对象的属性。例如,我们可以通过 args.MODEL_NAME 的方式访问 MODEL_NAME 属性,获取其对应的值 '../models/rwkv-4-pile-430m/RWKV-4-Pile-430M-20220808-8066',也可以通过 args.batch_size 获取 batch_size 属性的值。这些属性值存储在对象的内部,在程序运行期间保持不变,可以在程序中被引用和使用。

为何要用这种方式?

types.SimpleNamespace() 方式通常用于将程序中的一些常用参数和值组织在一起,并方便地将它们传递给其他的 Python 函数或对象。这种方式与其他语言中的Struct或Record等结构非常类似。

使用 types.SimpleNamespace() 的一个主要好处是在一个对象中存储多个参数和值,从而方便进行相应的处理。这些参数可以在程序的多个部分中被引用和使用,而不必通过变量、字典、元组等复杂的数据结构来管理。这种方式也使得程序的可读性和可维护性得到了提高。

此外,通过使用 types.SimpleNamespace() 对象,可以轻松地扩展和更新程序的参数和配置信息。例如,要更改某个参数的值,只需要简单地修改该对象的属性即可,而不必在程序的多个部分中查找和修改相应的变量或字典键值,从而大大提高了程序的开发效率。

总的来说,types.SimpleNamespace() 对象为程序提供了一种简单而有效的方式来管理和组织参数和值,从而在代码编写和维护方面提供了很大的便利性。

sys.argv[1]参数的意思

try:
    os.environ["CUDA_VISIBLE_DEVICES"] = sys.argv[1]
except:
    pass
这个什么意思?

这段代码片段的含义是,在程序运行时,尝试读取并设置环境变量 CUDA_VISIBLE_DEVICES 的值。如果 sys.argv[1] 存在,则将 CUDA_VISIBLE_DEVICES 的值设为 sys.argv[1];否则,不进行任何操作。其中,sys.argv[1] 表示程序运行时的第二个参数,也就是从命令行传入的第一个参数。

具体来说,这段代码使用 os.environ 对象来读取和设置环境变量,首先通过 try 捕获异常的方式来尝试获取 sys.argv[1] 的值。如果 sys.argv[1] 存在(也就是以命令行参数的形式传入了一个参数),则将 CUDA_VISIBLE_DEVICES 的值设置为 sys.argv[1] 所对应的值。如果不存在该参数或者在设置 CUDA_VISIBLE_DEVICES 的过程中发生异常,则使用 pass 语句跳过该代码块,不进行任何操作。

环境变量 CUDA_VISIBLE_DEVICES 是一个影响 TensorFlow、PyTorch 等深度学习框架在 GPU 上运行的重要环境变量。它的值可以为一个或多个 GPU 设备编号,并且以逗号分隔。例如,对于有两张 GPU 设备的系统,可以将 CUDA_VISIBLE_DEVICES 的值设为 '0,1' 来启用两张 GPU 设备来运行模型。这种方式可以控制模型在哪些 GPU 设备上运行,并避免程序占用系统所有的 GPU 资源。

总之,上述代码片段的作用是在程序运行时,以命令行参数的形式读取和设置环境变量 CUDA_VISIBLE_DEVICES 的值,并控制程序在特定的 GPU 设备上运行。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值