【theano-windows】学习笔记十——多层感知机手写数字分类

前言

上一篇学习了softmax, 然后更进一步就是学习一下基本的多层感知机(MLP)了. 其实多层感知机同时就是w*x+b用某个激活函数激活一下, 得到的结果作为下一层神经元的输入x, 类似于

output=f3(f2(f1(xw1+b2)w2+b2)w3+b3)

如果用感知器分类, 那么通常的做法是在最后接一个 softmax, 如果是回归或者拟合, 这个额, 回头用到了再说. 如果以 sigmoid作为激活函数, 那么每层单元的计算方法就是
yi=11+ewixbi1i<n1ewn1jyn1+bjtotalneuralj=1ewn1jyn1+bj

国际惯例,参考网址:

Multilayer Perceptron

预备知识

超参数

这些参数无法通过梯度下降算法优化, 严格点说就是为这些参数寻找最优值是不可行问题, 我们无法单独对每个参数进行优化, 在这, 我们无法使用之前介绍的梯度方法(因为一些参数是离散值, 其它的是实值), 最后就是优化问题是非凸的,找到(局部)极小值可能需要费很大劲.(笔者注:说了这么多, 其实那些神经元个数啊, 学习率啊,诸如此类的都属于超参)

非线性函数

其实就是激活函数, 截止到目前, 已经出现过好多激活函数了, 详细可以去看caffe的官方文档都有哪些. 早期主要使用sigmoidtanh, 其实它俩可以互相变换得到

12sigmoid(x)=tanh(x2)

详细区别可以戳 《在神经网络中,激活函数sigmoid和tanh除了阈值取值外有什么不同吗?》

权重初始化

一定不能把权重初始化为0, 因为全0的话所有的输出就一样了, 影响不同神经元上梯度的多样性. 初始化权重的时候, 我们希望能够让它尽量接近0, 这样梯度就在激活函数的接近线性区域的部分(比如sigmoidtanh在原点附近很接近y=x), 这时候梯度是最大的. 还有就是尤其对于深度神经网络, 会保存激活的反差以及层与层之间的梯度, 这允许神经网络中上行和下行过程正常流动, 并且降低层与层之间的差异性. 我们一般会遵循一个称为fan-in and fan-out的准则, 具体论文Understanding the difficulty of training deep feedforward neuralnetworks, 就是权重从如下分布中均匀采样:

uniform[6fanin+fanout,6fanin+fanout]fortanhuniform[46fanin+fanout,46fanin+fanout]forsigmoid

其中 fanin是输入神经元个数, fanout是隐层单元个数

学习率

最简单的就是采用常量值, 尝试一些对数空间值 (101,102,) , 逐渐缩小直到验证集误差最小

还有一个好方法是逐渐降低学习率.使用

μ01+dt
其中 μ0是初始学习率, d称为降低常量, 控制学习率的降低速度(经常是不大于103), t就是迭代次数

隐单元个数

这个超参与数据集非常相关, 如果数据分布复杂, 那么就需要更多的神经元个数, 是不是可以理解为”并不是说数据量越大网络就需要越复杂?”呢…….除非我们使用正则化方法(提前停止或者L1/L2惩罚项),否则隐单元个数与图模型的泛化能力将是U型的

惩罚项

典型的是L1/L2正则参数,λ 102,103,

算法实现

导入包

这个也就没啥好说的, 导入三种模块:thenao相关的、解压相关的, 读取数据相关的, 计时相关的

# -*- coding:utf-8 -*-
#导入模块
import theano
import theano.tensor as T
import numpy as np
import cPickle,gzip
import os
import timeit

读取数据集

这个没啥好说的, 所有theano手写数字分类的博客都是用这段代码读数据

#读取数据集
def load_data(dataset):data_dir,data_file=os.path.split(dataset)if os.path.isfile(dataset):with gzip.open(dataset,'rb') as f:train_set,valid_set,test_set=cPickle.load(f)#共享数据集def shared_dataset(data_xy,borrow=True):data_x,data_y=data_xyshared_x=theano.shared(np.asarray(data_x,dtype=theano.config.floatX),borrow=borrow)shared_y=theano.shared(np.asarray(data_y,dtype=theano.config.floatX),borrow=borrow)return shared_x,T.cast(shared_y,'int32')#定义三个元组分别返回训练集,验证集,测试集train_set_x,train_set_y=shared_dataset(train_set)valid_set_x,valid_set_y=shared_dataset(valid_set)test_set_x,test_set_y=shared_dataset(test_set)rval=[(train_set_x,train_set_y),(valid_set_x,valid_set_y),(test_set_x,test_set_y)]return rval

