因为最近这些天都在人工审查之前的哪些问答数据,所以迟迟都没有更新 AutoKeras 的练习成果。现在那部分数据都现已收拾好了,20w+ 的数据终究能够运用的高质量数据只剩下 2k+。这 2k+ 的数据现现已过数据校验并且对部分问题的发问办法和答案内容进行了不改动本意的重构,相信用这部分数据进行练习将会得到满足的作用。

在正式解说之前,仍是先将一些概念性的内容讲一下。

为什么选 AutoKeras?

首要作为一名人工智能的初学者是会存在挑选困难症的(毕竟人工智能种类五花八门,各有各特色。学习和施行门槛也各不相同,挺难挑选的),去生啃论文又看得云里雾里。再加上小公司要快速产出,上级一向输出压力,整个人会越来越焦躁,也越来越学不下去。就在这时我遇到了 AutoML 的 AutoKeras,它简直便是初学者的救星。

AutoKeras 依据 Keras,而 Keras 又依据 Tensorflow。Tensorflow 发展了这么久了社区十分庞大且活泼,小白不明白的地方要找查证资料也比较简略。除此之外,AutoKeras 经过结合运用神经网络查找算法和贝叶斯优化来查找给定数据集的最佳模型架构和超参数,因而它的参数简直都是可选的。它的详细实现是先创立一组具有不同架构和超参数的模型,然后在数据集上对其进行评价。终究依据模型的性能对模型进行排名,并挑选最佳模型(这关于初学者来说真的十分友爱!!)。AutoKeras 还供给了易于运用的 API,供开发人员快速开始深度学习。简略来说,只要你会 Python,会调用 API,再准备好你的数据,就能快速构建和布置模型。公司领导是“面向成果”管理的,关于他来说你能够快速产出比什么都重要。

什么是 AutoML 模型?

AutoML(Automated Machine Learning)是指运用主动化技能来简化机器学习模型的构建和练习过程的办法。个人觉得 AutoML 的最大优势在于下降了运用机器学习的门槛,即使像我这种初学者也能够轻松运用。

什么是 CNN?什么是 RNN?

先说 CNN,CNN 是卷积神经网络(Convolutional Neural Network)的简写,它主要由卷积层(Convolutional Layer)、池化层(Pooling Layer)和全衔接层(Fully Connected Layer)组成。简略来说,这三层的分工便是卷积层担任学习图画中的特征,池化层用于下降卷积层输出的空间维度,一起保存要害信息,而全衔接层则用于将卷积和池化层的输出映射到终究的输出类别。依据这种特征,CNN 多用于处理和剖析视觉数据,像图画识别、检测、生成等处理十分出色。

循环神经网络(Recurrent Neural Network,RNN)是一类用于处理序列数据的神经网络。它在处理序列数据时具有回忆性,能够坚持对从前输入的回忆,并在处理新输入时运用这些回忆。RNN 的根本结构是经过将网络的输出反馈到输入中,以实现对序列数据的处理。而咱们的方针是练习一个问答机器人,这种自然语言处理的人工智能十分适合运用 RNN 进行练习。

(那些过分深邃的原理等等我也不太会,以上都是我看完了之后的一些总结,如有疏忽的地方请各位纠正,谢谢)

开始练习

好了,上面根底概念的想说的都说了,下面就开始说说我是怎样做练习的吧。

更新榜首篇文章中建立的练习环境插件,如下图:

# 更新 pip
python3 -m pip install --upgrade pip
# 安装 pymysql 插件(因为数据需求从 mysql 中提取)
pip install pymysql

接着我就按照 AutoKeras 官网供给的例子进行了练习,但练习其实遇到了许多的问题。

榜首次练习时我直接调用 TextClassifier 这个高档 API,然而在练习到第三循环时就报错了,如下图:

