【AI with ML】第 12 章 :TensorFlow Lite 简介

news2024/11/25 0:58:36

 🔎大家好,我是Sonhhxg_柒,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流🔎

📝个人主页-Sonhhxg_柒的博客_CSDN博客 📃

🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝​

📣系列专栏 - 机器学习【ML】 自然语言处理【NLP】  深度学习【DL】

​​

 🖍foreword

✔说明⇢本人讲解主要包括Python、机器学习(ML)、深度学习(DL)、自然语言处理(NLP)等内容。

如果你对这个系列感兴趣的话,可以关注订阅哟👋

文章目录

什么是 TensorFlow Lite?

演练:创建模型并将其转换为 TensorFlow Lite

步骤 1. 保存模型

步骤 2. 转换并保存模型

第 3 步. 加载 TFLite 模型并分配张量

步骤 4. 执行预测

演练:迁移学习图像分类器并转换为 TensorFlow Lite

步骤 1. 构建并保存模型

步骤 2. 将模型转换为 TensorFlow Lite

步骤 3. 优化模型

概括


到目前为止,在本书的所有章节中,您一直在探索如何使用 TensorFlow 创建机器学习模型,这些模型可以在没有显式规则编程的情况下提供计算机视觉、自然语言处理和序列建模等功能。相反,使用标记数据,神经网络能够学习将一件事与另一件事区分开来的模式,然后可以将其扩展到解决问题中。对于本书的其余部分,我们将换档看看如何在常见场景中使用这些模型。我们将介绍的第一个也是最明显也可能是最有用的主题是如何在移动应用程序中使用模型。在本章中,我将介绍使在移动(和嵌入式)设备上进行机器学习成为可能的底层技术:TensorFlow Lite。然后,在接下来的两章中,我们将探讨在 Android 和 iOS 上使用这些模型的场景。

TensorFlow 精简版是一套补充 TensorFlow 的工具,可实现两个主要目标。首先是使您的模型适合移动设备。这通常涉及减小它们的尺寸和复杂性,尽可能减少对其准确性的影响,以使它们在电池受限的环境(如移动设备)中更好地工作。二是为不同的移动平台提供运行时,包括Android、iOS、移动Linux(例如Raspberry Pi)和各种微控制器。请注意,您无法使用 TensorFlow Lite训练模型。您的工作流程将是使用 TensorFlow 对其进行训练,然后其转换为 TensorFlow Lite 格式,然后使用 TensorFlow Lite 解释器加载和运行它。

什么是 TensorFlow Lite?

TensorFlow 精简版最初是针对 Android 和 iOS 开发人员的 TensorFlow 移动版本,目标是成为满足他们需求的有效 ML 工具包。在计算机或云服务上构建和执行模型时,电池消耗、屏幕尺寸和移动应用程序开发的其他方面等问题都不是问题,因此当以移动设备为目标时,需要解决一组新的限制条件。

首先是移动应用程序框架需要轻量级。与用于训练模型的典型机器相比,移动设备的资源有限得多。因此,开发人员必须非常注意不仅由应用程序使用的资源,而且还要注意应用程序框架使用的资源。事实上,当用户浏览应用程序商店时,他们会看到每个应用程序的大小,并且必须根据他们的数据使用情况来决定是否下载它。如果运行模型的框架很大,模型本身也很大,这会使文件大小膨胀并让用户失望。

框架也必须是低延迟的。在移动设备上运行的应用程序需要运行良好,否则用户可能会停止使用它们。只有 38% 的应用程序使用次数超过 11 次,这意味着 62% 的应用程序使用次数不超过 10 次。事实上,25% 的应用程序只使用一次。高延迟,即应用程序启动或处理关键数据的速度很慢,是导致这种放弃率的一个因素。因此,基于 ML 的应用程序的框架需要快速加载并快速执行必要的推理。

与低延迟合作,移动框架需要高效的模型格式。在强大的超级计算机上训练时,模型格式通常不是最重要的信号。正如我们在前面的章节中看到的,高模型精度、低损失、避免过度拟合等是模型创建者将追求的指标。但是在移动设备上运行时,为了轻量级和低延迟,还需要考虑模型格式。到目前为止,我们看到的神经网络中的大部分数学运算都是高精度的浮点运算。对于科学发现,这是必不可少的。对于在移动设备上运行,它可能不是。一个适合移动设备的框架将需要帮助您进行这样的权衡,并在必要时为您提供转换模型的工具。

