0

0

【提前过年吧】来对对联吧,基于transformer

P粉084495128

P粉084495128

发布时间:2025-07-16 14:29:35

|

889人浏览过

|

来源于php中文网

原创

对联又称对偶、门对、春贴、春联、对子、桃符、楹联(因古时多悬挂于楼堂宅殿的楹柱而得名)等,是一种对偶文学,一说起源于桃符。另一来源是春贴,古人在立春日多贴“宜春”二字,后渐渐发展为春联,表达了中国劳动人民一种辟邪除灾、迎祥纳福的美好愿望。对联是写在纸、布上或刻在竹子、木头、柱子上的对偶语句。言简意深,对仗工整,平仄协调,字数相同,结构相同,是中文语言的独特的艺术形式。

☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜

【提前过年吧】来对对联吧,基于transformer - php中文网

1.项目背景

对联又称对偶、门对、春贴、春联、对子、桃符、楹联(因古时多悬挂于楼堂宅殿的楹柱而得名)等,是一种对偶文学,一说起源于桃符。另一来源是春贴,古人在立春日多贴“宜春”二字,后渐渐发展为春联,表达了中国劳动人民一种辟邪除灾、迎祥纳福的美好愿望。对联是写在纸、布上或刻在竹子、木头、柱子上的对偶语句。言简意深,对仗工整,平仄协调,字数相同,结构相同,是中文语言的独特的艺术形式。

该项目基于transformer模型训练了一个自动对下联模型,也就是你给出上联,该模型可以对出下联。实际效果如下:

上联:  <start>腾飞上铁,锐意改革谋发展,勇当qian里马<end>真实的下联: <start>和谐南供,安全送电保畅通,争做领头羊<end>预测的下联: <start> 发 展 开 花 , 和 谐 发 展 创 和 谐 , 更 上 一 层 楼 <end>上联:  <start>风弦未拨心先乱<end>真实的下联: <start>夜幕已沉梦更闲<end>预测的下联: <start> 月 影 犹 怜 梦 已 空 <end>

下面来看下实现该模型的全流程吧qwq

2.环境设置

我们需要的依赖主要有:

  • paddle系列:组装数据集、搭建模型框架
  • numpy: NumPy (Numerical Python) 是 Python 语言的一个扩展程序库,支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库
  • functools:主要使用partial,用于数据集的构建工作
  • random: 随机函数库
  • matplotlib.pyplot:画图使用
  • tqdm: 绘制进度条
In [1]
import paddleimport paddlenlpimport tqdmimport numpy as npimport stringimport randomimport matplotlib.pyplot as pltfrom functools import partial

3.数据集

我们使用的数据集是基于开源的对联数据集couplet-clean-dataset处理后的对联,并删掉了其中14条中文编码错误的对联,共744915条对联。我们使用的数据集地址:对联数据集

3.1 加载数据集

In [2]
data_in_path="/home/aistudio/data/data110057/fixed_couplets_in.txt"   # 上联路径data_out_path="/home/aistudio/data/data110057/fixed_couplets_out.txt" # 下联路径
In [3]
# 从文件中读取数据def openfile(src):
    with open(src,'r',encoding="utf-8") as source:
        lines=source.readlines()    return lines

data_in=openfile(data_in_path)
data_out=openfile(data_out_path)
all_data_lines=len(data_in) # 统计对联的总数,为划分数据集做准备

3.2 对联预处理

  • 添加[start] token与 [end] token,这两个token的作用是告诉网络我们输入的对联的开始和结束。
  • 对联token的划分,根据空格划分token(一个汉字、标点都是一个token)
In [4]
def delete_newline_and_space(lista): 
    newlist=[]    for i in range(len(lista)):
        newlist.append(["<start>"]+lista[i].strip().split()+['<end>'])    return newlist

