动手学深度学习53 语言模型

07-09 1670阅读

动手学深度学习53 语言模型

  • 语言模型
  • 代码
  • QA

    语言模型

    核心:预测文本出现的概率

    最常见应用:做预训练模型

    动手学深度学习53 语言模型

    动手学深度学习53 语言模型

    动手学深度学习53 语言模型

    当数据序列很长怎么办?常用n-gram 。

    一元语法:马尔科夫假设tao=0 基本认为每一个字是独立的,不管前面的东西。

    二元语法:马尔科夫假设tao=1 每一个字只与前一个字相关。例如:x3只依赖于x2…………

    三元语法:马尔科夫假设tao=2 每一个字只与前两个字相关。例如:x3依赖于x2,x1,…………

    最大的好处:可以处理很长的序列。每次看的序列是固定的。

    n元语法,数据存储是指数关系 一元语法忽略掉了很多时序信息。n越大,空间复杂度越大。

    动手学深度学习53 语言模型

    n元语法:每次看n个子序列。

    动手学深度学习53 语言模型

    代码

    num_steps: 时间t–tao

    扫一遍数据,所有数据只用一次。问题:有数据可能访问不到。

    每次把前k个数据扔掉,能遍历所有可能的数据?每次切的不一样。

    X:两个长为num_steps=5的序列,Y:每个元素是对应X序列的后一个元素。

    数据采样做法:

    第一种做法:所有 min-batch采样都是独立的。

    第二种做法:两个相邻小批量的数据是相邻的。数据是连续的,可以做更长的序列出来。

    import random
    import torch
    from d2l import torch as d2l
    import re
    d2l.DATA_HUB['time_machine'] = (d2l.DATA_URL + 'timemachine.txt', '090b5e7e70c295757f55df93cb0a180b9691891a')
    def read_time_machine():
        """将时间机器数据集加载到文本行的列表中"""
        with open(d2l.download('time_machine'), 'r') as f:
            lines = f.readlines()
        return [re.sub('[^A-Za-z]+', ' ', line).strip().lower() for line in lines]
    tokens = d2l.tokenize(read_time_machine())
    # 因为每个文本行不一定是一个句子或一个段落,因此我们把所有文本行拼接到一起
    corpus = [token for line in tokens for token in line]
    vocab = d2l.Vocab(corpus)
    # print(vocab.token_freqs[:10])
    freqs = [freq for token, freq in vocab.token_freqs]
    d2l.plot(freqs, xlabel='token: x', ylabel='frequency: n(x)',
             xscale='log', yscale='log')
    bigram_tokens = [pair for pair in zip(corpus[:-1], corpus[1:])]
    # print(bigram_tokens)
    # bigram_vocab = d2l.Vocab(bigram_tokens)
    # print(bigram_vocab.token_freqs[:10])
    trigram_tokens = [triple for triple in zip(corpus[:-2], corpus[1:-1], corpus[2:])]
    trigram_vocab = d2l.Vocab(trigram_tokens)
    print(trigram_vocab.token_freqs[:10])
    bigram_freqs = [freq for token, freq in bigram_vocab.token_freqs]
    trigram_freqs = [freq for token, freq in trigram_vocab.token_freqs]
    d2l.plot([freqs, bigram_freqs, trigram_freqs], xlabel='token: x',
             ylabel='frequency: n(x)', xscale='log', yscale='log',
             legend=['unigram', 'bigram', 'trigram'])
    def seq_data_iter_random(corpus, batch_size, num_steps):
        """使用随机抽样生成一个小批量子序列"""
        # 从随机偏移量开始对序列进行分区,随机范围包括num_steps-1
        corpus = corpus[random.randint(0, num_steps - 1):]
        # 减去1,是因为我们需要考虑标签
        num_subseqs = (len(corpus) - 1) // num_steps
        # 长度为num_steps的子序列的起始索引
        initial_indices = list(range(0, num_subseqs * num_steps, num_steps))
        # 在随机抽样的迭代过程中,
        # 来自两个相邻的、随机的、小批量中的子序列不一定在原始序列上相邻
        random.shuffle(initial_indices)
        def data(pos):
            # 返回从pos位置开始的长度为num_steps的序列
            return corpus[pos: pos + num_steps]
        num_batches = num_subseqs // batch_size
        for i in range(0, batch_size * num_batches, batch_size):
            # 在这里,initial_indices包含子序列的随机起始索引
            initial_indices_per_batch = initial_indices[i: i + batch_size]
            X = [data(j) for j in initial_indices_per_batch]
            Y = [data(j + 1) for j in initial_indices_per_batch]
            yield torch.tensor(X), torch.tensor(Y)
    my_seq = list(range(35))
    for X, Y in seq_data_iter_random(my_seq, batch_size=2, num_steps=5):
        print('X: ', X, '\nY:', Y)
    def seq_data_iter_sequential(corpus, batch_size, num_steps):
        """使用顺序分区生成一个小批量子序列"""
        # 从随机偏移量开始划分序列
        offset = random.randint(0, num_steps)
        num_tokens = ((len(corpus) - offset - 1) // batch_size) * batch_size
        Xs = torch.tensor(corpus[offset: offset + num_tokens])
        Ys = torch.tensor(corpus[offset + 1: offset + 1 + num_tokens])
        Xs, Ys = Xs.reshape(batch_size, -1), Ys.reshape(batch_size, -1)
        num_batches = Xs.shape[1] // num_steps
        for i in range(0, num_steps * num_batches, num_steps):
            X = Xs[:, i: i + num_steps]
            Y = Ys[:, i: i + num_steps]
            yield X, Y
    for X, Y in seq_data_iter_sequential(my_seq, batch_size=2, num_steps=5):
        print('X: ', X, '\nY:', Y)
    class SeqDataLoader:
        """加载序列数据的迭代器"""
        def __init__(self, batch_size, num_steps, use_random_iter, max_tokens):
            if use_random_iter:
                self.data_iter_fn = d2l.seq_data_iter_random
            else:
                self.data_iter_fn = d2l.seq_data_iter_sequential
            self.corpus, self.vocab = d2l.load_corpus_time_machine(max_tokens)
            self.batch_size, self.num_steps = batch_size, num_steps
        def __iter__(self):
            return self.data_iter_fn(self.corpus, self.batch_size, self.num_steps)
    def load_data_time_machine(batch_size, num_steps, use_random_iter=False, max_tokens=10000):
        """返回时光机器数据集的迭代器和词表"""
        data_iter = SeqDataLoader(
            batch_size, num_steps, use_random_iter, max_tokens)
        return data_iter, data_iter.vocab
    
    Downloading ../data/timemachine.txt from http://d2l-data.s3-accelerate.amazonaws.com/timemachine.txt...
    [('the', 2261), ('i', 1267), ('and', 1245), ('of', 1155), ('a', 816), ('to', 695), ('was', 552), ('in', 541), ('that', 443), ('my', 440)]
    --------
    

    排序报错待解决。

    动手学深度学习53 语言模型

    不调用d2l的Vocab,按照前面的代码重新写一份。

    import random
    import torch
    from d2l import torch as d2l
    import re
    import collections
    d2l.DATA_HUB['time_machine'] = (d2l.DATA_URL + 'timemachine.txt', '090b5e7e70c295757f55df93cb0a180b9691891a')
    def read_time_machine():
        """将时间机器数据集加载到文本行的列表中"""
        with open(d2l.download('time_machine'), 'r') as f:
            lines = f.readlines()
        return [re.sub('[^A-Za-z]+', ' ', line).strip().lower() for line in lines]
    tokens = d2l.tokenize(read_time_machine())
    class Vocab:
        """
        文本词表
        min_freq:  出现少于多少次 就不管他 扔掉
        reserved_tokens: 标记句子开始或者结束的token
        """
        def __init__(self, tokens=None, min_freq=0, reserved_tokens=None):
            if tokens is None:
                tokens = []
            if reserved_tokens is None:
                reserved_tokens = []
            # 按出现频率排序  对token排序
            counter = count_corpus(tokens)
            self._token_freqs = sorted(counter.items(), key=lambda x: x[1], reverse=True)
            # 未知词元的索引为0  unk 未知token  NLP 常见的 token的一个表示方法
            self.idx_to_token = [''] + reserved_tokens
            self.token_to_idx = {token: idx for idx, token in enumerate(self.idx_to_token)}
            # 把词数据全部count一遍,扔掉出现次数比较少的词
            for token, freq in self._token_freqs:
                if freq  
    
    [(('the', 'time', 'traveller'), 59), (('the', 'time', 'machine'), 30), (('the', 'medical', 'man'), 24), (('it', 'seemed', 'to'), 16), (('it', 'was', 'a'), 15), (('here', 'and', 'there'), 15), (('seemed', 'to', 'me'), 14), (('i', 'did', 'not'), 14), (('i', 'saw', 'the'), 13), (('i', 'began', 'to'), 13)]
    X:  tensor([[17, 18, 19, 20, 21],
            [27, 28, 29, 30, 31]]) 
    Y: tensor([[18, 19, 20, 21, 22],
            [28, 29, 30, 31, 32]])
    X:  tensor([[ 2,  3,  4,  5,  6],
            [22, 23, 24, 25, 26]]) 
    Y: tensor([[ 3,  4,  5,  6,  7],
            [23, 24, 25, 26, 27]])
    X:  tensor([[12, 13, 14, 15, 16],
            [ 7,  8,  9, 10, 11]]) 
    Y: tensor([[13, 14, 15, 16, 17],
            [ 8,  9, 10, 11, 12]])
    X:  tensor([[ 1,  2,  3,  4,  5],
            [17, 18, 19, 20, 21]]) 
    Y: tensor([[ 2,  3,  4,  5,  6],
            [18, 19, 20, 21, 22]])
    X:  tensor([[ 6,  7,  8,  9, 10],
            [22, 23, 24, 25, 26]]) 
    Y: tensor([[ 7,  8,  9, 10, 11],
            [23, 24, 25, 26, 27]])
    X:  tensor([[11, 12, 13, 14, 15],
            [27, 28, 29, 30, 31]]) 
    Y: tensor([[12, 13, 14, 15, 16],
            [28, 29, 30, 31, 32]])
    

    动手学深度学习53 语言模型

    QA

    动手学深度学习53 语言模型

    1 数字会做embedding。

    2 连续单词是有时序的,有先后顺序,不能打乱。

    3 不存count为0的词,空间复杂度还是n–文本长度。

    4 过滤掉长尾,不是长尾效应–电商名词。

    动手学深度学习53 语言模型

    5 n-gram 中文gram-字,n个字。也可用词。

    6 T 序列的长度,每次看多长的序列。

    7 把一对词做成一个token。广告中可以把特定产品映射成特定token。

    8 T 16 32 不错选择,可以先试试。256 512长度都有。T根据模型复杂度考虑。

VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]