分类器函数

这里要注意由于多层感知机最后一层输出是softmax, 而之前的隐层都是它前一层与权重乘积加上偏置被激活得来的(详细看前言中的那个计算每层单元值的方法), 所以我们要定义两种层:softmax层和HiddenLayer

softmax

直接复制粘贴前面一篇博客的定义方法就行啦

#定义最后一层softmax
class LogisticRegression(object):def __init__(self,input,n_in,n_out):#共享权重self.W=theano.shared(value=np.zeros((n_in,n_out),dtype=theano.config.floatX),name='W',borrow=True)#共享偏置self.b=theano.shared(value=np.zeros((n_out,),dtype=theano.config.floatX),name='b',borrow=True)#softmax函数self.p_y_given_x=T.nnet.softmax(T.dot(input,self.W)+self.b)#预测值self.y_pred=T.argmax(self.p_y_given_x,axis=1)self.params=[self.W,self.b]#模型参数self.input=input#模型输入#定义负对数似然def negative_log_likelihood(self,y):return -T.mean(T.log(self.p_y_given_x)[T.arange(y.shape[0]),y])#定义误差def errors(self, y):# check if y has same dimension of y_predif y.ndim != self.y_pred.ndim:raise TypeError('y should have the same shape as self.y_pred',('y', y.type, 'y_pred', self.y_pred.type))# check if y is of the correct datatypeif y.dtype.startswith('int'):# the T.neq operator returns a vector of 0s and 1s, where 1# represents a mistake in predictionreturn T.mean(T.neq(self.y_pred, y))else:raise NotImplementedError()

HiddenLayer

因为MLP的损失函数都是softmax控制的, 而HiddenLayer只需要完成中间隐层单元值的计算就行了

#定义多层感知器的隐层单元相关操作
class HiddenLayer(object):def __init__(self,rng,input,n_in,n_out,W=None,b=None,activation=T.tanh):self.input=inputif W is None:W_values=np.asarray(rng.uniform(low=- np.sqrt(6./(n_in+n_out)),high= np.sqrt(6./(n_in+n_out)),size=(n_in,n_out)),dtype=theano.config.floatX)if activation==T.nnet.sigmoid:W_values *= 4W=theano.shared(value=W_values,name='W',borrow=True)if b is None:b_vaules=np.zeros((n_out,),dtype=theano.config.floatX)b=theano.shared(value=b_vaules,name='b',borrow=True)self.W=Wself.b=blin_output=T.dot(input,self.W)+self.b#未被激活的线性操作self.output=(lin_output if activation is None else activation(lin_output))self.params=[self.W,self.b]

组合成MLP

搭建一个具有单隐层的MLP网络就是将这两个网络堆起来, 堆的方法就是将HiddenLayer的输出丢给softmax的输入, 还有一个就是要将HiddenLayer中的参数与softmax中的参数组合起来存到一起相当于是MLP的参数了

#定义感知器
class MLP(object):def __init__(self,rng,input,n_in,n_hidden,n_out):self.hiddenLayer=HiddenLayer(rng=rng,input=input,n_in=n_in,n_out=n_hidden,activation=T.tanh)self.logRegressitionLayer=LogisticRegression(input=self.hiddenLayer.output,n_in=n_hidden,n_out=n_out)#正则项self.L1=(abs(self.hiddenLayer.W).sum()+abs(self.logRegressitionLayer.W).sum())self.L2=((self.hiddenLayer.W**2).sum()+(self.logRegressitionLayer.W**2).sum())#损失函数self.negative_log_likelihood=(self.logRegressitionLayer.negative_log_likelihood)self.errors=self.logRegressitionLayer.errorsself.params=self.hiddenLayer.params+self.logRegressitionLayer.params#两类参数存一起

训练

接下来就是训练了, 说白了就是梯度计算, 更新梯度, 提前终止训练, 以下代码都放在test_mlp()函数中

