【NLP+Android】AI 对联 APP


该项目是对联生成系统的升级版本,从简单界面可视化升级为Android APP。项目用Seq2seq框架,先处理对联数据,建立语料库和字典,划分数据集并封装。接着搭建Encoder、AttentionLayer等网络组件,定义损失函数和超参数后训练模型。还涉及模型预测及动态图转静态图,最后进行Android开发,生成opt模型并编写相关代码实现功能。

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

【nlp+android】ai 对联 app -

项目简介

该项目是我之前精品项目使用Seq2seq框架搭建对联生成系统的升级版本。在之前的项目中,我仅实现了简单的界面可视化,现在升级到了Android APP,嘿嘿!

安卓代码及APP下载地址:点我

APP界面如下图所示:

【NLP+Android】AI 对联 APP -        

In [1]
import ioimport osimport numpy as npimport paddleimport paddlenlpfrom functools import partialfrom paddle.static import InputSpec
   

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
    In [4]
data_in=openfile(data_in_path)
data_out=openfile(data_out_path)
    In [5]
print(len(data_in))print(len(data_out))print(data_in[0])print(data_out[0])print(len(data_in[0]))
       
744915
744915
腾 飞 上 铁 , 锐 意 改 革 谋 发 展 , 勇 当 千 里 马 

和 谐 南 供 , 安 全 送 电 保 畅 通 , 争 做 领 头 羊 

37
        In [6]
def delete_newline_and_space(lista): 
    newlist=[]    for i in range(len(lista)):
        newlist.append(["<start>"]+lista[i].strip().split()+['<end>'])    return newlist
    In [7]
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>']
       

计算最长的对联长度couplet_maxlen,并将该长度+2作为向量长。不足进行填充。

In [8]
couplet_maxlen=max([len(i) for i in data_in_nospace])
couplet_maxlen
       
34
               

1.1 建立语料库、字符转id的字典和id转字符的字典

  • 字符主要指的是汉字,当然还有标点

有个问题: 输入输出的语料库是二者分别建立一个,还是二者一起建立一个?

在这里建立一个统一的语料库进行实验。(毕设的时候我是分开建的,不知道哪个做法正确)

In [9]
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 [10]
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 [11]
word_frequency=0word2id_dict,id2word_dict=build_dict(bulid_cropus(data_in_nospace,data_out_nospace),word_frequency)
   

词汇量大小

In [12]
word_size=len(word2id_dict)
id_size=len(id2word_dict)print("汉字个数:",word_size,"\n id个数:",id_size)
       
汉字个数: 9017 
 id个数: 9017
        In [13]
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')
    In [14]
print(word2id_dict['<end>'])print(word2id_dict['<start>'])
       
1
0
       

创建 tensor

In [15]
def getensor(w2i,datalist,maxlength):
    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 in_tensor
    In [16]
in_tensor=getensor(word2id_dict,data_in_nospace,couplet_maxlen)
out_tensor=getensor(word2id_dict,data_out_nospace,couplet_maxlen)
   

转成数字,带上shape属性

In [17]
in_tensor=np.array(in_tensor)
out_tensor=np.array(out_tensor)
   

1.2 划分训练集、验证集、测试集 ,按照8:1:1 固定划分

In [18]
train_in_tensor=in_tensor[:595933]
val_in_tensor=in_tensor[595933:670424]
test_in_tensor=in_tensor[670424:]

train_out_tensor=out_tensor[:595933]
val_out_tensor=out_tensor[595933:670424]
test_out_tensor=out_tensor[670424:]
    In [19]
print(len(train_in_tensor),len(test_in_tensor),len(val_in_tensor))
       
595933 74491 74491
       

1.3 封装数据集为可直接进行训练的dataset

In [20]
# 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 [21]
train_tensor=Mydataset(train_in_tensor,train_out_tensor)
val_tensor=Mydataset(val_in_tensor,val_out_tensor)
test_tensor=Mydataset(test_in_tensor,test_out_tensor)
   

数据加载

In [22]
BATCH_SIZE=64padid=word2id_dict['<end>']
    In [23]