您的模型在设备上运行的一个主要好处是它们不需要将数据传递到云服务来对它们执行推理。这导致用户隐私功耗的改善。不需要将无线电用于蜂窝或 WiFi 信号来发送数据和接收预测是好的,只要设备上的推理不会消耗更多的功率。出于显而易见的原因,将数据保存在设备上以运行预测也是一项强大且日益重要的功能!(在本书的后面,我们将讨论联邦学习,它是设备上机器学习和基于云的机器学习的混合体,可以让你两全其美,同时还能保护隐私。)

因此,考虑到所有这些,创建了 TensorFlow Lite。如前所述,它不是训练模型的框架,而是一组补充工具,旨在满足移动和嵌入式系统的所有限制。

广义上应该被视为两个主要的东西:一个转换器,它接受你的 TensorFlow 模型并将其转换为.tflite格式,缩小和优化它,以及一套用于各种运行时的解释器(图 12-1)。

图 12-1。TensorFlow Lite 套件

 解释器环境还支持其特定框架内的加速选项。例如,在 Android 上 支持神经网络 API,因此 TensorFlow Lite 可以在可用的设备上利用它。

请注意,TensorFlow Lite 或 TensorFlow Lite 转换器目前不支持 TensorFlow 中的每个操作(或“op”)。您在转换模型时可能会遇到此问题,最好查看文档以了解详细信息。正如您将在本章后面看到的,一个有用的工作流程是采用现有的移动友好模型并为您的场景使用迁移学习。你可以在TensorFlow 网站上找到经过优化以与 TensorFlow Lite 配合使用的模型列表,并且 张量流枢纽。

演练:创建模型并将其转换为 TensorFlow Lite

出色地从分步演练开始,展示如何使用 TensorFlow 创建简单模型,将其转换为 TensorFlow Lite 格式,然后使用 TensorFlow Lite 解释器。对于本演练,我将使用 Linux 解释器,因为它在 Google Colab 中很容易获得。在第 13 章中,您将了解如何在 Android 上使用该模型,在第 14 章中,您将探索如何在 iOS 上使用它。

回到第 1 章,您看到了一个非常简单的 TensorFlow 模型,该模型学习了最终为 Y = 2X – 1 的两组数字之间的关系。为方便起见,完整代码如下:

l0 = Dense(units=1, input_shape=[1])
model = Sequential([l0])
model.compile(optimizer='sgd', loss='mean_squared_error')

xs = np.array([-1.0, 0.0, 1.0, 2.0, 3.0, 4.0], dtype=float)
ys = np.array([-3.0, -1.0, 1.0, 3.0, 5.0, 7.0], dtype=float)

model.fit(xs, ys, epochs=500)

print(model.predict([10.0]))
print("Here is what I learned: {}".format(l0.get_weights()))

一旦训练完成,如您所见,您就可以做到model.predict[x]并获得预期的y. 在前面的代码中,x=10模型y将返回给我们的值接近 19。

由于此模型很小且易于训练,我们可以将其用作我们将转换为 TensorFlow Lite 以展示所有步骤的示例。

步骤 1. 保存模型

TensorFlow Lite 转换器适用于多种不同的文件格式,包括SavedModel(首选)和凯拉斯 H5 格式。对于本练习,我们将使用SavedModel。

为此,只需指定保存模型的目录并调用tf.saved_model.save,将模型和目录传递给它:

export_dir = 'saved_model/1'
tf.saved_model.save(model, export_dir)

模型将被保存为资产和变量以及saved_model.pb文件,如图 12-2所示。

图 12-2。SavedModel结构

 保存模型后,您可以使用 TensorFlow Lite 转换器对其进行转换。

笔记

TensorFlow 团队建议使用 SavedModel 格式以实现整个 TensorFlow 生态系统的兼容性,包括未来与新 API 的兼容性。

第 3 步. 加载 TFLite 模型并分配张量

下一步是将模型加载到解释器中,将用于输入数据的张量分配给模型进行预测,然后读取模型输出的预测。从程序员的角度来看,这就是使用 TensorFlow Lite 与使用 TensorFlow 有很大不同的地方。使用 TensorFlow,您可以直接说出并获得结果,但由于 TensorFlow Lite 没有 TensorFlow 所具有的许多依赖项,尤其是在非 Python 环境中,您现在必须获得更底层的信息并处理输入并输出张量,格式化您的数据以适合它们并以对您的设备有意义的方式解析输出。model.predict(something)