data_in_nospace=delete_newline_and_space(data_in)
data_out_nospace=delete_newline_and_space(data_out)# 展示处理结果print("上联:",data_in_nospace[0])print("下联",data_out_nospace[0])
上联: ['<start>', '腾', '飞', '上', '铁', ',', '锐', '意', '改', '革', '谋', '发', '展', ',', '勇', '当', '千', '里', '马', '<end>']
下联 ['<start>', '和', '谐', '南', '供', ',', '安', '全', '送', '电', '保', '畅', '通', ',', '争', '做', '领', '头', '羊', '<end>']
In [5]
couplet_maxlen=max([len(i) for i in data_in_nospace]) # 获取对联的最大长度,作为统一的长度标准。couplet_maxlen
34

3.3 建立语料库

  • 首先根据训练集数据建立总语料库
  • 然后建立token-->id的字典、id-->token的字典。在获取字典时,我们的写法是根据token频率获取;在实际应用的时候,我们设置的频率限制为0,也就是获取所有的token,因为总的token才不到1万个,数量不大,可以全部获取。
In [6]
def bulid_cropus(data_in,data_out):
    crpous=[]    for i in data_in:
        crpous.extend(i)    for i in data_out:
        crpous.extend(i)    return crpous
In [7]
def build_dict(corpus,frequency):
    # 首先统计不同词(汉字)的频率,使用字典记录
    word_freq_dict={}    for ch in corpus:        if ch not in word_freq_dict:
            word_freq_dict[ch]=0
        word_freq_dict[ch]+=1
    
    # 根据频率对字典进行排序
    word_freq_dict=sorted(word_freq_dict.items(),key=lambda x:x[1],reverse=True)
    
    
    word2id_dict={}
    id2word_dict={}    
    # 按照频率,从高到低,开始遍历每个单词,并赋予第一无二的 id
    for word,freq in word_freq_dict:        if freq>frequency:
            curr_id=len(word2id_dict)
            word2id_dict[word]=curr_id
            id2word_dict[curr_id]=word        else: 
            # else 部分在 使 单词 指向unk,对于汉字,我们不设置unk,令frequency=0
            word2id_dict[word]=1
    return word2id_dict,id2word_dict
In [8]
word_frequency=0word2id_dict,id2word_dict=build_dict(bulid_cropus(data_in_nospace,data_out_nospace),word_frequency)

word_size=len(word2id_dict)
id_size=len(id2word_dict)print("汉字个数:",word_size,"\n id个数:",id_size)
汉字个数: 9017 
 id个数: 9017
In [9]
# 将token-->id的字典、id-->token的字典存储到文件中(不是必须的)with open("word2id.txt",'w',encoding='utf-8') as w2i:    for k,v in word2id_dict.items():
        w2i.write(str(k)+","+str(v)+'\n')with open("id2word.txt",'w',encoding='utf-8') as w2i:    for k,v in id2word_dict.items():
        w2i.write(str(k)+","+str(v)+'\n')

3.4 输入向量化并划分数据集

  • 统一长度:couplet_maxlen
  • padid使用token的id代替
  • 测试集:验证集:训练集=1:1:18.
In [10]
def getensor(w2i,datalist,maxlength=couplet_maxlen):
    in_tensor=[]    for lista in datalist:
        in_samll_tensor=[]        for li in lista:
            in_samll_tensor.append(w2i[li])        if len(in_samll_tensor)<maxlength:
            in_samll_tensor+=[w2i['<end>']]*(maxlength-len(in_samll_tensor))
        in_tensor.append(in_samll_tensor)    return np.array(in_tensor)
In [11]
in_tensor=getensor(word2id_dict,data_in_nospace)
out_tensor=getensor(word2id_dict,data_out_nospace)


test_data_lines=int(all_data_lines*0.05)
val_data_lines=int(all_data_lines*0.1)


test_in_tensor=in_tensor[:test_data_lines]
val_in_tensor=in_tensor[test_data_lines:val_data_lines]
train_in_tensor=in_tensor[val_data_lines:]

