特征工程技巧——字符串编码成数字序列

这段时间在参加比赛,发现有一些比赛上公开的代码,其中的数据预处理步骤值得我们参考。

平常我们见到的都是数据预处理,现在我们来讲一下特征工程跟数据预处理的区别。

  1. 数据预处理是指对原始数据进行清洗、转换、缩放等操作,以便为后续的建模或分析任务做准备。这包括处理缺失值、异常值、重复值,以及对数据进行归一化、标准化等操作,使数据适合模型处理。

  2. 特征工程则更侧重于从原始数据中提取、构建或转换特征,以提高模型的性能。这包括特征选择、特征抽取、特征转换等过程。在特征工程中,可以创建新的特征、组合现有特征、进行降维等操作,以便使模型更好地捕捉数据中的模式和关系

 训练集

测试集

注:这个代码也可以用在自己的工程项目中,还是比较不错的!也是目前在Kaggle社区里公开代码分数比较高的一个单模型。

在这个代码里,我们将训练使用所有的数据可用的深度学习模型!

预处理: 我把所有训练集的和测试集的smiles编码并保存在这里,这可能需要1个小时的 TPU。

训练与推理: 我使用了一个简单的1dcnn 模型对20个epochs进行训练。

如何改进:

尝试不同的体系结构: 我能够得到0.604的 LB 分数,只需对这个体系结构进行一些小的更改。

尝试另一个模型,如Transformer,或 LSTM。

为更多的epochs而训练。

添加更多特性,比如 bb2或 bb3的热编码。

当然还有 GBDT 模型。

1、导入相应的包 

!pip install fastparquet -q

fastparquet用于读写Parquet格式的数据文件。 

2、导入库

import gc
import os
import pickle
import random
import joblib
import numpy as np
import pandas as pd
from tqdm import tqdm
from sklearn.model_selection import StratifiedKFold
from sklearn.metrics import average_precision_score as APS

 这段代码导入了必要的Python库,包括用于数据处理和建模的常见库,例如pandas、numpy、scikit-learn等。它还使用了tqdm来显示进度条。

3、定义配置参数

class CFG:PREPROCESS = FalseEPOCHS = 100BATCH_SIZE = 4096LR = 1e-3WD = 0.05NBR_FOLDS = 15SELECTED_FOLDS = [0]SEED = 2024

这里定义了一个名为CFG的类,用于存储一些全局配置参数。这些参数包括是否进行数据预处理、训练时的迭代次数、批量大小、学习率、权重衰减等。NBR_FOLDS表示交叉验证的折数,SELECTED_FOLDS表示选择参与训练的折数,SEED是随机种子。这里我们表示只选择第一份数据作为验证集,其余14份数据作为训练集。

4、设置随机数种子

import tensorflow as tf
def set_seeds(seed):os.environ['PYTHONHASHSEED'] = str(seed)random.seed(seed)tf.random.set_seed(seed)np.random.seed(seed)set_seeds(seed=CFG.SEED)

set_seeds()函数用于设置随机种子,确保实验的可重复性。它设置了Python、NumPy、random和TensorFlow的随机种子。 

注:str是用于字符串操作的内置数据类型,而os.environ是用于管理操作系统环境变量的模块对象。在这段代码中,str(seed)用于将整数转换为字符串,os.environ['PYTHONHASHSEED']用于设置Python的哈希种子。

5、分布式策略

import tensorflow as tf# Detect hardware, return appropriate distribution strategy
try:tpu = tf.distribute.cluster_resolver.TPUClusterResolver.connect(tpu="local") # "local" for 1VM TPUstrategy = tf.distribute.TPUStrategy(tpu)print("Running on TPU")print("REPLICAS: ", strategy.num_replicas_in_sync)
except tf.errors.NotFoundError:print("Not on TPU")

这段代码尝试连接到TPU(如果可用),并创建了一个分布式策略strategy,以便在TPU上进行训练。如果没有TPU可用,则打印"Not on TPU"。strategy.num_replicas_in_sync用于获取分布式策略中的副本数。 