首先,加载模型并分配张量:

interpreter = tf.lite.Interpreter(model_content=tflite_model)
interpreter.allocate_tensors()

然后您可以从模型中获取输入和输出的详细信息,这样您就可以开始了解它期望的数据格式,以及它将返回给您的数据格式:

input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()
print(input_details)
print(output_details)

你会得到很多输出!

首先,让我们检查输入参数。请注意shape设置,它是 type 的数组[1,1]。还要注意类,它是numpy.float32. 这些设置将决定输入数据的形状及其格式:

[{'name': 'dense_input', 'index': 0, 'shape': array([1, 1], dtype=int32), 
  'shape_signature': array([1, 1], dtype=int32), 'dtype': <class 
  'numpy.float32'>, 'quantization': (0.0, 0), 'quantization_parameters': 
  {'scales': array([], dtype=float32), 'zero_points': array([], dtype=int32), 
  'quantized_dimension': 0}, 'sparsity_parameters': {}}]

所以,为了格式化输入数据,如果你想预测yfor ,你需要使用这样的代码来定义输入数组的形状和类型x=10.0

to_predict = np.array([[10.0]], dtype=np.float32)
print(to_predict)

周围的双括号10.0可能会引起一些混淆——我在array[1,1]这里使用的助记符是说有一个列表,给我们第一组[],而该列表只包含一个值,即[10.0],因此给出[[10.0]]dtype=int32形状定义为,而您使用的是 ,这也可能令人困惑numpy.float32。参数是定义形状的dtype数据类型,而不是封装在该形状中的列表的内容。为此,您将使用该类。

输出细节非常相似,这里要注意的是形状。因为它也是 type 的数组[1,1],所以您可以预期答案[[y]]与输入的方式大致相同[[x]]

[{'name': 'Identity', 'index': 3, 'shape': array([1, 1], dtype=int32), 
  'shape_signature': array([1, 1], dtype=int32), 'dtype': <class 
  'numpy.float32'>, 'quantization': (0.0, 0), 'quantization_parameters': 
  {'scales': array([], dtype=float32), 'zero_points': array([], dtype=int32), 
  'quantized_dimension': 0}, 'sparsity_parameters': {}}]

步骤 4. 执行预测

让解释器进行预测,将输入张量设置为要预测的值,告诉它要使用的输入值:

interpreter.set_tensor(input_details[0]['index'], to_predict)
interpreter.invoke()

输入张量使用输入详细信息数组的索引指定。在这种情况下,您有一个非常简单的模型,它只有一个输入选项,所以它是input_details[0],您将在索引处解决它。输入详细信息项 0 只有一个索引,索引为 0,并且它需要一个[1,1]如前定义的形状。所以,你把to_predict价值放在那里。然后使用该invoke方法调用解释器。

然后,您可以通过调用get_tensor并提供您想要读取的张量的详细信息来读取预测:

tflite_results = interpreter.get_tensor(output_details[0]['index'])
print(tflite_results)

同样,只有一个输出张量,因此它将是output_details[0],并且您指定索引以获取其下方的详细信息,它将具有输出值。

因此,例如,如果您运行此代码:

to_predict = np.array([[10.0]], dtype=np.float32)
print(to_predict)
interpreter.set_tensor(input_details[0]['index'], to_predict)
interpreter.invoke()
tflite_results = interpreter.get_tensor(output_details[0]['index'])
print(tflite_results)

你应该看到如下输出:

[[10.]]
[[18.975412]]

其中10是输入值,18.97是预测值,非常接近19,即X=10时2X-1。为什么不是19,请回头看第一章!

鉴于这是一个非常简单的例子,接下来让我们看一些更复杂的东西——在一个著名的图像分类模型上使用迁移学习,然后将其转换为 TensorFlow Lite。从那里我们也将能够更好地探索优化和量化模型的影响。

独立解释器

