kaggle平台学习复习笔记 | 计算机视觉

news2024/11/20 3:25:08

目录

    • 1.The Convolutional Classifier
    • 2.Convolution and ReLU
    • 3.Maximum Pooling
    • 4.The Sliding Window
    • 5.Custom Convnets
    • 6.Data Augmentation

在这里插入图片描述

1.The Convolutional Classifier

使用Keras创建第一个计算机视觉模型。
用于图像分类的网络由两部分组成:卷积层和密集层

卷积分类器
在这里插入图片描述
base使用的是卷积层,主要功能是提取特征
head使用的是密集层,主要功能是决定图片的分类
整个过程类似于下图:
在这里插入图片描述
训练一个卷积分类器
Step 1 - Load Data

# Load training and validation sets
ds_train_ = image_dataset_from_directory(
    '../input/car-or-truck/train',
    labels='inferred',
    label_mode='binary',
    image_size=[128, 128],
    interpolation='nearest',
    batch_size=64,
    shuffle=True,
)
ds_valid_ = image_dataset_from_directory(
    '../input/car-or-truck/valid',
    labels='inferred',
    label_mode='binary',
    image_size=[128, 128],
    interpolation='nearest',
    batch_size=64,
    shuffle=False,
)
# Data Pipeline
def convert_to_float(image, label):
    image = tf.image.convert_image_dtype(image, dtype=tf.float32)
    return image, label

AUTOTUNE = tf.data.experimental.AUTOTUNE
ds_train = (
    ds_train_
    .map(convert_to_float)
    .cache()
    .prefetch(buffer_size=AUTOTUNE)
)
ds_valid = (
    ds_valid_
    .map(convert_to_float)
    .cache()
    .prefetch(buffer_size=AUTOTUNE)
)

Step 2 - Define Pretrained Base
载入预训练的VGG16模型

pretrained_base = tf.keras.models.load_model(
    '../input/cv-course-models/cv-course-models/vgg16-pretrained-base',
)
pretrained_base.trainable = False

Step 3 - Attach Head
pretrained_base所需要的是二维输入,
Dense层所需要的是一维输入

Flatten层将基底的二维输出转换为头部所需的一维输入。
如下所示:

from tensorflow import keras
from tensorflow.keras import layers

model = keras.Sequential([
    pretrained_base,
    layers.Flatten(),
    layers.Dense(6, activation='relu'),
    layers.Dense(1, activation='sigmoid'),
])

Step 4 - Train

model.compile(
    optimizer='adam',  # 优化器
    loss='binary_crossentropy',  # 损失函数
    metrics=['binary_accuracy'], # acc评价函数
)

history = model.fit(
    ds_train,
    validation_data=ds_valid,
    epochs=30,
    verbose=0,
)
import pandas as pd

history_frame = pd.DataFrame(history.history)
history_frame.loc[:, ['loss', 'val_loss']].plot()
history_frame.loc[:, ['binary_accuracy', 'val_binary_accuracy']].plot();

在这里插入图片描述

2.Convolution and ReLU

在我们讨论卷积的细节之前,让我们讨论一下网络中这些层的用途。我们将了解如何使用这三个操作(卷积、ReLU和池化层)来实现特征提取过程。

卷积: Filter an image
Relu: Detect that feature
池化层:Condense the image (压缩)

类似于以下三个步骤:
在这里插入图片描述
Filter 卷积层:

from tensorflow import keras
from tensorflow.keras import layers

model = keras.Sequential([
    layers.Conv2D(filters=64, kernel_size=3), # activation is None
    # More layers follow
])

我们可以通过查看这些参数与层的权重和激活函数关系来理解这些参数。
These weights we call kernels. We can represent them as small arrays:
在这里插入图片描述
内核通过扫描图像并产生像素值的加权和来操作。通过这种方式,内核的作用有点像偏振透镜,强调或淡化某些信息模式。
在这里插入图片描述
从内核中的数字模式,您可以知道它创建的特征图的类型。通常,卷积在其输入中强调的内容将与内核中正数的形状相匹配。

