【阅读笔记】概率预测之DeepAR(含Pytorch代码实现)

news2025/1/12 21:04:35

本文作为自己阅读论文后的总结和思考,不涉及论文翻译和模型解读,适合大家阅读完论文后交流想法,关于论文翻译可以查看参考文献。论文地址:https://arxiv.org/abs/1704.04110

DeepAR

    • 一. 全文总结
    • 二. 研究方法
    • 三. 结论
    • 四. 创新点
    • 五. 思考
    • 六. 参考文献
    • 七. Pytorch实现⭐
      • util(工具函数)
      • Model
      • 主函数

一. 全文总结

本文中提出了DeepAR,一种产生准确概率预测的方法,基于在大量相关时间序列上训练一个自回归递归网络模型。本文展示了如何通过将深度学习技术应用于概率预测,克服广泛使用的经典方法面临的许多挑战。通过对几个真实世界预测数据集的广泛经验评估,表明与最先进的方法相比,准确性提高了15%左右。
在这里插入图片描述

二. 研究方法

  1. 首先假设预测数据的分布情况,例如对于连续数据假设其分布为高斯分布,对于计数数据假设其为负二项分布,针对其他类型数据有其对应的分布。

高斯分布:
在这里插入图片描述
负二项分布:
在这里插入图片描述

  1. 提出了一种用于概率预测的RNN架构,预测预测值分布的参数,通过最小化负对数似然函数来更新模型参数。

在这里插入图片描述
值得注意的是,在实验时由于编码器模型与解码器相同,在计算损失时包括了训练的历史序列,即 t 0 t_0 t0=0。

  1. 针对多时序尺度不一致的问题,引入尺度因子来调节尺度;针对不同尺度的时序数量不一致的问题,基于尺度因子在训练时进行非均匀采样

模型的预测性能如下表所示,三个数据集均为计数数据(positive count-valued),采用负二项分布的假设是更准确的,因此rnn-gaussian性能很差。rnn-negbin和DeepAR的差别就是有没有采用尺度因子和非均匀采样,可以看到在数据中没有scale-gap的数据集中二者的性能相近,在scale-gap数据集中DeepAR性能最优。
在这里插入图片描述

三. 结论

基于现代深度学习技术的预测方法可以在各种数据集上大大提高最先进的预测方法的预测精度。我们提出的DeepAR模型有效地从相关的时间序列中学习全球模型,通过尺度因子缩放基于尺度的非均匀采样处理序列中尺度不一致的问题,以高精度生成校准概率预测,并能够从数据中学习复杂的模式,如季节性不确定性随时间的增长。

四. 创新点

  1. 与传统RNN相比,本文预测每个时间点的概率分布参数从而获得每个时间点的概率密度函数,通过极大似然的方法来优化模型参数。
  2. DeepAR以蒙特卡罗样本的形式进行概率预测,该样本可用于计算预测视界内所有子范围的一致分位数估计
  3. 对于多时序尺度不一致的问题,传统的方法是在数据预处理时标准化或者分组预测,本文采用引入尺度因子非均匀加权采样的方法来解决这个问题。
  4. 支持直接输入多重时间序列,并且可以通过Embedding层来学习同类时间序列的共性,方便处理海量时间序列,并且能够处理序列中存在缺失值时的预测问题。

五. 思考

DeepAR属于是将深度学习与概率预测结合的一个突破,然而DeepAR属于概率预测中的参数预测,对预测值分布的提前假设会预测精度会产生极大影响。

六. 参考文献

  1. DeepAR:自回归循环网络进行时序概率进行预测
  2. 【时序】DeepAR 概率预测模型论文笔记
  3. [论文精读] DeepAR:使用自回归RNN预测时序概率分布⭐

七. Pytorch实现⭐

以下代码参考:https://github.com/jingw2/demand_forecast,附添加了一些必要的注释让大家更好理解。

import torch 
from torch import nn
import torch.nn.functional as F 
from torch.optim import Adam

import numpy as np
import os
import random
import matplotlib.pyplot as plt
import pickle
from tqdm import tqdm
import pandas as pd
from sklearn.preprocessing import StandardScaler
from datetime import date
import argparse
from progressbar import *