tf.distribute.cluster_resolver.TPUClusterResolver 是 TensorFlow 中用于连接 TPU(Tensor Processing Unit,张量处理单元)集群的类。下面是对其功能的解释:

  • 连接到TPU集群:TPUClusterResolver 的主要作用是连接到 TPU 集群,以便在该集群上执行 TensorFlow 计算任务。

  • **指定TPU名称:**你可以通过 TPUClusterResolver 类来指定要连接的 TPU 的名称,可以是本地的 TPU(local),也可以是远程的 TPU。例如,在上述代码中,使用了 tpu="local" 来指定连接到本地的 TPU。

  • **解析TPU集群地址:**除了连接到指定的 TPU 外,TPUClusterResolver 还可以解析 TPU 集群的地址,以便连接到指定地址的 TPU 集群。这对于连接到远程的 TPU 集群非常有用。

  • **获取TPU实例信息:**一旦连接到了 TPU 集群,TPUClusterResolver 还可以提供关于 TPU 实例的信息,例如 TPU 的数量、类型等。

在上述代码中,TPUClusterResolver 被用于连接到本地的 TPU(tpu="local")。如果连接成功,将返回一个 TPUClusterResolver 对象,否则会抛出异常。连接成功后,可以使用该对象来获取有关 TPU 集群的信息,并将其用于 TensorFlow 的分布式计算任务。我这里用的是云服务器上的TPU。

tf.distribute.TPUStrategy 是 TensorFlow 中专门用于在 TPU 上进行分布式训练的策略。类似地,TensorFlow 也提供了用于在 CPU 和 GPU 上进行分布式训练的相应策略。

  • **tf.distribute.MirroredStrategy:**用于在多个 GPU 上进行分布式训练。每个 GPU 上的模型副本会在各自的 GPU 上运行,同时使用 AllReduce 算法来进行梯度聚合和参数同步。

  • **tf.distribute.MultiWorkerMirroredStrategy:**用于在多个工作节点(通常是多台机器)的多个 GPU 上进行分布式训练。它在 MirroredStrategy 的基础上增加了多个工作节点之间的通信和同步。

  • **tf.distribute.experimental.MultiDeviceMirroredStrategy:**用于在多个 GPU 或 CPU 上进行分布式训练。与 MirroredStrategy 类似,但允许跨设备进行梯度和参数同步。

  • **tf.distribute.experimental.CentralStorageStrategy:**用于在多个工作节点的多个 GPU 或 CPU 上进行分布式训练。与 MirroredStrategy 类似,但使用中心化参数服务器来进行梯度聚合和参数同步。

这些策略都允许在不同的硬件设备上进行分布式训练,包括 CPU、GPU 和 TPU。选择合适的策略取决于你的硬件环境、任务需求和性能要求。例如,如果你拥有多个 GPU,并且想要在这些 GPU 上进行训练,可以选择 MirroredStrategy;如果你想要在多台机器上进行训练,则可以选择 MultiWorkerMirroredStrategy

6、数据预处理