Detect ReLU层
ReLU特定的激活层中定义,但通常只将其作为Conv2D的激活函数。

model = keras.Sequential([
    layers.Conv2D(filters=64, kernel_size=3, activation='relu')
    # More layers follow
])

您可以将激活函数视为根据某种重要度量对像素值进行评分。ReLU激活表示负值不重要,因此将其设置为0。

在这里插入图片描述
与其他激活函数一样,ReLU函数是非线性的。本质上,这意味着网络中所有层的总效果变得不同于仅将这些效果相加所获得的效果。非线性确保特征在深入网络时以有趣的方式组合。

Example - Apply Convolution and ReLU

import tensorflow as tf
import matplotlib.pyplot as plt
plt.rc('figure', autolayout=True)
plt.rc('axes', labelweight='bold', labelsize='large',
       titleweight='bold', titlesize=18, titlepad=10)
plt.rc('image', cmap='magma')

image_path = '../input/computer-vision-resources/car_feature.jpg'
image = tf.io.read_file(image_path)
image = tf.io.decode_jpeg(image)

plt.figure(figsize=(6, 6))
plt.imshow(tf.squeeze(image), cmap='gray')
plt.axis('off')
plt.show();

在这里插入图片描述
你可以用tf.constant定义它,就像你用np.array定义Numpy中的数组一样。这会创建TensorFlow使用的张量。

import tensorflow as tf

kernel = tf.constant([
    [-1, -1, -1],
    [-1,  8, -1],
    [-1, -1, -1],
])

plt.figure(figsize=(3, 3))
show_kernel(kernel)

TensorFlow在其tf.nn模块中包含许多由神经网络执行的常见操作。我们将使用的两个是conv2d和relu。这些只是Keras层的函数版本。

image_filter = tf.nn.conv2d(
    input=image,
    filters=kernel,
    # we'll talk about these two in lesson 4!
    strides=1,
    padding='SAME',
)
plt.figure(figsize=(6, 6))
plt.imshow(tf.squeeze(image_filter)) 
# 并删除所有维度为1的维度
plt.axis('off')
plt.show();

在这里插入图片描述

image_detect = tf.nn.relu(image_filter)

plt.figure(figsize=(6, 6))
plt.imshow(tf.squeeze(image_detect))
plt.axis('off')
plt.show();

在这里插入图片描述
现在我们已经创建了一个功能图!像这样的图像是头部用来解决分类问题的。我们可以想象,某些特征可能更具汽车的特征,而其他特征则更具卡车的特征。在训练期间,convnet的任务是创建能够找到这些特征的内核。

我们在本课中看到了convnet用于执行特征提取的前两个步骤:使用Conv2D层过滤和使用relu激活进行检测。

3.Maximum Pooling

Condense with Maximum Pooling

from tensorflow import keras
from tensorflow.keras import layers

model = keras.Sequential([
    layers.Conv2D(filters=64, kernel_size=3), # activation is None
    layers.MaxPool2D(pool_size=2),
    # More layers follow
])

请注意,在应用ReLU激活函数后,特征图最终会出现大量“死空间”,即仅包含0的大区域(图像中的黑色区域)。在整个网络中携带这种"死空间"将增加模型的大小,而不会添加太多有用的信息。相反,我们希望精简特征图,只保留最有用的部分——特征本身。

池化层作用如下图所示:
在这里插入图片描述
Example

import tensorflow as tf

image_condense = tf.nn.pool(
    input=image_detect, # image in the Detect step above
    window_shape=(2, 2),
    pooling_type='MAX',
    # we'll see what these do in the next lesson!
    strides=(2, 2),
    padding='SAME',
)

plt.figure(figsize=(6, 6))
plt.imshow(tf.squeeze(image_condense))
plt.axis('off')
plt.show();

应用卷积和ReLU激活函数是图片是这样的
(未应用池化层前)
在这里插入图片描述

