准备照着重打一遍代码,不过是用tensorflow.js
持续更新。
粗略理解 首先先粗略的理解一下文本生成的原理吧,虽然非常幼稚…
注意力:对应两个token之间的关系 文本生成:根据上个token预测下一个token k,q,v:k与q相对应,v作为输入,输出v2,v2又作为下一个输入… 所以理论上,一层注意力也是能用来生成的,只要参数够大… 希望没有错的太离谱。
一个js transformer实现 在github上发现了一个有趣的项目transformer-tfjs 直接在浏览器里训练模型,太牛逼了,准备照着做…
归一化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 tf.util.shuffle(data) const epsilon = tf.scalar(1e-4) // 创建一个很小的标量epsilon const inputs = data.map((d) => d.horsepower) const labels = data.map((d) => d.mpg) const inputTensor = tf.tensor2d(inputs, [inputs.length, 1]) const labelTensor = tf.tensor2d(labels, [labels.length, 1]) const sqrt_pow_mean = inputTensor .square() .mean(1) .sqrt() .expandDims(1) .add(epsilon) const label_pow_mean = inputTensor .square() .mean(1) .sqrt() .expandDims(1) .add(epsilon)
最简单的,RMS_Norm归一化。
但我不是很懂mean()这个函数,沿着第1维和第2维好像都能出现结果。。。 (划掉)
而且出现了未完全归一化的结果… 呃…大体上是完成了吧。(还是用简单点的ba…)
data 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 //import * as assert from 'assert' import { getEncoding, encodingForModel } from 'js-tiktoken' import * as fs from 'fs' import * as nj from 'numjs' //import * as os from 'os' import * as path from 'path' //import * as tf from '@tensorflow/tfjs' //import { fileURLToPath } from 'url' //const __filename = fileURLToPath(import.meta.url) //const __dirname = path.dirname(__filename) const enc = getEncoding('gpt2') //assert.strictEqual(enc.decode(enc.encode('hello world')), 'hello world') fs.readFile('./night.txt', 'utf8', (err: Error | null, content: string) => { if (err) { console.error('Error reading file:', err) return } console.log(content.length) const n = content.length const train_data = content.slice(0, Math.floor(n * 0.8)) //切片,前80% const val_data = content.slice(Math.floor(n * 0.8)) //后20% let train_ids = enc.encode(train_data) //编码 let val_ids = enc.encode(val_data) console.log('train tokens:', train_ids.length) console.log('val tokens:', val_ids.length) var train_ids_list = nj.array(train_ids, 'uint16') var val_ids_list = nj.array(val_ids, 'uint16') const trainArray = train_ids_list.tolist() // 转换为普通数组 const trainBuffer = Buffer.from(trainArray) // 转换为 Buffer 对象 const valArray = train_ids_list.tolist() const valBuffer = Buffer.from(valArray) fs.writeFileSync(path.join('./data', 'train.bin'), trainBuffer) fs.writeFileSync(path.join('./data', 'val.bin'), valBuffer) })
用numjs和js-tiktoken实现编码,模仿prepare.py保存为二进制。