test_out_tensor=out_tensor[:test_data_lines]
val_out_tensor=out_tensor[test_data_lines:val_data_lines]
train_out_tensor=out_tensor[val_data_lines:]print("训练集数目:",len(train_in_tensor),"测试集数目:",len(test_in_tensor),"验证集数目:",len(val_in_tensor))
训练集数目: 670424 测试集数目: 37245 验证集数目: 37246

3.5 封装数据集

In [12]
# 1.继承paddle.io.Datasetclass Mydataset(paddle.io.Dataset):
    
    # 2. 构造函数,定义数据集大小
    def __init__(self,first,second):
        super(Mydataset,self).__init__()
        self.first=first
        self.second=second        
    # 3. 实现__getitem__方法,定义指定index时如何获取数据,并返回单条数据(训练数据,对应的标签)
    def __getitem__(self,index):
        return self.first[index],self.second[index]    
    # 4. 实现__len__方法,返回数据集总数目
    def __len__(self):
        return self.first.shape[0]
In [13]
def prepare_input(inputs,padid):
    src=np.array([inputsub[0] for inputsub in inputs])
    trg=np.array([inputsub[1] for inputsub in inputs])
    trg_mask =(trg[:,:-1]!=padid).astype(paddle.get_default_dtype())    return src,trg[:,:-1],trg[:,1:,np.newaxis],trg_mask
In [14]
def create_data_loader(dataset):
    data_loader=paddle.io.DataLoader(dataset,batch_sampler=None,drop_last=True,batch_size=BATCH_SIZE,collate_fn=partial(prepare_input, padid=padid))    return data_loader
In [15]
# 封装数据集BATCH_SIZE=128padid=word2id_dict['<end>']

train_tensor=Mydataset(train_in_tensor,train_out_tensor)
val_tensor=Mydataset(val_in_tensor,val_out_tensor)

train_loader=create_data_loader(train_tensor)
val_loader=create_data_loader(val_tensor)
In [16]
for i,data in enumerate(val_loader):    for d in data:        print(d.shape)    break
[128, 34]
[128, 33]
[128, 33, 1]
[128, 33]

4.模型组网

In [17]
# 为方便调试网络,我们提前定义一些参数embed_dim=256 # 词嵌入embedding的维度latent_dim=2048 # feed forward 前馈神经网络的相关参数num_heads=8 # 多头注意力机制的‘头’数

4.1 Encoder

Encoder部分主要包含了多头注意力机制、层归一化层以及前馈神经网络序列。

What-the-Diff
What-the-Diff

检查请求差异,自动生成更改描述

下载
  • MultiHeadAttention :使用paddle.nn.MultiHeadAttention实现多头注意力机制,需要注意其掩码attn_mask需要的shape是[batch_szie,num_heads,sequence_legth,sequence_legth]
  • Feed Forward:点式前馈网络由两层全联接层组成,两层之间有一个 ReLU 激活函数。
  • LayerNorm:归一化层
In [18]
class TransformerEncoder(paddle.nn.Layer):
    def __init__(self, embed_dim, dense_dim, num_heads):
        super(TransformerEncoder, self).__init__()
        self.embed_dim = embed_dim
        self.dense_dim = dense_dim
        self.num_heads = num_heads
        self.attention = paddle.nn.MultiHeadAttention(num_heads=num_heads, embed_dim=embed_dim, dropout =0.1)

        self.dense_proj =paddle.nn.Sequential(
            paddle.nn.Linear(embed_dim, dense_dim), 
            paddle.nn.ReLU(),
            paddle.nn.Linear(dense_dim, embed_dim) )

        self.layernorm_1 = paddle.nn.LayerNorm(embed_dim)
        self.layernorm_2 = paddle.nn.LayerNorm(embed_dim)
        self.supports_masking = True

    def forward(self, inputs, mask=None):
        padding_mask=None
        if mask is not None:
            padding_mask = paddle.cast(mask[:, np.newaxis, np.newaxis, :], dtype="int32")
    
        attention_output = self.attention(query=inputs, value=inputs, key=inputs, attn_mask=padding_mask)

        proj_input = self.layernorm_1(inputs + attention_output)
        proj_output = self.dense_proj(proj_input)        return self.layernorm_2(proj_input + proj_output)# pencoder=TransformerEncoder(embed_dim, latent_dim, num_heads)# print(pencoder)# inputs=paddle.rand([BATCH_SIZE,34,256])# print("inputs.shape:",inputs.shape)# out=pencoder(inputs)# print("out.shape:",out.shape)

