【再学Tensorflow2】TensorFlow2的层次结构

news2024/11/17 20:50:57

TensorFlow2的层次结构

  • Tensorflow的层次结构
  • Tensorflow的低阶API示例
    • 线性回归模型
      • 准备数据
      • 定义模型
      • 训练模型
    • DNN二分类模型
      • 准备数据
      • 定义模型
      • 训练模型
  • Tensorflow的中阶API示例
    • 线性回归模型
    • DNN二分类模型
  • Tensorflow的高阶API示例
    • 线性回归模型
      • 定义模型
      • 训练模型
    • DNN二分类模型
      • 定义模型
      • 训练模型
  • 参考资料

TensorFlow中5个不同的层次结构:即硬件层,内核层,低阶API,中阶API,高阶API。本文以线性回归和DNN二分类模型为例,直观对比展示在不同层级实现模型的特点。

Tensorflow的层次结构

TensorFlow的层次结构从低到高可以分成如下五层:

  • 最底层为硬件层,TensorFlow支持CPU、GPU或TPU加入计算资源池。
  • 第二层为C++实现的内核,kernel可以跨平台分布运行。
  • 第三层为Python实现的操作符,提供了封装C++内核的低级API指令,主要包括各种张量操作算子、计算图、自动微分。如tf.Variable,tf.constant,tf.function,tf.GradientTape,tf.nn.softmax… 如果把模型比作一个房子,那么第三层API就是模型之砖
  • 第四层为Python实现的模型组件,对低级API进行了函数封装,主要包括各种模型层,损失函数,优化器,数据管道,特征列等等。如tf.keras.layers,tf.keras.losses,tf.keras.metrics,tf.keras.optimizers,tf.data.DataSet,tf.feature_column…如果把模型比作一个房子,那么第四层API就是模型之墙
  • 第五层为Python实现的模型成品,一般为按照OOP方式封装的高级API,主要为tf.keras.models提供的模型的类接口。如果把模型比作一个房子,那么第五层API就是模型本身,即模型之屋

Tensorflow的层次结构

Tensorflow的低阶API示例

低阶API主要包括张量操作计算图自动微分

import tensorflow as tf