def test_mlp(learning_rate=0.01,L1_reg=0.00,L2_reg=0.0001,n_epochs=1000,dataset='mnist.pkl.gz',batch_size=20,n_hidden=500):

首先是读取数据, 计算批总数

    #读取数据datasets = load_data(dataset)train_set_x,train_set_y=datasets[0]valid_set_x,valid_set_y=datasets[1]test_set_x,test_set_y=datasets[2]#总批次n_train_batches=train_set_x.get_value(borrow=True).shape[0]//batch_sizen_valid_batches=valid_set_x.get_value(borrow=True).shape[0] //batch_sizen_test_batches=test_set_x.get_value(borrow=True).shape[0]//batch_size

随后构建存储数据和标签的容器, 并实例化一个分类器

#建立模型print '建立模型......'index=T.iscalar()#批索引x=T.matrix('x')#存储数据集y=T.ivector('y')#存储标签rng=np.random.RandomState(1234)#创建分类器classifier=MLP(rng=rng,input=x,n_in=28*28,n_hidden=n_hidden,n_out=10)

定义具有正则项的损失函数(softmax的负对数似然+λ1L1+λ2L2), 并且对参数(包含softmaxHiddenLayer两种层的权重和偏置)求导, 并且进行梯度更新

    #创建具有正则项的损失函数cost=(classifier.negative_log_likelihood(y)+L1_reg*classifier.L1+L2_reg*classifier.L2)#梯度计算gparams=[T.grad(cost,param) for param in classifier.params]updates=[(param,param-learning_rate*gparams) for param,gparams in zip(classifier.params,gparams)]

接下来就是训练模型、验证模型、测试模型的三个函数设计

    #训练模型train_model=theano.function(inputs=[index],outputs=cost,updates=updates,givens={x:train_set_x[index*batch_size:(index+1)*batch_size],y:train_set_y[index*batch_size:(index+1)*batch_size]})#验证模型valid_model=theano.function(inputs=[index],outputs=classifier.errors(y),givens={x:valid_set_x[index*batch_size:(index+1)*batch_size],y:valid_set_y[index*batch_size:(index+1)*batch_size]})#测试模型test_model=theano.function(inputs=[index],outputs=classifier.errors(y),givens={x:test_set_x[index*batch_size:(index+1)*batch_size],y:test_set_y[index*batch_size:(index+1)*batch_size]})

使用提前终止算法开始训练

    #提前终止法训练patiences=10000patiences_increase=2improvement_threshold=0.995#模型性能提升阈值validation_frequency=min(n_train_batches,patiences//2)best_validation_loss=np.inf#最好的模型损失best_iter=0#最好的迭代次数best_score=0#最好的得分start_time=timeit.default_timer()epoch=0done_looping=Falsewhile(epoch<n_epochs) and (not done_looping):epoch=epoch+1for minibatch_index in range(n_train_batches):minibatch_avg_cost=train_model(minibatch_index)#迭代次数iter=(epoch-1)*n_train_batches+minibatch_indexif (iter+1)%validation_frequency==0:validation_loss=[valid_model(i) for i in range(n_valid_batches)]this_validation_loss=np.mean(validation_loss)print('epoch %i, minibatch %i/%i, validation error %f %%' %(epoch,minibatch_index + 1,n_train_batches,this_validation_loss * 100.))if this_validation_loss<best_validation_loss:if this_validation_loss<best_validation_loss*improvement_threshold:patiences=max(patiences,iter*patiences_increase)best_validation_loss=this_validation_lossbest_iter=iter#测试集的效果test_losses=[test_model(i) for i in range(n_test_batches)]test_score=np.mean(test_losses)print(('     epoch %i, minibatch %i/%i, test error of ''best model %f %%') %(epoch, minibatch_index + 1, n_train_batches,test_score * 100.))if patiences<iter:done_looping=Truebreakend_time=timeit.default_timer()print(('Optimization complete. Best validation score of %f %% ''obtained at iteration %i, with test performance %f %%') %(best_validation_loss * 100., best_iter + 1, test_score * 100.))