if CFG.PREPROCESS:enc = {'l': 1, 'y': 2, '@': 3, '3': 4, 'H': 5, 'S': 6, 'F': 7, 'C': 8, 'r': 9, 's': 10, '/': 11, 'c': 12, 'o': 13,'+': 14, 'I': 15, '5': 16, '(': 17, '2': 18, ')': 19, '9': 20, 'i': 21, '#': 22, '6': 23, '8': 24, '4': 25, '=': 26,'1': 27, 'O': 28, '[': 29, 'D': 30, 'B': 31, ']': 32, 'N': 33, '7': 34, 'n': 35, '-': 36}train_raw = pd.read_parquet('/kaggle/input/leash-BELKA/train.parquet')smiles = train_raw[train_raw['protein_name']=='BRD4']['molecule_smiles'].valuesassert (smiles!=train_raw[train_raw['protein_name']=='HSA']['molecule_smiles'].values).sum() == 0assert (smiles!=train_raw[train_raw['protein_name']=='sEH']['molecule_smiles'].values).sum() == 0def encode_smile(smile):tmp = [enc[i] for i in smile]tmp = tmp + [0]*(142-len(tmp))return np.array(tmp).astype(np.uint8)smiles_enc = joblib.Parallel(n_jobs=96)(joblib.delayed(encode_smile)(smile) for smile in tqdm(smiles))smiles_enc = np.stack(smiles_enc)train = pd.DataFrame(smiles_enc, columns = [f'enc{i}' for i in range(142)])train['bind1'] = train_raw[train_raw['protein_name']=='BRD4']['binds'].valuestrain['bind2'] = train_raw[train_raw['protein_name']=='HSA']['binds'].valuestrain['bind3'] = train_raw[train_raw['protein_name']=='sEH']['binds'].valuestrain.to_parquet('train_enc.parquet')test_raw = pd.read_parquet('/kaggle/input/leash-BELKA/test.parquet')smiles = test_raw['molecule_smiles'].valuessmiles_enc = joblib.Parallel(n_jobs=96)(joblib.delayed(encode_smile)(smile) for smile in tqdm(smiles))smiles_enc = np.stack(smiles_enc)test = pd.DataFrame(smiles_enc, columns = [f'enc{i}' for i in range(142)])test.to_parquet('test_enc.parquet')else:train = pd.read_parquet('/kaggle/input/belka-enc-dataset/train_enc.parquet')test = pd.read_parquet('/kaggle/input/belka-enc-dataset/test_enc.parquet')

如果CFG.PREPROCESS为True,则执行数据预处理。否则,直接从parquet文件中读取处理好的训练和测试数据。 

enc = {...}:这里定义了一个字典 enc,将 SMILES 字符串中的字符映射为整数编码。这个编码过程是为了将 SMILES 字符串转换为数字序列。

train_raw[train_raw['protein_name']=='BRD4'] 这部分代码实际上是在利用 Pandas DataFrame 的索引功能。让我们解释一下它是如何工作的:

  1. train_raw['protein_name']=='BRD4':这部分代码首先选择了 train_raw DataFrame 中的 protein_name 列,并将其与字符串 'BRD4' 进行比较。这将返回一个布尔数组,其中对应的位置为 True 表示该位置对应的蛋白质名称为 'BRD4',否则为 False。例如,如果 train_raw['protein_name'] 的值分别是 ['BRD4', 'HSA', 'BRD4', 'sEH', 'HSA'],那么上述代码返回的布尔数组就是 [True, False, True, False, False]

  2. train_raw[train_raw['protein_name']=='BRD4']:这部分代码将上一步得到的布尔数组作为索引,从 train_raw DataFrame 中选择出满足条件的行。具体来说,它保留了布尔数组中对应位置为 True 的行,而过滤掉了对应位置为 False 的行。这样,就实现了根据条件筛选数据的目的。

综上所述,train_raw[train_raw['protein_name']=='BRD4'] 的含义是:从 train_raw DataFrame 中选择出满足条件(蛋白质名称为 'BRD4')的所有行。

np.stack() 函数的作用是沿着新的轴堆叠数组序列。当你有一系列形状相同的数组时,你可以使用 np.stack() 将它们沿着新的轴堆叠起来,形成一个新的数组。

7、定义神经网络模型