util(工具函数)

def get_data_path():
    folder = os.path.dirname(__file__)
    return os.path.join(folder, "data")

def RSE(ypred, ytrue):
    rse = np.sqrt(np.square(ypred - ytrue).sum()) / \
            np.sqrt(np.square(ytrue - ytrue.mean()).sum())
    return rse

def quantile_loss(ytrue, ypred, qs):
    '''
    Quantile loss version 2
    Args:
    ytrue (batch_size, output_horizon)
    ypred (batch_size, output_horizon, num_quantiles)
    '''
    L = np.zeros_like(ytrue)
    for i, q in enumerate(qs):
        yq = ypred[:, :, i]
        diff = yq - ytrue
        L += np.max(q * diff, (q - 1) * diff)
    return L.mean()

def SMAPE(ytrue, ypred):
    ytrue = np.array(ytrue).ravel()
    ypred = np.array(ypred).ravel() + 1e-4
    mean_y = (ytrue + ypred) / 2.
    return np.mean(np.abs((ytrue - ypred) \
        / mean_y))

def MAPE(ytrue, ypred):
    ytrue = np.array(ytrue).ravel() + 1e-4
    ypred = np.array(ypred).ravel()
    return np.mean(np.abs((ytrue - ypred) \
        / ytrue))

def train_test_split(X, y, train_ratio=0.7):
    '''
    - X (array like): shape (num_samples, num_periods, num_features)
    - y (array like): shape (num_samples, num_periods)
    '''
    num_ts, num_periods, num_features = X.shape
    train_periods = int(num_periods * train_ratio)
    random.seed(2)
    Xtr = X[:, :train_periods, :]
    ytr = y[:, :train_periods]
    Xte = X[:, train_periods:, :]
    yte = y[:, train_periods:]
    return Xtr, ytr, Xte, yte

class StandardScaler:
    
    def fit_transform(self, y):
        self.mean = np.mean(y)
        self.std = np.std(y) + 1e-4
        return (y - self.mean) / self.std
    
    def inverse_transform(self, y):
        return y * self.std + self.mean

    def transform(self, y):
        return (y - self.mean) / self.std

class MaxScaler:

    def fit_transform(self, y):
        self.max = np.max(y)
        return y / self.max
    
    def inverse_transform(self, y):
        return y * self.max

    def transform(self, y):
        return y / self.max


class MeanScaler:
    
    def fit_transform(self, y):
        self.mean = np.mean(y)
        return y / self.mean
    
    def inverse_transform(self, y):
        return y * self.mean

    def transform(self, y):
        return y / self.mean

class LogScaler:

    def fit_transform(self, y):
        return np.log1p(y)
    
    def inverse_transform(self, y):
        return np.expm1(y)

    def transform(self, y):
        return np.log1p(y)


def gaussian_likelihood_loss(z, mu, sigma):
    '''
    Gaussian Liklihood Loss
    Args:
    z (tensor): true observations, shape (num_ts, num_periods)
    mu (tensor): mean, shape (num_ts, num_periods)
    sigma (tensor): standard deviation, shape (num_ts, num_periods)
    likelihood: 
    (2 pi sigma^2)^(-1/2) exp(-(z - mu)^2 / (2 sigma^2))
    log likelihood:
    -1/2 * (log (2 pi) + 2 * log (sigma)) - (z - mu)^2 / (2 sigma^2)
    '''
    negative_likelihood = torch.log(sigma + 1) + (z - mu) ** 2 / (2 * sigma ** 2) + 6
    return negative_likelihood.mean()

def negative_binomial_loss(ytrue, mu, alpha):
    '''
    Negative Binomial Sample
    Args:
    ytrue (array like)
    mu (array like)
    alpha (array like)
    maximuze log l_{nb} = log Gamma(z + 1/alpha) - log Gamma(z + 1) - log Gamma(1 / alpha)
                - 1 / alpha * log (1 + alpha * mu) + z * log (alpha * mu / (1 + alpha * mu))
    minimize loss = - log l_{nb}
    Note: torch.lgamma: log Gamma function
    '''
    batch_size, seq_len = ytrue.size()
    likelihood = torch.lgamma(ytrue + 1. / alpha) - torch.lgamma(ytrue + 1) - torch.lgamma(1. / alpha) \
        - 1. / alpha * torch.log(1 + alpha * mu) \
        + ytrue * torch.log(alpha * mu / (1 + alpha * mu))
    return - likelihood.mean()