应用池化层后是这样的
在这里插入图片描述
我们称零像素为“不重要”。这是否意味着它们根本不携带信息?事实上,零像素携带位置信息。空白区域仍将在图像中定位特征。当MaxPool2D删除其中一些像素时,它会删除要素地图中的一些位置信息。
具有最大池化的神经网络将倾向于 不通过其在图像中的位置 来区分特征。

观察当我们对以下功能图重复应用最大池时会发生什么。
在这里插入图片描述
在重复池化之后,原始图像中的两个点变得无法区分。换句话说,池化效果破坏了他们的一些位置信息。由于网络不再能够在特征图中区分它们,因此它也无法在原始图像中区分它们:它已经对位置的差异不敏感。
事实上,池化效果就像图像中的两个点一样。开始时相距很远的特征在合并后将保持不同;只丢失了一些位置信息,但没有丢失全部位置信息。
这使得卷积网络比仅具有密集层的网络具有更大的效率优势。

4.The Sliding Window

卷积神经网络中两个重要的参数:stride and padding

stride

卷积和池运算有一个共同的特点:它们都是在滑动窗口上执行的。通过卷积,这个“窗口”由内核的维度,即参数kernel_size给出。对于池,它是池窗口,由pool_size给出。

在这里插入图片描述
stride参数表示窗口在每一步应该移动多远,填充参数表示我们如何处理输入边缘的像素。

from tensorflow import keras
from tensorflow.keras import layers

model = keras.Sequential([
    layers.Conv2D(filters=64,
                  kernel_size=3,
                  strides=1,
                  padding='same',
                  activation='relu'),
    layers.MaxPool2D(pool_size=2,
                     strides=1,
                     padding='same')
    # More layers follow
])

请添加图片描述
步幅有什么影响?每当任一方向的步幅大于1时,滑动窗口将在每个步骤跳过输入中的一些像素。

因为我们希望使用高质量的特征进行分类,卷积层通常具有stride=(1,1)。增加步幅意味着我们错过了可能有价值的信息。然而,最大池层的步长值几乎总是大于1,如(2,2)或(3,3),但不大于窗口本身。

最后,请注意,当两个方向上的步幅值都是相同的数字时,您只需要设置该数字;例如,您可以在参数设置中使用stride=2,而不是stride=(2,2)。

Padding
当执行滑动窗口计算时,存在一个问题,即在输入的边界处做什么。完全停留在输入图像内意味着窗口永远不会像对输入中的其他像素那样,位于这些边界像素之上。既然我们对所有像素的处理不完全相同,那么会有问题吗?

卷积如何处理这些边界值取决于其填充参数。在TensorFlow中,您有两个选择:padding='same’或padding=‘valid’。每种方法都有利弊得失。

当我们设置padding='valid’时,卷积窗口将完全位于输入内部。缺点是输出会缩小(丢失像素),对于较大的内核会缩小更多。

另一种方法是使用padding=‘same’。这里的技巧是在输入的边界周围填充0,使用足够的0使输出的大小与输入的大小相同。然而,这可能会削弱边界处像素的影响。

下面的动画显示了一个带有“SAME”填充的滑动窗口。请添加图片描述
VGG架构相当简单。它使用步幅为1的卷积,2×2窗口和步幅为2的最大池。
VGG模型的展示;

show_extraction(
    image, kernel,

    # Window parameters
    conv_stride=1,#步幅为1的卷积
    pool_size=2, #2×2窗口
    pool_stride=2,# 步幅为2

    subplot_shape=(1, 4),
    figsize=(14, 6),
)

效果:
在这里插入图片描述
效果很好!内核被设计为检测水平线,我们可以看到,在生成的特征图中,输入的水平部分越多,激活程度越高。

如果我们将卷积的步长改为3,会发生什么?

show_extraction(
    image, kernel,

    # Window parameters
    conv_stride=3,#步幅为3的卷积
    pool_size=2,
    pool_stride=2,

    subplot_shape=(1, 4),
    figsize=(14, 6),    
)