def prepare_input(inputs,padid):

    src,src_length=paddlenlp.data.Pad(pad_val=padid,ret_length=True)([inputsub[0] for inputsub in inputs])
    trg,trg_length=paddlenlp.data.Pad(pad_val=padid,ret_length=True)([inputsub[1] for inputsub in inputs])    #src=src.astype(paddle.get_default_dtype())
    trg_mask =(trg[:,:-1]!=padid).astype(paddle.get_default_dtype())    return src,src_length,trg[:,:-1],trg[:,1:,np.newaxis],trg_mask
    In [24]
def create_data_loader(dataset):
    data_loader=paddle.io.DataLoader(dataset,batch_sampler=None,batch_size=BATCH_SIZE,collate_fn=partial(prepare_input, padid=padid))    return data_loader
    In [25]
train_loader=create_data_loader(train_tensor)
val_loader=create_data_loader(val_tensor)
test_loader=create_data_loader(test_tensor)
    In [26]
# j=0# for i in train_loader:#     print(len(i))#     for ind,each in enumerate(i):#         print(ind,each.shape,each)#         #print(ind,each.shape)#     j+=1#     if j==2:#         break
    In [ ]
<br/>
    In [27]
# for i in train_loader:#     x,x_length,y,_,_= i#     break# # print(x)
   

2.网络搭建

主要参考的是官方的项目,直达:https://aistudio.baidu.com/aistudio/projectdetail/1321118?shared=1

简小派 简小派

简小派是一款AI原生求职工具,通过简历优化、岗位匹配、项目生成、模拟面试与智能投递,全链路提升求职成功率,帮助普通人更快拿到更好的 offer。

简小派 123 查看详情 简小派

2.1 Encoder

In [28]
class Encoder(paddle.nn.Layer):
    def __init__(self,vocab_size,embedding_dim,hidden_size,num_layers):
        super(Encoder,self).__init__()
        
        self.embedding=paddle.nn.Embedding(vocab_size,embedding_dim)
        self.lstm=paddle.nn.LSTM(input_size=embedding_dim,
                                hidden_size=hidden_size,
                                num_layers=num_layers,
                                dropout=0.2 if num_layers>1 else 0)            
    # src_length 的形状为[batch_size],作用是控制inputs中的time_step超过[batch_size]的不再更新状态,就是那些填充
    def forward(self,src,src_length):
        inputs=self.embedding(src)  # [batch_size,time_steps,embedding_dim]
        encoder_out,encoder_state=self.lstm(inputs,sequence_length=src_length) # out[batch_szie,time_steps,hidden_size] state:[[num_layers*1,batch_size,hidden_size],[num_layers*1,batch_size,hidden_size]]
        # encoder_out,encoder_state=self.lstm(inputs)
        return encoder_out,encoder_state
    In [29]
# encoder=Encoder(word_size,256,128,2)# #paddle.summary(encoder,[(64,18),(64)],dtypes='int64')# out,state=encoder(x,x_length)# print(out.shape)# print(state)
   

2.2 注意力层

In [30]
class AttentionLayer(paddle.nn.Layer):
    def __init__(self,hidden_size):
        super(AttentionLayer,self).__init__()
        self.attn1=paddle.nn.Linear(hidden_size,hidden_size)
        self.attn2=paddle.nn.Linear(hidden_size+hidden_size,hidden_size)    def forward(self,decoder_hidden_h,encoder_output,encoder_padding_mask):
        
        encoder_output=self.attn1(encoder_output) # [batch_size,time_steps,hidden_size]
        
        # decodr_hidden_h 的形状 [batch_size,hidden_size],是lstm公式中的ht.
        # unsqueeze之后[batch_size,1,hidden_size]
        # transpose_y=True,后两维转置 [batch_size,hidden_size,time_steps]
        # matmul之后的 形状 [batch_size,1,time_steps]
        a=paddle.unsqueeze(decoder_hidden_h,[1])        # print(a.shape)
        # print(encoder_output.shape)
        attn_scores=paddle.matmul(a,encoder_output,transpose_y=True)        
        
        # 注意力机制中增加掩码操作,在padding 位加上个非常小的数:-1e9
        if encoder_padding_mask is not None:            # encoder_padding_mask的形状为[batch_size,1,time_steps]
            attn_scores=paddle.add(attn_scores,encoder_padding_mask)        # softmax操作,默认是最后一个维度,axis=-1,形状不变
        attn_scores=paddle.nn.functional.softmax(attn_scores) 

        # [batch_size,1,time_steps]*[batch_size,time_steps,hidden_size]-->[batch_size,1,hidden_size]
        # squeeze之后:[batch_size,hidden_size]
        attn_out=paddle.squeeze(paddle.matmul(attn_scores,encoder_output),[1])        
        # concat之后 [batch_size,hidden_size+hidden_size]
        attn_out=paddle.concat([attn_out,decoder_hidden_h],1)        # 最终结果[batch_size,hidden_size]
        attn_out=self.attn2(attn_out)        return attn_out
   