Search: Running Trial #3
Value             |Best Value So Far |Hyperparameter
bert              |transformer       |text_block_1/block_type
0                 |0                 |classification_head_1/dropout
adam_weight_decay |adam              |optimizer
2e-05             |0.001             |learning_rate
512               |None              |text_block_1/bert_block_1/max_sequence_length
Downloading data from https://storage.googleapis.com/keras-nlp/models/bert_base_en_uncased/v1/vocab.txt
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/urllib/request.py", line 1350, in do_open
    h.request(req.get_method(), req.selector, req.data, headers,
...
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1124)
....
    raise Exception(error_msg.format(origin, e.errno, e.reason))
Exception: URL fetch failure on https://storage.googleapis.com/keras-nlp/models/bert_base_en_uncased/v1/vocab.txt: None -- [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1124)
Trial 3 Complete [00h 00m 00s]

上面的报错说 block_type 在运用 bert 类型的时分就呈现了错误,疑似是需求经过网络下载某些东西之后才能继续。已然就在原代码中参加以下两行代码来躲避掉 https 的验证,如下图:

# 引入 ssl 模块
import ssl
# 设置 ssl 验证
ssl._create_default_https_context = ssl._create_unverified_context

参加以上代码后又能够继续练习了,接着又呈现了以下报错,如下图:

Traceback (most recent call last):
  File "/Users/yuanzhenhui/Documents/code_space/git/processing/python/autokeras-env/phw2-industry-bot/model_train.py", line 130, in <module>
    main()