4.2 位置编码

Transformer模型并不包括任何的循环或卷积网络,所以模型添加了位置编码,为模型提供一些关于单词在句子中相对位置的信息。我们用paddle.nn.Embedding实现位置编码,其中num_embeddings=sequence_length。

In [19]
class PositionalEmbedding(paddle.nn.Layer):
    def __init__(self, sequence_length, vocab_size, embed_dim):
        super(PositionalEmbedding, self).__init__()
        self.token_embeddings = paddle.nn.Embedding(num_embeddings =vocab_size, embedding_dim =embed_dim)
        self.position_embeddings = paddle.nn.Embedding(num_embeddings =sequence_length, embedding_dim =embed_dim)

        self.sequence_length = sequence_length
        self.vocab_size = vocab_size
        self.embed_dim = embed_dim    def forward(self, inputs):
        length = inputs.shape[-1]
        positions = paddle.arange(start=0, end=length, step=1)
        embedded_tokens = self.token_embeddings(inputs)
        embedded_positions = self.position_embeddings(positions)        return embedded_tokens + embedded_positions    def compute_mask(self, inputs, mask=None):
        return paddle.not_equal(inputs, 0)# ps=PositionalEmbedding(34,word_size,256)# print(ps)# inputs=paddle.randint(0,word_size,[BATCH_SIZE,34])# print("inputs.shape:",inputs.shape)# out=ps(inputs)# print("out.shape:",out.shape)

4.3 Decoder

编码器含有两个多头注意力组件,一个用于处理西班牙语的输入,另一个用于处理编码器的输出和前一个多头注意力机制的输出。

In [20]
class TransformerDecoder(paddle.nn.Layer):
    def __init__(self, embed_dim, latent_dim, num_heads):
        super(TransformerDecoder, self).__init__()
        self.embed_dim = embed_dim
        self.latent_dim = latent_dim
        self.num_heads = num_heads
        self.attention_1 = paddle.nn.MultiHeadAttention(num_heads=num_heads, embed_dim=embed_dim)

        self.attention_2 = paddle.nn.MultiHeadAttention(num_heads=num_heads, embed_dim=embed_dim)

        self.dense_proj = paddle.nn.Sequential(
            paddle.nn.Linear(embed_dim, latent_dim), 
            paddle.nn.ReLU(),
            paddle.nn.Linear(latent_dim, embed_dim) )

        self.layernorm_1 = paddle.nn.LayerNorm(embed_dim)
        self.layernorm_2 = paddle.nn.LayerNorm(embed_dim)
        self.layernorm_3 = paddle.nn.LayerNorm(embed_dim)
        self.supports_masking = True

    def forward(self, inputs, encoder_outputs, mask=None):
        causal_mask = self.get_causal_attention_mask(inputs) #[batch_size, equence_length, sequence_length]
        padding_mask=None
        if mask is not None:
            padding_mask = paddle.cast(mask[:, np.newaxis, :], dtype="int32")
            padding_mask = paddle.minimum(padding_mask, causal_mask)

        attention_output_1 = self.attention_1(query=inputs, value=inputs, key=inputs, attn_mask=causal_mask)
        out_1 = self.layernorm_1(inputs + attention_output_1)

        attention_output_2 = self.attention_2(
            query=out_1,
            value=encoder_outputs,
            key=encoder_outputs,
            attn_mask=padding_mask,
        )

        out_2 = self.layernorm_2(out_1 + attention_output_2)

        proj_output = self.dense_proj(out_2)        return self.layernorm_3(out_2 + proj_output)    def get_causal_attention_mask(self, inputs):
        input_shape = inputs.shape
        batch_size, sequence_length = input_shape[0], input_shape[1]
        i = paddle.arange(sequence_length)[:, np.newaxis]
        j = paddle.arange(sequence_length)
        mask = paddle.cast(i >= j, dtype="int32") #[sequence_length, sequence_length]
        mask = paddle.reshape(mask, (1,1, input_shape[1], input_shape[1])) #[1, equence_length, sequence_length]
        mult = paddle.concat(
            [paddle.to_tensor(BATCH_SIZE,dtype='int32'), paddle.to_tensor([1,1, 1], dtype="int32")],
            axis=0,) #[batch_size,1,1]
        return paddle.tile(mask, mult) #[batch_size, equence_length, sequence_length]# decoder=TransformerDecoder(embed_dim, latent_dim, num_heads)# print(decoder)# inputs=paddle.rand([BATCH_SIZE,34,256])# enout=paddle.rand([BATCH_SIZE,34,256])# out=decoder(inputs,enout)# print("out.shape:",out.shape)