def batch_generator(X, y, num_obs_to_train, seq_len, batch_size):
    '''
    Args:
    X (array like): shape (num_samples, train_periods, num_features)
    y (array like): shape (num_samples, train_periods)
    num_obs_to_train (int): 训练的历史窗口长度
    seq_len (int): sequence/encoder/decoder length
    batch_size (int)
    '''
    num_ts, num_periods, _ = X.shape
    if num_ts < batch_size:
        batch_size = num_ts
    t = random.choice(range(num_obs_to_train, num_periods-seq_len)) # 从num_obs_to_train和num_periods-seq_len-1之间随机选一个整数,作为预测点
    batch = random.sample(range(num_ts), batch_size) # 从num_ts条数据中随机选择batch_size条
    X_train_batch = X[batch, t-num_obs_to_train:t, :] # (batch_size, num_obs_to_train, num_features)
    y_train_batch = y[batch, t-num_obs_to_train:t] # (batch_size, num_obs_to_train)
    Xf = X[batch, t:t+seq_len, :] # (batch_size, seq_len, num_features)
    yf = y[batch, t:t+seq_len] # (batch_size, seq_len)
    return X_train_batch, y_train_batch, Xf, yf

Model

class Gaussian(nn.Module):

    def __init__(self, hidden_size, output_size):
        '''
        Gaussian Likelihood Supports Continuous Data
        Args:
        input_size (int): hidden h_{i,t} column size
        output_size (int): embedding size
        '''
        super(Gaussian, self).__init__()
        self.mu_layer = nn.Linear(hidden_size, output_size)
        self.sigma_layer = nn.Linear(hidden_size, output_size)

        # initialize weights
        # nn.init.xavier_uniform_(self.mu_layer.weight)
        # nn.init.xavier_uniform_(self.sigma_layer.weight)
    
    def forward(self, h): # h为神经网络隐藏层输出 (batch, hidden_size)
        _, hidden_size = h.size()
        sigma_t = torch.log(1 + torch.exp(self.sigma_layer(h))) + 1e-6
        sigma_t = sigma_t.squeeze(0)
        mu_t = self.mu_layer(h).squeeze(0)
        return mu_t, sigma_t # (batch, output_size)

class NegativeBinomial(nn.Module):

    def __init__(self, input_size, output_size):
        '''
        Negative Binomial Supports Positive Count Data
        Args:
        input_size (int): hidden h_{i,t} column size
        output_size (int): embedding size
        '''
        super(NegativeBinomial, self).__init__()
        self.mu_layer = nn.Linear(input_size, output_size)
        self.sigma_layer = nn.Linear(input_size, output_size)
    
    def forward(self, h): # h为神经网络隐藏层输出 (batch, hidden_size)
        _, hidden_size = h.size()
        alpha_t = torch.log(1 + torch.exp(self.sigma_layer(h))) + 1e-6
        mu_t = torch.log(1 + torch.exp(self.mu_layer(h)))
        return mu_t, alpha_t # (batch, output_size)

def gaussian_sample(mu, sigma):
    '''
    Gaussian Sample
    Args:
    ytrue (array like)
    mu (array like) # (num_ts, 1)
    sigma (array like): standard deviation # (num_ts, 1)
    gaussian maximum likelihood using log 
        l_{G} (z|mu, sigma) = (2 * pi * sigma^2)^(-0.5) * exp(- (z - mu)^2 / (2 * sigma^2))
    '''
    # likelihood = (2 * np.pi * sigma ** 2) ** (-0.5) * \
    #         torch.exp((- (ytrue - mu) ** 2) / (2 * sigma ** 2))
    # return likelihood
    gaussian = torch.distributions.normal.Normal(mu, sigma)
    ypred = gaussian.sample(mu.size())
    return ypred # (num_ts, 1)