在这里插入图片描述
这似乎降低了提取的特征的质量。我们的输入圆相当“精细”,只有1个像素宽。步幅为3的卷积过于粗糙,无法从中生成良好的特征图。

有时,模型将在其初始层使用具有较大步长的卷积。这通常也会与更大的内核相结合。例如,ResNet50模型在其第一层使用7×7内核,步长为2。这似乎加快了大规模功能的生产,而不会牺牲输入中的太多信息。

5.Custom Convnets

设计你自己的卷积网络
既然您已经看到了convnet用于提取特征的层,那么是时候将它们放在一起并构建自己的网络了!

在最后三节课中,我们看到了卷积网络如何通过三个操作执行特征提取:过滤、检测和压缩。单轮特征提取只能从图像中提取相对简单的特征,例如简单的线条或对比度。这些太简单,无法解决大多数分类问题。相反,convnets将反复重复这种提取,从而使特征在深入网络时变得更加复杂和精细。

通过执行该提取的卷积块的长链来实现这一点。
在这里插入图片描述
在这里插入图片描述
每个块代表一轮提取,通过组合这些块,convnet可以组合和重组生成的特征,使其生长和成形,以更好地解决当前的问题。现代对流的深层结构使得这种复杂的特征工程得以实现,并在很大程度上为其卓越的性能负责。

Example
Step 1 - Load Data

# Imports
import os, warnings
import matplotlib.pyplot as plt
from matplotlib import gridspec

import numpy as np
import tensorflow as tf
from tensorflow.keras.preprocessing import image_dataset_from_directory

# Reproducability
def set_seed(seed=31415):
    np.random.seed(seed)
    tf.random.set_seed(seed)
    os.environ['PYTHONHASHSEED'] = str(seed)
    os.environ['TF_DETERMINISTIC_OPS'] = '1'
set_seed()

# Set Matplotlib defaults
plt.rc('figure', autolayout=True)
plt.rc('axes', labelweight='bold', labelsize='large',
       titleweight='bold', titlesize=18, titlepad=10)
plt.rc('image', cmap='magma')
warnings.filterwarnings("ignore") # to clean up output cells


# Load training and validation sets
ds_train_ = image_dataset_from_directory(
    '../input/car-or-truck/train',
    labels='inferred',
    label_mode='binary',
    image_size=[128, 128],
    interpolation='nearest',
    batch_size=64,
    shuffle=True,
)
ds_valid_ = image_dataset_from_directory(
    '../input/car-or-truck/valid',
    labels='inferred',
    label_mode='binary',
    image_size=[128, 128],
    interpolation='nearest',
    batch_size=64,
    shuffle=False,
)

# Data Pipeline
def convert_to_float(image, label):
    image = tf.image.convert_image_dtype(image, dtype=tf.float32)
    return image, label

AUTOTUNE = tf.data.experimental.AUTOTUNE
ds_train = (
    ds_train_
    .map(convert_to_float)
    .cache()
    .prefetch(buffer_size=AUTOTUNE)
)
ds_valid = (
    ds_valid_
    .map(convert_to_float)
    .cache()
    .prefetch(buffer_size=AUTOTUNE)
)

Step 2 - Define Model
现在我们来定义模型。
看看我们的模型是如何由三个Conv2D和MaxPool2D层(基础)组成的,然后是一个密集层的头部。只需填写适当的参数,我们就可以将该图直接转换为Keras Sequential模型。

from tensorflow import keras
from tensorflow.keras import layers

model = keras.Sequential([

    # First Convolutional Block
    # filters are "过滤器"
    layers.Conv2D(filters=32, kernel_size=5, activation="relu", padding='same',
                  # give the input dimensions in the first layer
                  # [height, width, color channels(RGB)]
                  input_shape=[128, 128, 3]),
    layers.MaxPool2D(),

    # Second Convolutional Block
    layers.Conv2D(filters=64, kernel_size=3, activation="relu", padding='same'),
    layers.MaxPool2D(),

    # Third Convolutional Block
    layers.Conv2D(filters=128, kernel_size=3, activation="relu", padding='same'),
    layers.MaxPool2D(),

    # Classifier Head
    layers.Flatten(),
    layers.Dense(units=6, activation="relu"),
    layers.Dense(units=1, activation="sigmoid"),
])
model.summary()