TensorFlow 精简版是整个 TensorFlow 生态系统的一部分,由转换训练模型和解释模型所需的工具组成。在接下来的两章中,您将分别了解如何使用 Android 和 iOS 的解释器,但还有一个基于 Python 的独立解释器,可以安装在任何运行 Python 的系统上,例如树莓派。这为您提供了一种在可运行 Python 的嵌入式系统上运行模型的方法。从句法上讲,它的工作方式与您刚才看到的解释器相同。

演练:迁移学习图像分类器并转换为 TensorFlow Lite

在本节中,我们将构建一个新版本的第3章和第4章使用迁移学习的 Dogs vs. Cats 计算机视觉模型。这将使用来自 TensorFlow Hub 的模型,因此如果您需要安装它,您可以按照网站上的说明进行操作。

步骤 1. 构建并保存模型

首先,得到所有数据:

import numpy as np
import matplotlib.pylab as plt

import tensorflow as tf
import tensorflow_hub as hub
import tensorflow_datasets as tfds


def format_image(image, label):
    image = tf.image.resize(image, IMAGE_SIZE) / 255.0
    return  image, label


(raw_train, raw_validation, raw_test), metadata = tfds.load(
    'cats_vs_dogs',
    split=['train[:80%]', 'train[80%:90%]', 'train[90%:]'],
    with_info=True,
    as_supervised=True,
)

num_examples = metadata.splits['train'].num_examples
num_classes = metadata.features['label'].num_classes
print(num_examples)
print(num_classes)