def negative_binomial_sample(mu, alpha):
    '''
    Negative Binomial Sample
    Args:
    ytrue (array like)
    mu (array like)
    alpha (array like)
    maximuze log l_{nb} = log Gamma(z + 1/alpha) - log Gamma(z + 1) - log Gamma(1 / alpha)
                - 1 / alpha * log (1 + alpha * mu) + z * log (alpha * mu / (1 + alpha * mu))
    minimize loss = - log l_{nb}
    Note: torch.lgamma: log Gamma function
    '''
    var = mu + mu * mu * alpha
    ypred = mu + torch.randn(mu.size()) * torch.sqrt(var)
    return ypred
class DeepAR(nn.Module):

    def __init__(self, input_size, embedding_size, hidden_size, num_layers, lr=1e-3, likelihood="g"):
        super(DeepAR, self).__init__()

        # network
        self.input_embed = nn.Linear(1, embedding_size)
        self.encoder = nn.LSTM(embedding_size+input_size, hidden_size, \
                num_layers, bias=True, batch_first=True)
        if likelihood == "g":
            self.likelihood_layer = Gaussian(hidden_size, 1)
        elif likelihood == "nb":
            self.likelihood_layer = NegativeBinomial(hidden_size, 1)
        self.likelihood = likelihood
    
    def forward(self, X, y, Xf):
        '''
        Args:
        num_time_series = batch_size
        X (array like): shape (num_time_series, num_obs_to_train, num_features)
        y (array like): shape (num_time_series, num_obs_to_train)
        Xf (array like): shape (num_time_series, seq_len, num_features)
        Return:
        mu (array like): shape (num_time_series, num_obs_to_train + seq_len)
        sigma (array like): shape (num_time_series, num_obs_to_train + seq_len)
        '''
        if isinstance(X, type(np.empty(2))): # 转换为tensor
            X = torch.from_numpy(X).float()
            y = torch.from_numpy(y).float()
            Xf = torch.from_numpy(Xf).float()
        num_ts, num_obs_to_train, _ = X.size()
        _, seq_len, num_features = Xf.size()
        ynext = None
        ypred = []
        mus = []
        sigmas = []
        h, c = None, None
        # 遍历所有时间点
        for s in range(num_obs_to_train + seq_len): # num_obs_to_train为历史序列长度,seq_len为预测长度
            if s < num_obs_to_train: # Encoder,ynext为真实值
                ynext = y[:, s].view(-1, 1) # (num_ts,1)
                yembed = self.input_embed(ynext).view(num_ts, -1) # (num_ts,embedding_size)
                x = X[:, s, :].view(num_ts, -1) # (num_ts,num_features)
            else: # Decoder,ynext为预测值
                yembed = self.input_embed(ynext).view(num_ts, -1) # (num_ts,embedding_size)
                x = Xf[:, s-num_obs_to_train, :].view(num_ts, -1) # (num_ts,num_features)
            x = torch.cat([x, yembed], dim=1) # (num_ts, num_features + embedding)
            inp = x.unsqueeze(1) # (num_ts,1, num_features + embedding)
            if h is None and c is None:
                out, (h, c) = self.encoder(inp) # h size (num_layers, num_ts, hidden_size)
            else:
                out, (h, c) = self.encoder(inp, (h, c))
            hs = h[-1, :, :] # (num_ts, hidden_size)
            hs = F.relu(hs) # (num_ts, hidden_size)
            mu, sigma = self.likelihood_layer(hs)  # (num_ts, 1)
            mus.append(mu.view(-1, 1))
            sigmas.append(sigma.view(-1, 1))
            if self.likelihood == "g":
                ynext = gaussian_sample(mu, sigma) #(num_ts, 1)
            elif self.likelihood == "nb":
                alpha_t = sigma
                mu_t = mu
                ynext = negative_binomial_sample(mu_t, alpha_t) #(num_ts, 1)
            # if without true value, use prediction
            if s >= num_obs_to_train - 1 and s < num_obs_to_train + seq_len  - 1: #在预测区间内
                ypred.append(ynext)
        ypred = torch.cat(ypred, dim=1).view(num_ts, -1) #(num_ts, seq_len)
        mu = torch.cat(mus, dim=1).view(num_ts, -1) #(num_ts, num_obs_to_train + seq_len)
        sigma = torch.cat(sigmas, dim=1).view(num_ts, -1) #(num_ts, num_obs_to_train + seq_len)
        return ypred, mu, sigma

