全文共8094字,预计学习时长30分钟或更长python
图片来源:pexels.com/@pixabaygit
TensorFlow是谷歌2015年开源的通用高性能计算库。最初主要是为构建神经网络(NNs)提供高性能的API。然而,随着时间的推移和机器学习(ML)社区的兴起,TensorFlow已经发展为一个完整的机器学习生态系统。程序员
TensorFlow自诞生以来变化巨大。TensorFlow 2.0目前处于测试阶段,与TF1.x相比有了许多变化。下面是主要的几个变化。github
首先,eager execution是运行TF代码的默认方式。web
为了在TF1.x中构建一个神经网络,须要定义一个名为图形(Graph)的抽象数据结构。另外,若是试图打印其中一个图节点,将看不到指望值,却能够看到对图节点的引用。实际上,要运行图形,须要使用一个名为会话(Session)的封装。使用Session.run()法,能够将Python数据传给图形,并对模型进行实际训练。编程
TF 1.x代码示例api
利用eager execution能够进行改变。如今,TensorFlow代码能够像普通的Python代码同样运行。这意味着能够迅速建立并评估操做。浏览器
Tensorflow 2.0代码示例服务器
TensorFlow 2.0代码看起来很像NumPy代码。事实上,TensorFlow和NumPy的对象能够很容易地切换。所以没必要担忧占位符、会话、feed_dictionaties等问题。网络
许多API,如tf.gans、tf.app、tf.contrib、tf.flags,会被清理或移动到单独的存储库。
然而,最重要的清理之一涉及到咱们如何构建模型。TF1.x中有超过1或2种不一样的构建/训练ML模型的方法。
tf.slim,tf.layers,tf.contrib.layers,tf.keras都是能够用来构建神经网络的API。不包括TF1.x中的序列到API序列。大多数状况下,每种状况下要选择哪种尚不明确。
尽管许多API性能良好,但彷佛并无收敛出一种通用的开发方式。此外,若是在其中一个API中训练模型,那么使用其余API来再利用该代码并不简单。
在TF2.0中,tf.keras是推荐的高级API。
能够看到,目前正试图利用KerasAPI解决全部可能的用例。
与1.0版本相比,2.0版本中的初学者API变化不大。可是如今,Keras为默认和推荐的高级API。总之,Keras指的是一组图层,经过使用明确的标准来构建神经网络。使用pip安装TensorFlow时,通常会获得完整的Keras API和一些附加功能。
model= tf.keras.models.Sequential() model.add(Flatten(input_shape= (IMAGE_HEIGHT,IMAGE_WIDTH))) model.add(Dense(units=32,activation='relu')) model.add(Dropout(0.3)) model.add(Dense(units=32,activation='relu')) model.add(Dense(units=10,activation='softmax')) #Configures the model for training. #Define the model optimizer, the loss function and the accuracy metrics model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy']) model.summary()
初学者API称为序列化,通常会将神经网络定义为一组层。除了简单性,它还有其余优势。请注意,模型是根据数据结构(一组层)来定义的。所以,因为模型定义而产生错误的几率降至最低。
Keras-tuner是一个对Keras模型进行超参数调整的专用库。在撰写本文时,该库处于α以前的状态,可是使用tf.keras和TensorFlow 2.0β能够在Colab上很好地运行。
传送门:https://github.com/keras-team/keras-tuner
这个概念很是简单。首先,须要定义一个返回编译后的Keras模型的建模函数。函数接受一个名为hp的参数做为输入。经过使用hp,能够定义一个候选值的范围,对超参数值进行采样。
下面创建了一个简单的模型,并对3个超参数进行了优化。为了查看隐藏单元,对预约义范围之间的整数值进行采样。为了计算丢失率和学习率,在一些给定值之间随机选择。
defbuild_model(hp): # define the hyper parameter ranges for thelearning rate, dropout and hidden unit hp_units = hp.Range('units', min_value=32,max_value=128, step=32) hp_lr = hp.Choice('learning_rate',values=[1e-2, 1e-3, 1e-4]) hp_dropout = hp.Choice('dropout',values=[0.1,0.2,0.3]) # build a Sequential model model = keras.Sequential() model.add(Flatten(input_shape=(IMAGE_HEIGHT,IMAGE_WIDTH))) model.add(Dense(units=hp_units,activation='relu')) model.add(Dropout(hp_dropout)) model.add(Dense(units=32, activation='relu')) model.add(layers.Dense(10,activation='softmax')) # compile and return the model model.compile(optimizer=keras.optimize rs.Adam(hp_lr), loss='sparse_categorical_crossentropy', metrics=['accuracy']) return model #create a Random Search tunertuner= RandomSearch( build_model, objective='val_accuracy', # define themetric to be optimized over max_trials=3, executions_per_trial=1, directory='my_logs') # define the outputlog/checkpoints folder # start hyper-parameter optmization searchtuner.search(x_train,y_train, epochs=2, validation_data=(x_test, y_test))
而后建立一个调谐器对象。在这种状况下,会实现随机搜索策略。最后可使用search() 开始优化。它具备与 fit()相同的签名。
最后,能够检查调谐器的结论,并选择最佳模型。请注意,训练日志和模型检查点都保存在目录文件夹(my_logs)中。此外,最小化或最大化目标(验证精度)的选择是自动推断的。
当你看到这种类型的implementation时,要追溯到面向对象编程。这里的模型是一个扩展tf.keras.Model的Python类。模型子类化是由Chainer提出的,与PyTorch如何定义模型有很大关联。
经过模型子类化来定义类构造函数中的模型层。call()负责正推法的定义和执行。
class Model(tf.keras.Model): def__init__(self): # Define thelayers here super(Model,self).__init__() self.conv1 =Conv2D(filters=8, kernel_size=4, padding="same", strides=1,input_shape=(IMAGE_HEIGHT,IMAGE_WIDTH,IMAGE_DEPTH)) self.conv2 =Conv2D(filters=16, kernel_size=4, padding="same", strides=1) self.pool =MaxPool2D(pool_size=2, strides=2, padding="same") self.flat =Flatten() elf.probs =Dense(units=N_CLASSES, activation='softmax', name="output") def call(self,x): # Define theforward pass net =self.conv1(x) net =self.pool(net) net =self.conv2(net) net =self.pool(net) net =self.flat(net) net =self.probs(net) return net defcompute_output_shape(self, input_shape): # You need tooverride this function if you want to use the subclassed model # as part of afunctional-style model. # Otherwise,this method is optional. shape =tf.TensorShape(input_shape).as_list() shape[-1] =self.num_classes returntf.TensorShape(shape)
子类化优势不少:简化模型检查;(使用断点调试)在给定的行中止并检查模型的激活或逻辑。
然而,灵活性增长以后,随之而来的是更多的漏洞。
模型子类化须要程序员更多的关注和了解。
总之,代码的错误会更明显(如模型布线)。
在TF2.0中训练模型的最简便方法是使用 fit() 。fit()支持序列化模型和子类化模型。若是使用模型子类化,惟一须要调整的就是重写compute_output_shape()分类方法。除此以外,应该可以将fit()与tf.data.Dataset 或标准NumPynd-arrays一块儿输入。
可是,若是想清楚地了解梯度或丢失的状况,可使用梯度带。这在研究中格外有效。
使用梯度带,就能够手动定义训练过程的每一个步骤。可分别应用于训练神经网络的每一个基本步骤,如:
· 正推法
· 损失函数求值
· 逆推法
· 梯度降低法
能够直观地了解神经网络是如何训练的。也能够直接输出损失值w.r.t、模型权重或梯度向量自己来进行检查。
梯度带提供了更大的灵活性。可是,就像子类化与序列化同样,灵活性越大,额外的成本越高。与fit()相比,须要手动定义一个训练回路。做为一个天然结果,它使代码的漏洞更加突出,而且更难调试。这是一个很好的折衷,和那些对开发新产品感兴趣的研究人员相比,更适合代码工程师(寻找标准化的代码)。
另外,使用fit() 能够简便地设置TensorBoard。
使用 fit()能够 简便地设置TensorBoard的实例。它也适用于Jupyter/Colab notebook。
添加TensorBoard,做为fit的回调函数。
fit()能够用于序列化API和子类化API。
# Load theTensorBoard notebook extension%load_exttensorboard # create thetensorboard callbacktensorboard= TensorBoard (log_dir='logs/{}'.format(time.time()), histogram_freq=1) # train themodelmodel.fit(x=x_train, y=y_train, epochs=2, validation_data=(x_test, y_test), callbacks=[tensorboard]) # launchTensorBoard%tensorboard--logdir logs
若是选择使用模型子类化并本身编写训练回路(使用分级带),则还须要手动定义TensorBoard。包括使用 tf.summary.create_file_writer()建立摘要文件,并指定须要可视化的变量。
有许多回调函数可供使用,其中较为有效的是:
· EarlyStopping:顾名思义,它创建了一个规则——当监控量中止增长时,就中止培训。
· ReduceLROnPlateau:当测度中止增长时,下降学习速率。
· TerminateOnNaN:遇到NaN丢失时终止培训。
· LambdaCallback:用于建立简单的自定义联机回调。
可在 TensorFlow 2.0 callbacks查看完整目录。
传送门:https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/keras/callbacks
若是选择使用梯度带进行模型训练,性能会显著降低。
执行TF代码有助于理解,但性能不佳。为了不这个问题,TF2.0引入了tf.function。
基本上,若是用tf.function修饰Python函数,TensorFlow会接收函数并将其转换为一个TF高性能抽象。
@tf.functiondeftrain_step(images, labels): with tf.GradientTape() as tape: # forward pass predictions = model(images) # compute the loss loss = cross_entropy(tf.one_hot(labels,N_CLASSES), predictions) # get the gradients w.r.t the model's weights gradients = tape.gradient(loss,model.trainable_variables) # perform a gradient descent step optimizer.apply_gradients(zip(gradients,model.trainable_variables)) # accumulates the training loss and accuracy train_loss(loss) train_accuracy(labels, predictions)
这意味着该函数将标记为JIT编辑,以便TensorFlow将其做为图形运行。所以,能够得到TF1.x(图形)的性能优点,如节点修剪、内核融合等。
简而言之,TF2.0旨在将代码设计为更小的函数。而后,可使用tf.function对所需的代码进行标记以得到额外的性能。最适用于修饰表示最大计算瓶颈的函数。这些一般是训练回路或模型的正推。
注意,用tf.function修饰函数时,会失去eager execution的一些优点。也就是说,没法在该代码段中设置断点或使用print()。
TF1.x对于如何保存/加载通过培训的模型以用于生产缺少一致的标准。TF2.0试图经过定义单个API来解决这个问题。
TF2.0保存模型的方法很少,而是对一个称为SavedModel的抽象进行标准化。
这里无需多言。若是使用tf.keras.模型建立序列化模型或扩展类,则类将从tf.train.Checkpoints继承。所以,能够将模型序列化为SavedModel对象。
# serialize your model to a SavedModel object # It includes the entire graph, all variables andweightsmodel.save('/tmp/model', save_format='tf') # load your saved modelmodel = tf.keras. models.load_ model('/tmp/model')
SavedModel与Tensorflow生态系统结合到一块儿。换句话说,可以将其分配到许多不一样的设备,包括移动电话、边缘设备和服务器。
若是要将SavedModel分配到Raspberry Pi、Edge TPU或手机等嵌入式设备,请使用TF Lite转换器。
请注意,在2.0版本中中,TFLite转换器不支持冻结的GraphDef(一般在TF1.x中生成)。若是要将冻结的GraphDefs转换为在TF2.0中运行,可使用tf.compat.v1.TFLite转换器。
在分配到嵌入式设备以前,通常会进行训练后量化。要使用TFLite转换器执行此操做,请将优化标志设置为“OPTIMIZE_FOR_SIZE”。这将把模型的权重从浮点量化到8位精度。可在不下降模型精度的状况下减少模型尺寸并改善延迟。
# create a TF Lite converter converter =tf.lite.TFLiteConverter.from_keras_mode l(model) # performs model quantization to reduce the size of themodel and improve latency converter.optimizations =[tf.lite.Optimize.OPTIMIZE_FOR_SIZE] tflite_model = converter.convert()
请注意,这是一个实验性标志,可能会发生更改。
如要关闭,可使用相同的SavedModel对象并将其转换为TensorFlow.js格式。而后可以使用JavaScript进行加载,并在浏览器上运行模型。
!tensorflowjs_converter\ --input_format=tf_saved_model \ --saved_model_tags=serve \ --output_format=tfjs_graph_model \ /tmp/model \ /tmp/web_model
首先,须要经过pip安装TensorFlow.js。而后使用tensorflowjs_converter脚本获取训练模型并转换为Javascript兼容的代码。最后,可进行加载并用Javascript进行推断。
还能够在浏览器上使用Tesnorflow.js来训练模型。
最后来介绍2.0版本的其余功能。首先,向序列化模型或子类化模型添加更多层是很是简单的。尽管TF覆盖了Conv2D、TransposeConv2D等层,但总会出现不可用的状况。对于论文再现或研究来讲尤其如此。
好消息是,能够开发自定义层。经过遵循相同的Keras API,能够建立一个类并将其扩展到tf.keras.Layer。实际上,能够按照很是类似的模式建立自定义激活函数、正则化层或测度。
资源传送门:https://www.tensorflow.org/tutorials/eager/custom_layers
此外,还能够将现有的TensorFlow 1.x代码转换为TF2.0。为此,TF团队建立了tf_upgrade_v2。
此脚本不将TF1.x代码转换为2.0惯用代码。它基本上将tf.compat.v1模块用于更更名称空间的函数。另外,若是旧代码使用tf.contrib,将没法进行转换。可能须要使用其余库或缺失函数的新TF2.0版本。
留言 点赞 发个朋友圈
咱们一块儿分享AI学习与发展的干货