运用贝叶斯优化调节深度神经网络
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><img src="https://mmbiz.qpic.cn/mmbiz_jpg/7PuqRWWU6zPD0sR6Eowibialuo8232497yktvgKq4DqAAgNd8E4b5fMGDUicWJriaE3Pib51QODjC9nFu9z4ia2LD2JQ/640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" style="width: 50%; margin-bottom: 20px;"></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">在前一篇<span style="color: black;">文案</span>中,<span style="color: black;">咱们</span>介绍了一个<span style="color: black;">运用</span>Tensorflow和深度学习<span style="color: black;">办法</span>进行图像<span style="color: black;">归类</span>的案例<span style="color: black;">科研</span>。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">尽管案例<span style="color: black;">科研</span>很少,但它展示了<span style="color: black;">设备</span>学习项目的<span style="color: black;">每一个</span><span style="color: black;">周期</span>:清理、预处理、模型构建、训练和<span style="color: black;">评定</span>。但<span style="color: black;">咱们</span>跳过了调优。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">在本文中,<span style="color: black;">咱们</span>将深入<span style="color: black;">科研</span>超参数优化。<span style="color: black;">一样</span>,<span style="color: black;">咱们</span>将<span style="color: black;">运用</span>Tensorflow中<span style="color: black;">包括</span>的Fashion MNIST数据集。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">提醒一下,数据集<span style="color: black;">包括</span>60000个 训练集中的灰度图像和10,000 测试集中的图像。<span style="color: black;">每一个</span><span style="color: black;">照片</span><span style="color: black;">表率</span>属于10个类别(“T恤/上衣”、“裤子”、“套头衫”等)之一的时尚项目。<span style="color: black;">因此呢</span>,<span style="color: black;">咱们</span>有一个多类<span style="color: black;">归类</span>问题。</p>
<h3 style="color: black; text-align: left; margin-bottom: 10px;"><span style="color: black;">设置</span></h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">我将简要介绍准备数据集的<span style="color: black;">过程</span>。<span style="color: black;">相关</span><span style="color: black;">更加多</span>信息,请查看上一篇<span style="color: black;">文案</span>的<span style="color: black;">第1</span>部分:简而言之,<span style="color: black;">过程</span>如下:</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">加载数据。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">分为训练、验证和测试集。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">规范化0–255到0–1范围内的像素值。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">one-hot<span style="color: black;">目的</span>变量。</p><span style="color: black;">#load data</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()</p><span style="color: black;"># split into train, validation and test sets</span>train_x, val_x, train_y, val_y = train_test_split(train_images, train_labels, stratify=train_labels, random_state=<span style="color: black;">48</span>, test_size=<span style="color: black;">0.05</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">)</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">(test_x, test_y)=(test_images, test_labels)</p><span style="color: black;"># normalize pixels to range 0-1</span>train_x = train_x / <span style="color: black;">255.0</span>val_x = val_x / <span style="color: black;">255.0</span>test_x = test_x /<span style="color: black;">255.0</span><span style="color: black;">#one-hot encode target variable</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">train_y = to_categorical(train_y)</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">val_y = to_categorical(val_y)</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">test_y = to_categorical(test_y)</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">概括<span style="color: black;">来讲</span>,所有训练、验证和测试集的形状如下:</p>print(train_x.shape) <span style="color: black;">#(57000, 28, 28)</span>print(train_y.shape) <span style="color: black;">#(57000, 10)</span>print(val_x.shape) <span style="color: black;">#(3000, 28, 28)</span>print(val_y.shape) <span style="color: black;">#(3000, 10)</span>print(test_x.shape)<span style="color: black;">#(10000, 28, 28)</span>print(test_y.shape) <span style="color: black;">#(10000, 10)</span>
<h3 style="color: black; text-align: left; margin-bottom: 10px;"><span style="color: black;">超参数<span style="color: black;">调节</span></span></h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">此刻</span>,<span style="color: black;">咱们</span>将<span style="color: black;">运用</span>Keras Tuner库:它将<span style="color: black;">帮忙</span><span style="color: black;">咱们</span><span style="color: black;">容易</span>地<span style="color: black;">调节</span>神经网络的超参数。要安装它,请执行以下操作:</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">pip install keras-tuner</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">重视</span>:Keras Tuner需要Python 3.6+和TensorFlow 2.0+</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">快速提醒一下,超参数<span style="color: black;">调节</span>是<span style="color: black;">设备</span>学习项目的基本部分。超参数有两种类型:</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">结构超参数:定义模型整体架构的超参数(例如,<span style="color: black;">隐匿</span>单元的数量、层数)</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">优化器超参数:影响训练速度和质量的参数(例如,优化器的学习速度和类型、批次<span style="color: black;">体积</span>、epoch数)</p><span style="color: black;"><span style="color: black;">为何</span>调优很棘手?</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">为何</span>需要超参数调优库?<span style="color: black;">咱们</span><span style="color: black;">不可</span>尝试所有可能的组合,<span style="color: black;">瞧瞧</span>验证集上什么是最好的吗?</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">不幸的是,<span style="color: black;">无</span>:</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">深层神经网络需要<span style="color: black;">海量</span>时间来训练,<span style="color: black;">乃至</span>需要几天。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">倘若</span>你在云上训练大型模型(<span style="color: black;">例如</span>亚马逊Sagemaker),记住每次实验都要花钱。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">因此呢</span>,一种限制超参数搜索空间的剪枝策略是必要的。</p><span style="color: black;">贝叶斯优化</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">幸运的是,Keras<span style="color: black;">调节</span>器<span style="color: black;">供给</span>了贝叶斯优化<span style="color: black;">调节</span>器。贝叶斯优化<span style="color: black;">调节</span>器<span style="color: black;">无</span>搜索每一个可能的组合,而是遵循一个迭代过程,随机<span style="color: black;">选取</span>前几个。<span style="color: black;">而后</span>,基于这些超参数的性能,贝叶斯<span style="color: black;">调节</span>器<span style="color: black;">选取</span>下一个可能的最佳。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">因此呢</span>,<span style="color: black;">每一个</span>超参数的<span style="color: black;">选取</span>都取决于先前的尝试。<span style="color: black;">按照</span>历史<span style="color: black;">选取</span>下一组超参数并<span style="color: black;">评定</span>性能的迭代次数将<span style="color: black;">连续</span>,直到<span style="color: black;">调节</span>器找到最佳组合或用尽最大次数的尝试。<span style="color: black;">咱们</span><span style="color: black;">能够</span>用参数“max_trials”来配置它。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">除了贝叶斯优化<span style="color: black;">调节</span>器之外,Keras<span style="color: black;">调节</span>器还<span style="color: black;">供给</span>了两个<span style="color: black;">调节</span>器:RandomSearch和Hyperband。<span style="color: black;">咱们</span>将在本文末尾讨论它们。</p>
<h3 style="color: black; text-align: left; margin-bottom: 10px;"><span style="color: black;">回到<span style="color: black;">咱们</span>的例子</span></h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">接下来,<span style="color: black;">咱们</span>将对网络应用超参数<span style="color: black;">调节</span>。在上一篇<span style="color: black;">文案</span>中,<span style="color: black;">咱们</span>尝试了两种网络架构,标准多层感知器(MLP)和卷积神经网络(CNN)。</p><span style="color: black;">多层感知器(MLP)</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">但<span style="color: black;">首要</span>,让<span style="color: black;">咱们</span>记住<span style="color: black;">咱们</span>的基线MLP模型是什么:</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">model_mlp = Sequential()</p>model_mlp.add(Flatten(input_shape=(<span style="color: black;">28</span>, <span style="color: black;">28</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">)))</p>model_mlp.add(Dense(<span style="color: black;">350</span>, activation=<span style="color: black;">relu</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">))</p>model_mlp.add(Dense(<span style="color: black;">10</span>, activation=<span style="color: black;">softmax</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">))</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">print(model_mlp.summary())</p>model_mlp.compile(optimizer=<span style="color: black;">"adam"</span>,loss=<span style="color: black;">categorical_crossentropy</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">)</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">调节</span>过程需要两种<span style="color: black;">重点</span><span style="color: black;">办法</span>:</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">hp.Int:设置值为整数的超参数范围-例如,“Dense”层中的<span style="color: black;">隐匿</span>单位数:</span></p>model.add(Dense(units = hp.Int(<span style="color: black;">dense-bot</span>, min_value=<span style="color: black;">50</span>, max_value=<span style="color: black;">350</span>, step=<span style="color: black;">50</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">))</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">hp.Choice:为超参数<span style="color: black;">供给</span>一组值-例如,Adam或SGD是最佳优化器?</span></p>hp_optimizer=hp.Choice(<span style="color: black;">Optimizer</span>, values=[<span style="color: black;">Adam</span>, <span style="color: black;">SGD</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">])</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">因此呢</span>,在原始MLP示例中<span style="color: black;">运用</span>贝叶斯优化<span style="color: black;">调节</span>器,<span style="color: black;">咱们</span>测试以下超参数:</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">隐匿</span>层数:1–3</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">第1</span>层<span style="color: black;">体积</span>:50–350</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">第二和第三层<span style="color: black;">体积</span>:50–350</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Dropout率:0、0.1、0.2</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">优化器:SGD(nesterov=True, momentum=0.9)或Adam</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">学习率:0.1、0.01、0.001</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">model = Sequential()</p>model.add(Dense(units = hp.Int(<span style="color: black;">dense-bot</span>, min_value=<span style="color: black;">50</span>, max_value=<span style="color: black;">350</span>, step=<span style="color: black;">50</span>), input_shape=(<span style="color: black;">784</span>,), activation=<span style="color: black;">relu</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">))</p><span style="color: black;">for</span> i <span style="color: black;">in</span> range(hp.Int(<span style="color: black;">num_dense_layers</span>, <span style="color: black;">1</span>, <span style="color: black;">2</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">)):</p> model.add(Dense(units=hp.Int(<span style="color: black;">dense_</span>+ str(i), min_value=<span style="color: black;">50</span>, max_value=<span style="color: black;">100</span>, step=<span style="color: black;">25</span>), activation=<span style="color: black;">relu</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">))</p> model.add(Dropout(hp.Choice(<span style="color: black;">dropout_</span>+ str(i), values=[<span style="color: black;">0.0</span>, <span style="color: black;">0.1</span>, <span style="color: black;">0.2</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">])))</p>model.add(Dense(<span style="color: black;">10</span>,activation=<span style="color: black;">"softmax"</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">))</p>hp_optimizer=hp.Choice(<span style="color: black;">Optimizer</span>, values=[<span style="color: black;">Adam</span>, <span style="color: black;">SGD</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">])</p><span style="color: black;">if</span> hp_optimizer == <span style="color: black;">Adam</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">:</p> hp_learning_rate = hp.Choice(<span style="color: black;">learning_rate</span>, values=[<span style="color: black;">1e-1</span>, <span style="color: black;">1e-2</span>, <span style="color: black;">1e-3</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">])</p><span style="color: black;">elif</span> hp_optimizer == <span style="color: black;">SGD</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">:</p> hp_learning_rate = hp.Choice(<span style="color: black;">learning_rate</span>, values=[<span style="color: black;">1e-1</span>, <span style="color: black;">1e-2</span>, <span style="color: black;">1e-3</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">])</p> nesterov=<span style="color: black;">True</span> momentum=<span style="color: black;">0.9</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">重视</span>第5行的for循环:<span style="color: black;">咱们</span>让模型决定网络的深度!</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">最后,<span style="color: black;">咱们</span><span style="color: black;">起步</span><span style="color: black;">调节</span>器。<span style="color: black;">重视</span>前面<span style="color: black;">说到</span>的max_trials参数。</p>model.compile(optimizer = hp_optimizer, loss=<span style="color: black;">categorical_crossentropy</span>, metrics=[<span style="color: black;">accuracy</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">])</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">tuner_mlp = kt.tuners.BayesianOptimization(</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"> model,</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"> seed=random_seed,</p> objective=<span style="color: black;">val_loss</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">,</p> max_trials=<span style="color: black;">30</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">,</p> directory=<span style="color: black;">.</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">,</p> project_name=<span style="color: black;">tuning-mlp</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">)</p>tuner_mlp.search(train_x, train_y, epochs=<span style="color: black;">50</span>, batch_size=<span style="color: black;">32</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">, validation_data=(dev_x, dev_y), callbacks=callback)</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">这将打印:</p><img src="https://mmbiz.qpic.cn/mmbiz_png/7PuqRWWU6zPD0sR6Eowibialuo8232497yDT0DuG76sxVkpxDHIstnnkDS9y8Wt0S0qPww9CYc4e6TpV31CRBEkQ/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" style="width: 50%; margin-bottom: 20px;">
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">该过程耗尽了迭代次数,花费了约1小时完成。<span style="color: black;">咱们</span>还<span style="color: black;">能够</span><span style="color: black;">运用</span>以下命令打印模型的最优超参数:</p>best_mlp_hyperparameters = tuner_mlp.get_best_hyperparameters(<span style="color: black;">1</span>)[<span style="color: black;">0</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">]</p>print(<span style="color: black;">"Best Hyper-parameters"</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">)</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">best_mlp_hyperparameters.values</p><img src="https://mmbiz.qpic.cn/mmbiz_png/7PuqRWWU6zPD0sR6Eowibialuo8232497yOoZaaqKqrnnI3RpHf1F2nhlHQcnWJiaicSPPQf2K4IyBibIpZQjku5Uog/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" style="width: 50%; margin-bottom: 20px;">
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">就<span style="color: black;">这般</span>!<span style="color: black;">咱们</span><span style="color: black;">此刻</span><span style="color: black;">能够</span><span style="color: black;">运用</span>最优超参数重新训练<span style="color: black;">咱们</span>的模型:</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">model_mlp = Sequential()</p>model_mlp.add(Dense(best_mlp_hyperparameters[<span style="color: black;">dense-bot</span>], input_shape=(<span style="color: black;">784</span>,), activation=<span style="color: black;">relu</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">))</p><span style="color: black;">for</span> i <span style="color: black;">in</span> range(best_mlp_hyperparameters[<span style="color: black;">num_dense_layers</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">]):</p>model_mlp.add(Dense(units=best_mlp_hyperparameters[<span style="color: black;">dense_</span> +str(i)], activation=<span style="color: black;">relu</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">))</p> model_mlp.add(Dropout(rate=best_mlp_hyperparameters[<span style="color: black;">dropout_</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"> +str(i)]))</p>model_mlp.add(Dense(<span style="color: black;">10</span>,activation=<span style="color: black;">"softmax"</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">))</p>model_mlp.compile(optimizer=best_mlp_hyperparameters[<span style="color: black;">Optimizer</span>], loss=<span style="color: black;">categorical_crossentropy</span>,metrics=[<span style="color: black;">accuracy</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">])</p>history_mlp= model_mlp.fit(train_x, train_y, epochs=<span style="color: black;">100</span>, batch_size=<span style="color: black;">32</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">, validation_data=(dev_x, dev_y), callbacks=callback)</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">或</span>,<span style="color: black;">咱们</span><span style="color: black;">能够</span>用更少的<span style="color: black;">仔细</span>信息重新训练<span style="color: black;">咱们</span>的模型:</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">model_mlp=tuner_mlp.hypermodel.build(best_mlp_hyperparameters)</p>history_mlp=model_mlp.fit(train_x, train_y, epochs=<span style="color: black;">100</span>, batch_size=<span style="color: black;">32</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">, </p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">validation_data=(dev_x, dev_y), callbacks=callback)</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">咱们</span><span style="color: black;">此刻</span>要做的<span style="color: black;">便是</span><span style="color: black;">检测</span>测试精度:</p>mlp_test_loss, mlp_test_acc = model_mlp.evaluate(test_x, test_y, verbose=<span style="color: black;">2</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">)</p>print(<span style="color: black;">\nTest accuracy:</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">, mlp_test_acc)</p><span style="color: black;"># Test accuracy: 0.8823</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">与基线的模型测试精度相比:</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">基线MLP模型:86.6%</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">最佳MLP模型:88.2%</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">事实上,<span style="color: black;">咱们</span>观察到测试准确度相差约3%!</p><span style="color: black;">卷积神经网络(CNN)</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">一样</span>,<span style="color: black;">咱们</span>将遵循相同的程序。<span style="color: black;">运用</span>CNN,<span style="color: black;">咱们</span><span style="color: black;">能够</span>测试<span style="color: black;">更加多</span>的参数。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">首要</span>,这是<span style="color: black;">咱们</span>的基线模型:</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">model_cnn = Sequential()</p>model_cnn.add(Conv2D(<span style="color: black;">32</span>, (<span style="color: black;">3</span>, <span style="color: black;">3</span>), activation=<span style="color: black;">relu</span>, input_shape=(<span style="color: black;">28</span>, <span style="color: black;">28</span>, <span style="color: black;">1</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">)))</p>model_cnn.add(MaxPooling2D((<span style="color: black;">2</span>, <span style="color: black;">2</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">)))</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">model_cnn.add(Flatten())</p>model_cnn.add(Dense(<span style="color: black;">100</span>, activation=<span style="color: black;">relu</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">))</p>model_cnn.add(Dense(<span style="color: black;">10</span>, activation=<span style="color: black;">softmax</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">))</p>model_cnn.compile(optimizer=<span style="color: black;">"adam"</span>, loss=<span style="color: black;">categorical_crossentropy</span>, metrics=[<span style="color: black;">accuracy</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">])</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">基线模型仅<span style="color: black;">包括</span>一组滤波和池层。<span style="color: black;">针对</span><span style="color: black;">咱们</span>的调优,<span style="color: black;">咱们</span>将测试以下内容:</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">卷积、MaxPooling和Dropout层的“块”数</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">每一个</span>块中Conv层的滤波器尺寸:32、64</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Conv层上的有效或相同填充</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">最后</span>附加层的<span style="color: black;">隐匿</span>层<span style="color: black;">体积</span>:25–150,乘以25</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">优化器:SGD(nesterov=真,动量=0.9)或Adam</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">学习率:0.01,0.001</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">model = Sequential()</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">model = Sequential()</p>model.add(Input(shape=(<span style="color: black;">28</span>, <span style="color: black;">28</span>, <span style="color: black;">1</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">)))</p><span style="color: black;">for</span> i <span style="color: black;">in</span> range(hp.Int(<span style="color: black;">num_blocks</span>, <span style="color: black;">1</span>, <span style="color: black;">2</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">)):</p>hp_padding=hp.Choice(<span style="color: black;">padding_</span>+ str(i), values=[<span style="color: black;">valid</span>, <span style="color: black;">same</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">])</p> hp_filters=hp.Choice(<span style="color: black;">filters_</span>+ str(i), values=[<span style="color: black;">32</span>, <span style="color: black;">64</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">])</p> model.add(Conv2D(hp_filters, (<span style="color: black;">3</span>, <span style="color: black;">3</span>), padding=hp_padding, activation=<span style="color: black;">relu</span>, kernel_initializer=<span style="color: black;">he_uniform</span>, input_shape=(<span style="color: black;">28</span>, <span style="color: black;">28</span>, <span style="color: black;">1</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">)))</p> model.add(MaxPooling2D((<span style="color: black;">2</span>, <span style="color: black;">2</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">)))</p> model.add(Dropout(hp.Choice(<span style="color: black;">dropout_</span>+ str(i), values=[<span style="color: black;">0.0</span>, <span style="color: black;">0.1</span>, <span style="color: black;">0.2</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">])))</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">model.add(Flatten())</p>hp_units = hp.Int(<span style="color: black;">units</span>, min_value=<span style="color: black;">25</span>, max_value=<span style="color: black;">150</span>, step=<span style="color: black;">25</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">)</p>model.add(Dense(hp_units, activation=<span style="color: black;">relu</span>, kernel_initializer=<span style="color: black;">he_uniform</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">))</p>model.add(Dense(<span style="color: black;">10</span>,activation=<span style="color: black;">"softmax"</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">))</p>hp_learning_rate = hp.Choice(<span style="color: black;">learning_rate</span>, values=[<span style="color: black;">1e-2</span>, <span style="color: black;">1e-3</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">])</p>hp_optimizer=hp.Choice(<span style="color: black;">Optimizer</span>, values=[<span style="color: black;">Adam</span>, <span style="color: black;">SGD</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">])</p><span style="color: black;">if</span> hp_optimizer == <span style="color: black;">Adam</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">:</p> hp_learning_rate = hp.Choice(<span style="color: black;">learning_rate</span>, values=[<span style="color: black;">1e-2</span>, <span style="color: black;">1e-3</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">])</p><span style="color: black;">elif</span>hp_optimizer ==<span style="color: black;">SGD</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">:</p> hp_learning_rate = hp.Choice(<span style="color: black;">learning_rate</span>, values=[<span style="color: black;">1e-2</span>, <span style="color: black;">1e-3</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">])</p> nesterov=<span style="color: black;">True</span> momentum=<span style="color: black;">0.9</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">像以前<span style="color: black;">同样</span>,<span style="color: black;">咱们</span>让网络决定其深度。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">此刻</span>,<span style="color: black;">咱们</span>准备好调用贝叶斯<span style="color: black;">调节</span>器了。最大迭代次数设置为100:</p>model.compile( optimizer=hp_optimizer,loss=<span style="color: black;">categorical_crossentropy</span>, metrics=[<span style="color: black;">accuracy</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">])</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">tuner_cnn = kt.tuners.BayesianOptimization(</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"> model,</p> objective=<span style="color: black;">val_loss</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">,</p>max_trials=<span style="color: black;">100</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">,</p> directory=<span style="color: black;">.</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">,</p> project_name=<span style="color: black;">tuning-cnn</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">)</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">这将打印:</p><img src="https://mmbiz.qpic.cn/mmbiz_png/7PuqRWWU6zPD0sR6Eowibialuo8232497yofGpeZLluiciadoeZfEfaiaibibo6fWrLCcGYC34ZHRtPibTGMJDqV7l3DKg/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" style="width: 50%; margin-bottom: 20px;">
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">最好的超参数是:</p><img src="https://mmbiz.qpic.cn/mmbiz_png/7PuqRWWU6zPD0sR6Eowibialuo8232497ydAicDib5NTX6khMFftks5TdyAg2WN9xfIwzTK6lkK88jusXOW4KAQBSQ/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" style="width: 50%; margin-bottom: 20px;">
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">最后,<span style="color: black;">咱们</span><span style="color: black;">运用</span>最佳超参数训练<span style="color: black;">咱们</span>的CNN模型:</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">model_cnn = Sequential()</p>model_cnn.add(Input(shape=(<span style="color: black;">28</span>, <span style="color: black;">28</span>, <span style="color: black;">1</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">)))</p><span style="color: black;">for</span>i<span style="color: black;">in</span> range(best_cnn_hyperparameters[<span style="color: black;">num_blocks</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">]):</p> hp_padding=best_cnn_hyperparameters[<span style="color: black;">padding_</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">+ str(i)]</p> hp_filters=best_cnn_hyperparameters[<span style="color: black;">filters_</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">+ str(i)]</p> model_cnn.add(Conv2D(hp_filters, (<span style="color: black;">3</span>, <span style="color: black;">3</span>), padding=hp_padding, activation=<span style="color: black;">relu</span>, kernel_initializer=<span style="color: black;">he_uniform</span>, input_shape=(<span style="color: black;">28</span>, <span style="color: black;">28</span>, <span style="color: black;">1</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">)))</p>model_cnn.add(MaxPooling2D((<span style="color: black;">2</span>, <span style="color: black;">2</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">)))</p> model_cnn.add(Dropout(best_cnn_hyperparameters[<span style="color: black;">dropout_</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">+ str(i)]))</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">model_cnn.add(Flatten())</p>model_cnn.add(Dense(best_cnn_hyperparameters[<span style="color: black;">units</span>], activation=<span style="color: black;">relu</span>, kernel_initializer=<span style="color: black;">he_uniform</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">))</p>model_cnn.add(Dense(<span style="color: black;">10</span>,activation=<span style="color: black;">"softmax"</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">))</p>model_cnn.compile(optimizer=best_cnn_hyperparameters[<span style="color: black;">Optimizer</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">], </p> loss=<span style="color: black;">categorical_crossentropy</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">, </p> metrics=[<span style="color: black;">accuracy</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">])</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">print(model_cnn.summary())</p>history_cnn= model_cnn.fit(train_x, train_y, epochs=<span style="color: black;">50</span>, batch_size=<span style="color: black;">32</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">, validation_data=(dev_x, dev_y), callbacks=callback)</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">并<span style="color: black;">检测</span>测试集的准确性:</p>cnn_test_loss, cnn_test_acc = model_cnn.evaluate(test_x, test_y, verbose=<span style="color: black;">2</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">)</p>print(<span style="color: black;">\nTest accuracy:</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">, cnn_test_acc)</p><span style="color: black;"># Test accuracy: 0.92</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">与基线的CNN模型测试精度相比(来自<span style="color: black;">咱们</span>上一篇<span style="color: black;">文案</span>):</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">基线CNN模型:90.8%</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">最佳CNN模型:92%</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">一样</span>,<span style="color: black;">咱们</span>看到了优化模型的性能<span style="color: black;">加强</span>!</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">除了准确性之外,<span style="color: black;">咱们</span><span style="color: black;">能够</span>确认<span style="color: black;">调节</span>器的工作做得很好,<span style="color: black;">原由</span>如下:</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">调节</span>器在每种<span style="color: black;">状况</span>下都<span style="color: black;">选取</span>了一个非零的Dropout值,尽管<span style="color: black;">咱们</span><span style="color: black;">亦</span>为<span style="color: black;">调节</span>器<span style="color: black;">供给</span>了零Dropout。这是意料之中的,<span style="color: black;">由于</span>Dropout是一种减少过拟合的机制。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">有趣的是,最好的CNN架构是标准管道,其中每层中的滤波器数量<span style="color: black;">逐步</span><span style="color: black;">增多</span>。这是意料之中的,<span style="color: black;">由于</span>随着后续层中的计算向前推进,模式变得更加<span style="color: black;">繁杂</span>。<span style="color: black;">因此呢</span>,有<span style="color: black;">更加多</span>的模式组合需要<span style="color: black;">更加多</span>的滤波器<span style="color: black;">才可</span>被<span style="color: black;">捕捉</span>。</p>
<h3 style="color: black; text-align: left; margin-bottom: 10px;"><span style="color: black;">结束</span></h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">毫无疑问,Keras Tuner是<span style="color: black;">运用</span>Tensorflow优化深度神经网络的通用工具。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">最<span style="color: black;">显著</span>的<span style="color: black;">选取</span>是贝叶斯优化<span style="color: black;">调节</span>器。<span style="color: black;">然则</span>,还有两个选项<span style="color: black;">能够</span><span style="color: black;">运用</span>:</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">随机搜索:这种类型的<span style="color: black;">调节</span>器<span style="color: black;">经过</span>随机<span style="color: black;">选取</span>几个超参数来避免探索超参数的<span style="color: black;">全部</span>搜索空间。<span style="color: black;">然则</span>,它<span style="color: black;">不可</span>保证此<span style="color: black;">调节</span>器会找到最佳<span style="color: black;">调节</span>器。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Hyperband:这个<span style="color: black;">调节</span>器<span style="color: black;">选取</span><span style="color: black;">有些</span>超参数的随机组合,并<span style="color: black;">运用</span>它们来训练模型,只用于几个epoch。<span style="color: black;">而后</span>,<span style="color: black;">调节</span>器<span style="color: black;">运用</span>这些超参数来训练模型,直到所有的epoch都用完,并从中<span style="color: black;">选取</span>最好的。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">感谢阅读!</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><strong style="color: blue;">参考引用</strong></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Fashion MNIST dataset by Zalando, https://www.kaggle.com/datasets/zalando-research/fashionmnist, MIT Licence (MIT) Copyright © </p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Keras Tuner, https://keras.io/keras_tuner/</p><span style="color: black;">✄-----------------------------------------------</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">看到<span style="color: black;">这儿</span>,说明你<span style="color: black;">爱好</span>这篇<span style="color: black;">文案</span>,请点击「</span><span style="color: black;">在看</span><span style="color: black;">」或顺手「</span><span style="color: black;">转发</span><span style="color: black;">」「</span><span style="color: black;">点赞</span><span style="color: black;">」。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">欢迎<span style="color: black;">微X</span>搜索「</span><span style="color: black;">panchuangxx</span><span style="color: black;">」,添加<span style="color: black;">博主</span></span><span style="color: black;">磐小小仙</span><span style="color: black;"><span style="color: black;">微X</span>,每日<span style="color: black;">伴侣</span>圈更新一篇高质量推文(无<span style="color: black;">宣传</span>),为您<span style="color: black;">供给</span><span style="color: black;">更加多</span>精彩内容。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">▼ </span><span style="color: black;">▼</span><span style="color: black;"> 扫描二维码添加<span style="color: black;">博主</span></span><span style="color: black;"> ▼</span><span style="color: black;">▼ </span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><img src="https://mmbiz.qpic.cn/mmbiz_png/7PuqRWWU6zMoOVLzfFjwnzCDnnoBFtHu8pTiaxLLosYuf9QnFFsndFyVNLpEVmyzaRG1iajld2vRutibqgzMiaZvTQ/640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" style="width: 50%; margin-bottom: 20px;"></p>
太棒了、厉害、为你打call、点赞、非常精彩等。 感谢你的精彩评论,带给我新的思考角度。 你的话语如春风拂面,让我感到无比温暖。 在遇到你之前,我对人世间是否有真正的圣人是怀疑的。 你的话语如春风拂面,让我心生暖意。 楼主发的这篇帖子,我觉得非常有道理。
页:
[1]