4.4 搭建Transformer模型

In [21]
class Transformer(paddle.nn.Layer):
    def __init__(self, embed_dim, latent_dim, num_heads,sequence_length, vocab_size):
        super(Transformer, self).__init__()

        self.ps1=PositionalEmbedding(sequence_length, vocab_size, embed_dim)
        self.encoder=TransformerEncoder(embed_dim, latent_dim, num_heads)

        self.ps2=PositionalEmbedding(sequence_length, vocab_size, embed_dim)
        self.decoder=TransformerDecoder(embed_dim, latent_dim, num_heads) 

        self.drop=paddle.nn.Dropout(p=0.5)

        self.lastLinear=paddle.nn.Linear(embed_dim,vocab_size)

        self.softmax=paddle.nn.Softmax()    def forward(self,encoder_inputs,decoder_inputs):

        # 编码器
        encoder_emb=self.ps1(encoder_inputs)
        encoder_outputs=self.encoder(encoder_emb)        # 解码器
        deocder_emb=self.ps2(decoder_inputs)
        decoder_outputs=self.decoder(deocder_emb,encoder_outputs)        # dropout
        out=self.drop(decoder_outputs)        #最后输出
        out=self.lastLinear(out)        return out


trans=Transformer(embed_dim, latent_dim, num_heads,couplet_maxlen, word_size)
paddle.summary(trans,input_size=[(BATCH_SIZE,34),(BATCH_SIZE,34)],dtypes='int32')
W1122 09:28:31.102437  1380 gpu_resources.cc:61] Please NOTE: device: 0, GPU Compute Capability: 7.0, Driver API Version: 11.2, Runtime API Version: 11.2
W1122 09:28:31.106657  1380 gpu_resources.cc:91] device: 0, cuDNN Version: 8.2.
---------------------------------------------------------------------------------------------
    Layer (type)                Input Shape                Output Shape         Param #    
=============================================================================================
     Embedding-1                [[128, 34]]               [128, 34, 256]       2,308,352   
     Embedding-2                   [[34]]                   [34, 256]            8,704     
PositionalEmbedding-1           [[128, 34]]               [128, 34, 256]           0       
      Linear-1                [[128, 34, 256]]            [128, 34, 256]        65,792     
      Linear-2                [[128, 34, 256]]            [128, 34, 256]        65,792     
      Linear-3                [[128, 34, 256]]            [128, 34, 256]        65,792     
      Linear-4                [[128, 34, 256]]            [128, 34, 256]        65,792     