BATCH_SIZE = 32
train_batches = 
raw_train.shuffle(num_examples // 4)
.map(format_image).batch(BATCH_SIZE).prefetch(1)

validation_batches = raw_validation.map(format_image)
.batch(BATCH_SIZE).prefetch(1)
test_batches = raw_test.map(format_image).batch(1)

这将下载 Dogs vs. Cats 数据集并将其拆分为训练集、测试集和验证集。

接下来,你将使用mobilenet_v2来自 TensorFlow Hub 的模型创建一个名为feature_extractor

module_selection = ("mobilenet_v2", 224, 1280) 
handle_base, pixels, FV_SIZE = module_selection

MODULE_HANDLE ="https://tfhub.dev/google/tf2-preview/{}/feature_vector/4"
.format(handle_base)

IMAGE_SIZE = (pixels, pixels)

feature_extractor = hub.KerasLayer(MODULE_HANDLE,
                                   input_shape=IMAGE_SIZE + (3,), 
                                   output_shape=[FV_SIZE],
                                   trainable=False)

现在您有了特征提取器,您可以将其作为神经网络的第一层,并添加一个输出层,其中的神经元数量与您的类数量(在本例中为两个)相同。然后你可以编译和训练它:

model = tf.keras.Sequential([
            feature_extractor,
            tf.keras.layers.Dense(num_classes, activation='softmax')
        ])

model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

hist = model.fit(train_batches,
                 epochs=5,
                 validation_data=validation_batches)

仅需五个时期的训练,这应该给出一个在训练集上具有 99% 准确率和在验证集上具有 98% 以上准确率的模型。现在您可以简单地保存模型:

CATS_VS_DOGS_SAVED_MODEL = "exp_saved_model"
tf.saved_model.save(model, CATS_VS_DOGS_SAVED_MODEL)

保存模型后,您可以对其进行转换。

步骤 2. 将模型转换为 TensorFlow Lite

作为以前,您现在可以使用保存的模型并将其转换为.tflite模型。您将其保存为converted_model.tflite

converter = tf.lite.TFLiteConverter.from_saved_model(CATS_VS_DOGS_SAVED_MODEL)
tflite_model = converter.convert()
tflite_model_file = 'converted_model.tflite'

with open(tflite_model_file, "wb") as f:
    f.write(tflite_model)

一旦你有了这个文件,你就可以用它实例化一个解释器。完成后,您应该像以前一样获得输入和输出详细信息。分别将它们加载到名为input_indexoutput_index的变量中。这使代码更具可读性!

interpreter = tf.lite.Interpreter(model_path=tflite_model_file)
interpreter.allocate_tensors()

input_index = interpreter.get_input_details()[0]["index"]
output_index = interpreter.get_output_details()[0]["index"]

predictions = []

数据集在 中有很多测试图像test_batches,所以如果你想拍摄一百张图像并测试它们,你可以这样做(随意将 更改100为任何其他值):

test_labels, test_imgs = [], []
for img, label in test_batches.take(100):
    interpreter.set_tensor(input_index, img)
    interpreter.invoke()
    predictions.append(interpreter.get_tensor(output_index))
    test_labels.append(label.numpy()[0])
    test_imgs.append(img)

早些时候,在读取图像时,它们被调用的映射函数重新格式化format_image为适合训练和推理的大小,因此您现在要做的就是将解释器的张量设置为图像的输入索引。调用解释器后,您可以在输出索引处获取张量。

如果您想查看预测对标签的效果如何,您可以运行如下代码:

score = 0
for item in range(0,99):
    prediction=np.argmax(predictions[item])
    label = test_labels[item]
    if prediction==label:
        score=score+1

print("Out of 100 predictions I got " + str(score) + " correct")

这应该会给您 99 分或 100 分正确预测。

您还可以使用以下代码根据测试数据可视化模型的输出:

for index in range(0,99):
    plt.figure(figsize=(6,3))
    plt.subplot(1,2,1)
    plot_image(index, predictions, test_labels, test_imgs)
    plt.show()

您可以在图 12-3中看到其中的一些结果。(请注意,本书的GitHub 存储库中提供了所有代码,因此如果您需要,请查看那里。)

图 12-3。推理结果

这只是简单的转换模型,没有添加任何针对移动设备的优化。在下一步中,您将探索如何针对移动设备优化此模型。

步骤 3. 优化模型

现在如果您已经了解了训练、转换和使用带有 TensorFlow Lite 解释器的模型的端到端过程,让我们看看如何开始优化和量化模型。

第一种优化称为动态范围量化,是通过optimizations在执行转换之前设置转换器的属性来实现的。这是代码:

converter = tf.lite.>TFLiteConverter.from_saved_model(CATS_VS_DOGS_SAVED_MODEL)
converter.optimizations = [tf.lite.>Optimize.DEFAULT]

tflite_model = converter.convert()
tflite_model_file = >'converted_model.tflite'

>with open(tflite_model_file, >"wb") >as f:
    f.write(tflite_model)

 在撰写本文时,有几个可用的优化选项(稍后可能会添加更多)。这些包括:

OPTIMIZE_FOR_SIZE:执行使模型尽可能小的优化。

OPTIMIZE_FOR_LATENCY:执行优化以尽可能减少推理时间。

DEFAULT:在大小和延迟之间找到最佳平衡点。

在这种情况下,模型大小在这一步之前接近 9 MB,但之后只有 2.3 MB——减少了近 70%。各种实验表明,模型可以缩小 4 倍,加速 2-3 倍。但是,根据模型类型,准确性可能会有所下降,因此如果您像这样进行量化,最好彻底测试模型。在这种情况下,我发现模型的准确率从 99% 下降到 94% 左右。

你可以通过全整数量化 float16 量化以利用特定硬件。全整数量化将模型中的权重从 32 位浮点数更改为 8 位整数,这(特别是对于较大的模型)会对模型大小和延迟产生巨大影响,而对准确性的影响相对较小。

要获得完整的整数量化,您需要指定一个代表性数据集,该数据集告诉转换器大致期望的数据范围。更新代码如下:

converter = tf.lite.TFLiteConverter.from_saved_model(CATS_VS_DOGS_SAVED_MODEL)

converter.optimizations = [tf.lite.Optimize.DEFAULT]

def representative_data_gen():
    for input_value, _ in test_batches.take(100):
        yield [input_value]

converter.representative_dataset = representative_data_gen
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]

tflite_model = converter.convert()
tflite_model_file = 'converted_model.tflite'

with open(tflite_model_file, "wb") as f:
    f.write(tflite_model)

拥有这些具有代表性的数据后,转换器可以在数据流经模型时检查数据,并找到最适合进行转换的位置。然后,通过设置支持的操作(在本例中为INT8),您可以确保仅在模型的那些部分量化精度。结果可能是一个稍大的模型——在这种情况下,它从convertor.optimizations仅使用时的 2.3 MB 增加到 2.8 MB。然而,准确率又回到了 99%。因此,通过执行这些步骤,您可以将模型的大小减少大约三分之二,同时保持其准确性!

概括

