1. 前言
我一直有个口号:
我有两个爱好,一个是传统文化,一个是高新技术。
没错,我一直探索用高新技术来激活传统文化,用传统文化来滋养高新技术。人工智能概念股
我写了一个基于TensorFlow中GRU网络来自动对春联的程序测试抑郁症。
Inp测试抑郁症ut是人工输入的上联,Output是机器自动给出的下联。
Input: <start> 神 州 万 里 春 光 美 <end> [2, 61, 27, 26, 43, 4, 20, 78, 3]
Output:<start> 祖 国 两 制 好 事 兴 <end> [2, 138, 11, 120, 428, 73, 64, 46, 3]
Input: <start> 爆 竹 迎 新 春 <end> [2, 167, 108, 23, 9, 4, 3]
Output: <start> 瑞 雪 兆 丰 年 <end> [2, 92, 90, 290, 30, 8, 3]
Input: <start> 金 牛 送 寒 去 <end> [2, 63, 137, 183, 302, 101, 3]
Output: <start> 玉 鼠 喜 春 来 <end> [2, 126, 312, 17, 4, 26, 3]
Input: <start> 锦 绣 花 似 锦 <end> [2, 68, 117, 8, 185, 68, 3]
Output: <start> 缤 纷 春 如 风 <end> [2, 1651, 744, 4, 140, 7, 3]
Input: <start> 春 风 送 暖 山 河 好 <end> [2, 4, 5, 183, 60, 7, 71, 45, 3]
Output: <start> 瑞 雪 迎 春 世 纪 新 <end> [2, 92, 90, 27, 4, 36, 99, 5, 3]
Input: <start> 百 花 争 艳 春 风 得 意 <end> [2, 48, 8, 164, 76, 4, 5, 197, 50, 3]
Output: <start> 万 马 奔 腾 喜 气 福 多 <end> [2, 6, 28, 167, 58, 17, 33, 15, 113, 3]
2. 数据的准备
人工tensorflow2.0教程智能的背后是大量数据的训练,关于数据来源,我还有一篇文章《没啥才人工智能的定义艺,30行代码写了个春联数据爬虫》,主要讲述如何从网络上爬取春联数据。
我们就有了春联数据,就可以开始进行训练了。
2.1 导入所需要的包
不管是哪种开发语言,首先是导入包,导入的每一个都是有用的。
# tensorflow主包
import tensorflow as tf
# 分词器,将文字变为数字
from tensorflow.keras.preprocessing.text import Tokenizer
# 把序列填充,让数据长度相等,不足的补0
from tensorflow.keras.preprocessing.sequence import pad_sequences
# 维度数组与矩阵运算的数学函数库
import numpy as np
# 神经网络的序列
from tensorflow.python.keras.engine.sequential import Sequential
# 将训练集按照一定比例拆分为训练和测试数据
from sklearn.model_selection import train_test_split
# 神经网络的层
from tensorflow.keras import layers
# 神经网络的优化器
from tensorflow.keras.optimizers import Adam
# 系统文件一些操作
import os
# 时间
import time
2.2 读取要测试你的自卑程度训练的数据
首先要把我们准备的数据进行预处理。
你得从文件中读出文本吧,读完了还得分出测试你的自卑程度上下联单独存储吧,因为上联是输入,下联是输出,都要告诉机器的。机器呢,它又只认识数字,不认识文字。所以,你还得把它们转化成数字(这一步叫序列化)。
下面一段代码,做的事情是从.txt中读取文本,然后将文本拆分保存到上联、下联两个数组中。
# 给一段文本加上开始和结束标记,主要是告诉机器什么时候开始,什么时候结束
def preprocess_sentence(w):
w = w.strip()
w = '<start> ' + w + ' <end>'
return w
# 加载一定条数的数据
def load_data(num = 10000):
# 保存上联(input)和下联(target)的数组
inp_lang = []
targ_lang = []
# 指定文件位置(同级目录data下的data.txt文件)
file = open('F://all.txt','rb')
line = file.readline()
# 读取一行文本,如果此行存在
while line:
# 读出内容:【春 来 眼 际 , 喜 上 眉 梢】拆分上下联
wstr = str(line, encoding = "utf-8")
wstrs = wstr.split(',')
if len(wstrs) > 1:
inp_lang.append(preprocess_sentence(wstrs[0]))
targ_lang.append(preprocess_sentence(wstrs[1]))
# 接着再读下一行
line = file.readline()
# 如果超过预设最大数量,则退出循环
if len(inp_lang) > num:break
file.close()
return inp_lang, targ_lang
特别说明一下,文本内容样式是:
春 来 眼 际 , 喜 上 眉 梢
春 光 普 照 , 福 气 长 临
春 和 景 明 , 物 阜 年 丰
每个字之间都有人工智能al女神古力娜扎一个空格,主要目的是中文gitlab分词。上下联之间使用gitee,
区分。
调用一下,打印出两个数组如下:
inp_lang, targ_lang = load_data()
print("inp_lang=>","\n ",inp_lang,"inp_lang=>","\n ", targ_lang)
'''
inp_lang => ['<start> 春 来 眼 际 <end>', '<start> 春 光 普 照 <end>']
targ_lang=> ['<start> 喜 上 眉 梢 <end>', '<start> 福 气 长 临 <end>']
'''
2.3 将文本进行序列化
我们获得了上面人工智能概念股文字版的标准结构。但是,机器不认识,需要将他们变成数字版的。
下面我们要做的基本上就是要将人工智能的定义“床前明月光”变为“65498人工智能技术应用”。
# 分词器,将文本转化为序列:上天言好事->65234
def tokenize(lang):
# 创建分词器,默认以空格分词
lang_tokenizer = Tokenizer(oov_token='<OOV>', filters='',split=' ')
# 分词器设置处理训练的文本。 {'<end>': 2,'<start>': 1,'下': 54,'不': 5}
lang_tokenizer.fit_on_texts(lang)
# 分词器序列化文本为数字。[[18, 19],[1, 18, 19,20]]
tensor = lang_tokenizer.texts_to_sequences(lang)
max_sequence_len = max([len(x) for x in tensor])
# 预处理文本,补齐长度,统一格式 [[0, 0, 18, 19],[1, 18, 19, 20]]
tensor = pad_sequences(tensor, maxlen=max_sequence_len)
# 将序列化后的数字和包含段落信息的分词器返回
return tensor, lang_tokenizer
input_tensor, inp_lang_tokenizer = tokenize(inp_lang)
target_tensor, targ_lang_tokenizer = tokenize(targ_lang)
返回值里面,第一tensor是文字转变的数字,第二个lang_tokenizer是吃透了这段文本的分词器,里面包含了这段文本的信息,比如总共多少个字,这些字都是什么,每个字的编号是多少,相当于一个“数据管家”。
里面涉及到了一些知识点:Tokenizer、texts_to_sequences、pad_sequenc机器学习es。我都给你准备好了,你不点一下吗?
到了这里,春联里的上联和TensorFlow下联的序列化数据,我们就都有了。
上联是:[[1,3,5,7,9]]。下联是:[[2,4,6,8,0]]。
2.4 做更适合框架的数据
看似到这一步就可以了,但是为了更好地融入机器学习框架的体系,还需要对数据进一步加工和处理。tensorflow是干什么的
# 包装成TF需要的格式,采用8:2切分训练集和验证集
input_tensor_train, input_tensor_val, target_tensor_train, target_tensor_val = train_test_split(input_tensor, target_tensor, test_size=0.2)
BUFFER_SIZE = len(input_tensor_train) # 训练集的大小
BATCH_SIZE = 64 # 批次大小,一次取多少条数据
# 一轮训练,需要几步取完所有数据
steps_per_epoch = len(input_tensor_train)//BATCH_SIZE
# 将数据集顺序打乱
dataset = tf.data.Dataset.from_tensor_slices((input_tensor_train, target_tensor_train)).shuffle(BUFFER_SIZE)
# 生成训练批次,N批64条的数据drop_remainder=True最后一个批次不够的舍弃,去除余数。
dataset = dataset.batch(BATCH_SIZE, drop_remainder=True)
tr人工智能的定义ain_test_split
会按照一定的比例,将数据切分为训练数据和验证数据。
即便如此,数据量可能还是巨大的,比如500万条。一次吃起来太费劲,所以就有了一个批次batch
的概念,它表示每次取多少条数据BATCH_SIZE
进行处理。所有数据,按照一批一批地取,tensorflow菜鸟教程全部扫个遍,我们称为一个周期epoch
。每取一次数据进行处理,称为走了一步step
。
这些都是这个行业的黑话(shuyu)git教程。
3. 模型的人工智能al女神古力娜扎构建
模型是个啥?这里是有关神经网络模型的序列和层、激活函数的介绍。
看看最好,不看也行,我再简单一说。
模型就好比工厂里流水线的机器,塞进去原料,吐出来成品。
就如同一个小孩,你教测试抑郁症的20道题给他认识苹果、桔子、人工智能技术应用香蕉、梨这些都是人工智能之父水果tensorflow菜鸟教程,他自己找特点总结规律,最终开悟了。后面,你给他一个猕猴桃和馒头,他能清楚地知道馒头和水果不测试用例是一类东西。具体他怎么判断的,是基于他大脑里那个固定的模型推演的,大脑的结构是固定的,但是思维方式的变化的。测试手机是否被监控
对于人工智能来说也类github永久回家地址似,我们要构建的模型就是大脑的结构。
要实现自动对对联的功能,我们也得构建一个模型,让数据按照这种结构去自己组织和思考,最终让它具git命令备思维。
3.1 GRU神经网络
我们听github永久回家地址说过很多种神经网络,他们各有特点,就像京东、天猫gitlab、拼多多的差别一样,我们也需要测试抑郁症的20道题从众多网络中选取一个来解决问题。
本giti是什么牌子例子中,我们选择了GRU神经网络。
很遗憾,百度百科上都没有GRU的词giti是什么牌子条。我们想学点人工智能真的很难,找不到靠谱的资料。我想这也是为什么我这么菜,还有人来看我博客的原因。
GRU是RNN(Recugithub永久回家地址rrent NeTensorFlowural Network人工智能换脸鞠婧祎郑爽-循环神经网络)的一种。RNN上个世纪就出现了,但是有硬伤。后来,在1997年就出现了LSTM(Long-Short Term Memory-长短期记忆人工神经网人工智能电影络),但是它也有很多弊端。于是,在2014年,就出现了GRU(Gate Recurrent Unit-门循环单元)来救场。目前来看,用着还行。
说这github些测试抑郁程度的问卷的目的,主要是想说明你要想了解GRU,其实得先了解RNN。它是处理一段序列的,不同于图像识别处理单张图片,它更像是处理一段视频tensorflow菜鸟教程。那人工智能专业是后话,现在可以先了解一下我讲的GRU。
下面是GRU的示意图。
能看懂最好,看不懂也不强求,它人工智能概念股可能影响你的研究,但是绝对不影响你的使用。
我还是忍不住想解释一下。
我们看到这个单元有两个输入:h0、x1,输出了下一个h1。这里面x1是测试用例序列里某一时段的输入,h0是上一个序tensorflow安装列传来的状态,经过一番运测试抑郁程度的问卷算tensorflow版本,得出下一个状态h1。拿对联举例子,比如“春光普照”这一句。
序列 | x1 | h0 | h1 |
---|---|---|---|
1 | 春 | 前面没东西 | 后面的,你注意“春” |
2 | 光 | 上面好像说到“春”了 | 上家是“春”,tensorflow菜鸟教程我这里是“光” |
3 | 普 | 上面有提到“gitee春光” | “光”无所谓,把“春”记好就行,我出“普” |
4 | 照 | “春”是一tensorflow和pytorch的区别个季节,“普”是全的意思 | …… |
它就是这么朴实无华,同一个结构,一遍遍地去循环,但是每Git次都得到了新的信息保存在h里遗传下去,于是就拥有tensorflow训练模型了记忆。
字——,机器是不认识的,即便是变成了数字,它也是理解不了语义的,他需要转为多维向量来解释这一切,这一步叫编码。
为什么要编码,可以去了解下嵌入Embedding的概念。
编好码之后,对联数据就这样交给神经网络,训练上几次,它就学到里面的“道”、“规则”、“猫腻”。它就会特别注意,字与字之间是如何联系的,一句话之中,前言和后语是如何对应的。其实都是多维向量之间的参数计算人工智能。
训练时,神经网络计算出了向量参数,也就是评委团tensorflow2.0教程。当我们想要让它预测的时候,可以将向量转化为字符,这tensorflow是干什么的个过程叫做解码。
所人工智能的定义以,训练和预测的流程就是:编码—观察计算总结—解码对照答案。
3.2 编码器
首先我们将序列进行编码,也就是把输入进行升维。有了前面的介绍,相信下面这30行代码你可以轻松掌握了。
embedding_dim = 256 # 嵌入层的维度
units = 1024 # 神经元数量
# 输入集字库的数量,+1是因为有长度不够时,为了凑数的补0
vocab_inp_size = len(inp_lang_tokenizer.word_index)+1
# 输出集字库的数量,+1是因为有0
vocab_tar_size = len(targ_lang_tokenizer.word_index)+1
# 编码器,把数据转化为向量
class Encoder(tf.keras.Model):
def __init__(self, vocab_size, embedding_dim, enc_units, batch_sz):
super(Encoder, self).__init__()
self.batch_sz = batch_sz # 每次批次大小
self.enc_units = enc_units # 神经元数量
# 嵌入层(字符数量,维度数)
self.embedding = tf.keras.layers.Embedding(vocab_size, embedding_dim)
# 门控循环单元 GRU
self.gru = tf.keras.layers.GRU(self.enc_units, # 神经元数量
return_sequences=True, # 返回序列
return_state=True, # 返回状态
recurrent_initializer='glorot_uniform') # 选择初始化器,固定值
def call(self, x, hidden):
x = self.embedding(x)
output, state = self.gru(x, initial_state = hidden)
return output, state
def initialize_hidden_state(self):
return tf.zeros((self.batch_sz, self.enc_units))
encoder = Encoder(vocab_inp_size, embedding_dim, units, BATCH_SIZE)
基本思路就是:每个字拆分出上百个维度,然后和上千个神经元进行运算,通过自己猜测的结果和标准输出进行比较,最终得出最适合的参数值。
3.3 注意力机器
如果只有编码和解码,流程就像下面这样,是可以满足需求的。
但是,这也有问题。当预测Y1时,Git评委是c,预人工智能测Y2时评委也是c,也就是说某时段的X对Ygitlab的影响是相同的。
但是,实际上一个序列中前后的内容是有关联的,比如这样一句话:我没有否定我不是不想你。如果只有一个固定评委,句子越长,携带的信息就会被稀释的越严重。
所以,除了全局状态之外,也需要关注局部的状态,测试抑郁症因此需要引入注意力机器。
引入注意力机制之后,“我没有否定我不是不想你”中的否定词语将被注意或者忽略。把“没有”、“否定”、“不是”、“不”去掉,这句话就变成了“我想你”。
其实,注意力机制就是一个权重配置。
# 注意力机器
class BahdanauAttention(tf.keras.layers.Layer):
def __init__(self, units):
super(BahdanauAttention, self).__init__()
self.W1 = tf.keras.layers.Dense(units)
self.W2 = tf.keras.layers.Dense(units)
self.V = tf.keras.layers.Dense(1)
def call(self, query, values):
# 隐藏层的形状 == (批大小,隐藏层大小)
# hidden_with_time_axis 的形状 == (批大小,1,隐藏层大小)
# 这样做是为了执行加法以计算分数
hidden_with_time_axis = tf.expand_dims(query, 1)
# 分数的形状 == (批大小,最大长度,1)
# 我们在最后一个轴上得到 1, 因为我们把分数应用于 self.V
# 在应用 self.V 之前,张量的形状是(批大小,最大长度,单位)
score = self.V(tf.nn.tanh(self.W1(values) + self.W2(hidden_with_time_axis)))
# 注意力权重 (attention_weights) 的形状 == (批大小,最大长度,1)
attention_weights = tf.nn.softmax(score, axis=1)
# 上下文向量 (context_vector) 求和之后的形状 == (批大小,隐藏层大小)
context_vector = attention_weights * values
context_vector = tf.reduce_sum(context_vector, axis=1)
return context_vector, attention_weights
上面输出一个向Git量和它的权人工智能技术应用重。
3.4 解码器
下面是解码器的代码,它和编码相反。最终是降维,将多维向量再复原到语料库中。
# 解码器
class Decoder(tf.keras.Model):
def __init__(self, vocab_size, embedding_dim, dec_units, batch_sz):
super(Decoder, self).__init__()
self.batch_sz = batch_sz
self.dec_units = dec_units
self.embedding = tf.keras.layers.Embedding(vocab_size, embedding_dim)
self.gru = tf.keras.layers.GRU(self.dec_units,
return_sequences=True,
return_state=True,
recurrent_initializer='glorot_uniform')
self.fc = tf.keras.layers.Dense(vocab_size)
# 用于注意力
self.attention = BahdanauAttention(self.dec_units)
def call(self, x, hidden, enc_output):
# 编码器输出 (enc_output) 的形状 == (批大小,最大长度,隐藏层大小)
context_vector, attention_weights = self.attention(hidden, enc_output)
# x 在通过嵌入层后的形状 == (批大小,1,嵌入维度)
x = self.embedding(x)
# x 在拼接 (concatenation) 后的形状 == (批大小,1,嵌入维度 + 隐藏层大小)
x = tf.concat([tf.expand_dims(context_vector, 1), x], axis=-1)
# 将合并后的向量传送到 GRU
output, state = self.gru(x)
# 输出的形状 == (批大小 * 1,隐藏层大小)
output = tf.reshape(output, (-1, output.shape[2]))
# 输出的形状 == (批大小,vocab)
x = self.fc(output)
return x, state, attention_weights
decoder = Decoder(vocab_tar_size, embedding_dim, units, BATCH_SIZE)
这样,编码器,解码器Git,注意力机器,都有了,下面测试用例就可以进行数据训练了。
4. 训练数据
上面,格式化的训练数据准备好了。模型也准备好了,下面就该训练了。
训练就是把数据,按照模型预设的层次(网络结构),按照一定的幅度(损失函数)进行探索。
4.1 损失函数
下面是损失函数的设置,同时也设置了训练结果文件的保存位置。
optimizer = tf.keras.optimizers.Adam()
loss_object = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True, reduction='none')
# 保存训练数据的位置,此处设置了绝对路径
checkpoint_dir = 'F://juejin_chunlian/training_checkpoints'
checkpoint_prefix = os.path.join(checkpoint_dir, "ckpt")
checkpoint = tf.train.Checkpoint(optimizer=optimizer,encoder=encoder,decoder=decoder)
def loss_function(real, pred):
mask = tf.math.logical_not(tf.math.equal(real, 0))
loss_ = loss_object(real, pred)
mask = tf.cast(mask, dtype=loss_.dtype)
loss_ *= mask
return tf.reduce_mean(loss_)
4.2 训练一步
下面这个函数,就是执行一步训练的。
@tf.function
def train_step(inp, targ, enc_hidden):
loss = 0
with tf.GradientTape() as tape:
enc_output, enc_hidden = encoder(inp, enc_hidden)
dec_hidden = enc_hidden
dec_input = tf.expand_dims([targ_lang_tokenizer.word_index['<start>']] * BATCH_SIZE, 1)
# 强制 - 将目标词作为下一个输入
for t in range(1, targ.shape[1]):
# 将编码器输出 (enc_output) 传送至解码器
predictions, dec_hidden, _ = decoder(dec_input, dec_hidden, enc_output)
loss += loss_function(targ[:, t], predictions)
# 使用强制
dec_input = tf.expand_dims(targ[:, t], 1)
batch_loss = (loss / int(targ.shape[1]))
variables = encoder.trainable_variables + decoder.trainable_variables
gradients = tape.gradient(loss, variables)
optimizer.apply_gradients(zip(gradients, variables))
return batch_loss
将上联输入giti是什么牌子序列、下联输出序列、编码隐藏层传入,它最终返回本次训练的损失情况。
损失越小,说明越好,和预期越接近。
4.3 多轮训练
上面是tensorflow菜鸟教程训练一步。
我们知道,所有数据扫个遍gitlab叫一个epoch
,tensorflow版本对应一个epoch
需要好多步才能完成。但是,我们还需要训练多个epoch
。
EPOCHS = 2000
for epoch in range(EPOCHS):
start = time.time()
enc_hidden = encoder.initialize_hidden_state()
total_loss = 0
for (batch, (inp, targ)) in enumerate(dataset.take(steps_per_epoch)):
batch_loss = train_step(inp, targ, enc_hidden)
total_loss += batch_loss
if batch % 10 == 0:
print('Epoch {} Batch {} Loss {:.4f}'.format(epoch + 1, batch,batch_loss.numpy()))
# 每10个周期(epoch),保存(检查点)一次模型
if (epoch + 1) % 10 == 0:
print('save model')
checkpoint.save(file_prefix = checkpoint_prefix)
print('Epoch {} Loss {:.4f}'.format(epoch + 1,total_loss / steps_per_epoch))
print('Time taken for 1 epoch {} sec\n'.format(time.time() - start))
就这样github中文官网网页训练吧。tensorflow和pytorch的区别
后面你就静静地看着日志打印,等着它训练完成。
这个过程很慢,具体看你的机器giti轮胎情况。
我机器并不好,训练一轮大约30分钟。开始没有耐心,急于验证效果,训练100轮就停止了,试了下它对出来的下联是什tensorflow菜鸟教程么样子的,结果连字数一致都没法保证,更别提意义相对,效果那叫一个差测试工程师。
我减少春联条数到200条,增大训练轮数giti到1000次,效果也是很差,giti我一度认为是算法有问题。
后来,耐下心来,大数据量下的千轮级别的大出血训练了好几天,效人工智能技术应用果就好了不少。看来,机器学测试抑郁程度的问卷习的两个基础真的很重要:大数据量、多训练次数。而好的算法,是后面的事情。测试仪
5. 验证效果
最后Git是验证效果。
def max_length(tensor):
return max(len(t) for t in tensor)
# 计算目标张量的最大长度 (max_length)。如果训练集确定,其实这个可以写个固定的。
max_length_targ, max_length_inp = max_length(target_tensor), max_length(input_tensor)
def evaluate(sentence):
sentence = preprocess_sentence(sentence)
inputs = [inp_lang_tokenizer.word_index[i] for i in sentence.split(' ')]
print("inputs:",inputs)
inputs = pad_sequences([inputs], maxlen=max_length_inp)
inputs = tf.convert_to_tensor(inputs)
result = ''
hidden = [tf.zeros((1, units))]
enc_out, enc_hidden = encoder(inputs, hidden)
dec_hidden = enc_hidden
dec_input = tf.expand_dims([targ_lang_tokenizer.word_index['<start>']], 0)
outputs = []
for t in range(max_length_targ):
predictions, dec_hidden, attention_weights = decoder(dec_input,dec_hidden, enc_out)
predicted_id = tf.argmax(predictions[0]).numpy()
outputs.append(predicted_id)
result += targ_lang_tokenizer.index_word[predicted_id] + ' '
if targ_lang_tokenizer.index_word[predicted_id] == '<end>':
print("outputs:",outputs)
return result, sentence
# 预测的 ID 被输送回模型
dec_input = tf.expand_dims([predicted_id], 0)
return result, sentence
# 恢复检查点目录 (checkpoint_dir) 中最新的检查点
checkpoint.restore(tf.train.latest_checkpoint(checkpoint_dir))
s = '百 花 争 艳 春 风 得 意'
result, sentence = evaluate(s)
print('Input: %s' % (sentence))
print('Predicted: {}'.format(result))
最后结果就是:
Input: <start> 百 花 争 艳 春 风 得 意 <end> [2, 48, 8, 164, 76, 4, 5, 197, 50, 3]
Predicted: <start> 万 马 奔 腾 喜 气 福 多 <end> [2, 6, 28, 167, 58, 17, 33, 15, 113, 3]
6. 其他
带上注释才300行代码,去了注释估计也就200出头。但是,它却实现了一个完整的对春联的基本功能。
有一些知识点没有讲的太细,比如损失函数、优化器这些,我打算以后专项再讲测试工程师。
其实,这个例子正统是tensorflow官网用于语言翻译的(原文链接),比如西班牙语翻译英语。
我此测试手机是否被监控处是尝试用于对春联,但是看效果也可以。
它也可以用于文言文翻译白话文,原理都是一样机器学习的,它支持输入输出的长度不一样。
github上传了dem人工智能专业o代码和8000条春联训练数据 hlwgy/co测试工程师uplets:自动对春联 (github.com)。