MultiHeadAttention-1                 []                   [128, 34, 256]           0       
     LayerNorm-1              [[128, 34, 256]]            [128, 34, 256]          512      
      Linear-5                [[128, 34, 256]]           [128, 34, 2048]        526,336    
       ReLU-1                [[128, 34, 2048]]           [128, 34, 2048]           0       
      Linear-6               [[128, 34, 2048]]            [128, 34, 256]        524,544    
     LayerNorm-2              [[128, 34, 256]]            [128, 34, 256]          512      
TransformerEncoder-1          [[128, 34, 256]]            [128, 34, 256]           0       
     Embedding-3                [[128, 34]]               [128, 34, 256]       2,308,352   
     Embedding-4                   [[34]]                   [34, 256]            8,704     
PositionalEmbedding-2           [[128, 34]]               [128, 34, 256]           0       
      Linear-7                [[128, 34, 256]]            [128, 34, 256]        65,792     
      Linear-8                [[128, 34, 256]]            [128, 34, 256]        65,792     
      Linear-9                [[128, 34, 256]]            [128, 34, 256]        65,792     
      Linear-10               [[128, 34, 256]]            [128, 34, 256]        65,792     
MultiHeadAttention-2                 []                   [128, 34, 256]           0       
     LayerNorm-3              [[128, 34, 256]]            [128, 34, 256]          512      
      Linear-11               [[128, 34, 256]]            [128, 34, 256]        65,792     
      Linear-12               [[128, 34, 256]]            [128, 34, 256]        65,792     
      Linear-13               [[128, 34, 256]]            [128, 34, 256]        65,792     
      Linear-14               [[128, 34, 256]]            [128, 34, 256]        65,792     
MultiHeadAttention-3                 []                   [128, 34, 256]           0       
     LayerNorm-4              [[128, 34, 256]]            [128, 34, 256]          512      
      Linear-15               [[128, 34, 256]]           [128, 34, 2048]        526,336    
       ReLU-2                [[128, 34, 2048]]           [128, 34, 2048]           0       
      Linear-16              [[128, 34, 2048]]            [128, 34, 256]        524,544    
     LayerNorm-5              [[128, 34, 256]]            [128, 34, 256]          512      
TransformerDecoder-1  [[128, 34, 256], [128, 34, 256]]    [128, 34, 256]           0       
      Dropout-1               [[128, 34, 256]]            [128, 34, 256]           0       
      Linear-17               [[128, 34, 256]]           [128, 34, 9017]       2,317,369   
=============================================================================================
Total params: 9,845,305
Trainable params: 9,845,305
Non-trainable params: 0
---------------------------------------------------------------------------------------------
Input size (MB): 0.03
Forward/backward pass size (MB): 818.03
Params size (MB): 37.56
Estimated Total Size (MB): 855.62
---------------------------------------------------------------------------------------------
{'total_params': 9845305, 'trainable_params': 9845305}

5.模型训练与评估

5.1 自定义loss函数

In [22]
class CrossEntropy(paddle.nn.Layer):
    def __init__(self):
        super(CrossEntropy,self).__init__()    def forward(self,pre,real,trg_mask):

        # 返回的数据类型与pre一致,除了axis维度(未指定则为-1),其他维度也与pre一致
        # logits=pre,[batch_size,sequence_len,word_size],猜测会进行argmax操作,[batch_size,sequence_len,1]
        # 默认的soft_label为False,lable=real,[bacth_size,sequence_len,1]
        cost=paddle.nn.functional.softmax_with_cross_entropy(logits=pre,label=real)        
        # 删除axis=2 shape上为1的维度
        # 返回结果的形状应为 [batch_size,sequence_len]
        cost=paddle.squeeze(cost,axis=[2])        # trg_mask 的形状[batch_size,suqence_len]
        # * 这个星号应该是对应位置相乘,返回结果的形状 [bathc_szie,sequence_len]
        masked_cost=cost*trg_mask        # paddle.mean 对应轴的对应位置求平均
        return paddle.mean(paddle.mean(masked_cost,axis=[0]))

