神经概率语言模型

news2024/11/16 12:03:51

本文主要参考《A Neural Probabilistic Language Model》这是一篇很重要的语言模型论文,发表于2003年。主要贡献如下:

  1. 提出了一种基于神经网络的语言模型,是较早将神经网络应用于语言模型领域的工作之一,具有里程碑意义。
  2. 采用神经网络模型预测下一个单词的概率分布,已经成为神经网络语言模型训练的标准方法之一。
  3. 在论文中,作者训练了一个前馈神经网络,同时学习词的特征表示和词序列的概率函数,并取得了比 trigram 语言模型更好的单词预测效果,这证明了神经网络语言模型的有效性。
  4. 论文提出的思想与模型为后续的许多神经网络语言模型研究奠定了基础。

模型结构

在这里插入图片描述

模型的目标是学到一个概率函数,根据上下文预测下一个词的概率分布:
在这里插入图片描述

import os
import time
import pandas as pd
from dataclasses import dataclass

import torch
import torch.nn as nn
from torch.nn import functional as F
from torch.utils.data import Dataset
from torch.utils.data.dataloader import DataLoader
from torch.utils.tensorboard import SummaryWriter

加载数据

数据集来10+中文外卖评价数据集:

data = pd.read_csv('./dataset/waimai_10k.csv')
data.dropna(subset='review',inplace=True)
data['review_length'] = data.review.apply(lambda x:len(x))
data.sample(5)

labelreviewreview_length
45450从说马上送餐,到收到餐,时间特别久,给的送餐电话打不通!28
98550韩餐做得像川菜,牛肉汤油得不能喝,量也比实体少很多,送餐时间久得太久了,1个半小时,唉。44
56640太糟了。等了两个小时,牛肉我吃的快吐了,再也不可能第二次28
23231很好吃,就是粥撒了点,等了一个多小时18
81170送餐员给我打电话比较粗鲁12

统计信息:

data = data[data.review_length <= 50] 
words = data.review.tolist()
chars = sorted(list(set(''.join(words))))    
max_word_length = max(len(w) for w in words)

print(f"number of examples: {len(words)}")
print(f"max word length: {max_word_length}")
print(f"size of vocabulary: {len(chars)}")

number of examples: 10796
max word length: 50
size of vocabulary: 2272

划分训练/测试集

test_set_size = min(1000, int(len(words) * 0.1)) 
rp = torch.randperm(len(words)).tolist()
train_words = [words[i] for i in rp[:-test_set_size]]
test_words = [words[i] for i in rp[-test_set_size:]]
print(f"split up the dataset into {len(train_words)} training examples and {len(test_words)} test examples")

split up the dataset into 9796 training examples and 1000 test examples

