使用 AMD GPUs 进行基于 Transformers 的时间序列预测

news2024/11/15 10:58:08

Using AMD GPUs for Enhanced Time Series Forecasting with Transformers — ROCm Blogs

时间序列预测(TSF)是信号处理、数据科学和机器学习(ML)等领域的关键概念。TSF 通过分析系统的过去时间模式来预测其未来行为,利用历史数据预测未来数据点。经典的 TSF 方法依赖于各种统计方法。最近,机器学习技术越来越多地用于 TSF,引发了社区关于这些现代方法是否优于经典统计方法的讨论(参见:Are Transformers Effective for Time Series Forecasting? 和 Yes, Transformers are Effective for Time Series Forecasting (+ Autoformer))。

本文将不讨论传统统计方法或基于机器学习的模型哪个更适合预测。相反,我们将提供一个关于实现其中一种关键机器学习方法—Transformers 的实用指南。在本文中,我们将实现一个完整的基于 Transformers 的 TSF 工作流程,从数据预处理到模型训练和评估。

简介

Transformer 架构在时间序列预测中的应用已成为替代传统统计模型(如自回归积分滑动平均(ARIMA)或指数平滑(ETS))的一个重要选择。Transformers 能够捕捉复杂的时间依赖关系,并且能够处理不同类型的输入数据,如文本、音频、图像和时间序列数据。

什么是基于 Transformer 的模型?

基于 Transformer 的模型是一种神经网络架构,设计用于处理序列数据和捕捉长程依赖性。Transformers 最早在论文Attention is All You Need中被提出。虽然最初是为自然语言处理(NLP)任务处理文本数据而设计,Transformers 已被改编用于图像分类、语音识别和预测等应用。

对于时间序列数据和预测,时间序列 Transformer、Autoformer 和 Informer 是一些使用 Transformer 架构来提高预测任务准确性和效率的模型。

时间序列 Transformer 专为分析时间序列数据设计。它通过结合修改后的机制来更好地捕捉数据中的长程依赖性,从而适应原始的 Transformer 架构。

Autoformer 通过集成分解架构和自动相关机制扩展了原始的 Transformer 架构。分解和自动相关机制有助于更好地捕捉时间和周期模式。
Informer 专为长序列时间序列预测设计,它解决了原始 Transformer 的高计算复杂性和内存使用问题。它通过使用概率稀疏自注意力机制和自注意力蒸馏机制,允许更低的时间复杂度,并通过逐步减少输入序列保留主要特征。
在本文中,我们将探索这三种模型在使用 AMD GPUs 进行时间序列预测方面的能力。我们还将使用 traffic_hourly 数据集提供一个实用应用,数据集是 monash_tsf 时间序列数据存储库的一部分。
你可以在这个GitHub 文件夹中找到与本文相关的文件。

要求

• AMD GPU:请参阅ROCm 文档页面 了解支持的硬件和操作系统。
• ROCm 6.1:请参阅ROCm Linux 安装说明 了解安装说明。
• Docker:请参阅在 Ubuntu 上安装 Docker Engine 了解安装说明。
• PyTorch 2.0.1:使用官方 ROCm Docker 镜像rocm/pytorch:rocm6.0_ubuntu22.04_py3.9_pytorch_2.0.1。

跟随本文

本文使用 GluonTS Python 库进行数据管理和转换。更多信息请参阅 [GluonTS - 使用Python进行概率时间序列建模](GluonTS documentation)。

• 克隆仓库并进入博文目录:

git clone git@github.com:ROCm/rocm-blogs.git
cd rocm-blogs/blogs/artificial-intelligence/timeseries_transformers

 • 构建并启动容器。关于构建过程的详细信息,请参阅 timeseries_transformers/docker/Dockerfile 文件。

cd docker
docker compose build
docker compose up