2.3 解码器单元

In [31]
class DecoderCell(paddle.nn.RNNCellBase):
    def __init__(self,num_layers,embedding_dim,hidden_size):
        super(DecoderCell,self).__init__()

        self.dropout=paddle.nn.Dropout(0.2)
        self.lstmcells=paddle.nn.LayerList([paddle.nn.LSTMCell(
            input_size=embedding_dim+hidden_size if i==0 else hidden_size,
            hidden_size=hidden_size
        ) for i in range(num_layers)])

        self.attention=AttentionLayer(hidden_size)    
    def forward(self,decoder_input,decoder_initial_states,encoder_out,encoder_padding_mask=None):
        #forward 函数会执行squence_len次 ,每次的decoder_input 为[batch_size,embeddding_dim]

        # 状态分解 states [encoder_final_states,decoder_init_states]
        # encoder_final_states [num_layes,batch_size,hiden_size] ???
        # decoder_init_states [] ???

        encoder_final_states,decoder_init_states=decoder_initial_states        #num_layers=len(encoder_final_states[0])
        #decoder_init_states=lstm_init_state

        # ???
        new_lstm_states=[]        # decoder_input: [batch_size,embedding_dim]
        # print("decodercell ",decoder_input.shape)
        inputs=paddle.concat([decoder_input,decoder_init_states],1)        # print("concant之后",inputs.shape)

        for i ,lstm_cell in enumerate(self.lstmcells):            # inputs 的形状为 [batch_size,input_size]  input_size:输入的大小
            state_h,new_lstm_state=lstm_cell(inputs,encoder_final_states[i])

            inputs=self.dropout(state_h)

            new_lstm_states.append(new_lstm_state)
        
        state_h=self.attention(inputs,encoder_out,encoder_padding_mask)        # print(state_h.shape)

        return state_h,[new_lstm_states,state_h]
   

2.4 解码器

解码器由embedding+解码器单元+线性输出层组成

In [32]
class Decoder(paddle.nn.Layer):
    def __init__(self,vocab_size,embedding_dim,hidden_size,num_layers):
        super(Decoder,self).__init__()
        self.embedding=paddle.nn.Embedding(vocab_size,embedding_dim)
        self.lstm_attention=paddle.nn.RNN(DecoderCell(num_layers,embedding_dim,hidden_size))
        self.fianl=paddle.nn.Linear(hidden_size,vocab_size)    def forward(self,trg, decoder_initial_states,encoder_output,encoder_padding_mask):

        # trg 的形状为 [batch_size,sequence_length]
        # embedding 之后, [batch_size,sequence_length,embedding_dim]
        inputs=self.embedding(trg)        # print("embedding 后的 输入维度",inputs.shape)
        
        # decodr_out [batch_szie,hidden_size]
        decoder_out,_ = self.lstm_attention(inputs,
                                         initial_states=decoder_initial_states,
                                         encoder_out=encoder_output,
                                         encoder_padding_mask=encoder_padding_mask)        # predict [batch_size,sequence_len,word_size]
        predict=self.fianl(decoder_out)        # print("最后的维度",decoder_out.shape)

        return predict
   

2.5 组装Seq2Seq