5.2 训练与验证

In [23]
epochs = 10   trans=Transformer(embed_dim, latent_dim, num_heads,couplet_maxlen, word_size)
model=paddle.Model(trans)


model.prepare(optimizer=paddle.optimizer.Adam(learning_rate=0.001,parameters=model.parameters()),
                loss=CrossEntropy(), 
                metrics=paddlenlp.metrics.Perplexity())

model.fit(train_data=train_loader, 
            epochs=epochs,
             eval_data= val_loader,
             save_dir='./savemodel',
             save_freq=5,
             verbose =0,
             log_freq =2000,
             callbacks=[paddle.callbacks.VisualDL('./log')])
save checkpoint at /home/aistudio/savemodel/0
save checkpoint at /home/aistudio/savemodel/5
save checkpoint at /home/aistudio/savemodel/final

10个epoch下的loss与Perplexity曲线图: 【提前过年吧】来对对联吧,基于transformer - php中文网

【提前过年吧】来对对联吧,基于transformer - php中文网

6. 结果预测

In [24]
def evalute(eng,maxlen=couplet_maxlen):
    
    encoder_input=paddle.unsqueeze(eng,axis=0)
    decoded_sentence = "<start>"

    def get_pre_tensor(w2i,s,maxlen=maxlen):
        x=[padid]*couplet_maxlen
        lista=s.split()        for i in range(len(lista)):
            x[i]=w2i[lista[i]]        return paddle.to_tensor([x],dtype='int32')        
    for i in range(maxlen):
        decoder_input=get_pre_tensor(word2id_dict,decoded_sentence)
        pre=trans(encoder_input,decoder_input)
        sampled_token_index = np.argmax(pre[0, i, :])
        sampled_token = id2word_dict[sampled_token_index]
        decoded_sentence += " " + sampled_token        if sampled_token == "<end>":            break

    return decoded_sentence
In [25]
def translate():
    with open('result.txt','w+') as re:        #for i in tqdm.tqdm(range(len(test_in_tensor))):
        for i in range(5):    
            result=evalute(paddle.to_tensor(test_in_tensor[i]))
            re.write(result+'\n')
translate()
In [26]
with open('result.txt','r') as re:
    pre=re.readlines()for i in range(2):    print('上联: ',"".join(l for l in data_in_nospace[i]))    print('真实的下联:',"".join(l for l in data_out_nospace[i]))    print('预测的下联:',pre[i])
上联:  <start>腾飞上铁,锐意改革谋发展,勇当qian里马<end>
真实的下联: <start>和谐南供,安全送电保畅通,争做领头羊<end>
预测的下联: <start> 发 展 宏 图 , 激 情 发 展 建 和 谐 , 喜 做 万 年 春 <end>

上联:  <start>风弦未拨心先乱<end>
真实的下联: <start>夜幕已沉梦更闲<end>
预测的下联: <start> 月 色 初 圆 梦 亦 空 <end>

7.总结

  1. 本项目基于tranformer训练了一个可以对对联的神经网络模型,输出的结果在对仗方面很好。
  2. 本项目的不足在与模型输出的下联在语义上不是非常好,比如上联的“勇当qian里马”,我们下联给的“喜做万年春”,马和春在语义上是不相关的。因此,本项目的一个改进方向就是语义方向。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

16

2026.03.11

Go高并发任务调度与Goroutine池化实践
Go高并发任务调度与Goroutine池化实践

本专题围绕 Go 语言在高并发任务处理场景中的实践展开,系统讲解 Goroutine 调度模型、Channel 通信机制以及并发控制策略。内容包括任务队列设计、Goroutine 池化管理、资源限制控制以及并发任务的性能优化方法。通过实际案例演示,帮助开发者构建稳定高效的 Go 并发任务处理系统,提高系统在高负载环境下的处理能力与稳定性。