在本章中,您了解了 TensorFlow Lite 的介绍,并了解了它是如何设计用来让您的模型准备好在比您的开发环境更小、更轻的设备上运行的。其中包括移动操作系统,如 Android、iOS 和 iPadOS,以及基于 Linux 的移动计算环境,如 Raspberry Pi 和支持 TensorFlow 的基于微控制器的系统。您构建了一个简单的模型并使用它来探索转换工作流程。然后,您完成了一个更复杂的示例,使用迁移学习为数据集重新训练现有模型,将其转换为 TensorFlow Lite,并针对移动环境对其进行优化。在下一章中,您将利用这些知识并探索如何使用基于 Android 的解释器在您的 Android 应用程序中使用 TensorFlow Lite。

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

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

相关文章

css浮动

浮动的顺序贴靠特性 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>浮动</title><style>.box{width: 250px;height: 100px;border: 1px solid #000;}.box .c1{width: 150px;height: 100p…

云上在野容器攻防战:“杀”不掉的挖矿木马

编者按 数字化浪潮蓬勃兴起&#xff0c;企业面临的安全挑战亦日益严峻。 腾讯安全近期将复盘2022年典型的攻击事件&#xff0c;帮助企业深入了解攻击手法和应对措施&#xff0c;完善自身安全防御体系。 本篇是第二期&#xff0c;讲述了国内某高端制造厂商遭遇云上在野容器攻…

将scss文件转换成css文件

大家平时做项目肯定都习惯了使用scss或者less去写样式&#xff0c;如果是使用工程化的项目我们可以借助插件很方便的将scss或者less转换成css。那如果我们没有使用工程化&#xff0c;比如简单的demo或者官网等项目又希望可以通过scss去编写文件应该怎么办呢&#xff0c;我们可以…

200 万年薪能拿多久?因 ChatGPT 爆红的「提示工程师」竟面临光速失业

【简介】ChatGPT大火后&#xff0c;“提示工程师”开始流行。然而&#xff0c;他们很可能被光速下岗&#xff1f; 最近爆发的ChatGPT真的让人上瘾。 但是&#xff0c;你只是在玩游戏&#xff0c;有些人已经在上面赚取了数百万的年薪&#xff01; 这位名叫莱利古德塞德的小弟最…

Codeforces Round #839 (Div. 3)题解

A. AB? 直接读入字符串然后把下标0和2的数字提取出来就行 // Problem: A. AB? // Contest: Codeforces - Codeforces Round #839 (Div. 3) // URL: https://codeforces.com/contest/1772/problem/A // Memory Limit: 512 MB // Time Limit: 2000 ms // // Powered by CP E…

还在堆人力处理工单?找准耗时源头才是关键!

对于提供企业级服务的公司来说&#xff0c;服务质量与效率日益受到关注。服务质量的本质是整体团队的效能&#xff0c;重中之重则是站在客户视角的工单解决效率。 当下很多这个领域的企业都会设立客户成功中心&#xff0c;其中就有专门对接客户工单处理的职责&#xff1b;而随…

Lifelong Embedding Learning and Transfer for Growing Knowledge Graphs

摘要 现有的知识图谱(KG)嵌入模型主要关注静态KG,但真实世界的KG并不是静态的,而是随着KG应用程序的发展而发展和增长。因此,新的事实和以前看不到的实体和关系不断出现,需要一个嵌入模型,可以通过增长快速学习和转移新知识。基于此,本文研究了KG嵌入的一个扩展领域,即…

96.第十九章 MySQL数据库 -- 多表查询(六)

3.7.2 多表查询 多表查询,即查询结果来自于多张表 子查询:在SQL语句嵌套着查询语句,性能较差,基于某语句的查询结果再次进行的查询 联合查询:UNION,表和表的纵向合并 交叉连接:笛卡尔乘积 内连接: 等值连接:让表之间的字段以“等值”建立连接关系 不等值连接 自然连接…

python数据清洗的三个常用的处理方式!

关于python数据处理过程中三个主要的数据清洗说明&#xff0c;分别是缺失值/空格/重复值的数据清洗。 这里还是使用pandas来获取excel或者csv的数据源来进行数据处理。若是没有pandas的非标准库需要使用pip的方式安装一下。 pip install pandas准备一下需要处理的脏数据&…

【愚公系列】2022年12月 .NET CORE工具案例-PLG轻量级日志可视化服务

文章目录前言1.Serilog简介2.Grafana简介3.Loki是什么一、Serilog对接Grafana轻量级日志可视化服务1.Grafana部署2.Loki部署3.promtail部署4.测试.NET Core写入日志效果5.测试查询日志总结前言 日志功能是几乎所有程序或系统都必备的一个功能。该文章通过使用LokiGrafana来实现…

算法题:N个元素之和

做题思路&#xff1a; 1&#xff09;首先对数组进行排序 2&#xff09;创建一个for循环&#xff1a; 第一个元素指向for循环 3&#xff09;然后创建一个while循环&#xff1b;第二个元素指向for循环的下一个元素&#xff0c;第三个元素指向最后一个元素 4&#xff09;如果三个元…

Java基础之《netty(15)—HTTP服务》

一、使用netty开发一个简单的http服务 1、netty服务器在6668端口监听&#xff0c;浏览器发出请求http://localhost:6668/ 在写netty的http server的例子过程中&#xff0c;发现浏览器使用端口号6668一直无法连接&#xff0c;报错ERR_UNSAFE_PORT。改成7000就可以了。 2、服务器…

2018年高职组——信息评估与管理赛题(解析)

这篇文章为2018年赛题第一阶段DCRS解析 都是自己的想法(仅供参考)不对请指正评论 先来张拓扑养养眼: 2018年拓扑 接下来是IP地址规划表: IP地址的配置就不用我再多赘述了吧,接下来是DCRS的题目 23、DCRS 为接入交换机,为终端产生防止 MAC 地址防洪攻击,请配置端口安全,…

【嵌入式Linux】开发环境搭建

一、概述 在进行某一个芯片平台开发前&#xff0c;一般都需要在电脑上安装一系列软件&#xff0c;然后在这些软件上阅读、编写、编译和调试在该平台上运行的代码&#xff0c;最后将编写好的代码通过某种方式烧录到该芯片的对应地址运行。在电脑上安装的这一系列软件的过程&…

知行之桥2022版本升级之页面变化以及监控邮件答疑

近期有些客户将知行EDI系统升级到了我们最新知行之桥2022版本&#xff0c;升级过程或者升级后对于新版本的使用会有些疑问&#xff0c;根据近期协助大家进行知行EDI系统升级遇到的问题&#xff0c;我们的运维团队整理了一些Q&A&#xff0c;将分为上下两篇分享给大家&#x…

深度学习入门(六十二)循环神经网络——双向循环神经网络

深度学习入门&#xff08;六十二&#xff09;循环神经网络——双向循环神经网络前言循环神经网络——双向循环神经网络课件未来很重要双向RNN推理总结教材1 隐马尔可夫模型中的动态规划2 双向模型2.1 定义2.2 模型的计算代价及其应用3 双向循环神经网络的错误应用4 小结前言 核…

排序算法之直接选择排序(图文详解)

文章目录一、选择排序思想二、排序过程详解2.1 排序的次数2.2 排序演示三、代码范例3.1 SelectSort函数3.2 整体代码实现3.3 结果展示四、选择排序分析4.1 稳定性4.2 复杂度4.3适用场景五、选泽排序优化总结一、选择排序思想 选择排序&#xff08;Selection sort&#xff09;是…

ABBYY15免费版直接编辑PDF格式文件

日常生活中&#xff0c;我们常常使用PDF格式的文件。其优点就是PDF的文本内容不会随着软件版本、电脑字体的变化而变化&#xff0c;保证了其完整性。但也正因为这一点&#xff0c;如果没有源文件&#xff0c;我们就很难对PDF文档的内容进行编辑了。今天&#xff0c;我就向大家展…

前端一面必会vue面试题(边面边更)

为什么要使用异步组件 节省打包出的结果&#xff0c;异步组件分开打包&#xff0c;采用jsonp的方式进行加载&#xff0c;有效解决文件过大的问题。核心就是包组件定义变成一个函数&#xff0c;依赖import() 语法&#xff0c;可以实现文件的分割加载。 components:{ AddCustom…

关于GitHub的.gitignore无法忽略 “default-2021.dwlt“ 文件的问题

问题描述 我在使用sourcetree往github提交工程时&#xff0c;UserSettings/Layouts/default-2021.dwlt文件无缘无故每次都被暂存。 尽管我在.gitignore文件中反复修改忽略路径&#xff0c;该文件始终无法被屏蔽。如下图 解决办法 在网上找了很多资料&#xff0c;最终找到了…