再回顾一下这个提前终止算法:最大迭代上限就是n_epochs, 在迭代过程中设置了一个最大耐心值patiences, 每批数据迭代一次算是更新了一次梯度(所以这个次数iter是一直递增的, 不会在某次循环被置零), 每更新validation_frequency次就测试以下模型的精度如何, 如果模型还在优化且性能提升超过阈值, 那么取max(原始耐心值, iter*增量)作为新的耐心值, 当模型性能不再优化或者优化程度不高的时候(不会再更新耐心值), 一旦梯度更新次数超过耐心值, 就强制终止循环了.

接下来执行训练过程【先别训练, 继续看博客】

if __name__=='__main__':test_mlp()

贴出我训练的时候最后一次迭代的准确率:

......
epoch 1000, minibatch 2500/2500, validation error 1.700000 %
Optimization complete. Best validation score of 1.690000 % obtained at iteration 2367500, with test performance 1.650000 %

那么问题出现了?我丫没保存模型哇,待会咋测试。。。。。。然后尝试着在上面的test_mlp()中添加保存过程

print(('epoch %i, minibatch %i/%i, test error of ''best model %f %%') %(epoch, minibatch_index + 1, n_train_batches,test_score * 100.))# 保存最优模型with open('best_model_MPL.pkl', 'wb') as f:pickle.dump(classifier, f)if patiences<iter:done_looping=Truebreak

我勒个擦,提示错误了

TypeError: can't pickle instancemethod objects

允许我这个python菜鸡逃避这个错误的修改方法, 尝试使用其它方法保存模型

想啊想,想啊想,好吧,把参数提取出来保存吧

 print(('epoch %i, minibatch %i/%i, test error of ''best model %f %%') %(epoch, minibatch_index + 1, n_train_batches,test_score * 100.))# 保存最优模型save_file=open('best_model_MLP.pkl','wb')model=[classifier.hiddenLayer,classifier.logRegressitionLayer]cPickle.dump( model,save_file)if patiences<iter:done_looping=Truebreak

竟然成功了, 哈哈哈哈哈哈嗝o(╯□╰)o

测试

保存成功以后当然是来一波测试咯

读之

classifier=cPickle.load(open('best_model_MLP.pkl'))

初始化一个MLP, 注意要与训练的一模一样

x=T.matrix('x')
n_hidden=500
classifier_test=MLP(rng=np.random.RandomState(1234),input=x,n_in=28*28,n_hidden=n_hidden,n_out=10)

然后用set_value更改这个初始化MLP的权重和偏置

classifier_test.hiddenLayer.W.set_value(classifier[0].W.get_value())
classifier_test.hiddenLayer.b.set_value(classifier[0].b.get_value())classifier_test.logRegressitionLayer.W.set_value(classifier[1].W.get_value())
classifier_test.logRegressitionLayer.b.set_value(classifier[1].b.get_value())

读一个数据出来

dataset='mnist.pkl.gz'
datasets=load_data(dataset)
test_set_x,test_set_y=datasets[2]
test_set_x=test_set_x.get_value()
test_data=test_set_x[10:11]

跟上一篇softmax一样使用y_pred()函数测试以下准确度

predict_model=theano.function(inputs=[x],outputs=classifier_test.logRegressitionLayer.y_pred)
predicted_value=predict_model(test_data)
print predicted_value

我勒个擦,竟然没错,出结果了,为了严谨性,我们输出以下这个图像

from skimage import io
import matplotlib.pyplot as plt
img= np.ceil(test_data*255)
img_res=np.asarray(img.reshape(28,28),dtype=np.int32)
io.imshow(img_res)
plt.show()

这里写图片描述

完全正确,多试几个也是对的,偷偷说一下,为了保存这个模型, 我后来只训练了模型2次哇

建立模型......
epoch 1, minibatch 2500/2500, validation error 9.620000 %
epoch 1, minibatch 2500/2500, test error of best model 10.090000 %
epoch 2, minibatch 2500/2500, validation error 8.610000 %
epoch 2, minibatch 2500/2500, test error of best model 8.740000 %
Optimization complete. Best validation score of 8.610000 % obtained at iteration 5000, with test performance 8.740000 %

剩下的测试我就不说啦,毕竟和softmax一样,批测试和自己的手写数字测试, 一样的道理咯

后记

这一次主要还是学会了怎么分开保存模型的每一部分的参数, 其它的看大家一起分享分享咯, 都学会啥了捏?