def my_model():with strategy.scope():INP_LEN = 142NUM_FILTERS = 32hidden_dim = 128inputs = tf.keras.layers.Input(shape=(INP_LEN,), dtype='int32')x = tf.keras.layers.Embedding(input_dim=36, output_dim=hidden_dim, input_length=INP_LEN, mask_zero = True)(inputs)x = tf.keras.layers.Conv1D(filters=NUM_FILTERS, kernel_size=3,  activation='relu', padding='valid',  strides=1)(x)x = tf.keras.layers.Conv1D(filters=NUM_FILTERS*2, kernel_size=3,  activation='relu', padding='valid',  strides=1)(x)x = tf.keras.layers.Conv1D(filters=NUM_FILTERS*3, kernel_size=3,  activation='relu', padding='valid',  strides=1)(x)x = tf.keras.layers.GlobalMaxPooling1D()(x)x = tf.keras.layers.Dense(1024, activation='relu')(x)x = tf.keras.layers.Dropout(0.1)(x)x = tf.keras.layers.Dense(1024, activation='relu')(x)x = tf.keras.layers.Dropout(0.1)(x)x = tf.keras.layers.Dense(512, activation='relu')(x)x = tf.keras.layers.Dropout(0.1)(x)outputs = tf.keras.layers.Dense(3, activation='sigmoid')(x)model = tf.keras.models.Model(inputs = inputs, outputs = outputs)optimizer = tf.keras.optimizers.Adam(learning_rate=CFG.LR, weight_decay = CFG.WD)loss = 'binary_crossentropy'weighted_metrics = [tf.keras.metrics.AUC(curve='PR', name = 'avg_precision')]model.compile(loss=loss,optimizer=optimizer,weighted_metrics=weighted_metrics,)return model

 模型详解

    with strategy.scope():

 TensorFlow 中的一种分布式策略,strategy.scope() 用于在分布式环境中构建模型。

        INP_LEN = 142NUM_FILTERS = 32hidden_dim = 128

 定义了一些常量和超参数,如输入序列长度 INP_LEN、卷积层滤波器数量 NUM_FILTERS 和嵌入层的隐藏维度 hidden_dim

        inputs = tf.keras.layers.Input(shape=(INP_LEN,), dtype='int32')

 定义了模型的输入层,指定了输入序列的形状和数据类型。

        x = tf.keras.layers.Embedding(input_dim=36, output_dim=hidden_dim, input_length=INP_LEN, mask_zero=True)(inputs)

 这是一个嵌入层,用于将输入的离散特征(SMILES 编码)映射到稠密的低维空间。

        x = tf.keras.layers.Conv1D(filters=NUM_FILTERS, kernel_size=3,  activation='relu', padding='valid',  strides=1)(x)x = tf.keras.layers.Conv1D(filters=NUM_FILTERS*2, kernel_size=3,  activation='relu', padding='valid',  strides=1)(x)x = tf.keras.layers.Conv1D(filters=NUM_FILTERS*3, kernel_size=3,  activation='relu', padding='valid',  strides=1)(x)

一系列卷积层,用于从输入序列中提取特征。

        x = tf.keras.layers.GlobalMaxPooling1D()(x)

全局最大池化层,用于从卷积层输出的特征图中提取最显著的特征。

        x = tf.keras.layers.Dense(1024, activation='relu')(x)x = tf.keras.layers.Dropout(0.1)(x)x = tf.keras.layers.Dense(1024, activation='relu')(x)x = tf.keras.layers.Dropout(0.1)(x)x = tf.keras.layers.Dense(512, activation='relu')(x)x = tf.keras.layers.Dropout(0.1)(x)

一系列全连接层,用于学习特征之间的非线性关系。

        outputs = tf.keras.layers.Dense(3, activation='sigmoid')(x)

模型的输出层,输出预测的概率。 

        model = tf.keras.models.Model(inputs=inputs, outputs=outputs)

 将输入和输出连接成模型。

        optimizer = tf.keras.optimizers.Adam(learning_rate=CFG.LR, weight_decay=CFG.WD)

 定义优化器,这里使用 Adam 优化器。

        loss = 'binary_crossentropy'

 定义损失函数,这里使用二元交叉熵损失函数。

        weighted_metrics = [tf.keras.metrics.AUC(curve='PR', name='avg_precision')]

 定义评估指标,这里使用了平均精度 (Average Precision)。

        model.compile(loss=loss, optimizer=optimizer, weighted_metrics=weighted_metrics)

 编译模型,将优化器、损失函数和评估指标配置到模型中。

        return model

 返回构建好的模型对象。

 8、交叉验证循环