In [33]
class Seq2Seq(paddle.nn.Layer):

    def __init__(self, vocab_size,embedding_dim,hidden_size,num_layers,eos_id):
        
        super(Seq2Seq,self).__init__()

        self.hidden_size=hidden_size
        self.eos_id=eos_id
        self.num_layers=num_layers
        self.INF= 1e9

        self.encoder=Encoder(vocab_size,embedding_dim,hidden_size,num_layers)
        self.decoder=Decoder(vocab_size,embedding_dim,hidden_size,num_layers)        
    def forward(self,src,src_length,trg):

        # encoder_output 的形状为[batch_size,sequence_len,hidden_size]
        # encoder_final_state ([num_layers*1,batch_size,hidden_size],[num_layers*1,batch_size,hidden_size]])  tuple类型
        encoder_output,encoder_final_state=self.encoder(src,src_length)

        encoder_final_states=[(encoder_final_state[0][i],encoder_final_state[1][i]) for i in range(self.num_layers)]        #print(encoder_final_states[0])

        # [batch_size,hidden_size] 初始化为0
        #lstm_init_state= self.decoder.lstm_attention.cell.get_initial_states(batch_ref=encoder_output,shape=[self.hidden_size])
       
        decoder_initial_states=[encoder_final_states,
                                self.decoder.lstm_attention.cell.get_initial_states(batch_ref=encoder_output,shape=[self.hidden_size])]

        src_mask=(src!=self.eos_id).astype(paddle.get_default_dtype())
        encoder_mask=(src_mask-1)*self.INF
        encoder_padding_mask=paddle.unsqueeze(encoder_mask,[1])

        predict=self.decoder(trg,decoder_initial_states,encoder_output,encoder_padding_mask)        return predict
   

2.6 自定义交叉熵损失函数及超参数

In [34]
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 对应轴的对应位置求平均, 在这里返回结果为 [sequence_len]
        # paddle.sum 求解方法与paddle.mean一致,最终返回的结果应为[1]
        return paddle.sum(paddle.mean(masked_cost,axis=[0]))
    In [35]
epochs=20eos_id=word2id_dict['<end>']
num_layers=2dropout_rate=0.2hidden_size=128embedding_dim=256max_grad_norm=5lr=0.001log_freq=200model_path='./train_model/train_model'
    In [36]
s2s=Seq2Seq(word_size,embedding_dim,hidden_size,num_layers,eos_id)
       
W0609 11:31:02.978509  1421 device_context.cc:404] Please NOTE: device: 0, GPU Compute Capability: 7.0, Driver API Version: 11.2, Runtime API Version: 10.1
W0609 11:31:02.982554  1421 device_context.cc:422] device: 0, cuDNN Version: 7.6.
        In [37]
model=paddle.Model(s2s)# model.parameters() 返回一个包含所有模型参数的列表optimizer=paddle.optimizer.Adam(learning_rate=lr,parameters=model.parameters())# 困惑度ppl_metric=paddlenlp.metrics.Perplexity()

model.prepare(optimizer,CrossEntropy(),ppl_metric)
   

2.7 训练并保存

#eval_freq 多少个epoch评估一次 #s*e_freq 多少个epoch保存模型一次

model.fit(train_data=train_loader, eval_data=val_loader, epochs=epochs, eval_freq=1, s*e_freq=2, s*e_dir=model_path, log_freq=log_freq, verbose=2, callbacks=[paddle.callbacks.VisualDL('./log')])

#保存用于预测的模型 #model.s*e("./infer_model/infer_model",False)

3.模型预测

3.1 定义预测模型