code:链接: https://pan.baidu.com/s/1c1GDh5Y 密码: wpvc

训练好的模型:链接: https://pan.baidu.com/s/1gf1ohSR 密码: dv6r

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/246635.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【theano-windows】学习笔记十一——theano中与神经网络相关函数

前言 经过softmax和MLP的学习, 我们发现thenao.tensor中除了之前的博客【theano-windows】学习笔记五——theano中张量部分函数提到的张量的定义和基本运算外, 还有一个方法称为nnet, 如果自己实现过前面两篇博客中的代码就会发现用到了theano.tensor.nnet.sigmoid和thenao.te…

【caffe-windows】全卷积网络特征图分析

前言 突然就想分析一下全卷积网络的转置卷积部分了, 就是这么猝不及防的想法, 而且这个网络对图片的输入大小无要求&#xff0c;这么神奇的网络是时候分析一波了&#xff0c;我个人的学习方法调试代码&#xff0c;然后对照论文看理论 本次分析主要针对每层的权重大小和特征图…

【theano-windows】学习笔记十二——卷积神经网络

前言 按照进度, 学习theano中的卷积操作 国际惯例, 来一波参考网址 Convolutional Neural Networks (LeNet) 卷积神经网络如何应用在彩色图像上&#xff1f; 卷积小知识 三大特性&#xff1a;局部感知(稀疏连接), 权值共享, 池化 上图很重要, 描述的是前一个隐层m-1具有四…

【theano-windows】学习笔记十三——去噪自编码器

前言 上一章节学习了卷积的写法,主要注意的是其实现在theano.tensor.nnet和theano.sandbox.cuda.dnn中都有对应函数实现, 这一节就进入到无监督或者称为半监督的网络构建中. 首先是自编码器(Autoencoders)和降噪自编码器(denoising Autoencoders) 国际惯例, 参考网址: Denoi…

【theano-windows】学习笔记十四——堆叠去噪自编码器

前言 前面已经学习了softmax,多层感知器,CNN&#xff0c;AE&#xff0c;dAE&#xff0c;接下来可以仿照多层感知器的方法去堆叠自编码器 国际惯例&#xff0c;参考文献&#xff1a; Stacked Denoising Autoencoders (SdA) Greedy Layer-Wise Training of Deep Networks 理…

【theano-windows】学习笔记十五——受限玻尔兹曼机