主函数

num_epoches = 100
step_per_epoch = 3 #在一个epoch中,从训练集中提取step_per_epoch次训练数据
lr = 1e-3
n_layers = 1
hidden_size = 50
embedding_size = 10 #将上一时刻的真实值编码为embedding_size长度
likelihood = "g"
seq_len = 60 #预测的未来窗口长度
num_obs_to_train = 168  #训练的历史窗口长度
num_results_to_sample = 10
show_plot = True
run_test = True
standard_scaler = False
log_scaler = False
mean_scaler = True
batch_size = 64
sample_size = 100
# 读取数据
data = pd.read_csv("LD_MT200_hour.csv", parse_dates=["date"])
data["year"] = data["date"].apply(lambda x: x.year)
data["day_of_week"] = data["date"].apply(lambda x: x.dayofweek)
data = data.loc[(data["date"].dt.date >= date(2014, 1, 1)) & (data["date"].dt.date <= date(2014, 3, 1))]
print(data.shape)
plt.figure(figsize=(16, 4)) 
plt.plot(data['MT_200'])
data.head()

在这里插入图片描述

# 数据预处理
features = ["hour", "day_of_week"]
# hours = pd.get_dummies(data["hour"])
# dows = pd.get_dummies(data["day_of_week"])
hours = data["hour"]
dows = data["day_of_week"]
X = np.c_[np.asarray(hours), np.asarray(dows)] #X:(len,2)
num_features = X.shape[1]
num_periods = len(data)
X = np.asarray(X).reshape((-1, num_periods, num_features))
y = np.asarray(data["MT_200"]).reshape((-1, num_periods))
print("X_shape=",X.shape) # (series_num,len,features_num)
print("y_shape=",y.shape) # (series_num,len)
# X = np.tile(X, (10, 1, 1))
# y = np.tile(y, (10, 1))

'''
输出
X_shape= (1, 1440, 2)
y_shape= (1, 1440)
'''
'''
Args:
- X (array like): shape (num_samples, num_periods, num_features)
- y (array like): shape (num_samples, num_periods)
- epoches (int): number of epoches to run
- step_per_epoch (int): steps per epoch to run
- num_obs_to_train (int): 训练的历史窗口长度
- seq_len (int): output horizon
- likelihood (str): what type of likelihood to use, default is gaussian
- num_skus_to_show (int): how many skus to show in test phase
- num_results_to_sample (int): how many samples in test phase as prediction
'''
# 定义模型和优化器
num_ts, num_periods, num_features = X.shape
model = DeepAR(num_features, embedding_size, 
    hidden_size, n_layers, lr, likelihood)
optimizer = Adam(model.parameters(), lr=lr)
random.seed(2)

# 分割训练集和测试集
Xtr, ytr, Xte, yte = train_test_split(X, y, 0.7)
print("X_train:{},y_train:{}".format(Xtr.shape,ytr.shape))
print("X_test:{},y_test:{}".format(Xte.shape,yte.shape))
# Xtr:(num_samples, train_periods, num_features), ytr:(num_samples, train_periods)
# Xte:(num_samples, test_periods, num_features),  yte:(num_samples, test_periods)

# 标准化
yscaler = None
if standard_scaler:
    yscaler = StandardScaler()
elif log_scaler:
    yscaler = LogScaler()
elif mean_scaler:
    yscaler = MeanScaler()
if yscaler is not None:
    ytr = yscaler.fit_transform(ytr)
losses = []
cnt = 0    
    