请注意,在这个定义中,过滤器的数量是如何逐块加倍的:32、64、128。这是一种常见的模式。由于MaxPool2D层减少了特征的大小,我们可以增加创建的数量。
Step 3 - Train

model.compile(
    optimizer=tf.keras.optimizers.Adam(epsilon=0.01),
    loss='binary_crossentropy',
    metrics=['binary_accuracy']
)

history = model.fit(
    ds_train,
    validation_data=ds_valid,
    epochs=40,
    verbose=0,
)

import pandas as pd

history_frame = pd.DataFrame(history.history)
history_frame.loc[:, ['loss', 'val_loss']].plot()
history_frame.loc[:, ['binary_accuracy', 'val_binary_accuracy']].plot();

在这里插入图片描述
该模型比第1课中的VGG16模型小得多——只有3个卷积层,而VGG16只有16个。尽管如此,它仍然能够很好地拟合这个数据集。我们仍然可以通过添加更多卷积层来改进这个简单的模型,希望创建更适合数据集的特征。

6.Data Augmentation

通过创建额外的训练数据来提高性能。

提高机器学习模型性能的最佳方法是在更多数据上对其进行训练。模型需要学习的例子越多,它就能更好地识别哪些图像差异重要,哪些图像差异不重要。更多的数据有助于模型更好地概括。

获取更多数据的一种简单方法是使用现有数据。如果我们能够以保留类的方式转换数据集中的图像,我们就可以教分类器忽略这些类型的转换。例如,照片中的汽车是朝左还是朝右,并不能改变这是一辆汽车而不是卡车的事实。因此,如果我们用翻转图像来增强训练数据,我们的分类器将了解到“左或右”是一个应该忽略的差异。

这就是数据扩充背后的全部想法:添加一些看起来很像真实数据的额外伪数据,您的分类器将得到改进

通常,在扩充数据集时使用多种转换。这些可能包括旋转图像、调整颜色或对比度、扭曲图像或其他许多通常组合应用的事情。下面是一个可以转换单个图像的不同方式的示例。

在这里插入图片描述
每次在训练期间使用图像时,都会应用新的随机变换。通过这种方式,模型总是看到一些与以前不同的东西。训练数据中的这种额外差异有助于模型处理新数据。

但重要的是要记住,并不是每个转换都对给定的问题有用。最重要的是,无论使用什么转换,都不应混淆图片所属类。例如,如果你正在训练一个数字识别器,旋转图像会混淆9和6。

最后,找到好的扩充的最佳方法与大多数ML问题相同。

Step 1 - Load Model

Step 2 - Define Model
为了说明增强的效果,我们将向教程1中的模型添加几个简单的转换。

from tensorflow import keras
from tensorflow.keras import layers
# these are a new feature in TF 2.2
# 预处理库
from tensorflow.keras.layers.experimental import preprocessing


pretrained_base = tf.keras.models.load_model(
    '../input/cv-course-models/cv-course-models/vgg16-pretrained-base',
)
pretrained_base.trainable = False

model = keras.Sequential([
    # Preprocessing
    preprocessing.RandomFlip('horizontal'), 
    # 从左向右翻转
    preprocessing.RandomContrast(0.5), 
    # 对比度变化高达50%
    # Base   VGG模型
    pretrained_base, 
    # Head
    layers.Flatten(),
    layers.Dense(6, activation='relu'),
    layers.Dense(1, activation='sigmoid'),
])

Step 3 - Train and Evaluate

model.compile(
    optimizer='adam',  # adam优化器
    loss='binary_crossentropy',
    metrics=['binary_accuracy'],
)

history = model.fit(
    ds_train,
    validation_data=ds_valid,
    epochs=30,
    verbose=0,
)
import pandas as pd