FEATURES = [f'enc{i}' for i in range(142)]
TARGETS = ['bind1', 'bind2', 'bind3']
skf = StratifiedKFold(n_splits = CFG.NBR_FOLDS, shuffle = True, random_state = 42)
#定义了特征列的名称和目标列的名称,以及使用Stratified K-Fold进行交叉验证的划分。
all_preds = []
for fold,(train_idx, valid_idx) in enumerate(skf.split(train, train[TARGETS].sum(1))):if fold not in CFG.SELECTED_FOLDS:continue;X_train = train.loc[train_idx, FEATURES]y_train = train.loc[train_idx, TARGETS]X_val = train.loc[valid_idx, FEATURES]y_val = train.loc[valid_idx, TARGETS]es = tf.keras.callbacks.EarlyStopping(patience=5, monitor="val_loss", mode='min', verbose=1)checkpoint = tf.keras.callbacks.ModelCheckpoint(monitor='val_loss', filepath=f"model-{fold}.h5",save_best_only=True, save_weights_only=True,mode='min')reduce_lr_loss = tf.keras.callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.05, patience=5, verbose=1)model = my_model()history = model.fit(X_train, y_train,validation_data=(X_val, y_val),epochs=CFG.EPOCHS,callbacks=[checkpoint, reduce_lr_loss, es],batch_size=CFG.BATCH_SIZE,verbose=1,)model.load_weights(f"model-{fold}.h5")oof = model.predict(X_val, batch_size = 2*CFG.BATCH_SIZE)print('fold :', fold, 'CV score =', APS(y_val, oof, average = 'micro'))preds = model.predict(test, batch_size = 2*CFG.BATCH_SIZE)all_preds.append(preds)preds = np.mean(all_preds, 0)

这是交叉验证的主要循环。在每个折中,根据SELECTED_FOLDS选择指定的折数进行训练和预测。在每个折数中,首先选择对应的训练和验证数据,然后建立模型并进行训练。训练完成后,使用模型对测试集进行预测,并将预测结果存储在all_preds列表中。 

代码详解

定义特征和目标列

FEATURES = [f'enc{i}' for i in range(142)]
TARGETS = ['bind1', 'bind2', 'bind3']

 这里,FEATURES 是一个包含特征列名称的列表,TARGETS 是一个包含目标列名称的列表。

Stratified K-Fold 交叉验证:

skf = StratifiedKFold(n_splits=CFG.NBR_FOLDS, shuffle=True, random_state=42)

 这段代码初始化了一个 Stratified K-Fold 对象,使用了由 CFG.NBR_FOLDS 指定的折数。Stratified K-Fold 保持每个折中类别的分布,以确保每个折都代表整体数据集。

模型训练

all_preds = []
for fold, (train_idx, valid_idx) in enumerate(skf.split(train, train[TARGETS].sum(1))):if fold not in CFG.SELECTED_FOLDS:continueX_train = train.loc[train_idx, FEATURES]y_train = train.loc[train_idx, TARGETS]X_val = train.loc[valid_idx, FEATURES]y_val = train.loc[valid_idx, TARGETS]

 这个循环遍历了 Stratified K-Fold 对象生成的每个折。它将数据分割成当前折的训练集和验证集。

 回调函数

es = tf.keras.callbacks.EarlyStopping(patience=5, monitor="val_loss", mode='min', verbose=1)
checkpoint = tf.keras.callbacks.ModelCheckpoint(monitor='val_loss', filepath=f"model-{fold}.h5",save_best_only=True, save_weights_only=True,mode='min')
reduce_lr_loss = tf.keras.callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.05, patience=5, verbose=1)

 这些是在模型训练过程中使用的回调函数。EarlyStopping 在监控的指标停止改善时停止训练。ModelCheckpoint 如果是到目前为止最佳的模型,则在每个周期后保存模型。ReduceLROnPlateau 在监控的指标停止改善时降低学习率。

模型训练(继续)

model = my_model()
history = model.fit(X_train, y_train,validation_data=(X_val, y_val),epochs=CFG.EPOCHS,callbacks=[checkpoint, reduce_lr_loss, es],batch_size=CFG.BATCH_SIZE,verbose=1,
)

 这段代码使用训练数据(X_trainy_train)训练模型。它在验证数据上(X_valy_val)验证模型的性能。回调函数用于监控训练过程。

加载最佳模型

model.load_weights(f"model-{fold}.h5")

 训练后,从 ModelCheckpoint 保存的文件中加载最佳模型的权重。