构造字符数据集[tensor]

  • < BLANK> : 0
  • token seqs : [1, 2, 3, 4, 5, 6]
  • block_size : 3,上下文长度
  • x : [[0, 0, 0],[0, 0, 1],[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6]
  • y : [1, 2, 3, 4, 5, 6, 0]
`class CharDataset(Dataset):

    def __init__(self, words, chars, max_word_length, block_size=1):
        self.words = words
        self.chars = chars
        self.max_word_length = max_word_length
        self.block_size = block_size
        
        self.char2i = {ch:i+1 for i,ch in enumerate(chars)}
        self.i2char = {i:s for s,i in self.char2i.items()}    

    def __len__(self):
        return len(self.words)

    def contains(self, word):
        return word in self.words

    def get_vocab_size(self):
        return len(self.chars) + 1      

    def get_output_length(self):
        return self.max_word_length + 1

    def encode(self, word):
        
        ix = torch.tensor([self.char2i[w] for w in word], dtype=torch.long)
        return ix

    def decode(self, ix):
        
        word = ''.join(self.i2char[i] for i in ix)
        return word

    def __getitem__(self, idx):
        word = self.words[idx]
        ix = self.encode(word)
        x = torch.zeros(self.max_word_length + self.block_size, dtype=torch.long)
        y = torch.zeros(self.max_word_length, dtype=torch.long)
        x[self.block_size:len(ix)+self.block_size] = ix
        y[:len(ix)] = ix
        
        y[len(ix)+1:] = -1 
        if self.block_size > 1:
            xs = []
            for i in range(x.shape[0]-self.block_size):
                xs.append(x[i:i+self.block_size].unsqueeze(0))
            return torch.cat(xs), y
        else:
            return x, y` 


数据加载器[DataLoader]

class InfiniteDataLoader:
    
    def __init__(self, dataset, **kwargs):
        train_sampler = torch.utils.data.RandomSampler(dataset, replacement=True, num_samples=int(1e10))
        self.train_loader = DataLoader(dataset, sampler=train_sampler, **kwargs)
        self.data_iter = iter(self.train_loader)

    def next(self):
        try:
            batch = next(self.data_iter)
        except StopIteration: 
            self.data_iter = iter(self.train_loader)
            batch = next(self.data_iter)
        return batch

构建模型

context_tokens → \to → embedding → \to → concate feature vector → \to → hidden layer → \to → output layer

@dataclass
class ModelConfig:
    block_size: int = None 
    vocab_size: int = None 
    n_embed : int = None
    n_hidden: int = None

`class MLP(nn.Module):
    """
    takes the previous block_size tokens, encodes them with a lookup table,
    concatenates the vectors and predicts the next token with an MLP.

    Reference:
    Bengio et al. 2003 https://www.jmlr.org/papers/volume3/bengio03a/bengio03a.pdf
    """

    def __init__(self, config):
        super().__init__()
        self.block_size = config.block_size
        self.vocab_size = config.vocab_size
        self.wte = nn.Embedding(config.vocab_size + 1, config.n_embed) 
        
        self.mlp = nn.Sequential(
            nn.Linear(self.block_size * config.n_embed, config.n_hidden),
            nn.Tanh(),
            nn.Linear(config.n_hidden, self.vocab_size)
        )

    def get_block_size(self):
        return self.block_size

    def forward(self, idx, targets=None):

        
        embs = []
        for k in range(self.block_size):
            tok_emb = self.wte(idx[:,:,k]) 
            
            
            embs.append(tok_emb)

        
        x = torch.cat(embs, -1) 
        logits = self.mlp(x)

        
        loss = None
        if targets is not None:
            loss = F.cross_entropy(logits.view(-1, logits.size(-1)), targets.view(-1), ignore_index=-1)

        return logits, loss` 

![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)

*   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


@torch.inference_mode()
def evaluate(model, dataset, batch_size=10, max_batches=None):
    model.eval()
    loader = DataLoader(dataset, shuffle=True, batch_size=batch_size, num_workers=0)
    losses = []
    for i, batch in enumerate(loader):
        batch = [t.to('cuda') for t in batch]
        X, Y = batch
        logits, loss = model(X, Y)
        losses.append(loss.item())
        if max_batches is not None and i >= max_batches:
            break
    mean_loss = torch.tensor(losses).mean().item()
    model.train() 
    return mean_loss

训练模型

环境初始化

torch.manual_seed(seed=12345)
torch.cuda.manual_seed_all(seed=12345)

work_dir = "./Mlp_log"
os.makedirs(work_dir, exist_ok=True)
writer = SummaryWriter(log_dir=work_dir)

config = ModelConfig(vocab_size=train_dataset.get_vocab_size(),
                     block_size=7,
                     n_embed=64,
                     n_hidden=128)

格式化数据

train_dataset = CharDataset(train_words, chars, max_word_length, block_size=config.block_size)
test_dataset = CharDataset(test_words, chars, max_word_length, block_size=config.block_size)

train_dataset[0][0].shape, train_dataset[0][1].shape

(torch.Size([50, 7]), torch.Size([50]))

初始化模型

model = MLP(config)

model.to('cuda')

MLP(
  (wte): Embedding(2274, 64)
  (mlp): Sequential(
    (0): Linear(in_features=448, out_features=128, bias=True)
    (1): Tanh()
    (2): Linear(in_features=128, out_features=2273, bias=True)
  )
)

 `optimizer = torch.optim.AdamW(model.parameters(), lr=5e-4, weight_decay=0.01, betas=(0.9, 0.99), eps=1e-8)

batch_loader = InfiniteDataLoader(train_dataset, batch_size=64, pin_memory=True, num_workers=4)

best_loss = None
step = 0
train_losses, test_losses = [],[]
while True:

    t0 = time.time()

    
    batch = batch_loader.next()
    batch = [t.to('cuda') for t in batch]
    X, Y = batch
    
    logits, loss = model(X, Y)

    
    model.zero_grad(set_to_none=True)
    loss.backward()
    optimizer.step()
    
    torch.cuda.synchronize()
    t1 = time.time()

    
    if step % 1000 == 0:
        print(f"step {step} | loss {loss.item():.4f} | step time {(t1-t0)*1000:.2f}ms")

    
    if step > 0 and step % 100 == 0:
        train_loss = evaluate(model, train_dataset, batch_size=100, max_batches=10)
        test_loss  = evaluate(model, test_dataset,  batch_size=100, max_batches=10)
        train_losses.append(train_loss)
        test_losses.append(test_loss)
        
        if best_loss is None or test_loss < best_loss:
            out_path = os.path.join(work_dir, "model.pt")
            print(f"test loss {test_loss} is the best so far, saving model to {out_path}")
            torch.save(model.state_dict(), out_path)
            best_loss = test_loss

    step += 1
    
    if step > 15100:
        break` 

![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)

*   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


`step 0 | loss 7.7551 | step time 13.09ms
test loss 5.533482551574707 is the best so far, saving model to ./Mlp_log/model.pt
test loss 5.163593292236328 is the best so far, saving model to ./Mlp_log/model.pt
test loss 4.864410877227783 is the best so far, saving model to ./Mlp_log/model.pt
test loss 4.6439409255981445 is the best so far, saving model to ./Mlp_log/model.pt
test loss 4.482759475708008 is the best so far, saving model to ./Mlp_log/model.pt
test loss 4.350367069244385 is the best so far, saving model to ./Mlp_log/model.pt
test loss 4.250306129455566 is the best so far, saving model to ./Mlp_log/model.pt
test loss 4.16674280166626 is the best so far, saving model to ./Mlp_log/model.pt
test loss 4.0940842628479 is the best so far, saving model to ./Mlp_log/model.pt
.......................
step 6000 | loss 2.8038 | step time 6.44ms
step 7000 | loss 2.7815 | step time 11.88ms
step 8000 | loss 2.6511 | step time 5.93ms
step 9000 | loss 2.5898 | step time 5.00ms
step 10000 | loss 2.6600 | step time 6.12ms
step 11000 | loss 2.4634 | step time 5.94ms
step 12000 | loss 2.5373 | step time 7.75ms
step 13000 | loss 2.4050 | step time 6.29ms
step 14000 | loss 2.5434 | step time 7.77ms
step 15000 | loss 2.4084 | step time 7.10ms` 

![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)

*   1
*   2
*   3
*   4
*   5
*   6
*   7
*   8
*   9
*   10
*   11
*   12
*   13
*   14
*   15
*   16
*   17
*   18
*   19
*   20
*   21


测试:评论生成器

`@torch.no_grad()
def generate(model, idx, max_new_tokens, temperature=1.0, do_sample=False, top_k=None):
    block_size = model.get_block_size()
    for _ in range(max_new_tokens):
        
        idx_cond = idx if idx.size(2) <= block_size else idx[:, :,-block_size:]
        
        logits, _ = model(idx_cond)
        
        logits = logits[:,-1,:] / temperature
        
        if top_k is not None:
            v, _ = torch.topk(logits, top_k)
            logits[logits < v[:, [-1]]] = -float('Inf')
        
        probs = F.softmax(logits, dim=-1)
        
        if do_sample:
            idx_next = torch.multinomial(probs, num_samples=1)
        else:
            _, idx_next = torch.topk(probs, k=1, dim=-1)
         
        
        idx = torch.cat((idx, idx_next.unsqueeze(1)), dim=-1)
    return idx` 

![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)

*   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


def print_samples(num=13, block_size=3, top_k = None):
    
    X_init = torch.zeros((num, 1, block_size), dtype=torch.long).to('cuda')
    steps = train_dataset.get_output_length() - 1 
    X_samp = generate(model, X_init, steps, top_k=top_k, do_sample=True).to('cuda')
    new_samples = []
    for i in range(X_samp.size(0)):
        
        row = X_samp[i, :, block_size:].tolist()[0] 
        
        crop_index = row.index(0) if 0 in row else len(row)
        row = row[:crop_index]
        word_samp = train_dataset.decode(row)
        new_samples.append(word_samp)
    return new_samples

不同上下文长度的生成效果

block_size=3

'送餐大叔叔风怎么第一次点的1迷就没有需减改进',
 '送餐很快!菜品一般,送到都等到了都很在店里吃不出肥肉,第我地佩也不好意思了。第一次最爱付了凉面味道不',
 '很不好进吧。。。。。这点一次都是卫生骑题!调菜油腻,真不太满意!',
 '11点送到指定地形,不知道他由、奶茶类应盒子,幸好咸。。。',
 '味道一般小份速度太难吃了。',
 '快递小哥很贴心也吃不习惯。',
 '非常慢。',
 '为什么,4个盒子,反正订的有点干,送餐速度把面洒了不超值!很快!!!!!少菜分量不够吃了!味道很少餐',
 '骑士剁疼倒还没给糖的',
 '怎么吃,正好吃,便宜'

block_size=5

['味道不错,送餐大哥工,餐大哥应不错。',
 '配送很不满意',
 '土豆炒几次,一小时才没吃,幸太多',
 '粥不好吃,没有病311小菜送到,吃完太差了',
 '太咸了,很感谢到,对这次送餐员辛苦,服务很不好',
 '真的很香菇沙,卷哪丝口气,无语了!',
 '菜不怎么夹生若梦粥,小伙n丁也没有收到餐。。。',
 '一点不脆1个多小时才送到。等了那个小时。',
 '就是送的太慢。。。。一京酱肉丝卷太不点了了,大份小太爱,真心不难吃,最后我的平时面没有听说什么呢,就',
 '慢能再提前的好,牛肉好吃而且感觉适合更能事,味道倒卷,送的也很快!']

block_size = 7

['味道还不错,但是酱也没给,一点餐不差',
 '都是肥肉,有差劲儿大的,也太给了,那么好给这么多~后超难吃~',
 '少了一个半小时才吃到了',
 '商务还菜很好的',
 '慢慢了~以后!点他家极支付30元分钟,送过用了呢。',
 '就是没送到就给送王一袋儿食吃起来掉了,有点辣,这油还这抄套!',
 '很好吃,就是送餐师傅不错',
 '包装好的牛肉卷糊弄错酱,重面太少了,肉不新鲜就吃了',
 '味道不错,送得太慢...',
 '非常好非常快递小哥,态度极差,一点也好,菜和粥洒了一袋软,以先订过哈哈哈哈']

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/817297.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring框架 —— 控制反转IOC

前言 在前一篇文章中荔枝已经初步了解了Spring并通过一个入门案例了解了Spring的基本操作&#xff0c;接下来荔枝就要梳理Spring中的最为重要的知识点之一——IoC控制反转&#xff0c;控制反转和属性注入均是基于Java中的反射机制来实现的。所以学习这个知识点之前必须要学习Ja…

【无标题】使用Debate Dynamics在知识图谱上进行推理(2020)7.31

使用Debate Dynamics在知识图谱上进行推理 摘要介绍背景与相关工作我们的方法 摘要 我们提出了一种新的基于 Debate Dynamics 的知识图谱自动推理方法。 其主要思想是将三重分类任务定义为两个强化学习主体之间的辩论游戏&#xff0c;这两个主体提取论点&#xff08;知识图中…

嵌入式基础知识-存储器

本篇介绍计算机存储硬件的一些基础知识&#xff0c;在嵌入式开发中&#xff0c;也同样适用。 1 计算机存储结构 存储器是计算机中的重要部件&#xff0c;理想的存储器应该是执行快&#xff0c;容量足&#xff0c;价格便宜等。但实际上&#xff0c;目前无法同时满足这些目标&a…

Vue2 第十节 内置指令和自定义指令

1.之前学过的指令 2. 内置指令 3. 自定义指令 一.之前学过的指令 指令名用法v-bind单项绑定解析表达式&#xff0c;可以简写为:xxxv-model双向绑定v-for遍历数组/对象/字符串v-on 绑定监听事件&#xff0c;可以简写为v-if条件渲染&#xff08;动态控制节点是否存在&#xf…

算法通关村第二关——反转链表白银挑战笔记

文章目录 1.链表指定区间翻转2.两两交换链表中的节点 1.链表指定区间翻转 LeetCode 92.反转链表 解法一&#xff1a;头插法。利用虚拟节点进行反转&#xff0c;因为头节点有可能发生变化&#xff0c;比如 left1 那么需要 dummyNode.next 记录头结点&#xff0c;使用虚拟头节点…

计算机网络(2) --- 网络套接字

计算机网络&#xff08;1&#xff09; --- 网络介绍_哈里沃克的博客-CSDN博客https://blog.csdn.net/m0_63488627/article/details/131967378?spm1001.2014.3001.5501 目录 1.端口号 2.TCP与UDP协议 1.TCP协议介绍 1.TCP协议 2.UDP协议 3.理解 2.网络字节序 发送逻辑…

学会这13个问题,轻松拿捏Java容器面试

java 容器都有哪些&#xff1f; 常用容器的图录&#xff1a; Collection 和 Collections 有什么区别&#xff1f; java.util.Collection 是一个集合接口&#xff08;集合类的一个顶级接口&#xff09;。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java …

29.利用fminbnd 求解 最大容积问题(matlab程序)

1.简述 用于求某个给定函数的最小值点。 使用方法是&#xff1a; xfminbnd(func,x1,x2) func是函数句柄&#xff0c;然后x1和x2就是函数的区间&#xff0c;得到的结果就是使func取最小值的x值 当然也可以使用[x,fv]fminbnd(func,x1,x2)的方式&#xff0c;这个时候fv就是函数…

项目实战 — 消息队列(2){数据库操作}

目录 一、SQLite &#x1f345; 1、添加依赖 &#x1f345; 2、修改配置文件后缀&#xff08;properties -> yaml&#xff09; &#x1f345; 3、编写配置文件 二、建立数据表 三、添加插入和删除方法 四、整合数据库操作&#xff08;DataBaseManger类&#xff09; &a…

螺旋矩阵(JS)

螺旋矩阵 题目 给你一个正整数 n &#xff0c;生成一个包含 1 到 n2 所有元素&#xff0c;且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;[[1,2,3],[8,9,4],[7,6,5]]示例 2&#xff1a; 输入&#xff…

【自动化运维】编写LNMP分布式剧本

目录 一 playbook编写LNMP1.1环境设置1.2编写Nginx剧本1.3、编写Mysql剧本1.4准备PHP剧本 一 playbook编写LNMP 1.1环境设置 ip服务192.168.243.100ansible192.168.243.102nginx192.168.243.103PHP192.168.243.104mysql 1.2编写Nginx剧本 1.编写Nginx源 mkdir -p /etc/ans…

Linux之 centos、Ubuntu 安装常见程序

CentOS 安装 MySql 注意 需要有root权限 安装5.7版本 – 由于MySql并不在CentOS的官方仓库中&#xff0c;所以需要通过rmp命令&#xff1a; 导入MySQL仓库密钥 1、配置MySQL的yum仓库 配置yum仓库 更新密钥 rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022 安装…

【AHB-Lite总线】hreadyin和hreadyout的区别

AHB-Lite总线协议请查看 AHB-Lite总线协议 首先看下hreadyin和hreadyout在系统中的位置 从图中可以看到&#xff0c;每个AHB从设备都有一个HREADY输出信号&#xff08;hreadyout&#xff09;&#xff0c;它连接到多路复用器。该多路复用器的输出是AHB主机看到的全局hready信…

看完ChatGPT的两个比喻,更加确信为什么人人都应该去使用它

​ ChatGPT就像火 丹尼刘是悉尼大学教育创新临时学术总监。去年年底&#xff0c;在一次工作组会议上&#xff0c;他第一次向同事展示了ChatGPT。同事说出了让刘大吃一惊的话。 “他说&#xff0c;‘哇&#xff0c;这就像火一样&#xff0c;’”刘回忆道。 刘一开始觉得这个…

《JavaSE-第二十二章》之线程安全问题

前言 在你立足处深挖下去,就会有泉水涌出!别管蒙昧者们叫嚷:“下边永远是地狱!” 博客主页&#xff1a;KC老衲爱尼姑的博客主页 博主的github&#xff0c;平常所写代码皆在于此 共勉&#xff1a;talk is cheap, show me the code 作者是爪哇岛的新手&#xff0c;水平很有限&…

安卓相关内容

adb环境变量设置完之后&#xff0c;要重启一次“终端”窗口。 adb安装apk到手机 Android开发&#xff1a;用adb命令安装apk到手机-腾讯云开发者社区-腾讯云 This adb servers $ADB_VENDOR_KEYS is not set frida 出现问题&#xff1a;unable to start: address already in …

软件测试面试题——接口自动化测试怎么做?

面试过程中&#xff0c;也问了该问题&#xff0c;以下是自己的回答&#xff1a; 接口自动化测试&#xff0c;之前做过&#xff0c;第一个版本是用jmeter 做的&#xff0c;1 主要是将P0级别的功能接口梳理出来&#xff0c;根据业务流抓包获取相关接口&#xff0c;并在jmeter中跑…

ES开启身份认证

文章目录 X-Pack简介之前的安全方案ES开启认证ES服务升级https协议开启集群节点之间的证书认证 X-Pack简介 X-Pack是Elastic Stack扩展功能&#xff0c;提供安全性&#xff0c;警报&#xff0c;监视&#xff0c;报告&#xff0c;机器学习和许多其他功能。 X-Pack的发展演变&am…

聊聊拉长LLaMA的一些经验

Sequence Length是指LLM能够处理的文本的最大长度&#xff0c;越长&#xff0c;自然越有优势&#xff1a; 更强的记忆性。更多轮的历史对话被拼接到对话中&#xff0c;减少出现遗忘现象 长文本场景下体验更佳。比如文档问答、小说续写等 当今开源LLM中的当红炸子鸡——LLaMA…

开放麒麟1.0发布一个月后,到底怎么样?另一款操作系统引发热议

具有里程碑意义 7月5日&#xff0c;国产首个开源桌面操作系统“开放麒麟1.0”正式发布。 标志着我国拥有了操作系统组件自主选型、操作系统独立构建的能力&#xff0c;填补了我国在这一领域的空白。 举国欢庆&#xff0c;算的上是里程碑意义了&#xff01; 发布后用着如何&a…