#打印时间分割线
@tf.function
def printbar():
    today_ts = tf.timestamp() % (24 * 60 * 60)

    hour = tf.cast(today_ts // 3600 + 8, tf.int32) % tf.constant(24)
    minite = tf.cast((today_ts % 3600) // 60, tf.int32)
    second = tf.cast(tf.floor(today_ts % 60), tf.int32)

    def timeformat(m):
        if tf.strings.length(tf.strings.format("{}", m)) == 1:
            return (tf.strings.format("0{}", m))
        else:
            return (tf.strings.format("{}", m))

    timestring = tf.strings.join([timeformat(hour), timeformat(minite), timeformat(second)], separator=":")
    tf.print("==========" * 8 + timestring)

下面使用TensorFlow的低阶API实现线性回归模型和DNN二分类模型:

线性回归模型

准备数据

import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
import tensorflow as tf

# 样本数量
n = 400
# 生成测试用数据集
X= tf.random.uniform([n,2], minval=-10, maxval=10)
w0 = tf.constant([[2.0], [-3.0]])
b0 = tf.constant([[3.0]])

# @表示矩阵惩罚,并增加正态扰动
Y = X@w0+b0+tf.random.normal([n,1],mean=0.0, stddev=2.0)

数据可视化

%matplotlib inline
%config InlineBackend.figure_format = 'svg'
# 数据可视化
plt.figure(figsize=(12, 5))
ax1 = plt.subplot(121)
ax1.scatter(X[:,0], Y[:,0], c='b')
plt.xlabel('x1')
plt.ylabel('y', rotation = 0)

ax2 = plt.subplot(122)
ax2.scatter(X[:,1],Y[:,0],c='g')
plt.xlabel('x2')
plt.ylabel('y', rotation=0)
plt.show()

数据可视化
构建数据管道迭代器

def data_iter(features, labels, batch_size=8):
    num_examples = len(features)
    indices = list(range(num_examples))
    np.random.shuffle(indices) # 样本的读取顺序是随机的
    for i in range(0, num_examples, batch_size):
        indexs = indices[i: min(i + batch_size, num_examples)]
        yield tf.gather(features,indexs), tf.gather(labels, indexs)

# 测试数据管道效果
batch_size = 8
(features, labels) = next(data_iter(X, Y, batch_size))
print(features)
print(labels)

数据管道效果:

tf.Tensor(
[[-5.076039   -0.9657364 ]
 [-6.358912   -3.6004496 ]
 [-7.056513   -3.9889216 ]
 [ 2.3329067  -2.8891182 ]
 [-5.9270716  -8.905029  ]
 [-0.16547203 -3.6211562 ]
 [ 6.9834538  -1.579752  ]
 [-5.3834534   2.5390549 ]], shape=(8, 2), dtype=float32)
tf.Tensor(
[[ -1.4625118]
 [  1.6316607]
 [  2.0894573]
 [ 12.264805 ]
 [ 16.555326 ]
 [ 10.086447 ]
 [ 21.4322   ]
 [-14.078172 ]], shape=(8, 1), dtype=float32)

定义模型

w = tf.Variable(tf.random.normal(w0.shape))
b = tf.Variable(tf.zeros_like(b0, dtype=tf.float32))


# 定义模型
class LinearRegression:
    # 正向传播
    def __call__(self, x):
        return x @ w + b

    # 损失函数
    def loss_func(self, y_true, y_pred):
        return tf.reduce_mean((y_true - y_pred) ** 2 / 2)


model = LinearRegression()

训练模型

  1. 使用动态图调试
# 使用动态图调试
def train_step(model, features, labels):
    with tf.GradientTape() as tape:
        predictions = model(features)
        loss = model.loss_func(labels, predictions)
    # 反向传播求梯度
    dloss_dw, dloss_db = tape.gradient(loss, [w, b])
    # 梯度下降法更新参数
    w.assign(w - 0.001*dloss_dw)
    b.assign(b - 0.001*dloss_db)
    return loss

测试train_step效果:

batch_size = 10
(features, labels) = next(data_iter(X, Y, batch_size))
train_step(model, features, labels)
'''
<tf.Tensor: shape=(), dtype=float32, numpy=277.26096>
'''

定义模型训练函数:

def train_model(model, epochs):
    for epoch in tf.range(1, epochs+1):
        for features, labels in data_iter(X, Y, 10):
            loss = train_step(model, features, labels)

        if epoch%50==0:
            tf.print('=========='*8)
            tf.print('epoch =',epoch, "loss = ",loss)
            tf.print('w = ',w)
            tf.print('b = ',b)

train_model(model, epochs=200)

训练过程:

================================================================================
epoch = 50 loss =  0.846690834
w =  [[1.99412823]
 [-2.99952745]]
b =  [[3.04354715]]
================================================================================
epoch = 100 loss =  1.1837182
w =  [[1.99304128]
 [-2.99331546]]
b =  [[3.04392529]]
================================================================================
epoch = 150 loss =  1.58060181
w =  [[1.99656463]
 [-2.98927522]]
b =  [[3.04404855]]
================================================================================
epoch = 200 loss =  2.5443294
w =  [[2.00231266]
 [-2.97837281]]
b =  [[3.04363918]]
  1. 使用autograph机制转换成静态图加速
@tf.function
def train_step(model, features, labels):
    with tf.GradientTape() as tape:
        predictions = model(features)
        loss = model.loss_func(labels, predictions)
    # 反向传播求梯度
    dloss_dw, dloss_db = tape.gradient(loss, [w, b])
    # 梯度下降法更新参数
    w.assign(w - 0.001 * dloss_dw)
    b.assign(b - 0.001 * dloss_db)

    return loss


def train_model(model, epochs):
    for epoch in tf.range(1, epochs + 1):
        for features, labels in data_iter(X, Y, 10):
            loss = train_step(model, features, labels)
        if epoch % 50 == 0:
            tf.print('=========='*8)
            tf.print("epoch =", epoch, "loss = ", loss)
            tf.print("w =", w)
            tf.print("b =", b)


train_model(model, epochs=200)

训练过程:

================================================================================
epoch = 50 loss =  1.16669047
w = [[1.99806643]
 [-2.99671936]]
b = [[3.04368925]]
================================================================================
epoch = 100 loss =  1.40429044
w = [[2.00206447]
 [-2.98451281]]
b = [[3.04383779]]
================================================================================
epoch = 150 loss =  1.7426182
w = [[1.98978758]
 [-2.99107504]]
b = [[3.04403]]
================================================================================
epoch = 200 loss =  2.16272426
w = [[1.99508071]
 [-2.98746681]]
b = [[3.04382515]]

结果可视化

%matplotlib inline
%config InlineBackend.figure_format = 'svg'

plt.figure(figsize=(12, 5))
ax1 = plt.subplot(121)
ax1.scatter(X[:, 0], Y[:, 0], c="b", label="samples")
ax1.plot(X[:, 0], w[0] * X[:, 0] + b[0], "-r", linewidth=5.0, label="model")
ax1.legend()
plt.xlabel("x1")
plt.ylabel("y", rotation=0)

ax2 = plt.subplot(122)
ax2.scatter(X[:, 1], Y[:, 0], c="g", label="samples")
ax2.plot(X[:, 1], w[1] * X[:, 1] + b[0], "-r", linewidth=5.0, label="model")
ax2.legend()
plt.xlabel("x2")
plt.ylabel("y", rotation=0)

plt.show()

线性回归拟合可视化

DNN二分类模型

准备数据

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf

配置notebook的cell:

%matplotlib inline
%config InlineBackend.figure_format = 'svg'

生成正负样本:

# 正负样本数量
n_positive, n_negative = 2000, 2000

# 生成正样本,小圆环分布
r_p = 5.0 + tf.random.truncated_normal([n_positive,1], 0.0, 1.0)
theta_p = tf.random.uniform([n_positive,1], 0.0, 2*np.pi)
Xp = tf.concat([r_p*tf.cos(theta_p), r_p*tf.sin(theta_p)], axis=1)
Yp = tf.ones_like(r_p)

# 生成负样本, 大圆环分布
r_n = 8.0 + tf.random.truncated_normal([n_negative, 1], 0.0, 1.0)
theta_n = tf.random.uniform([n_negative, 1], 0.0, 2*np.pi)
Xn = tf.concat([r_n*tf.cos(theta_n), r_n*tf.sin(theta_n)], axis=1)
Yn = tf.zeros_like(r_n)

# 汇总数据
X = tf.concat([Xp, Xn], axis=0)
Y = tf.concat([Yp, Yn], axis=0)

可视化数据:

# 可视化
plt.figure(figsize=(6,6))
plt.scatter(Xp[:,0].numpy(), Xp[:,1].numpy(), c='r')
plt.scatter(Xn[:,0].numpy(), Xn[:,1].numpy(), c='g')
plt.legend(['positive','negative'])

数据分布
构建数据管道迭代器:

# 构建数据管道迭代器
def data_iter(features, labels, batch_size=8):
    num_examples = len(features)
    indices = list(range(num_examples))
    np.random.shuffle(indices)  #样本的读取顺序是随机的
    for i in range(0, num_examples, batch_size):
        indexs = indices[i: min(i + batch_size, num_examples)]
        yield tf.gather(features,indexs), tf.gather(labels,indexs)

# 测试数据管道效果
batch_size = 10
(features, labels) = next(data_iter(X, Y, batch_size))
print(features)
print(labels)

定义模型

这里利用tf.Module来组织模型变量:

class DNNModel(tf.Module):
    def __init__(self, name=None):
        super(DNNModel, self).__init__(name=name)
        self.w1 = tf.Variable(tf.random.truncated_normal([2, 4]), dtype=tf.float32)
        self.b1 = tf.Variable(tf.zeros([1, 4]), dtype=tf.float32)
        self.w2 = tf.Variable(tf.random.truncated_normal([4, 8]), dtype=tf.float32)
        self.b2 = tf.Variable(tf.zeros([1, 8]), dtype=tf.float32)
        self.w3 = tf.Variable(tf.random.truncated_normal([8, 1]), dtype=tf.float32)
        self.b3 = tf.Variable(tf.zeros([1, 1]), dtype=tf.float32)

    # 正向传播
    @tf.function(input_signature=[tf.TensorSpec(shape=[None, 2], dtype=tf.float32)])
    def __call__(self, x):
        x = tf.nn.relu(x @ self.w1 + self.b1)
        x = tf.nn.relu(x @ self.w2 + self.b2)
        y = tf.nn.sigmoid(x @ self.w3 + self.b3)
        return y

    # 损失函数(二元交叉熵)
    @tf.function(input_signature=[tf.TensorSpec(shape=[None, 1], dtype=tf.float32),
                                  tf.TensorSpec(shape=[None, 1], dtype=tf.float32)])
    def loss_func(self, y_true, y_pred):
        # 将预测值限制在1e-7以下, 1-1e-7以下,避免log(0)错误
        eps = 1e-7
        y_pred = tf.clip_by_value(y_pred, eps, 1.0 - eps)
        bce = -y_true * tf.math.log(y_pred) - (1 - y_true) * tf.math.log(1 - y_pred)
        return tf.reduce_mean(bce)

    # 评估指标(准确率)
    @tf.function(input_signature=[tf.TensorSpec(shape=[None, 1], dtype=tf.float32),
                                  tf.TensorSpec(shape=[None, 1], dtype=tf.float32)])
    def metric_func(self, y_true, y_pred):
        y_pred = tf.where(y_pred > 0.5, tf.ones_like(y_pred, dtype=tf.float32), tf.zeros_like(y_pred, dtype=tf.float32))
        acc = tf.reduce_mean(1 - tf.abs(y_true - y_pred))
        return acc


model = DNNModel()

测试模型结构:

batch_size = 10
(features, labels) = next(data_iter(X, Y, batch_size))

predictions = model(features)

loss = model.loss_func(labels, predictions)
metric = model.metric_func(labels, predictions)

tf.print("init loss:", loss)
tf.print("init metric", metric)
'''
init loss: 0.475380838
init metric 0.8
'''
print(len(model.trainable_variables)) # 6

训练模型

使用autograph机制转换成静态图加速:

@tf.function
def train_step(model, features, labels):
    # 正向传播,计算损失
    with tf.GradientTape() as tape:
        predictions = model(features)
        loss = model.loss_func(labels, predictions)
    # 反向传播,计算梯度
    grads = tape.gradient(loss, model.trainable_variables)
    # 执行梯度下降
    for p, dloss_dp in zip(model.trainable_variables, grads):
        p.assign(p - 0.001 * dloss_dp)

    # 计算评估指标
    metric = model.metric_func(labels, predictions)
    return loss, metric


def train_model(model, epochs):
    for epoch in tf.range(1, epochs + 1):
        for features, labels in data_iter(X, Y, 100):
            loss, metric = train_step(model, features, labels)
        if epoch % 100 == 0:
            print('======='*10)
            tf.print("epoch =", epoch, "loss = ", loss, "accuracy = ", metric)


train_model(model, epochs=600)

训练记录:

======================================================================
epoch = 100 loss =  0.544845939 accuracy =  0.79
======================================================================
epoch = 200 loss =  0.475 accuracy =  0.85
======================================================================
epoch = 300 loss =  0.391879201 accuracy =  0.88
======================================================================
epoch = 400 loss =  0.378405839 accuracy =  0.92
======================================================================
epoch = 500 loss =  0.289739966 accuracy =  0.98
======================================================================
epoch = 600 loss =  0.310408324 accuracy =  0.87

结果可视化:

fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=(12, 5))
ax1.scatter(Xp[:, 0], Xp[:, 1], c="r")
ax1.scatter(Xn[:, 0], Xn[:, 1], c="g")
ax1.legend(["positive", "negative"]);
ax1.set_title("y_true");

Xp_pred = tf.boolean_mask(X, tf.squeeze(model(X) >= 0.5), axis=0)
Xn_pred = tf.boolean_mask(X, tf.squeeze(model(X) < 0.5), axis=0)

ax2.scatter(Xp_pred[:, 0], Xp_pred[:, 1], c="r")
ax2.scatter(Xn_pred[:, 0], Xn_pred[:, 1], c="g")
ax2.legend(["positive", "negative"]);
ax2.set_title("y_pred");

结果可视化

Tensorflow的中阶API示例

TensorFlow的中阶API主要包括各种模型层损失函数优化器数据管道特征列等。

线性回归模型

构建输入数据管道

ds = tf.data.Dataset.from_tensor_slices((X, Y)).shuffle(buffer_size=100).batch(10).prefetch(tf.data.experimental.AUTOTUNE)

定义模型

from tensorflow.keras import layers,losses,metrics,optimizers

model = layers.Dense(units=1)
model.build(input_shape=(2,)) # 用build方法创建variables
model.loss_func = losses.mean_squared_error
model.optimizer = optimizers.SGD(learning_rate=0.001)

训练模型
使用autograph机制转换成静态图加速

@tf.function
def train_step(model, features, labels):
    with tf.GradientTape() as tape:
        predictions = model(features)
        loss = model.loss_func(tf.reshape(labels, [-1]), tf.reshape(predictions, [-1]))
    grads = tape.gradient(loss, model.variables)
    model.optimizer.apply_gradients(zip(grads, model.variables))
    return loss


# 测试train_step效果
features, labels = next(ds.as_numpy_iterator())
train_step(model, features, labels)

训练模型:

def train_model(model, epochs):
    for epoch in tf.range(1, epochs + 1):
        loss = tf.constant(0.0)
        for features, labels in ds:
            loss = train_step(model, features, labels)
        if epoch % 50 == 0:
            print('=======' * 10)
            tf.print("epoch =", epoch, "loss = ", loss)
            tf.print("w =", model.variables[0])
            tf.print("b =", model.variables[1])


train_model(model, epochs=200)

训练结果:

======================================================================
epoch = 50 loss =  0.164111629
w = [[0.00108379347]
 [-0.0043063662]]
b = [0.401051134]
======================================================================
epoch = 100 loss =  0.168586373
w = [[-0.00195285561]
 [-0.00462398]]
b = [0.401163816]
======================================================================
epoch = 150 loss =  0.159221083
w = [[-0.0010873822]
 [-0.00306460424]]
b = [0.4011105]
======================================================================
epoch = 200 loss =  0.157091931
w = [[0.0010298203]
 [-0.00437747035]]
b = [0.401103854]

DNN二分类模型

构建输入数据管道

ds = tf.data.Dataset.from_tensor_slices((X, Y)).shuffle(buffer_size=4000).batch(100).prefetch(tf.data.experimental.AUTOTUNE)

定义模型

class DNNModel(tf.Module):
    def __init__(self, name=None):
        super(DNNModel, self).__init__(name=name)
        self.dense1 = layers.Dense(4, activation='relu')
        self.dense2 = layers.Dense(8, activation='relu')
        self.dense3 = layers.Dense(1, activation='sigmoid')

    # 正向传播
    @tf.function(input_signature=[tf.TensorSpec(shape=[None, 2], dtype=tf.float32)])
    def __call__(self, x):
        x = self.dense1(x)
        x = self.dense2(x)
        y = self.dense3(x)
        return y

model = DNNModel()
model.loss_func = losses.binary_crossentropy
model.metric_func = metrics.binary_crossentropy
model.optimizer = optimizers.Adam(learning_rate=0.001)

测试模型结构:

(features,labels) = next(ds.as_numpy_iterator())

predictions = model(features)

loss = model.loss_func(tf.reshape(labels,[-1]),tf.reshape(predictions,[-1]))
metric = model.metric_func(tf.reshape(labels,[-1]),tf.reshape(predictions,[-1]))

tf.print("init loss:",loss)
tf.print("init metric",metric)

训练模型
使用autograph机制转换成静态图加速

@tf.function
def train_step(model, features, labels):
    with tf.GradientTape() as tape:
        predictions = model(features)
        loss = model.loss_func(tf.reshape(labels,[-1]), tf.reshape(predictions,[-1]))
    grads = tape.gradient(loss,model.trainable_variables)
    model.optimizer.apply_gradients(zip(grads,model.trainable_variables))

    metric = model.metric_func(tf.reshape(labels,[-1]), tf.reshape(predictions,[-1]))

    return loss,metric

# 测试train_step效果
features,labels = next(ds.as_numpy_iterator())
train_step(model,features,labels)

模型训练:

def train_model(model,epochs):
    for epoch in tf.range(1,epochs+1):
        loss, metric = tf.constant(0.0),tf.constant(0.0)
        for features, labels in ds:
            loss,metric = train_step(model,features,labels)
        if epoch%10==0:
            print('=======' * 10)
            tf.print("epoch =",epoch,"loss = ",loss, "accuracy = ",metric)
train_model(model,epochs = 60)

Tensorflow的高阶API示例

TensorFlow的高阶API主要为tf.keras.models提供的模型的类接口。使用Keras接口有以下3种方式构建模型:①使用Sequential按层顺序构建模型,②使用函数式API构建任意结构模型,③继承Model基类构建自定义模型。

线性回归模型

使用Sequential按层顺序构建模型,并使用内置model.fit方法训练模型(初级方法)

定义模型

定义模型

训练模型

使用fit方法进行训练:
训练模型

DNN二分类模型

使用继承Model基类构建自定义模型,并构建自定义训练循环(高级方法):

ds_train = tf.data.Dataset.from_tensor_slices((X[0:n*3//4,:],Y[0:n*3//4,:])).shuffle(buffer_size = 1000).batch(20).prefetch(tf.data.experimental.AUTOTUNE).cache()

ds_valid = tf.data.Dataset.from_tensor_slices((X[n*3//4:,:],Y[n*3//4:,:])).batch(20).prefetch(tf.data.experimental.AUTOTUNE).cache()

定义模型

tf.keras.backend.clear_session()


class DNNModel(models.Model):
    def __init__(self):
        super(DNNModel, self).__init__()

    def build(self, input_shape):
        self.dense1 = layers.Dense(4, activation="relu", name="dense1")
        self.dense2 = layers.Dense(8, activation="relu", name="dense2")
        self.dense3 = layers.Dense(1, activation="sigmoid", name="dense3")
        super(DNNModel, self).build(input_shape)

    # 正向传播
    @tf.function(input_signature=[tf.TensorSpec(shape=[None, 2], dtype=tf.float32)])
    def call(self, x):
        x = self.dense1(x)
        x = self.dense2(x)
        y = self.dense3(x)
        return y


model = DNNModel()
model.build(input_shape=(None, 2))

model.summary()

模型概览:

Model: "dnn_model"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 dense1 (Dense)              multiple                  12        
                                                                 
 dense2 (Dense)              multiple                  40        
                                                                 
 dense3 (Dense)              multiple                  9         
                                                                 
=================================================================
Total params: 61
Trainable params: 61
Non-trainable params: 0
_________________________________________________________________

训练模型

自定义训练循环

optimizer = optimizers.Adam(learning_rate=0.01)
loss_func = tf.keras.losses.BinaryCrossentropy()

train_loss = tf.keras.metrics.Mean(name='train_loss')
train_metric = tf.keras.metrics.BinaryAccuracy(name='train_accuracy')

valid_loss = tf.keras.metrics.Mean(name='valid_loss')
valid_metric = tf.keras.metrics.BinaryAccuracy(name='valid_accuracy')


@tf.function
def train_step(model, features, labels):
    with tf.GradientTape() as tape:
        predictions = model(features)
        loss = loss_func(labels, predictions)
    grads = tape.gradient(loss, model.trainable_variables)
    optimizer.apply_gradients(zip(grads, model.trainable_variables))

    train_loss.update_state(loss)
    train_metric.update_state(labels, predictions)


@tf.function
def valid_step(model, features, labels):
    predictions = model(features)
    batch_loss = loss_func(labels, predictions)
    valid_loss.update_state(batch_loss)
    valid_metric.update_state(labels, predictions)


def train_model(model, ds_train, ds_valid, epochs):
    for epoch in tf.range(1, epochs + 1):
        for features, labels in ds_train:
            train_step(model, features, labels)

        for features, labels in ds_valid:
            valid_step(model, features, labels)
        logs = 'Epoch={},Loss:{},Accuracy:{},Valid Loss:{},Valid Accuracy:{}'

        if epoch % 100 == 0:
            print('=======' * 10)
            tf.print(tf.strings.format(logs,
                                       (epoch, train_loss.result(), train_metric.result(), valid_loss.result(),
                                        valid_metric.result())))

        train_loss.reset_states()
        valid_loss.reset_states()
        train_metric.reset_states()
        valid_metric.reset_states()

train_model(model, ds_train, ds_valid, 1000)

参考资料

[1] 《30天吃掉那只Tensorflow》

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

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

相关文章

微信小程序开发实战10_1 小程序支付业务介绍

移动支付已成大多数消费者日常使用的支付方式之一。移动支付拥有操作简单方便、无需带现金或银行卡&#xff0c;不用找零&#xff0c;目前超过四分之三的用户都在使用移动支付。小程序应用作为一个广泛使用的移动应用&#xff0c;自然也不会放弃移动支付这个大的蛋糕。本章将介…

opencv文件介绍

build&#xff1a;存放.h.hpp.lib文件 bin .dll etc&#xff1a;存放训练好的分类器&#xff0c;用于人脸识别 include&#xff1a;所有的头文件 opencv2 • calib3d&#xff1a;相机校准、姿态估计和三维重建 • core&#xff1a;核心功能模块 • dnn&#xff1a;深度学习模块…

docker(6):Docker网络

目录docker网络介绍docker网络模式常用命令docker网络原理自定义网络实战&#xff1a;redis主从部署docker网络介绍 实际只要我们启动docker&#xff0c;那么主机上就会产生一个名字为docker0的虚拟网桥。它在内核层连通了其他的物理或虚拟网卡&#xff0c;这就将所有容器和本…

【Apifox】Apifox导入knife4j文档

文章目录手动导入自动导入手动导入 在浏览器中打开knife4j文档地址&#xff0c;并按F12打开控制台&#xff1a; 复制api-docs这个接口的请求地址。打开Apifox >> 项目设置 >> 导入数据&#xff08;手动导入&#xff09; >> URL导入 >> 把接口的请求地…

蔚来汽车李斌与黑客的数据战争!

‍‍数据智能产业创新服务媒体——聚焦数智 改变商业全面拥抱数字化的浪潮早已袭来&#xff0c;但数据的安全性也成为各行各业关注的焦点。近日&#xff0c;蔚来汽车用户数据遭泄露引发热议。针对此次事件&#xff0c;蔚来先后由其官方、创始人李斌及相关负责人卢龙三次致歉&a…

从数据分析,看公司员工流失率分析报告

一、概述&#xff1a; 1、员工离职和员工流失率的概念&#xff1a; 员工离职&#xff1a;员工被辞退及辞职、不续签的情况 员工流失率&#xff08;离职率&#xff09;&#xff1a;公司离职的员工人数/&#xff08;入职人数最初原有人数&#xff09;*100% 例如&#xff1a;月…

Spring Cloud 介绍及负载均衡Ribbon、服务容错Hystrix 组件使用详解

Spring Cloud 概述 官网 简介 Spring Cloud是一个基于 Spring Boot实现的微服务架构开发框架。它为微服务架构中涉及的配置管理、服务治理、断路器、智能路由、微代理、控制总线、全局锁、决策竞选、分布式会话和集群状态管理等操作提供了一种简单的开发方式。 Spring Clou…

linux 生成火焰图

1. 火焰图简介 火焰图&#xff08;flame graph&#xff09;是性能分析的利器&#xff0c;通过它可以快速定位性能瓶颈点。 perf 命令&#xff08;performance 的缩写&#xff09;是 Linux 系统原生提供的性能分析工具&#xff0c;会返回 CPU 正在执行的函数名以及调用栈&#…

前瞻 2023年加密行业会更难吗?欧科云链研究院“七大趋势预测”

回望2022&#xff0c;加密行业遭遇了种种不可控因素而导致的艰难险阻&#xff0c;也在变革与发展中孕育着生机与活力。 这一年&#xff0c;我们亲眼目睹了Luna暴雷&#xff0c;三箭资本、FTX这些曾经被认为“大而不倒”的机构接连倒下&#xff0c;市场信心严重受挫&#xff1b;…

量子计算(十八):量子计算机

文章目录 量子计算机 一、量子计算机整体架构 1、量子计算的定位&#xff1a;异构计算 2、量子程序代码构成&#xff1a;宿主代码设备代码 二、量子程序架构&#xff08;设备代码的架构&#xff09; 1、量子高级语言 2、量子汇编语言的编译原则 3、不可直接执行的量子比…

当产业互联网时代来临,显著的特点就在于互联网技术不再是主导

事实上&#xff0c;以往&#xff0c;我们所经历的那个互联网玩家频出的年代&#xff0c;其实就是一个以互联网技术为主导的年代。在那样一个年代里&#xff0c;互联网技术几乎是解决一切痛点和难题的万能解药&#xff0c;几乎是破解一切行业痛点和难题的杀手锏。任何一个行业&a…

特斯拉超级充电突破1万桩 充电比加油更方便

12月26日&#xff0c;特斯拉中国大陆第1万个超级充电桩落户上海东方明珠脚下&#xff0c;成为我国新能源汽车整车品牌中屈指可数拥有“万级”大功率直流充电网络的企业&#xff0c;助力中国“新基建”再上高峰&#xff0c;也为中国“双碳”目标的达成再添“电力”。至此&#x…

SpringBoot+VUE前后端分离项目学习笔记 - 【01 环境配置以及VUE2集成ElementUI】

技术栈一览 SpringBoot2 Vue2 ElementUI Axios Hutool Mysql Echarts 所需软件环境 版本一览 JDK 1.8Mysql5.7Node 14.16.0navicatIdea 2021 Vue-cli 安装 npm install -g vue/cli 查看版本 创建VUE工程 初始化工程 vue create vue 选择Manually select feature…

PLDI‘21-Path-Sensitive Sparse Analysis without Path Conditions-基于程序依赖图的路径敏感稀疏分析

这篇文章是港科大团队在PLDI 2021会议上发表的文章。在这之前&#xff0c;作者在PLDI 2018发表Pinpoint。这篇文章在Pinpoint上改进。在Pinpoint的设计中&#xff0c;存储摘要的时候仍然需要缓存大量的路径条件&#xff0c;以及在应用摘要时进行大量的克隆&#xff0c;导致逻辑…

Memtiter-benchmark源码解析1client类功能解析

client类功能解析 client.h m_event_base 为libevent loop 的事件循环类 define MAIN_CONNECTION m_connections[0] client.cpp client 构造函数初始化 client.cpp Line 55 conn 构造一个新对象 connect()函数 从m_config中读取出服务器ip地址和端口&#xff0c;通过sc->…

利用mAP评估目标检测模型

在本文[1]中&#xff0c;我们将了解如何使用 precision 和召回率来计算平均精度 (mAP)。mAP 将真实边界框与检测到的框进行比较并返回分数。分数越高&#xff0c;模型的检测越准确。 之前我们详细研究了混淆矩阵、模型准确性、精确度和召回率。我们也使用 Scikit-learn 库来计算…

MindSpore模型快速调优攻略笔记分享(下)

3.MindSpore云上调试调优 ModelArts云上调试调优 详细教程: https://support.huaweicloud.com/prepare-modelarts/modelarts 08 0002.html MindSpore IDE插件效率提升 通过智能代码块推荐、代码自动补全等特性&#xff0c;提升MindSpore脚本开发效率&#xff0c;对接ModelA…

2023年无线运动耳机排行榜最新公布、公认最好的运动耳机推荐

随着人们日益对健康的重视&#xff0c;”全民健身“正在全国&#xff0c;乃至全世界蔓延开来&#xff0c;其中跑步锻炼凭借着门槛低&#xff0c;益处多成为了大部分人的健身的首选。而随着跑步大军的壮大&#xff0c;国内蓝牙耳机市场也是一片火热。其中蓝牙无线运动耳机凭借着…

快速了解ZigBee的协议栈

带大家来一起快速的看懂ZigBee的协议栈的运行流程。 1.读任何程序都需要从main函数入手&#xff0c;那我们先来看Zmain.c中的main函数。 问题&#xff1a;在main中我们会看到很多的函数&#xff0c;我们究竟要看哪个函数呢? 回答&#xff1a;这么多的函数中其实我们只需要关注…

Horn:2层BLS签名聚合协议

1. 引言 Horn为2层BLS签名聚合协议&#xff0c;使得在以太坊共识层&#xff0c;为每个slot&#xff0c;聚合来自整个validator set的所有签名&#xff0c;即使这个validator set成员多达100万个。相比于现有的只能聚合1/32的validator set来说&#xff0c;有了大幅改进。 现有…