In [38]
class Seq2SeqInfer(Seq2Seq):
    def __init__(self,word_size,embedding_dim,hidden_size,num_layers,bos_id,eos_id,beam_size,max_out_len=couplet_maxlen):

        self.bos_id=bos_id
        self.beam_size=beam_size
        self.max_out_len=max_out_len
        self.num_layers=num_layers        super(Seq2SeqInfer,self).__init__(word_size,embedding_dim,hidden_size,num_layers,eos_id)

        self.beam_search_decoder=paddle.nn.BeamSearchDecoder(
            self.decoder.lstm_attention.cell,
            start_token=bos_id,
            end_token=eos_id,
            beam_size=beam_size,
            embedding_fn=self.decoder.embedding,
            output_fn=self.decoder.fianl)    
    def forward(self,src,src_length):
        encoder_output,encoder_states=self.encoder(src,src_length)

        encoder_final_state=[(encoder_states[0][i],encoder_states[1][i]) for i in range(self.num_layers)]        # 初始化decoder的隐藏层状态
        decoder_initial_states=[encoder_final_state,
                                self.decoder.lstm_attention.cell.get_initial_states(batch_ref=encoder_output,shape=[self.hidden_size])]
        
        src_mask=(src!=self.eos_id).astype(paddle.get_default_dtype())
        encoder_padding_mask=(src_mask-1.0)*self.INF
        encoder_padding_mask=paddle.unsqueeze(encoder_padding_mask,[1])        # 扩展tensor的bacth维度
        encoder_out=paddle.nn.BeamSearchDecoder.tile_beam_merge_with_batch(encoder_output,self.beam_size)
        encoder_padding_mask=paddle.nn.BeamSearchDecoder.tile_beam_merge_with_batch(encoder_padding_mask,self.beam_size)

        seq_output,_=paddle.nn.dynamic_decode( decoder=self.beam_search_decoder,
                                               inits= decoder_initial_states,
                                               max_step_num= self.max_out_len,
                                               encoder_out=encoder_output,
                                               encoder_padding_mask=encoder_padding_mask)        
        return seq_output
    In [39]
def pre_process(seq,bos_idx,eos_idx):
    #print(bos_idx,eos_idx)
    # 结束位置
    eos_pos=len(seq)-1

    for i ,idx in enumerate(seq):        #print(i,idx[0])
        if idx==eos_idx: # 遇到结束标志
            eos_pos=i            break

    seq=[idx[0] for idx in seq[:eos_pos] if (idx !=bos_idx) ]    return seq
   

3.2 预测超参数

In [40]
beam_size=1bos_id=word2id_dict['<start>']
eos_id=word2id_dict['<end>']
max_out_len=couplet_maxlenprint(bos_id)
       
0
       

3.3 动态图转静态图

In [41]
x=paddle.to_tensor([[0  , 566, 566, 489, 42 , 165, 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  ]],dtype=paddle.int32)
y=paddle.to_tensor([7],dtype=paddle.int32)print(x)print(y)
       
Tensor(shape=[1, 34], dtype=int32, place=CUDAPlace(0), stop_gradient=True,
       [[0  , 566, 566, 489, 42 , 165, 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  ]])
Tensor(shape=[1], dtype=int32, place=CUDAPlace(0), stop_gradient=True,
       [7])
        In [42]
s2si=Seq2SeqInfer(word_size,embedding_dim,hidden_size,num_layers,bos_id,eos_id,beam_size,max_out_len)
dd=paddle.load('./trained_model/10.pdparams')
s2si.load_dict(dd)
net=paddle.jit.to_static(s2si)
out=net(x,y)
out
       
Tensor(shape=[1, 6, 1], dtype=int64, place=CUDAPlace(0), stop_gradient=False,
       [[[4 ],
         [24],
         [11],
         [75],
         [7 ],
         [1 ]]])
                In [43]
paddle.jit.s*e(net, './trained_model/net')
   

4.Android 开发

4.1 opt模型生成及优化

! pip install paddlelite==2.11-rc

! paddle_lite_opt --model_file=./trained_model/net.pdmodel --param_file=./trained_model/net.pdiparams --optimize_out=./trained_model/v1_opt·

4.2 下载预编译的预测库

可以参考官方文档 J*a完整示例

我使用的是2.11-rc版本

4.3 主代码展示