history_frame = pd.DataFrame(history.history)

history_frame.loc[:, ['loss', 'val_loss']].plot()
history_frame.loc[:, ['binary_accuracy', 'val_binary_accuracy']].plot();

在这里插入图片描述
该模型的学习曲线能够保持在一起,我们在验证损失和准确性方面取得了一些适度的改进。这表明数据集确实从增强中得到改进。

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

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

相关文章

华为云服务器无法正常访问端口

出错场景: 2023年1月7日22:05:32 在新服务器上运行自己服务端软件,其他客户端无法访问端口 进行连接。 服务端的程序启动了,客户端无法交互,连接失败。 首先检查能不能ping通 ping IP地址–发现是可以ping通的,再测…

活动星投票国风正当红网络评选微信的投票方式线上免费投票

“国风正当红”网络评选投票_第三方投票平台_优秀微信小程序_小程序投票优势近些年来,第三方的微信投票制作平台如雨后春笋般络绎不绝。随着手机的互联网的发展及微信开放平台各项基于手机能力的开放,更多人选择微信投票小程序平台,因为它有非…

python小游戏————兔子

♥️作者:小刘在这里 ♥️每天分享云计算网络运维课堂笔记,疫情之下,你我素未谋面,但你一定要平平安安,一 起努力,共赴美好人生! ♥️夕阳下,是最美的,绽放,…

【宝典】OpenStack集群、k8s集群与docker等集群综合巡检shell脚本

目标:学会编写高质量脚本的方法 高质量脚本应该至少满足两点: 1、当前最优 学会根据架构,设计出符合要求又便于理解的shell脚本 2、后期更新方便 优秀的shell脚本,具备伸缩性,既适用当前平台状态,又可以保证后期增加或下线哪个服务,脚本里增加代码不用改整体代码逻辑的…

JAVAEE-多线程(3)

volatile关键字 volatile禁止了编译器优化,还可以禁止指令重排序,避免了直接读取CPU寄存器中的缓存数据,而是每次都重新读内存。 因为编译器每次正常执行都是把主内存的数据加载到工作内存中,再进行计算处理。volatile即使保证每…

梦想cms1.4代码审计

目录 一、环境配置 二、代码审计 1、后台漏洞 (1)BookAction.class.php (2)BackdbAction.class.php任意文件删除 2、前台漏洞 (1)TagsAction.class.php (2)BookAction.cla…

深入理解数据结构 —— 树状数组

什么是树状数组 我们知道,前缀和数组能解决任意一段区间的累加和问题 但这建立在数组中的元素不发生变化的情况,如果可以修改原始数组中的某个元素,为了让前缀和数组正确,就需要在前缀和数组中修改该元素位置后面的所有的数&…

数组模拟实现单链表、双链表、栈、队列

文章目录 前引 一、数组模拟实现单链表 1、1 数组模拟的单链表解析 1、2 数组模拟实现单链表例题 二、数组模拟实现双链表 2、1 数组模拟实现双链表解析 2、2 数组模拟实现双链表例题 三、数组模拟实现栈 3、1 数组模拟实现栈解析 3、2 数组模拟实现栈例题 四、数组模拟实现队…

【C++学习】基础语法(一)

1、背景知识 1.1 什么是C C语言是结构化和模块化的语言,长用于处理较小规模的程序;对于规模较大、问题复杂的程序,则需要高度的抽象和建模,此时C语言不合适处理这类问题。为了解决此类影响软件的问题,20世纪80年代&am…

Python | Matplotlib | 不完全总结

本文对 Matplotlib 的用法进行不完全总结。 更新: 2023 / 1 / 4 Python | Matplotlib | 不完全总结ImageMagick导库画布创建多子图动图2D柱状图基本:水平 / 垂直柱形主题:颜色、文字、网格线动图线图基本动图3D柱状图基本线图动图参考链接Im…

Web文件操作:上传与下载