# training
print("开启训练")
progress = ProgressBar()
for epoch in progress(range(num_epoches)):
#     print("Epoch {} starts...".format(epoch))
    for step in range(step_per_epoch):
        Xtrain, ytrain, Xf, yf = batch_generator(Xtr, ytr, num_obs_to_train, seq_len, batch_size)
        # Xtrain:(num_samples, num_obs_to_train, num_features), ytrain:(num_samples, num_obs_to_train) 
        # Xf:(num_samples, seq_len, num_features), yf:(num_samples, seq_len) 如果num_samples比batch_size小,则batch_size=num_samples
        Xtrain_tensor = torch.from_numpy(Xtrain).float()
        ytrain_tensor = torch.from_numpy(ytrain).float()
        Xf = torch.from_numpy(Xf).float()  
        yf = torch.from_numpy(yf).float()
        # ypred:(num_samples, seq_len), mu&sigma:(num_samples, num_obs_to_train + seq_len)
        ypred, mu, sigma = model(Xtrain_tensor, ytrain_tensor, Xf)
        # ypred_rho = ypred
        # e = ypred_rho - yf
        # loss = torch.max(rho * e, (rho - 1) * e).mean()
        ## gaussian loss
        ytrain_tensor = torch.cat([ytrain_tensor, yf], dim=1) # (num_samples, num_obs_to_train+seq_len) 
        if likelihood == "g":
            loss = gaussian_likelihood_loss(ytrain_tensor, mu, sigma)
        elif likelihood == "nb":
            loss = negative_binomial_loss(ytrain_tensor, mu, sigma)
        losses.append(loss.item())
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        cnt += 1

# test 
print("开启测试")
mape_list = []
# select skus with most top K  提取测试集中最后一个序列(num_obs_to_train+seq_len)
X_test = Xte[:, -seq_len-num_obs_to_train:-seq_len, :].reshape((num_ts, -1, num_features)) # (num_samples, num_obs_to_train, num_features)
Xf_test = Xte[:, -seq_len:, :].reshape((num_ts, -1, num_features)) # (num_samples, seq_len, num_features)
y_test = yte[:, -seq_len-num_obs_to_train:-seq_len].reshape((num_ts, -1)) # (num_samples, num_obs_to_train)
yf_test = yte[:, -seq_len:].reshape((num_ts, -1)) # (num_samples, seq_len)
if yscaler is not None:
    y_test = yscaler.transform(y_test)
result = []
n_samples = sample_size # 采样个数
for _ in tqdm(range(n_samples)):
    y_pred, _, _ = model(X_test, y_test, Xf_test) # ypred:(num_samples, seq_len)
    y_pred = y_pred.data.numpy()
    if yscaler is not None:
        y_pred = yscaler.inverse_transform(y_pred)
    result.append(y_pred[:,:,np.newaxis]) # y_pred[:,:,np.newaxis]:(num_samples, seq_len,1)
#     result.append(y_pred.reshape((-1, 1)))

result = np.concatenate(result, axis=2) # (num_samples, seq_len, sample_size)
p50 = np.quantile(result, 0.5, axis=2) # (num_samples, seq_len)
p90 = np.quantile(result, 0.9, axis=2) # (num_samples, seq_len)
p10 = np.quantile(result, 0.1, axis=2) # (num_samples, seq_len)

mape = MAPE(yf_test, p50)
print("P50 MAPE: {}".format(mape))
mape_list.append(mape)

if show_plot: # 序列总长度为:历史窗口长度(num_obs_to_train)+预测长度(seq_len)
    plt.figure(1, figsize=(20, 5))
    plt.plot([k + seq_len + num_obs_to_train - seq_len for k in range(seq_len)], p50[0,:], "r-") # 绘制50%分位数曲线
    # 绘制10%-90%分位数阴影
    plt.fill_between(x=[k + seq_len + num_obs_to_train - seq_len for k in range(seq_len)], y1=p10[0,:], y2=p90[0,:], alpha=0.5)
    plt.title('Prediction uncertainty')
    yplot = yte[0, -seq_len-num_obs_to_train:] #真实值 (1, seq_len+num_obs_to_train)
    plt.plot(range(len(yplot)), yplot, "k-")
    plt.legend(["P50 forecast", "P10-P90 quantile", "true"], loc="upper left")
    ymin, ymax = plt.ylim()
    plt.vlines(seq_len + num_obs_to_train - seq_len, ymin, ymax, color="blue", linestyles="dashed", linewidth=2)
    plt.ylim(ymin, ymax)
    plt.xlabel("Periods")
    plt.ylabel("Y")
    plt.show()

在这里插入图片描述