前言 终于到了最喜欢的模型: 受限玻尔兹曼机(RBM)了, 发现关于RBM是如何从能量模型发展过来的介绍非常不错, 而关于详细理论证明, 可以去看我前面的受限玻尔兹曼机的一系列博客. 国际惯例, 参考博客,超级强推第二个博客, 证明过程很给力: Restricted Boltzmann Machines (R…

【Ogre-windows】环境配置

前言 由于工程原因, 学习一下Ogre面向对象图形渲染开源引擎, 慢慢爬坑吧。首先还是环境的配置问题哎. 其实最重要的是要预先编译三方库, 虽然官方说可以自动编译, 但是在自己电脑上还是出现了无法解析外部符号之类的问题, 正常情况下我就认为是三方库的lib出现了问题, 最后额外…

【theano-windows】学习笔记十六——深度信念网络DBN

前言 前面学习了受限玻尔兹曼机(RBM)的理论和搭建方法, 如果稍微了解过的人, 肯定知道利用RBM可以堆叠构成深度信念网络(deep belief network, DBN)和深度玻尔兹曼机(deep Boltzmann machine), 这里就先学习一下DBN. 国际惯例, 参考博文: Deep Belief Networks A fast lear…

【Ogre-windows】实例配置

前言 折腾了好久才搞定教程实例, 主要是因为上一篇博客安装的具体版本是Ogre1.10.9, 而官方的Ogre Wiki Tutorial Framework没有指定具体版本, 如果单纯下载Ogre Wiki Tutorial Framework 1.10 - (Windows line endings, updated 2015-10-15) 运行, 基本会血崩. 所以, 在经过仔…

【Ogre-windows】旋转矩阵及位置解析

前言 这篇博客主要针对三种问题 如何创建动画帧如何获取全局位置如何计算全局旋转矩阵 仿真环境为VS2013Ogre1.10.9与matlab验证 创建动画帧 这里只做一个简单的实验: 将自带的人物模型Jaiqua的run运动给新创建的运动myrun中并播放&#xff0c;直接贴代码了 void JaiQua:…

BP推导——续

前言 之前有证明过一次人工神经网络——【BP】反向传播算法证明 &#xff0c;但是回头看的时候&#xff0c;有很多地方非常不严谨&#xff0c;特此拿出来再单独证明一次BP&#xff0c;并严格保证其严谨性。如果想看看粗略的证明&#xff0c;可以去看我之前的博客&#xff0c;毕…

matlab学习——强连通分量

前言 最近motion graph相关实验&#xff0c;发现实现运动过渡需要构建运动图&#xff0c;而为了避免运动过渡陷入死胡同&#xff0c;需要对图结构进行裁剪&#xff0c;方法就是计算图模型的极大强联通分量&#xff0c;但是自己懒得去实现&#xff0c;所以就去搜了一下matlab中…

【音频处理】离散傅里叶变换

前言 最近复现音乐驱动舞蹈的文章《Dancing-to-Music Character Animation》&#xff0c;用到了与傅里叶变换很相似的称为常Q变换的方法去分割音乐&#xff0c;所以对傅里叶变换做了一个小了解&#xff0c;本文不深入各种乱糟糟的理论&#xff0c;比如什么蝶形算法啥的&#x…

【音频处理】短时傅里叶变换

前言 上一篇博客讲了离散傅里叶变换&#xff0c;里面的实例是对整个信号进行计算&#xff0c;虽然理论上有N点傅里叶变换(本博客就不区分FFT和DFT了&#xff0c;因为它俩就是一个东东&#xff0c;只不过复杂度不同)&#xff0c;但是我个人理解是这个N点是信号前面连续的N个数值…

【theano-windows】学习笔记十九——循环神经网络

前言 前面已经介绍了RBM和CNN了&#xff0c;就剩最后一个RNN了&#xff0c;抽了一天时间简单看了一下原理&#xff0c;但是没细推RNN的参数更新算法BPTT&#xff0c;全名是Backpropagation Through Time。 【注】严谨来说RNN有两个称呼&#xff1a;①结构上递归的recursive n…

【theano-windows】学习笔记二十——LSTM理论及实现

前言 上一篇学习了RNN&#xff0c;也知道了在沿着时间线对上下文权重求梯度的时候&#xff0c;可能会导致梯度消失或者梯度爆炸&#xff0c;然后我们就得学习一波比较常见的优化方法之LSTM 国际惯例&#xff0c;参考网址&#xff1a; LSTM Networks for Sentiment Analysis …

刚体运动学——欧拉角、四元数、旋转矩阵

前言 刚体运动旋转一般用&#xff1a;欧拉角、四元数、轴角对等表示&#xff0c;在对某个坐标旋转的时候&#xff0c;只需将欧拉角或四元数转换为旋转矩阵&#xff0c;并与原始坐标相乘&#xff0c;便可得到旋转以后的坐标。这里主要看看欧拉角、四元数和旋转矩阵。 国际惯例…

刚体运动学-四元数插值

前言 之前对写了一篇关于刚体运动学相关知识博客&#xff1a;刚体运动学——欧拉角、四元数、旋转矩阵&#xff0c;本篇博客就举例来说明&#xff0c;如何在运动捕捉数据中进行四元数插值。 国际惯例&#xff0c;参考博客&#xff1a; 探讨&#xff1a;向量&#xff08;方向…

【TensorFlow-windows】学习笔记一——基础理解

前言 因为Theano已经停止更新了&#xff0c;所以在前面学完Theano搭建RBM,CNN,RNN相关结构以后&#xff0c;还是得选择一个主流框架的&#xff0c;由于我自身的学习最终是向强化学习靠近&#xff0c;可能用到的仿真环境是openai gym&#xff0c;所以选择了继续学习TensorFlow&…

【TensorFlow-windows】学习笔记二——低级API

前言 上一篇博客初步了解了tensorflow中建立机器学习模型的方法&#xff1a;可以使用eager execution和graph execution两种模式&#xff0c;可以使用高级API estimator中已经封装好的模型&#xff0c;也可以自己创建estimator&#xff0c;更重要的是我们也可以使用低级API自行…