23

2026.03.10

Kotlin Android模块化架构与组件化开发实践
Kotlin Android模块化架构与组件化开发实践

本专题围绕 Kotlin 在 Android 应用开发中的架构实践展开,重点讲解模块化设计与组件化开发的实现思路。内容包括项目模块拆分策略、公共组件封装、依赖管理优化、路由通信机制以及大型项目的工程化管理方法。通过真实项目案例分析,帮助开发者构建结构清晰、易扩展且维护成本低的 Android 应用架构体系,提升团队协作效率与项目迭代速度。

75

2026.03.09

JavaScript浏览器渲染机制与前端性能优化实践
JavaScript浏览器渲染机制与前端性能优化实践

本专题围绕 JavaScript 在浏览器中的执行与渲染机制展开,系统讲解 DOM 构建、CSSOM 解析、重排与重绘原理,以及关键渲染路径优化方法。内容涵盖事件循环机制、异步任务调度、资源加载优化、代码拆分与懒加载等性能优化策略。通过真实前端项目案例,帮助开发者理解浏览器底层工作原理,并掌握提升网页加载速度与交互体验的实用技巧。

95

2026.03.06

Rust内存安全机制与所有权模型深度实践
Rust内存安全机制与所有权模型深度实践

本专题围绕 Rust 语言核心特性展开,深入讲解所有权机制、借用规则、生命周期管理以及智能指针等关键概念。通过系统级开发案例,分析内存安全保障原理与零成本抽象优势,并结合并发场景讲解 Send 与 Sync 特性实现机制。帮助开发者真正理解 Rust 的设计哲学,掌握在高性能与安全性并重场景中的工程实践能力。

218

2026.03.05

PHP高性能API设计与Laravel服务架构实践
PHP高性能API设计与Laravel服务架构实践

本专题围绕 PHP 在现代 Web 后端开发中的高性能实践展开,重点讲解基于 Laravel 框架构建可扩展 API 服务的核心方法。内容涵盖路由与中间件机制、服务容器与依赖注入、接口版本管理、缓存策略设计以及队列异步处理方案。同时结合高并发场景,深入分析性能瓶颈定位与优化思路,帮助开发者构建稳定、高效、易维护的 PHP 后端服务体系。

420

2026.03.04

AI安装教程大全
AI安装教程大全

2026最全AI工具安装教程专题:包含各版本AI绘图、AI视频、智能办公软件的本地化部署手册。全篇零基础友好,附带最新模型下载地址、一键安装脚本及常见报错修复方案。每日更新,收藏这一篇就够了,让AI安装不再报错!

168

2026.03.04

Swift iOS架构设计与MVVM模式实战
Swift iOS架构设计与MVVM模式实战

本专题聚焦 Swift 在 iOS 应用架构设计中的实践,系统讲解 MVVM 模式的核心思想、数据绑定机制、模块拆分策略以及组件化开发方法。内容涵盖网络层封装、状态管理、依赖注入与性能优化技巧。通过完整项目案例,帮助开发者构建结构清晰、可维护性强的 iOS 应用架构体系。

222

2026.03.03

C++高性能网络编程与Reactor模型实践
C++高性能网络编程与Reactor模型实践

本专题围绕 C++ 在高性能网络服务开发中的应用展开,深入讲解 Socket 编程、多路复用机制、Reactor 模型设计原理以及线程池协作策略。内容涵盖 epoll 实现机制、内存管理优化、连接管理策略与高并发场景下的性能调优方法。通过构建高并发网络服务器实战案例,帮助开发者掌握 C++ 在底层系统与网络通信领域的核心技术。

33

2026.03.03

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 22.5万人学习

Django 教程
Django 教程

共28课时 | 4.9万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号