package com.baidu.paddle.lite;import android.content.Context;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.TextView;import j*a.io.BufferedOutputStream;import j*a.io.BufferedReader;import j*a.io.File;import j*a.io.FileInputStream;import j*a.io.FileOutputStream;import j*a.io.FileReader;import j*a.io.IOException;import j*a.io.InputStream;import j*a.io.InputStreamReader;import j*a.io.OutputStream;import j*a.util.Date;import j*a.util.HashMap;import j*a.util.Map;public class MainActivity extends AppCompatActivity {    public static final String TAG = "MainActivity";    private Button bt;    private EditText et;    public Map<String, String> word_id_map = new HashMap<String, String>();    public Map<String, String> id_word_map = new HashMap<String, String>();

    @Override    protected void onCreate(Bundle s*edInstanceState) {        super.onCreate(s*edInstanceState);
        setContentView(R.layout.activity_main);        //bt=(Button)findViewById(R.id.bt1);//        String path2="assets/word2id.txt";//        String path2="assets/id2word.txt";
        String np1 = copyFromAssetsToCache("word2id.txt", this);        String np2 = copyFromAssetsToCache("id2word.txt", this);        try {
            word_id_map=readTxtToObject(np1);
        } catch (IOException e) {
            e.printStackTrace();
        }        try {
            id_word_map=readTxtToObject(np2);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }    public void click(View v){        int id=v.getId();        switch (id) {            case R.id.bt1:
                Log.i("指定onClick属性方式","bt1点击事件");
                et=(EditText) findViewById(R.id.text_in);                String ss=et.getText().toString();//                Log.i("指定onClick属性方式",ss);//                Log.i("指定onClick属性方式", String.valueOf(ss.length()));//                Log.i("指定onClick属性方式",word_id_map.toString());
                int[] buffer1 = new int[]{0  , 1, 1, 1, 1 , 1, 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  ,                        1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1 };                for(int i=0;i<ss.length();i++) {                    //Log.i("指定onClick属性方式1", ss.substring(i, i+1));
                    //Log.i("指定onClick属性方式", word_id_map.get(ss.substring(i, i+1)));
                    buffer1[i+1]= Integer.parseInt(word_id_map.get(ss.substring(i, i+1)));                    if(i==34){                        break;
                    }
                }                //long[] dims1 = {1, ss.length()};
                long[] dims1 = {1, 34};                String re="";


                Tensor output=runModel("v1_opt.nb", dims1, buffer1, this);                long[] out = output.getLongData();                for(int i=0  ;i<out.length;i++){                    if( out[i]==1 || i==ss.length()){                        break;
                    }
                    Log.i("指定onClick属性方式1", String.valueOf(out[i]));
                    re+=id_word_map.get(String.valueOf(out[i]));
                }
                TextView textView = findViewById(R.id.text_view);
                textView.setText(re);                break;            case R.id.bt2:
                et=(EditText) findViewById(R.id.text_in);
                textView=(TextView)findViewById(R.id.text_view);
                textView.setText("");
                et.setText("");            default:                break;
        }

    }    public static Map<String, String> readTxtToObject(String ppath) throws IOException {
        Map<String, String> map = new HashMap<String, String>();
        File f=new File(ppath);        BufferedReader reader=new BufferedReader(new FileReader(f));        String lineTxt=null;        while((lineTxt=reader.readLine())!=null){            String[] names = lineTxt.split(" ");            map.put(names[0],  names[1]);
        }        return map;
    }    public static String getVersionInfo(String modelName, Context context) {        String modelPath = copyFromAssetsToCache(modelName, context);        //Log.d(TAG,modelPath);
        System.out.println(modelPath);
        MobileConfig config = new MobileConfig();
        config.setModelFromFile(modelPath);
        PaddlePredictor predictor = PaddlePredictor.createPaddlePredictor(config);        return predictor.getVersion();        //return modelPath;
    }    public static String copyFromAssetsToCache(String modelPath, Context context) {        //context.getCacheDir():获取应用缓存目录
        String newPath = context.getCacheDir() + "/" + modelPath;        //创建file对象
        File desDir = new File(newPath);        try {                // context.getAssets().open() 打开assets目录下的文件
                // Inputstream 字节输入流的最顶层父类
                InputStream stream = context.getAssets().open(modelPath);                // 创建BufferedOutputStream字节缓冲输出流
                OutputStream output = new BufferedOutputStream(new FileOutputStream(newPath));                byte data[] = new byte[1024];                int count;                while ((count = stream.read(data)) != -1) {
                    output.write(data, 0, count);
                }

                output.flush();//刷新缓冲输出流
                output.close();//关闭流
                stream.close();
        } catch (Exception e) {            throw new RuntimeException(e);
        }        return desDir.getPath();
    }    public static Tensor runModel(String modelName, long[] dims1, int[] inputBuffer1,Context context) {//    public static Tensor runModel(String modelName, long[] dims1, int[] inputBuffer1,//        long[] dims2, int[] inputBuffer2, Context context) {
        String modelPath = copyFromAssetsToCache(modelName, context);

        MobileConfig config = new MobileConfig();
        config.setModelFromFile(modelPath);
        config.setPowerMode(PowerMode.LITE_POWER_HIGH);
        config.setThreads(1);

        PaddlePredictor predictor = PaddlePredictor.createPaddlePredictor(config);//        System.out.println(predictor);//        System.out.println(predictor.getVersion());

        Tensor input1 = predictor.getInput(0);
        input1.resize(dims1);
        input1.setData(inputBuffer1);

        predictor.run();

        Tensor output = predictor.getOutput(0);       return output;
    }    public static Tensor setInputAndRunNaiveModel(String modelName, Context context) {        long[] dims1 = {1, 34};        int[] inputBuffer1 = new int[]{0  , 566, 566, 489, 42 , 165, 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  ,                1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1  , 1 };        return runModel(modelName, dims1, inputBuffer1, context);
    }    public static String getSecond(String first,Context context){        String result="";        return result;
    }
}
   

4.4 界面布局代码展示

<?xml version="1.0" encoding="utf-8"?><android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/rela"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gr*ity="center"
        tools:ignore="MissingConstraints">

    <EditText
        android:id="@+id/text_in"
        android:layout_width="fill_parent"
        android:layout_height="200dp"
        android:textSize="20dp"
        android:textStyle="bold"
        android:hint="请输入上联"
        android:gr*ity="center"
        android:textColorHint="#95A1AA"
        android:selectAllOnFocus="true"
        tools:ignore="MissingConstraints" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:layout_below="@id/text_in"
            android:gr*ity="center"
            >


        <Button
            android:id="@+id/bt1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/text_in"

            android:text="生成下联"
            android:onClick="click"
            tools:ignore="MissingConstraints" />



        <Button
            android:id="@+id/bt2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/text_in"
            android:layout_toRightOf="@id/bt1"
            android:text="清空"
            android:onClick="click"
            tools:ignore="MissingConstraints" />
        </LinearLayout>
    </RelativeLayout>


    <TextView
        android:id="@+id/text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="欢迎使用AI对联系统"
        android:padding="3dp"
        android:textSize="20dp"
        android:textStyle="bold"
        android:textColor="#000"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" /></android.support.constraint.ConstraintLayout>
   

以上就是【NLP+Android】AI 对联 APP的详细内容,更多请关注其它相关文章!


# ai  # 江苏网站建设如何  # 易搜 seo  # 我是  # 升级版本  # 安装包  # 多少个  # 一键  # 该项目  # 在这里  # 建立一个  # 的是  # type  # git  # switch  # 点击事件  # cos  # red  # perplexity  # udio  # fig  # opus  # 中文网  # 科技大国关键词排名  # 昆明如何网络营销推广  # 好网站建设工作  # 淘宝seo哪三家  # 潮州抖音seo优化优势  # 廉江网站建设推广订做  # 金昌口碑营销推广公司  # wp中文seo1001wp中文seo 


相关栏目: 【 Google疑问12 】 【 Facebook疑问10 】 【 优化推广96088 】 【 技术知识133117 】 【 IDC资讯59369 】 【 网络运营7196 】 【 IT资讯61894


相关推荐: 全新“AI助手”!讯飞星火助手中心人机协作共创新生态  从谷歌到亚马逊,科技巨头们的AI痴迷  腾讯TRS之元学习与跨域推荐的工业实战  7大探索区域打造沉浸式玩乐“元宇宙” 昆明京东MALL未来科技探索官全城招募中  研究预测HPC支持的人工智能增长迅速  Stability AI 推出文生图模型 SDXL0.9,GPU要求下探至消费级水平  当一切设备都受到人工智能的控制  Vision Pro 太贵,苹果基于 iPhone 的 VR 头显专利曝光  13条咒语挖掘GPT-4最大潜力,Github万星AI导师火了,网友:隔行再也不隔山了  马斯克回应“人工智能让一切变得更好”:我们已经是半机器人了  AI赋能艺术 超现实达利奇幻之旅在沪开启  华为AI大模型将融入HarmonyOS 4  国内首家,360智脑通过中国信通院可信AIGC大语言模型功能评估  卫星通信牵引物联网竞争升维,模组厂商如何决胜百亿市场?  专家解读国家网信办深度合成服务算法备案信息公告:不等于百度、阿里、腾讯等生成式AI产品获批  智能电网技术:提高能源效率和可靠性  七大主流AI企业包括OpenAI、谷歌等联合承诺:引入水印技术,并允许第三方审核AI内容  BLIP-2、InstructBLIP稳居前三!十二大模型,十六份榜单,全面测评「多模态大语言模型」  人工智能:解决劳动力短缺的关键策略  全场景智能车:智能无处不在|芯驰亮相世界人工智能大会  全国青少年无人机大赛重庆市选拔赛开赛 1252名中小学生参加  1.6亿美元收购Singularity AI,昆仑万维布局通用人工智能  工信部信通院发布《2025大模型和AIGC产业图谱》 360智脑覆盖全产业链  消息称 ChatGPT 未来有望增加更多功能:上传文件分析信息,还能记住用户画像  XREAL发布新款硬件XREAL Beam投屏盒子:可悬停AR空间屏  生成式AI与云结合,机遇与挑战并存  一文看懂被英伟达看中的九号机器人移动底盘  争鸣:OpenAI奥特曼、Hinton、杨立昆的AI观点到底有何不同?  MIT开发“PhotoGuard”技术保护图像免遭恶意AI编辑  发布最新版本的 PICO OS 5.7.0:支持VR头盔录屏并跨平台分享至微信  东软成立魔形科技研究院,积极布局大语言模型系统工程战略,迎接AI时代  清华系面壁智能开源中文多模态大模型VisCPM :支持对话文图双向生成,吟诗作画能力惊艳  人工智能如何与智能家居集成  30+大模型齐聚,大模型成世界人工智能大会“顶流”  如布科技发布新产品AI口袋学习机S12  OpenAI CEO 山姆・阿尔特曼呼吁 AI 领域中美应当合作  大语言模型的视觉天赋:GPT也能通过上下文学习解决视觉任务  全面拥抱大模型浪潮,ISC 2025打造全球首场AI数字安全峰会  彭博社:苹果Vision Pro曾测试VR手柄追踪方案  生成式AI引路产业加速来袭,微美全息探索“AIGC+虚拟人”融合应用  微软和谷歌面临的人工智能困境:需要投入大量资金才能获得盈利  华为小艺AI助手将实现强大的大模型能力  特斯拉 Optimus 人形机器人入驻北美门店,帮助提升汽车销量  央视报道!星纪魅族集团车载人机交互技术成世界移动通信大会焦点  史玉柱谈AI:国内最缺是计算数学人才,曾给浙大数学系捐五千万  人工智能产业竞跑“未来赛道” 创新发展放大“赋能”效应  字节、网易相继入局,AI之后大厂又找到下一个风口?  吉林首例!机器人辅助下搭桥手术成功实施  昇腾AI & 讯飞星火:深度联手,共话国产大模型“大未来”  Xbox游戏工作室负责人:VR/AR领域的用户规模还不足够 

 2025-07-29

了解您产品搜索量及市场趋势,制定营销计划

同行竞争及网站分析保障您的广告效果

点击免费数据支持

提交您的需求,1小时内享受我们的专业解答。

运城市盐湖区信雨科技有限公司


运城市盐湖区信雨科技有限公司

运城市盐湖区信雨科技有限公司是一家深耕海外推广领域十年的专业服务商,作为谷歌推广与Facebook广告全球合作伙伴,聚焦外贸企业出海痛点,以数字化营销为核心,提供一站式海外营销解决方案。公司凭借十年行业沉淀与平台官方资源加持,打破传统外贸获客壁垒,助力企业高效开拓全球市场,成为中小企业出海的可靠合作伙伴。

 8156699

 13765294890

 8156699@qq.com

Notice

We and selected third parties use cookies or similar technologies for technical purposes and, with your consent, for other purposes as specified in the cookie policy.
You can consent to the use of such technologies by closing this notice, by interacting with any link or button outside of this notice or by continuing to browse otherwise.