预测和评估

oof = model.predict(X_val, batch_size=2*CFG.BATCH_SIZE)
print('fold :', fold, 'CV score =', APS(y_val, oof, average='micro'))

 对验证集(X_val)进行预测。使用自定义函数 APS(此处未显示)评估模型的性能。

 最终预测

preds = np.mean(all_preds, 0)

 在所有折训练和验证完成后,对预测进行平均以获得测试数据的最终预测。这些预测存储在 preds 变量中。

9、生成预测结果

tst = pd.read_parquet('/kaggle/input/leash-BELKA/test.parquet')
tst['binds'] = 0
tst.loc[tst['protein_name']=='BRD4', 'binds'] = preds[(tst['protein_name']=='BRD4').values, 0]
tst.loc[tst['protein_name']=='HSA', 'binds'] = preds[(tst['protein_name']=='HSA').values, 1]
tst.loc[tst['protein_name']=='sEH', 'binds'] = preds[(tst['protein_name']=='sEH').values, 2]
tst[['id', 'binds']].to_csv('submission.csv', index = False)

原文地址:BELKA 1DCNN Starter with all data (kaggle.com)

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

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

相关文章

扩散变压器:开创图像生成新纪元

在深度学习领域,变换器(Transformer)架构已经成为自然语言处理、视觉识别等多个领域的核心技术。最近,一项新的研究探索了基于变换器的一类新型扩散模型——扩散变压器(Diffusion Transformers,简称DiTs&am…

VMware Workstation Pro 免费正版安装指南(非常详细)零基础入门到精通,收藏这一篇就够了

随着博通公司在2023年11月对VMware的收购和产品策略的调整,VMware宣布取消“永久许可证”并转向订阅制,这一改变引发了用户的不满。然而,在2024年5月14日,VMware发布了一个令人振奋的消息,宣布为个人用户免费提供两款桌…

Java编程常见问题汇总二

系列文章目录 文章目录 系列文章目录前言一、请使用XML解析器二、请使用JDom组装XML三、XML编码陷阱四、未指定字符编码五、未对数据流进行缓存 前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击…

跨平台,不需要下载的串口调试助手

在线串口调试助手是BBAIoT旗下的首款物联网工具,web端显示,不需要下载任何软件到电脑,方便快捷。 在线串口调试 链接地址:在线串口调试在线串口调试助手 Online serial port debugging assistanthttps://www.bbaiot.com/ 软件界…

重新定义你的上网体验,微软WowTab助你一臂之力!

大家好,我是 Java陈序员。 浏览器是我们日常生活工作中必备的工具软件,使用非常频繁。 目前很多浏览器的新标签页虽然说功能齐全,但是充斥着广告和各种无效的信息,十分影响体验! 今天,给大家安利一个浏览…

常用ai模型和一些术语的科普

本文是早年浏览easyai.tech后留下的笔记。 文章目录 神经网络CNNRNNGANKNNCPU和GPU/TPUNLPNo free lunch theoremtransformer注意力机制自动编码器,自编码器GNN推荐系统附录NFL的两个例子 神经网络 水流,水龙头,流量阀。 可以回想CNN分类MNI…

软件磁盘阵列与LVM

一、软件磁盘阵列 磁盘阵列(RAID)是通过硬件或软件技术将多个较小的磁盘整合成为一个较大的磁盘设备,而这个较大的磁盘除了存储还具备数据保护功能。 RAID分不同的级别,不同级别具有不同功能: 1、RAID 0:…

调用阿里云智能云实现垃圾分类

目录 1. 作者介绍2. API3. 阿里云API垃圾分类业务4. 实验过程4.1 接入阿里云4.2 创建并获取AccessKey ID和Secret4.3 登录阿里云官网,搜索垃圾分类技术文档4.4 配置环境变量4.5 代码部分 1. 作者介绍 孙作正,男,西安工程大学电子信息学院&am…

初中英语优秀作文分析-003My Favorite Movie Type-我最喜欢的电影类型

PDF格式公众号回复关键字:SHCZYF003 记忆树 1 I’d like to share my favorite movie type with you. 翻译 我想和你分享我最喜欢的电影类型。 简化记忆 电影类型 句子结构 I 主语 我,would 情态动词 愿意做某事,like 谓语 喜欢,to sha…

docker部署skywalking

skywalking版本下载 1:拉取skywalking的oap镜像(可以选择自己的版本,最好与ui,agent版本一致) docker pull apache/skywalking-oap-server:9.5.02:启动oap docker run -d -p 11800:11800 -p 12800:12800 --name sw_oap apache/…

蓝桥杯物联网竞赛_STM32L071_19_输出方波信号(PWM)

国赛考了一个方波,第一次考这个,连个示波器都没有 CUBMX配置: 按上述配置刚好是32MHZ / 32 / 100 1KHZ 理论: 频率:就是一秒钟能产生多少个脉冲,如下图: 这算是一个脉冲,1KHZ说明一秒钟产生1…

STM32使用HAL库UART接收不定长数据-1

使用STM32的HAL库实现UART串口不定长数据的接收 使用STM32的UART接收数据的时候,经常会遇到接收长度不固定的数据,比如一帧数据可能是10个字节,也可能是12个字节。这种数据称为不定长数据。 现有的很多通信协议是不定长的,比如mo…

Docker大学生看了都会系列(一、Docker介绍)

系列文章目录 第一章 Docker介绍 第二章 2.1 Mac通过Homebrew安装Docker 第二章 2.2 CentOS安装Docker 文章目录 前言Docker容器简介什么是Docker容器为什么要用Docker容器Docker容器的特性Docker容器对比VM(虚拟机)Docker容器三大组成要素镜像容器镜像仓库 Docker容器运行流程…

gradle构建项目简单入门

gradleProject 搭建gradle项目步骤 官网文档地址:https://docs.gradle.org/current/userguide/userguide.html Getting Started 1.Gradle核心内容 1.Gradle介绍 Project:类似模块划分Build Scripts:构建ProjectDependency Management&…

多线程新手村5--线程池

1.1 线程池是什么 线程诞生的意义是因为进程的创建/销毁开销太大,所以使用线程提高代码的执行效率;那如果想要进一步提升执行效率,该怎么办呢?有一个方法是使用线程池。 首先,什么是线程池:池就是池子&am…

Vue——样式绑定的几种方式

文章目录 前言往期回顾绑定对象绑定对象的另一种写法绑定数组数组与对象的嵌套 前言 样式绑定在vue中属于一种很常见的操作。在之前博客中针对样式的绑定操作,介绍了一个指令v-bind。缩写为:xxx。 vue 官网 样式绑定 往期回顾 先简单回顾下最开始绑定标签样式的操…

vue3_组件间通信方式

目录 一、父子通信 1.父传子( defineProps) 2.父传子(useAttrs) 3.子传父(ref,defineExpose ) 4.子传父(defineEmits) 5.子传父(v-model) …

车载测试面试题专题 - 如何测试蓝牙电话功能

现代车载系统中,蓝牙电话功能已经成为了一个必不可少的功能。它不仅提高了驾驶安全性,还提供了极大的便利性。作为车载行业的测试人员,如何全面、有效地测试车载蓝牙电话功能是我们工作的重要部分。因此在车载测试的面试过程中,蓝…

k8s怎么监听自定义资源的变更?(1)

这里我们通过 k8s的 code-generate来生成操作自定义资源的代码来监听变更 第一步下载工具 下载安装 k8s code-generate 查看我们的k8s版本 kubectl get node 输出结果为 可以看到我们的k8s版本为 v1.22.0 所以此时我们要下载与之对应的版本的code-generate git clone htt…

深入解析 Web 开发中的强缓存与协商缓存机制

在 Web 开发中,缓存机制是提高页面加载速度和用户体验的重要技术。缓存分为两种主要类型:强缓存和协商缓存。本文将详细介绍这两种缓存机制的原理、实现方式及其区别,并演示如何在 <meta> 元素中和 Nginx 服务器中进行缓存控制。 强缓存 强缓存(Strong Caching)是指…