文件上传与下载文件上传文件上传的实现表结构设计UploadFileServiceImpl的实现上传文件遇到的问题与解决文件下载文件上传 文件上传的表单中,需要注意的三个地方: 1.表单的请求方式必须为post; 2.表单域必须有file类型; 3.表单的e…

活动星投票奋斗青春,使命必达网络评选微信的投票方式线上免费投票

“奋斗青春,使命必达”网络评选投票_如何进行投票推广_参与投票活动_小程序的投票发展现在来说,公司、企业、学校更多的想借助短视频推广自己。通过微信投票小程序,网友们就可以通过手机拍视频上传视频参加活动,而短视频微信投票评…

英伟达528.02驱动发布支持4070 Ti!GFE新增9款游戏

自GTX 4070 Ti显卡发售后,英伟达便随即发布了支持该新显卡的Game Ready 528.02驱动,同时为《战意》和《达喀尔沙漠拉力赛》两款新游戏带来DLSS 3的支持,DLSS 3的队伍再度壮大! 驱动人生现已支持英伟达Game Ready 528.02驱动&…

围绕http请求头中Referer展开的一些知识

1. 什么是referer&#xff1f; <点击以获取跳转信息 >跳转过去记得按一下f12点击网络请求详情&#xff0c;再刷新一下&#xff0c;就可以看见referer字段&#xff1a; 当我们尝试在浏览器内部直接输入这熟悉的网址时&#xff0c;此时刷新后则是这样一番景象&#xff1…

C++类和对象的基本概念

目录 1.c和c中struct的区别 2.类的封装 3.类的访问权限 1.c和c中struct的区别 c语言中结构体中不能存放函数,也就是数据(属性)和行为(方 法)是分离的 c中结构体中是可以存放函数的,也就是数据(属性)和行为 (方法)是封装在一起的 #define _CRT_SECURE_NO_WARNINGS #include …

基于Python tensorflow机器学习的人脸识别登陆系统源码、人脸注册系统源码

face_login 代码下载地址&#xff1a;基于Python tensorflow机器学习的人脸识别登陆系统源码、人脸注册系统源码 介绍 本项目基于tensorflow机器学习&#xff0c;实现web端人脸识别登陆&#xff0c;人脸注册。 提供手机端页面(face_login_app)和网页端页面(vue_element-adm…

JUC并发编程学习笔记(六)线程池及分支合并框架

10 ThreadPool 线程池&#xff08;重点&#xff09; 10.1 线程池简介 回顾以前的连接池概念 连接池是创建和管理一个连接的缓冲池的技术&#xff0c;这些连接准备好被任何需要它们的线程使用 线程池&#xff08;英语&#xff1a;thread pool&#xff09;&#xff1a;一种线程…

实时数仓,为什么不可代替?

什么是实时数据仓库&#xff1f;它有哪些不可替代之处&#xff1f; 大数据时代中&#xff0c;数据仓库解决了商业智能分析过程中的数据管理问题&#xff0c;但是存在烟囱式、冗余高的弊端 随着商业智能的兴起和数据时代的到来&#xff0c;越来越多的企业开始汇总、整合和分析自…

ArcGIS基础实验操作100例--实验62点、线、面状符号

本实验专栏参考自汤国安教授《地理信息系统基础实验操作100例》一书 实验平台&#xff1a;ArcGIS 10.6 实验数据&#xff1a;请访问实验1&#xff08;传送门&#xff09; 高级编辑篇--实验62 点、线、面状符号 目录 一、实验背景 二、实验数据 三、实验步骤 &#xff08;1&…

C/C++中二级指针传递参数【个人遇到内存值发生改变现象的记录及相关修正方法】

目录 0、前言 1、二级指针传参奇怪现象 2、分析 3、解决方法 0、前言 在c/c中&#xff0c;时常会使用到主调函数通过参数去获取被调函数中的数值情况。针对这种情况&#xff0c;我前面也写过C/C主调函数从被调函数中获取&#xff08;各种类型&#xff09;数据内容方式的梳理…