# 绘制loss
if show_plot:
    plt.plot(range(len(losses)), losses, "k-")
    plt.xlabel("Period")
    plt.ylabel("Loss")
    plt.show()

在这里插入图片描述

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

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

相关文章

软件设计师--考前查漏补缺

软件设计师 上午题一、计算机系统二、操作系统三、数据库技术四、计算机网络五、软件工程概论六、程序设计语言与编译原理七、数据结构与算法八、算法分析与设计九、其他&#xff1a;标准化与知识产权、英语 下午题一、结构化分析设计二、数据库分析技术三、面向对象分析技术四…

代码随想录算法训练营第十四天|二叉树的遍历

这里主要掌握两种遍历方法&#xff1a;递归法和迭代法 递归法&#xff1a; 1、确定递归函数的参数和返回值&#xff0c;这里参数就是节点和用于存放节点数值的vector。 2、确认终止条件&#xff0c;这里的终止条件是节点为空。 3、确定单层递归逻辑&#xff0c;根据前序、中序…

随身WIFI折腾日记(三)---Docker+ssh远程访问+青龙面板

四、安装Docker 安装完Docker以后&#xff0c;我们便可以一键部署一些服务上去了。 sudo curl -fsSL get.docker.com -o get-docker.sh # 下载安装脚本 \&& sudo sh get-docker.sh --mirror Aliyun # 执行安装脚本 \&& sudo systemctl enable docker # 加入开…

一篇文章弄懂卷积神经网络基础概念

文章目录 一篇文章弄懂卷积神经网络基础概念下采样和上采样卷积普通卷积空洞卷积转置卷积膨胀卷积和转置卷积的区别 池化最大池化平均池化 全连接 一篇文章弄懂卷积神经网络基础概念 卷积神经网络可以说是图像处理的天花板&#xff0c;也是当下图像处理在深度学习方面最热门的…

2023/5/23总结

super关键字 super关键字的用法和this 关键字的用法相似 this:代表本类对象的引用&#xff08;this关键字指向调用该方法的对象一般我们是在当前类中使用this关键字&#xff0c;所以我们常说this代表本类对象的引用&#xff09;super:代表父类存储空间的标识(可以理解为父类对象…

AGV/AMR控制器--仙工

AGV/AMR控制器--仙工 1 行业介绍1.1 控制器概念1.2 行业发展1.3 竞争格局 2 仙工控制器 SRC2.1 介绍2.2 优势标准化软硬件&#xff0c;适配多种运动模型超强适配性&#xff0c;适配各大品牌支持车型多样&#xff0c;应对场景复杂灵活应对非标需求 2.3 产品矩阵2.4 实施工具Robo…

CLIP使用教程

文章目录 前言注意使用其他示例 原理篇 前言 本文主要介绍如何调用Hugging Face中openai提供的CLIP API. 注意 如果碰到模型无法自动下载&#xff0c;可手动下载到本地&#xff0c;注意本地调用路径后缀加/。 下载config.json、preprocessor_config.json、pytorch_model.bi…

热乎的过万字GameFramework讲解笔记文档

往期文章分享 点击跳转>《导航贴》- Unity手册&#xff0c;系统实战学习点击跳转>《导航贴》- Android手册&#xff0c;重温移动开发 本文约15千字&#xff0c;新手阅读需要27分钟&#xff0c;复习需要12分钟 【收藏随时查阅不再迷路】 &#x1f449;关于作者 众所周知&a…

YOLOv5改进系列(5)——替换主干网络之 MobileNetV3