• 在浏览器中打开 [http://localhost:8888/lab/tree/src/time_series_transformers.ipynb](http://localhost:8888/lab/tree/src/time_series_transformers.ipynb)并打开 time_series_transformers.ipynb 笔记本。

您可以使用 time_series_transformers.ipynb 笔记本跟随本文操作。

数据集

Monash 时间序列预测 仓库提供了一个广泛的数据集集合,专门用于开发和评估预测模型。在这些数据集中,traffic_hourly 数据集提供了详细的每小时交通流量数据,捕捉道路和网络上的交通流量。通过分析这个数据集,研究人员和实践者可以设计策略以优化交通控制系统并提升城市交通流动性。

我们将访问Hugging Face上提供的这个数据集版本。数据集由包含训练、测试和验证部分的DatasetDict对象组成。每个部分包含862个每小时采样的独立交通数据时间序列。

让我们来可视化部分时间序列数据:

在示例中,我们注意到验证集包含与训练集相同的数据,但在时间上延伸了更长的预测长度(48个点)。这种配置使我们能够将模型的预测与实际结果进行对比评估。类似地,测试集也覆盖了比验证集更长的48个点的预测长度。

接下来我们使用 traffic_hourly 数据集训练前面提到的各个模型。

时间序列Transformer模型

时间序列Transformer是一种深度学习模型,它利用Transformer架构的自注意机制处理序列数据,用于预测任务。传统模型如ARIMA或LSTM在处理长期依赖关系和并行化方面面临挑战。Transformers更有效地捕捉长期依赖关系,并支持并行处理,使其成为时间序列预测的良好选择。

时间序列Transformer适应标准的transformer架构来处理时序数据。它们进行了一些修改,以适合时间序列数据:
- 上下文窗口和预测窗口:时间序列Transformer使用上下文窗口(历史数据)和预测窗口(未来数据)来管理内存和计算需求,而不是处理整个序列。
- 因果掩码:确保模型仅使用过去的数据点来预测未来值。
- 包括时间特征:添加额外的时间特征,如星期几、月份或时间序列的年龄(从第一个数据点到最后一个数据点的顺序时间戳),帮助模型学习季节性模式。

- 处理缺失值:使用注意力掩码管理缺失值,使模型能够忽略数据间隙而无需补插值。

时间序列Transformer模型适合时间序列数据,因为它使用上下文窗口,因果掩码和其他时间特征,以及处理缺失值的机制。这些特性使其能够有效地捕捉时间依赖关系和模式。相比之下,为自然语言处理任务设计的transformer处理整个序列,主要关注标记之间的关系。有关时间序列Transformer模型的更多信息,请参见 [Hugging Face Transformers 说明文档](https://huggingface.co/docs/transformers/v4.41.3/en/model_doc/time_series_transformer#time-series-transformer)。

让我们使用 hourly_traffic 数据集和 Hugging Face 的 TimeSeriesTransformerConfig 类来设置用于预测下一个48小时值(`prediction_length`)的时间序列Transformer模型的参数。

在下面的代码中,我们将 prediction_length 设置为48。这个值来自训练集和验证集长度之间的差异。就超参数值而言,我们将 context_length 设置为 prediction_length 的5倍,编码器和解码器的层数设置为4,每个transformer层输入和输出的特征向量大小 d_layer 设置为32。

换句话说,我们希望基于过去10天(5倍的 prediction_length)的每小时交通数据预测未来2天(`prediction_length`)的每小时交通量。

prediction_length = 48
freq = "H" # data is sampled in an hourly frequency 

lags_sequence = get_lags_for_frequency(freq_str = freq) # Default lags provided by GluonTS for the given frequency
time_features = time_features_from_frequency_str(freq) # Default additional time features provided by GluonTS


config = TimeSeriesTransformerConfig(
    prediction_length = prediction_length,
    context_length = prediction_length * 5,
    # Lags provided by GluonTS
    lags_sequence=lags_sequence,
    # Add time features and "series age"
    num_time_features=len(time_features) + 1, 
    # Length of train dataset
    cardinality=[len(train_dataset)], 
    # Learn and embedding of size 5
    embedding_dimension=[5],         
    # Transformer parameters:
    encoder_layers=4,
    decoder_layers=4,
    d_model=32,
)

# Instantiate the model
model = TimeSeriesTransformerForPrediction(config)

接下来,我们使用给定参数值实例化相应的数据加载器:

train_dataloader = create_train_dataloader(
    config = config,
    freq=freq,
    data=train_dataset,
    batch_size=256,
    num_batches_per_epoch=100,
)


test_dataloader = create_backtest_dataloader(
    config=config,
    freq=freq,
    data=test_dataset,
    batch_size=64,
)

train_dataloader 和 test_dataloader 是GluonTS的可迭代对象。迭代器的每个元素都是一个包含以下键的字典:

# Print the keys of an instance of the train_dataloader
example = next(iter(train_dataloader))
example.keys()
dict_keys(['past_time_features', 'past_values', 'past_observed_mask', 'future_time_features', 'future_values', 'future_observed_mask'])

我们将模型训练20个周期,然后测量总训练时间。让我们开始训练过程:

# Train the model
from accelerate import Accelerator
from torch.optim import AdamW
from tqdm import tqdm

accelerator = Accelerator()
device = accelerator.device

model.to(device)
optimizer = AdamW(model.parameters(), lr=1e-4, betas=(0.9, 0.95), weight_decay=1e-1,)

model, optimizer, train_dataloader = accelerator.prepare(
    model,
    optimizer,
    train_dataloader,
)

model.train()
start_time = time.time()
for epoch in (range(20)):
    for idx, batch in enumerate(train_dataloader):
        optimizer.zero_grad()
        outputs = model(
            past_time_features=batch["past_time_features"].to(device),
            past_values=batch["past_values"].to(device),
            future_time_features=batch["future_time_features"].to(device),
            future_values=batch["future_values"].to(device),
            past_observed_mask=batch["past_observed_mask"].to(device),
            future_observed_mask=batch["future_observed_mask"].to(device),
        )
        loss = outputs.loss

        # Backprop
        accelerator.backward(loss)
        optimizer.step()

        if idx % 100 == 0:
            print(f'Epoch: {epoch}', f'Loss: {loss.item()}')

print(f'Total training time: {time.time() - start_time}')

训练后你会看到类似于以下的输出:

...
Epoch: 15 Loss: -3.1552791595458984
Epoch: 16 Loss: -3.1698923110961914
Epoch: 17 Loss: -3.1928699016571045
Epoch: 18 Loss: -3.072526216506958
Epoch: 19 Loss: -3.2241008281707764
Total training time: 156.99232363700867

在我们的设置中,总训练时间约为157秒。我们还观察到,虽然训练损失随时间减少,但它也是负的。这种行为是预期的,因为我们使用的是负对数似然损失函数,随着训练的进行,该函数倾向于收敛于负无穷。

最后,让我们进行推理并绘制生成的时间序列,以可视化我们的模型的表现:

model.eval()

forecasts = []

for batch in test_dataloader:
    outputs = model.generate(
        past_time_features=batch["past_time_features"].to(device),
        past_values=batch["past_values"].to(device),
        future_time_features=batch["future_time_features"].to(device),
        past_observed_mask=batch["past_observed_mask"].to(device),
    )
    forecasts.append(outputs.sequences.cpu().numpy())

forecasts = np.vstack(forecasts)
plot_ts(test_dataset, forecasts, 'Time Series Transformer')

该模型有效地捕捉了训练数据中的季节性和趋势,并能很好地预测时间序列的下48个时间步。 

Autoformer(带有自动相关性的分解变压器用于长期序列预测)

Autoformer 是一种设计用于时间序列预测的模型。它的开发目的是解决原始 Transformer 模型在处理时间数据时的局限性。Autoformer 使用分解模块提取时间序列数据的趋势和季节性成分。Autoformer 引入了分解方法,使其能够更好地捕捉数据中的模式,从而在处理时间序列数据的长期依赖性和季节性方面比 Time Series Transformer 更好。

Autoformer 和用于自然语言处理 (NLP) 任务的标准 Transformer 之间的主要区别包括:
- 分解模块:Autoformer 纳入了分解模块,可以将时间序列数据中的趋势和季节性成分分离出来。
- 自动相关机制:代替标准 Transformer 架构中使用的自注意力机制,Autoformer 使用自动相关机制以更高效地捕捉时间依赖性,从而减少计算开销。

- 降低复杂性:Autoformer 架构经过优化,专门处理时间序列数据的特性。特别是,Autoformer 使用了适合数据周期性的简化位置编码,从而降低了复杂性。

更多关于 Autoformer 模型的信息,请参见:Autoformer: Decomposition Transformers with Auto-Correlation for Long-Term Series Forecasting

与 Time Series Transformer 模型一样,我们使用相同的 prediction_length(预测长度)、`context_length`(上下文长度)以及其余参数值。我们可以如下实例化 AutoformerConfig 类:

from transformers import AutoformerConfig, AutoformerForPrediction
from gluonts.time_feature import time_features_from_frequency_str
from gluonts.time_feature import get_lags_for_frequency


prediction_length = 48
freq = "H"

lags_sequence = get_lags_for_frequency(freq_str = freq)
time_features = time_features_from_frequency_str(freq)


config = AutoformerConfig(
    
    prediction_length=prediction_length,    
    context_length=prediction_length * 5,
    lags_sequence=lags_sequence,    
    num_time_features=len(time_features) + 1,    
    cardinality=[len(train_dataset)],    
    embedding_dimension=[5],
    
    # transformer params:
    encoder_layers=4,
    decoder_layers=4,
    d_model=32,
)

model = AutoformerForPrediction(config)

在实例化相应的数据加载器后,我们继续训练模型,如下所示:

# Train the model
from accelerate import Accelerator
from torch.optim import AdamW
from tqdm import tqdm

accelerator = Accelerator()
device = accelerator.device

model.to(device)
optimizer = AdamW(model.parameters(), lr=1e-4, betas=(0.9, 0.95), weight_decay=1e-1,)

model, optimizer, train_dataloader = accelerator.prepare(
    model,
    optimizer,
    train_dataloader,
)

model.train()
start_time = time.time()
for epoch in (range(20)):
    for idx, batch in enumerate(train_dataloader):
        optimizer.zero_grad()
        outputs = model(
            past_time_features=batch["past_time_features"].to(device),
            past_values=batch["past_values"].to(device),
            future_time_features=batch["future_time_features"].to(device),
            future_values=batch["future_values"].to(device),
            past_observed_mask=batch["past_observed_mask"].to(device),
            future_observed_mask=batch["future_observed_mask"].to(device),
        )
        loss = outputs.loss

        # Backprop
        accelerator.backward(loss)
        optimizer.step()

        if idx % 100 == 0:
            print(f'Epoch: {epoch}', f'Loss: {loss.item()}')

print(f'Total training time: {time.time() - start_time}')

输出将类似于以下的结果:

...
Epoch: 15 Loss: -2.4633355140686035
Epoch: 16 Loss: -2.78301739692688
Epoch: 17 Loss: -2.3952136039733887
Epoch: 18 Loss: -2.4368600845336914
Epoch: 19 Loss: -2.4414479732513428
Total training time: 271.12153911590576

我们注意到,Autoformer 模型的训练时间比 Time Series Transformer 模型更长。由于 Autoformer 使用分解模块来分离趋势和季节性成分,我们预计会有额外的计算开销,目的是捕捉数据中更复杂的模式。我们来直观看一下模型的性能:

plot_ts(test_dataset, forecasts, 'Autoformer Model')

在上述图中,我们可以看到 Autoformer 模型与 Time Series Transformer 模型的表现相似,均能捕捉到数据的季节性和趋势。

Informer:用于长序列时间序列预测的高效Transformer

Informer是一个设计用于时间序列预测的模型,能够处理长期依赖性并减少计算复杂性,因此适用于大规模时间序列数据。Informer使用了ProbSparse自注意力机制,通过选择采样出一小部分最有信息量的查询,减少了标准自注意力机制的时间和空间复杂性。这里的“查询”指的是表示序列中当前点的向量,模型试图从整个序列中找到与其相关的信息。这与Transformer架构中的概念相同,查询、键和值用于计算注意力分数。在Informer模型中,这些查询通过ProbSparse自注意力机制进行优化,以适应长序列时间序列预测。

Informer的关键点包括:
- Informer使用ProbSparse自注意力机制,根据注意力矩阵的稀疏性选择一个子集的查询,从而在与用于NLP任务的标准Transformer相比降低了计算复杂性。

- Informer采用了一种叫做“蒸馏”的过程,通过一系列蒸馏层逐渐减少序列长度。每一层选择最有信息的点,总结信息并使序列更短,这有助于聚焦数据中的重要模式和趋势。这与标准Transformer不同,标准Transformer没有机制来减少序列长度,这对于非常长的序列来说效率较低。

关于Informer模型的更多信息,请参见:[Informer: Beyond Efficient Transformer for Long Sequence Time-Series Forecasting](https://arxiv.org/abs/2012.07436)

我们可以像之前一样设置`InformerConfig`类的配置参数:

from transformers import InformerConfig, InformerForPrediction

prediction_length = 48
freq = "H"

lags_sequence = get_lags_for_frequency(freq_str = freq)
time_features = time_features_from_frequency_str(freq)


config = InformerConfig(
    
    prediction_length=prediction_length,    
    context_length=prediction_length * 5,
    lags_sequence=lags_sequence,    
    num_time_features=len(time_features) + 1,    
    cardinality=[len(train_dataset)],    
    embedding_dimension=[5],
    
    # Transformer params:
    encoder_layers=4,
    decoder_layers=4,
    d_model=32,
)

model = InformerForPrediction(config)

在实例化数据加载器之后,我们可以按以下步骤训练模型:

# Train the model
from accelerate import Accelerator
from torch.optim import AdamW
from tqdm import tqdm

accelerator = Accelerator()
device = accelerator.device

model.to(device)
optimizer = AdamW(model.parameters(), lr=1e-4, betas=(0.9, 0.95), weight_decay=1e-1,)

model, optimizer, train_dataloader = accelerator.prepare(
    model,
    optimizer,
    train_dataloader,
)

model.train()
start_time = time.time()
for epoch in (range(20)):
    for idx, batch in enumerate(train_dataloader):
        optimizer.zero_grad()
        outputs = model(
            past_time_features=batch["past_time_features"].to(device),
            past_values=batch["past_values"].to(device),
            future_time_features=batch["future_time_features"].to(device),
            future_values=batch["future_values"].to(device),
            past_observed_mask=batch["past_observed_mask"].to(device),
            future_observed_mask=batch["future_observed_mask"].to(device),
        )
        loss = outputs.loss

        # Backprop
        accelerator.backward(loss)
        optimizer.step()

        if idx % 100 == 0:
            print(f'Epoch: {epoch}', f'Loss: {loss.item()}')

print(f'Total training time: {time.time() - start_time}')

输出结果如下:

...
Epoch: 14 Loss: -3.1271555423736572
Epoch: 15 Loss: -3.138277769088745
Epoch: 16 Loss: -3.078387975692749
Epoch: 17 Loss: -3.09626841545105
Epoch: 18 Loss: -3.276211977005005
Epoch: 19 Loss: -3.2201414108276367
Total training time: 183.03989911079407

我们观察到训练时间比*Autoformer*模型更短,但与*Time Series Transformer*模型相似。

如前所述,我们可以看到Informer模型在捕捉数据的季节性和趋势方面,与Autoformer和Time Series Transformer模型表现相似。

总结

在这篇博客中,我们探索了使用基于Transformer的方法进行时间序列预测的过程,使用了AMD GPU。通过利用AMD硬件的强大功能,我们展示了从数据预处理到模型训练和评估的完整工作流程。

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

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

相关文章

私域流量升级下的新机遇——“开源 AI 智能名片S2B2C 商城小程序”与新兴技术的融合

摘要:本文深入探讨了随着私域流量应用的进一步升级,智能对话式营销持续火爆的同时,CEM(客户体验管理)、MA(营销自动化)、CDP(客户数据平台)及 DAM(数据资产管…

《黑神话:悟空》之光线追踪技术

8月20日,国产单机游戏《黑神话:悟空》终于上市,并以实力演绎了爆款游戏的“盛况空前”。 这款游戏的成功,不仅源自对经典文学《西游记》的深刻解读与创新演绎,更在于其背后强大的科技力量支撑。 空间计算功不可没 土…

游戏服务器架构:基于匿名函数的高性能异步定时器系统

作者:码客(ygluu 卢益贵) 关键词:游戏服务器架构、匿名函数、高性能、异步定时器。 一、前言 本文主要介绍适用于MMO/RPG游戏服务端的、基于匿名函数做定时器回调函数的、高性能异步触发的定时器系统的设计方案,以解决…

《深入浅出WPF》读书笔记.7依赖属性和附加属性

《深入浅出WPF》读书笔记.7依赖属性和附加属性 背景 总结一下wpf依赖属性和附加属性的底层逻辑,方便更好的理解使用。 属性 CLR属性由来 static属性和非static属性的区别 static属性:对类有意义,内存只有一个实例; 非static属性:对类实…

WPF—LiveCharts图表

LiveCharts图表 LiveCharts是一个简单灵活、交互式以及功能强大的跨平台图表库,支持wpf、winform...应用程序。 快速入门 安装 在应用程序中右键引用​,点击管理NuGet程序包​,选择浏览​,搜索LiveChartsCore.SkiaSharpView.W…

自动驾驶-机器人-slam-定位面经和面试知识系列10之高频面试题(04)

这个博客系列会分为C STL-面经、常考公式推导和SLAM面经面试题等三个系列进行更新,基本涵盖了自己秋招历程被问过的面试内容(除了实习和学校项目相关的具体细节)。在知乎和牛客也会同步更新,全网同号(lonely-stone或者…

Cortex-A7的GIC(通用中断控制器):专有名词简介

0 资料 ARM Generic Interrupt Controller Architecture version 2.0 Architecture Specification1 专有名词简介 1.1 中断状态 说明: Inactive:未激活,中断无效。中断非挂起或非激活。 Pending:挂起,中断有效。等待…

【Web】NepCTF 2024题解

目录 PHP_MASTER!! NepDouble 蹦蹦炸弹(boom_it) NepRouter-白给 Always RCE First PHP_MASTER!! PHP反序列化键值逃逸mb_strpos与mb_substr连用导致的字符注入 https://www.cnblogs.com/EddieMurphy-blogs/p/18310518 flag在phpinfo里 payloa…

1/f噪声影响及解决措施

在将6位半数字万用表输入短接时,观察其输出。在逐渐增加均值次数后,噪声开始下降,达到一定程度后便停止下降,随着时间的推移,停止下降的噪声在逐渐增加,该部分主要是1/f噪声影响。 这种1/f噪声(…

mPLUG-Owl3环境搭建推理测试

mPLUG-Owl3环境搭建&推理测试 引子 多模态的大模型也写了很多篇,阿里系的之前有一篇Qwen-VL的相关部署,感兴趣的童鞋请移步(Qwen-VL环境搭建&推理测试-CSDN博客)。今天这个mPLUG-Qwl3,更新换代也很快&#x…

Windows下线程的竞争与资源保护(win32-API)

一、前言 在线程编程中,资源共享与保护是一个核心议题,尤其当多个线程试图同时访问同一份资源时,如果不采取适当的措施,就会引发一系列的问题,如数据不一致、竞态条件、死锁等。为了确保数据的一致性和线程安全&#…

【游戏速递】 小猪冲刺:萌动指尖的极速挑战,小虎鲸Scratch资源站独家献映!

在线玩:Scratch小猪冲刺:全新挑战的几何冒险游戏-小虎鲸Scratch资源站 想象一下,一群憨态可掬的小猪,穿上炫酷的装备,踏上了追逐梦想的赛道。它们或跳跃、或滑行,灵活躲避各种障碍,只为那终点的…

微软亚研院哈佛:同行评议互一致的rStar

本来想将近期另一篇DeepSeek的“DeepSeek-Prover-V1.5: Harnessing Proof Assistant Feedback for Reinforcement Learning and Monte-Carlo Tree Search”与这篇同样基于强化学习思想的小型清爽型推理模型放在一个笔记中相互对比借鉴一下,考虑虽然两者有着一些共通…

论文3解析(复现):六自由度机械臂轨迹规划研究+机器人基础知识-部分1

论文:六自由度机械臂轨迹规划研究,马强 机器人一些关于数学基础的知识,简单的说一下: 向量 在机器人中,向量的含义并不是算算数那样子,而是在空间的本质含义。 向量叉乘:ab |a|*|b|*sin&am…

燃烧控制模型

加热炉燃烧控制 主要功能: 1. 把要轧制的钢坯加热的规定温度,即出炉目标温度,并尽量减少黑印。 2. 协调加热炉及轧机的生产能力,以提高轧机总的生产效率。 3. 节省燃料 在轧钢生产过程中&#x…

s3c2440移植Linux内核之引导

最近想尝试把新的Linux内核移植到tq2440的开发板上,看看还能不能顺利的跑起来。我的基础版本是买板子的时候提供的2.6.30版本,编译器版本是4.3.3.。 下载源码和编译器 下载linux源码,源码的官方网站是The Linux Kernel Archives&#xff0c…

沉积层的厚度为自振周期波长的1/4

要理解为什么是1/4,需要明白如下两点。 (1)自振周期(fundamental model, or first harmonic)取决于在某边界条件下可以出现驻波(standing wave)的最短距离。Standing wave, also known as a st…

AI助力水体保护区无人值守垂钓智能预警,基于YOLOv8全系列【n/s/m/l/x】参数模型开发构建水体保护区场景下无人值守垂钓智能检测预警系统

保护我们赖以生存的自然生态环境,无疑是一项意义深远且需要长期坚持的任务。自然界的生态系统,由水、气、森林、土壤等多要素组成,它们相互依存、相互影响,共同维系着地球的生态平衡。然而,在人类活动的影响下&#xf…

浅谈进程,线程,协程以及服务端高并发的处理

进程、线程、协程 进程:独立的程序实例,资源开销较大,适合隔离性要求高的任务。 独立性:进程具有独立的内存空间和资源,互不干扰。 资源开销大:由于每个进程都需要分配独立的内存和资源,创建和…

5个常用的物理仿真JavaScript插件

还是大剑师兰特:曾是美国某知名大学计算机专业研究生,现为航空航海领域高级前端工程师;CSDN知名博主,GIS领域优质创作者,深耕openlayers、leaflet、mapbox、cesium,canvas,webgl,ech…