Public
Edited
Apr 28, 2023
2 forks
Importers
4 stars
Insert cell
Insert cell
encoder = FileAttachment("encoder.json").json()
Insert cell
bpe_file = FileAttachment("vocab.bpe.txt").text()
Insert cell
range = (x, y) => {
const res = Array.from(Array(y).keys()).slice(x)
return res
}
Insert cell
ord = x => {
return x.charCodeAt(0)
}

Insert cell
chr = x => {
return String.fromCharCode(x)
}

Insert cell
textEncoder = new TextEncoder("utf-8")

Insert cell
encodeStr = str => {
return Array.from(textEncoder.encode(str)).map(x => x.toString())
}

Insert cell
textDecoder = new TextDecoder("utf-8")

Insert cell
decodeStr = arr => {
return textDecoder.decode(new Uint8Array(arr));
}

Insert cell
dictZip = (x, y) => {
const result = {}
x.map((_, i) => { result[x[i]] = y[i] })
return result
}

Insert cell
function bytes_to_unicode() {
const bs = range(ord('!'), ord('~') + 1).concat(range(ord('¡'), ord('¬') + 1), range(ord('®'), ord('ÿ') + 1))

let cs = bs.slice()
let n = 0
for (let b = 0; b < 2 ** 8; b++) {
if (!bs.includes(b)) {
bs.push(b)
cs.push(2 ** 8 + n)
n = n + 1
}
}

cs = cs.map(x => chr(x))

const result = {}
bs.map((_, i) => { result[bs[i]] = cs[i] })
return result
}

Insert cell
function get_pairs(word) {
const pairs = new Set()
let prev_char = word[0]
for (let i = 1; i < word.length; i++) {
const char = word[i]
pairs.add([prev_char, char])
prev_char = char
}
return pairs
}

Insert cell
pat = /'s|'t|'re|'ve|'m|'ll|'d| ?\p{L}+| ?\p{N}+| ?[^\s\p{L}\p{N}]+|\s+(?!\S)|\s+/gu

Insert cell
decoder = {
let decoder = {};
Object.keys(encoder).map((x) => {
decoder[encoder[x]] = x;
});
return decoder;
}
Insert cell
lines = bpe_file.split('\n')
Insert cell

// bpe_merges = [tuple(merge_str.split()) for merge_str in bpe_data.split("\n")[1:-1]]
bpe_merges = lines.slice(1, lines.length - 1).map(x => {
return x.split(/(\s+)/).filter(function(e) { return e.trim().length > 0 })
})

Insert cell
byte_encoder = bytes_to_unicode()

Insert cell
byte_decoder = {
let byte_decoder = {};
Object.keys(byte_encoder).map((x) => {
byte_decoder[byte_encoder[x]] = x;
});
return byte_decoder;
}
Insert cell
bpe_ranks = dictZip(bpe_merges, range(0, bpe_merges.length))

Insert cell
cache = new Map()
Insert cell
function bpe(token) {
if (cache.has(token)) {
return cache.get(token)
}``

let word = token.split('')

let pairs = get_pairs(word)

if (!pairs) {
return token
}

while (true) {
const minPairs = {}
Array.from(pairs).map(pair => {
const rank = bpe_ranks[pair]
minPairs[(isNaN(rank) ? 10e10 : rank)] = pair
})
const bigram = minPairs[Math.min(...Object.keys(minPairs).map(x => {
return parseInt(x)
}
))]

if (!(bigram in bpe_ranks)) {
break
}

const first = bigram[0]
const second = bigram[1]
let new_word = []
let i = 0

while (i < word.length) {
const j = word.indexOf(first, i)
if (j === -1) {
new_word = new_word.concat(word.slice(i))
break
}
new_word = new_word.concat(word.slice(i, j))
i = j

if (word[i] === first && i < word.length - 1 && word[i + 1] === second) {
new_word.push(first + second)
i = i + 2
} else {
new_word.push(word[i])
i = i + 1
}
}

word = new_word
if (word.length === 1) {
break
} else {
pairs = get_pairs(word)
}
}

word = word.join(' ')
cache.set(token, word)

return word
}

Insert cell
function encode(text) {
let bpe_tokens = []
const matches = Array.from(text.matchAll(pat)).map(x => x[0])
for (let token of matches) {
token = encodeStr(token).map(x => {
return byte_encoder[x]
}).join('')
const new_tokens = bpe(token).split(' ').map(x => encoder[x])
bpe_tokens = bpe_tokens.concat(new_tokens)
}
return bpe_tokens
}

Insert cell
function decode(tokens) {
let text = tokens.map(x => decoder[x]).join('')
text = decodeStr(text.split('').map(x => byte_decoder[x]))
return text
}

Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more