【YOLOv5改进系列】前期回顾: YOLOv5改进系列(0)——重要性能指标与训练结果评价及分析 YOLOv5改进系列(1)——添加SE注意力机制 YOLOv5改进系列(2&#

【数据结构与算法篇】栈与队列(详解)附加Leetcode经典笔试题

​&#x1f47b;内容专栏&#xff1a;《数据结构与算法专栏》 &#x1f428;本文概括&#xff1a; 讲述数据结构栈与队列基本知识。 &#x1f43c;本文作者&#xff1a;花 碟 &#x1f438;发布时间&#xff1a;2023.5.23 文章目录 一、栈1.栈的概念及结构2.栈的实现 二、有效的…

C++中的函数模板

目录 1. 什么是函数模板&#xff1f; 2. 如何定义函数模板&#xff1f; 3. 如何使用函数模板&#xff1f; 4. 函数模板与函数重载的区别是什么&#xff1f; 5. 函数模板与类模板有何异同点&#xff1f; 1. 什么是函数模板&#xff1f; - 函数模板是一种通用的函数描述&…

STM32的SPI外设

文章目录 1. STM32 的 SPI 外设简介2. STM32 的 SPI 架构剖析2.1 通讯引脚2.2 时钟控制逻辑2.3 数据控制逻辑2.4 整体控制逻辑 3. 通讯过程4. SPI 初始化结构体详解 1. STM32 的 SPI 外设简介 STM32 的 SPI 外设可用作通讯的主机及从机&#xff0c;支持最高的 SCK 时钟频率为 …

语义分割实战项目(从原理到代码环境配置)

MMsegmentation是一个基于PyTorch的图像分割工具库,它提供了多种分割算法的实现,包括语义分割、实例分割、轮廓分割等。MMsegmentation的目标是提供一个易于使用、高效、灵活且可扩展的平台,以便开发者可以轻松地使用最先进的分割算法进行研究和开发。 看下结果 MMsegmenta…

安卓基础巩固(三)多线程、IO操作、数据存储

文章目录 多线程Handler相关概念UI线程/主线程MessageMessage QueueLooperHandler 使用步骤Handler.sendMessage&#xff08;&#xff09;Handler.post&#xff08;&#xff09; Handler 机制工作原理Handler内存泄露前置知识案例分析解决方案一&#xff1a;静态内部类弱引用解…

day09 MyBatis基础操作

为什么使用框架 框架的作用:可以直接调用写好的API,提高开发效率,框架是一种经过校验,有一定功能的半成品软件 为什么选择mybatis框架 它几乎避免了所有的JDBC的代码和手动设置参数及获取结果集.作用于持久层,支持定制化sql,存储过程及高级映射 项目所需要的jar包: lombok…

PowerShell系列(四):PowerShell进入交互环境的三种方式

目录 1、Win键X 方式 2、使用微软自带的搜索功能 3、命令行运行方式 4、命令行窗口方式 5、使用第三方命令行软件&#xff08;Terminal&#xff09;开启PowerShell环境 6、PowerShell交互环境执行脚本的一些优势 7、小技巧 今天继续给大家讲解PowerShell相关的知识&…

IMX6ULL裸机篇之DDR3实验-更新 imxdownload.h

一. DDR实验 之前关于 IMX6ULL开发板&#xff0c;有关DDR实验。做了DDR内存芯片的初始化&#xff0c;校验与超频测试。 博文链接如下&#xff1a; IMX6ULL裸机篇之DDR3初始化_凌雪舞的博客-CSDN博客 IMX6ULL裸机篇之DDR3校验与超频测试_凌雪舞的博客-CSDN博客 经过了初始化…

C Primer Plus第二章编程练习答案

学完C语言之后&#xff0c;我就去阅读《C Primer Plus》这本经典的C语言书籍&#xff0c;对每一章的编程练习题都做了相关的解答&#xff0c;仅仅代表着我个人的解答思路&#xff0c;如有错误&#xff0c;请各位大佬帮忙点出&#xff01; 1.编写一个程序&#xff0c;调用一次 …

【Linux系列P3】Linux的权限有什么重点?一文带你理清!

前言 大家好&#xff0c;这里是YY的Linux系列part3&#xff1b;本章主要内容面向能使用Linux的老铁&#xff0c;主要内容是【Linux的用户&用户指令】【文件属性】【权限&权限值的两者表达方式】【权限相关指令】【起始权限问题与掩码问题】【粘滞位的概念与特殊权限-t解…

[Ext JS3.9] 标签面板(TabPanel )介绍与开发

标签面板 标签面板是RIA 类应用使用较多的组件, 因为其可以显示的内容比较多。 标签面板的效果如下图: 标签面板开发也很简单, 配置式的开发代码类似: {xtype: tabpanel,items: [{title: 标签页1,html:标签页1内容}, {title: 标签页2,html:标签页2内容}, {title: 标签页…