...
    raise e.with_traceback(filtered_tb) from None
  File "/Users/yuanzhenhui/Documents/code_space/git/processing/python/autokeras-env/lib/python3.8/site-packages/tensorflow/python/eager/execute.py", line 53, in quick_execute
    tensors = pywrap_tfe.TFE_Py_Execute(ctx._handle, device_name, op_name,
tensorflow.python.framework.errors_impl.InvalidArgumentError: Graph execution error:
indices[18] = -1 is not in [0, 50)
         [[{{node embedding_lookup}}]]
         [[IteratorGetNext]] [Op:__inference_test_function_7479]
Segmentation fault: 11

经过网上的查找发现,这个问题是测试数据跟练习数据呈现较大差异时造成的。

这是因为我的练习数据、测试数据和验证数据都是独立构造出来的,虽然都是存放在同一张表中,但因为数据量较为庞大,因而难以保证所有数据向量都共同的状况这仍然是数据质量的问题。因为并不知道详细那条数据存在问题,于是只能减缩取数的规模后进入下一轮练习,如下图:

Search: Running Trial #4
Value             |Best Value So Far |Hyperparameter
vanilla           |vanilla           |text_block_1/block_type
none              |none              |text_block_1/embedding_1/pretraining
64                |64                |text_block_1/embedding_1/embedding_dim
0.25              |0.25              |text_block_1/embedding_1/dropout
5                 |5                 |text_block_1/conv_block_1/kernel_size
False             |False             |text_block_1/conv_block_1/separable
False             |False             |text_block_1/conv_block_1/max_pooling
1                 |1                 |text_block_1/conv_block_1/num_blocks
1                 |1                 |text_block_1/conv_block_1/num_layers
256               |256               |text_block_1/conv_block_1/filters_0_0
512               |512               |text_block_1/conv_block_1/filters_0_1
0                 |0                 |text_block_1/conv_block_1/dropout
64                |64                |text_block_1/conv_block_1/filters_1_0
256               |256               |text_block_1/conv_block_1/filters_1_1
0                 |0                 |classification_head_1/dropout
adam              |adam              |optimizer
0.001             |0.001             |learning_rate
Traceback (most recent call last):
  File "/Users/yuanzhenhui/Documents/code_space/git/processing/python/autokeras-env/lib/python3.8/site-packages/keras_tuner/src/engine/base_tuner.py", line 273, in _try_run_and_update_trial
    self._run_and_update_trial(trial, *fit_args, **fit_kwargs)
...
    max_tokens = self.max_tokens or hp.Choice(
  File "/Users/yuanzhenhui/Documents/code_space/git/processing/python/autokeras-env/lib/python3.8/site-packages/keras_tuner/src/engine/hyperparameters/hyperparameters.py", line 300, in Choice
    return self._retrieve(hp)
  File "/Users/yuanzhenhui/Documents/code_space/git/processing/python/autokeras-env/lib/python3.8/site-packages/keras_tuner/src/engine/hyperparameters/hyperparameters.py", line 208, in _retrieve
    return self.values[hp.name]
KeyError: 'text_block_1/max_tokens'
Trial 4 Complete [00h 00m 04s]
Best val_loss So Far: 4.101563930511475
Total elapsed time: 00h 24m 03s

又来了一个新问题,“实践 tokens 长度大于最大 tokens 长度”导致无法继续练习下去。其实这个问题才是 AutoML 较为丧命的。因为 AutoML 会主动调整参数,这或许会将部分参数调整过大,导致终究超出了硬件可支持的阈值。并且这事儿呈现概率还挺高的,因而你最好提前设定最大值让 AutoML 不要主动给你调这个参数了,或许你供给满足的资源其实也行。毕竟谁都不想练习好几天终究因为超出阈值停止练习。不过还好在 AutoKeras 中是供给参数挑选是否对练习好的内容进行掩盖的,假如不掩盖那么本来练习好的数据仍是会保存。

言归正传,上面这个报错只需求将 max_tokens 参数调大就能够了(下面将供给完成代码)。

终究我想说的是,做这个练习仍是要用 GPU 来做吧,虽然 AutoKeras 也承继了 Tensorflow 能够运用 CPU 来进行练习,但是速度太慢了。因而仍是建议各位在做练习的时分先找一台 Windows 的机器,里面装好 Nvidia 显卡装备好 CUDA 和 cuDNN。我自己亲测,快的不是一丁半点。

好了,上要害代码如下图:

...
def ak_qa_train_main(page, page_size):
    ...
    if tr_data.shape[0] != 0:
        # 自定义练习模型收拾
        text_input = ak.TextInput()
        # 直接运用 textblock 来对数据进行练习
        text_output = text_block_model(text_input)
        model = ak.AutoModel(inputs=text_input, outputs=text_output, project_name=auto_model_path, overwrite=True)
        # 练习模型
        model_fit = model.fit(tr_data[:, 0], tr_data[:, 1], batch_size=32, validation_split=0.15)
        print('history dict:', model_fit.history)
        # 将练习好的模型导出
        model.export_model().save(export_model_path, save_format="tf")
    ...
def text_block_model(input_node):
    output_cnn_block = ak.TextBlock(max_tokens=200000)(input_node)
    output_rnn_block = ak.TextToIntSequence(output_sequence_length=32, max_tokens=200000)(input_node)
    output_rnn_block = ak.Embedding()(output_rnn_block)
    output_rnn_block = ak.Normalization()(output_rnn_block)
    output_rnn_block = ak.RNNBlock(layer_type="lstm", return_sequences=True)(output_rnn_block)
    output_rnn_block = ak.DenseBlock()(output_rnn_block)
    output_block = ak.Merge()([output_cnn_block, output_rnn_block])
    return ak.ClassificationHead()(output_block)
...

以上代码中 ak_qa_train_main 内代码为榜首处要害代码,这儿我并没有用到 AutoKeras 的高档 API 进行练习(经过反复的实验发现高档 API 存在大量运用约束)而采用了自定义模型(AutoModel)的办法进行练习,因而我必须在练习前先定义好练习模型。

练习模型需求一个数据输入,而因为咱们是文本的练习数据,因而需求实例化一个 TextInput 作为练习数据输入。

而 text_block_model 办规律作为练习流程被运用(此处为第二处要害代码,下面会详细阐明),它的返回将会作为练习成果进行输出。这样咱们就有了输入和输出了,之后就能够将其指定到 AutoModel 的对应参数中。

AutoModel 履行之后将会得到一个 model 目标,有了 model 目标就能够进行实在的练习了,这时你只需求调用 fit API 就能履行练习。其间 fit 的榜首个参数应该传入“问题”数据集,第二个参数传入“答案”数据集,第三个参数 batch_size 便是一次性提取练习数据的批次巨细。

之后咱们需求经过 model_fit.history 检查一下模型的丢失(loss)和准确度(accuracy),用于判断模型是否适用。终究咱们会经过 model.export_model().save() 来保存模型,然后经过 loss 和 accuracy 判断终究保存哪个模型,删除掉那个模型。

这样咱们就现已将练习的根底装备和调用代码写好了,是不是十分简略。

那么接下来咱们就来说说第二处要害代码 text_block_model ,如下图:

def text_block_model(input_node):
    output_cnn_block = ak.TextBlock(max_tokens=200000)(input_node)
    output_rnn_block = ak.TextToIntSequence(output_sequence_length=32, max_tokens=200000)(input_node)
    output_rnn_block = ak.Embedding()(output_rnn_block)
    output_rnn_block = ak.Normalization()(output_rnn_block)
    output_rnn_block = ak.RNNBlock(layer_type="lstm", return_sequences=True)(output_rnn_block)
    output_rnn_block = ak.DenseBlock()(output_rnn_block)
    output_block = ak.Merge()([output_cnn_block, output_rnn_block])
    return ak.ClassificationHead()(output_block)

这段代码主要是描绘整个模型的练习结构的。

首要在接收到输入数据后,数据将会传入 TextBlock 进行 CNN 数据特征提取。这儿的 TextBlock 是 AutoKeras 的高档 API ,它会在练习过程中主动调整。一起,TextBlock 也供给了 max_tokens 参数,经过检查源码得知默许 max_tokens 只有 5000,如下图:

【AutoML】AutoKeras 进行 RNN 循环神经网络练习
这样索性调整到 200000 应该够用。

留意!!!

这个是重点,运用 TextBlock 是需求它对问答数据进行数据特征提取,这使得 TextBlock 的存在十分重要的。并且 TextBlock 能主动调整参数,在不清楚那种参数能够更好的提取到特征的状况下,TextBlock 能够主动协助我找到所需的模型参数,这十分方便。

ok,除了 TextBlock 外我还写了一个 RNN 练习分支。首要数据会先经过 TextToIntSequence 将文本转换为数字序列,这儿将语句的最大长度(output_sequence_length)设置为 32,避免主动调参时这个参数设置过高的状况。此外,TextToIntSequence 也有供给 max_tokens 参数的,顺手将这个参数也设置为 200000 吧。

然后经过 Embedding 将数字序列转换为稠密向量,之后经过 Normalization 对稠密向量进行归一化处理,之后就能够送去给 RNNBlock 进行 RNN 练习了,这儿指定了运用 lstm 类型进行练习,就不需求 AutoKeras 主动挑选 gru 了。练习之后的数据将会经过 DenseBlock 运用全衔接层生成下一个词,终究将 TextBlock 输出和 RNN 练习输出经过 Merge 办法进行合并,终究经过 ClassificationHead 进行会聚输出。

因为没有设置练习回数,因而不可能将默许练习的 100 次输出都展示出来,这儿就只截取其间一个比较有代表性的成果,如下图:

Search: Running Trial #9
Value             |Best Value So Far |Hyperparameter
transformer       |transformer       |text_block_1/block_type
none              |none              |embedding_1/pretraining
128               |128               |embedding_1/embedding_dim
0.25              |0.25              |embedding_1/dropout
True              |True              |rnn_block_1/bidirectional
2                 |2                 |rnn_block_1/num_layers
False             |False             |dense_block_1/use_batchnorm
2                 |2                 |dense_block_1/num_layers
32                |32                |dense_block_1/units_0
0                 |0                 |dense_block_1/dropout
32                |32                |dense_block_1/units_1
add               |add               |merge_1/merge_type
0.25              |0.25              |classification_head_1/dropout
adam              |adam              |optimizer
0.001             |0.001             |learning_rate
none              |none              |text_block_1/transformer_1/pretraining
128               |128               |text_block_1/transformer_1/embedding_dim
8                 |8                 |text_block_1/transformer_1/num_heads
2048              |2048              |text_block_1/transformer_1/dense_dim
0                 |0                 |text_block_1/transformer_1/dropout
1024              |None              |text_block_1/dense_block_1/units_2
256               |128               |text_block_1/text_to_int_sequence_1/output_sequence_length
flatten           |global_avg        |text_block_1/spatial_reduction_1/reduction_type
True              |False             |text_block_1/dense_block_1/use_batchnorm
1                 |1                 |text_block_1/dense_block_1/num_layers
1024              |512               |text_block_1/dense_block_1/units_0
0.5               |0                 |text_block_1/dense_block_1/dropout
64                |256               |text_block_1/dense_block_1/units_1
Epoch 1/1000
75/75 [==============================] - 12s 115ms/step - loss: 8.0654 - accuracy: 0.0000e+00 - val_loss: 467.1426 - val_accuracy: 0.0000e+00
Epoch 2/1000
75/75 [==============================] - 8s 103ms/step - loss: 6.8244 - accuracy: 0.0967 - val_loss: 272.3265 - val_accuracy: 0.0000e+00
Epoch 3/1000
75/75 [==============================] - 6s 86ms/step - loss: 2.3318 - accuracy: 0.5792 - val_loss: 353.9221 - val_accuracy: 0.0000e+00
Epoch 4/1000
75/75 [==============================] - 6s 86ms/step - loss: 0.5466 - accuracy: 0.9150 - val_loss: 392.8975 - val_accuracy: 0.0000e+00
Epoch 5/1000
75/75 [==============================] - 8s 104ms/step - loss: 0.2716 - accuracy: 0.9563 - val_loss: 268.3076 - val_accuracy: 0.0000e+00
Epoch 6/1000
75/75 [==============================] - 6s 86ms/step - loss: 0.1708 - accuracy: 0.9708 - val_loss: 304.3133 - val_accuracy: 0.0000e+00
Epoch 7/1000
75/75 [==============================] - 6s 87ms/step - loss: 0.1353 - accuracy: 0.9742 - val_loss: 352.0239 - val_accuracy: 0.0000e+00
Epoch 8/1000
75/75 [==============================] - 6s 87ms/step - loss: 0.0840 - accuracy: 0.9850 - val_loss: 313.1510 - val_accuracy: 0.0000e+00
Epoch 9/1000
75/75 [==============================] - 6s 86ms/step - loss: 0.0726 - accuracy: 0.9858 - val_loss: 315.7093 - val_accuracy: 0.0000e+00
Epoch 10/1000
75/75 [==============================] - 6s 86ms/step - loss: 0.0571 - accuracy: 0.9896 - val_loss: 328.4327 - val_accuracy: 0.0000e+00
Epoch 11/1000
75/75 [==============================] - 6s 86ms/step - loss: 0.0457 - accuracy: 0.9921 - val_loss: 278.0609 - val_accuracy: 0.0000e+00
Epoch 12/1000
75/75 [==============================] - 6s 86ms/step - loss: 0.0606 - accuracy: 0.9896 - val_loss: 463.8227 - val_accuracy: 0.0000e+00
Epoch 13/1000
75/75 [==============================] - 6s 86ms/step - loss: 0.0290 - accuracy: 0.9942 - val_loss: 336.2177 - val_accuracy: 0.0000e+00
Epoch 14/1000
75/75 [==============================] - 6s 86ms/step - loss: 0.0212 - accuracy: 0.9962 - val_loss: 320.1093 - val_accuracy: 0.0000e+00
Epoch 15/1000
75/75 [==============================] - 8s 103ms/step - loss: 0.0166 - accuracy: 0.9962 - val_loss: 257.0939 - val_accuracy: 0.0000e+00
Epoch 16/1000
75/75 [==============================] - 6s 86ms/step - loss: 0.0179 - accuracy: 0.9954 - val_loss: 371.0593 - val_accuracy: 0.0000e+00
Epoch 17/1000
75/75 [==============================] - 6s 86ms/step - loss: 0.0153 - accuracy: 0.9967 - val_loss: 347.0213 - val_accuracy: 0.0000e+00
Epoch 18/1000
75/75 [==============================] - 6s 86ms/step - loss: 0.0158 - accuracy: 0.9975 - val_loss: 348.9128 - val_accuracy: 0.0000e+00
Epoch 19/1000
75/75 [==============================] - 6s 86ms/step - loss: 0.0222 - accuracy: 0.9942 - val_loss: 387.7633 - val_accuracy: 0.0000e+00
Epoch 20/1000
75/75 [==============================] - 6s 86ms/step - loss: 0.0113 - accuracy: 0.9987 - val_loss: 371.1013 - val_accuracy: 0.0000e+00
Epoch 21/1000
75/75 [==============================] - 6s 86ms/step - loss: 0.0067 - accuracy: 0.9996 - val_loss: 271.1282 - val_accuracy: 0.0000e+00
Epoch 22/1000
75/75 [==============================] - 6s 86ms/step - loss: 0.0147 - accuracy: 0.9975 - val_loss: 355.8381 - val_accuracy: 0.0000e+00
Epoch 23/1000
75/75 [==============================] - 8s 103ms/step - loss: 0.0046 - accuracy: 1.0000 - val_loss: 204.0495 - val_accuracy: 0.0000e+00
Epoch 24/1000
75/75 [==============================] - 6s 86ms/step - loss: 0.0083 - accuracy: 0.9992 - val_loss: 272.5107 - val_accuracy: 0.0000e+00
Epoch 25/1000
75/75 [==============================] - 6s 86ms/step - loss: 0.0062 - accuracy: 0.9992 - val_loss: 314.7820 - val_accuracy: 0.0000e+00
Epoch 26/1000
75/75 [==============================] - 6s 87ms/step - loss: 0.0186 - accuracy: 0.9975 - val_loss: 384.4933 - val_accuracy: 0.0000e+00
Epoch 27/1000
75/75 [==============================] - 6s 86ms/step - loss: 0.0121 - accuracy: 0.9987 - val_loss: 426.2129 - val_accuracy: 0.0000e+00
Epoch 28/1000
75/75 [==============================] - 6s 87ms/step - loss: 0.0061 - accuracy: 0.9996 - val_loss: 496.2940 - val_accuracy: 0.0000e+00
Epoch 29/1000
75/75 [==============================] - 6s 86ms/step - loss: 0.0148 - accuracy: 0.9975 - val_loss: 494.6873 - val_accuracy: 0.0000e+00
Epoch 30/1000
75/75 [==============================] - 6s 86ms/step - loss: 0.0141 - accuracy: 0.9975 - val_loss: 678.3535 - val_accuracy: 0.0000e+00
Epoch 31/1000
75/75 [==============================] - 6s 87ms/step - loss: 0.0123 - accuracy: 0.9975 - val_loss: 675.3771 - val_accuracy: 0.0000e+00
Epoch 32/1000
75/75 [==============================] - 6s 86ms/step - loss: 0.0124 - accuracy: 0.9979 - val_loss: 683.1956 - val_accuracy: 0.0000e+00
Epoch 33/1000
75/75 [==============================] - 6s 87ms/step - loss: 0.0090 - accuracy: 0.9992 - val_loss: 617.5909 - val_accuracy: 0.0000e+00
Trial 9 Complete [00h 03m 46s]
val_loss: 204.0495147705078
Best val_loss So Far: 7.96969747543335
Total elapsed time: 00h 13m 37s

这个是第 9 次练习的输出,其他输出都跟这个差不多就不截取出来了。能够看到练习丢失率低,准确度高,但是验证的丢失率高,准确率低。这可不是什么好事儿,这个成果证明现在的模型存在过拟合的状况(估计是因为练习的数据太少所造成的的)。过拟合会导致模型过度依赖于练习数据的特定特征和噪声,而未能泛化到其他数据。

话虽这样,但至少证明方向是对的,假如继续走这条路的话后边就加大泛化数据练习就好。但这个并非终究方针,后边我会用 transformer 对中药材数据进行重新练习,到时将会再增加练习数据量级,等有详细成果我会再更新人工智能系列的文章,咱们 transformer 再会。