文章目录

  • What is anomaly detection?
  • Autoencoder Introduction
  • Applications of Autoencoders
  • Example Code 1
    • Step 1:Generate Dataset
    • Step 2:Autoencoder in Keras
  • Example Code 2
    • Load the data
    • Prepare training data
    • Build a model
    • Train the model
    • Detecting anomalies
    • Plot anomalies
  • Example Code 3
  • Other Example Code

What is anomaly detection?


(图自:参考2)

异常检测方法可以大致分为基于统计,基于邻近和基于偏差三种类型。

统计异常检测假定数据是根据指定的概率分布建模的。诸如高斯混合的参数模型或诸如核密度估计的非参数模型可用于定义概率分布。 如果数据点从模型生成的概率低于某个阈值,则将数据点定义为异常。这种模型的优点在于它给出概率作为判断异常的决策规则,这是客观的,理论上合理的。

基于邻近度的异常检测假设异常数据与大量数据隔离。以这种方式对异常建模有三种方式,即基于聚类,基于密度和基于距离。对于基于聚类的异常检测,将聚类算法应用于数据以识别数据中存在的密集区域或聚类。接下来,评估数据点与每个聚类的关系以形成异常分数。这样的标准包括到聚类质心的距离和最近聚类的大小。如果到集群质心的距离高于阈值或者最近集群的大小低于阈值,则将数据点定义为异常。基于密度的异常检测将异常定义为位于数据的稀疏区域中的数据点。例如,如果数据点的局部区域内的数据点的数量低于阈值,则将其定义为异常。基于距离的异常检测使用与给定数据点的相邻数据点相关的测量。可以以这样的方式使用K-最近邻距离,其中具有大k-最近邻距离的数据点被定义为异常。

基于偏差的异常检测主要基于光谱异常检测,其使用重建误差作为异常分数。 第一步是使用降维方法(如主成分分析或自动编码器)重建数据。 使用k个最重要的主成分重建输入并测量其原始数据点和重建之间的差异导致重建误差,其可以用作异常分数。 具有高重建误差的数据点被定义为异常。


  1. 异常检测的综述论文可参考:Deep Learning for Anomaly Detection: A Survey (2019)

  2. Charu C Aggarwal. Outlier analysis. In Data mining, 75–79. Springer, 2015.

  3. Charu C Aggarwal and Saket Sathe. Theoretical foundations and algorithms for outlier ensembles. ACM SIGKDD Explorations Newsletter, 17(1):24–47, 2015.


Autoencoder Introduction

论文中提到,基于自动编码器的异常检测是一种使用半监督学习的基于偏差的异常检测方法。 它使用重建误差作为异常评分。 具有高重构性的数据点被视为异常,仅使用具有正常实例的数据来训练自动编码器。先用正常的数据集训练一个Auto Encoder,用训练出的Auto Encoder计算异常数据的重建误差,重建误差大于某个阀值α,则为异常,否则为正常

首先看一下PCA的解释:原向量x乘以矩阵W得到中间编码c,再乘以W的转置,得到x head,得到的x head希望与原x越接近越好,有一点要注意,从x到c的变换过程是线性的。Auto Encoder和PCA类似,只是网络层数更深,变换是非线性的(因为可以加入一些非线性的激活函数)。Auto Encoder 能够将数据编码成包含较少特征的潜在表示(latent representation)。在训练过程中,评价指标是对输入数据重构的重构误差(reconstruction error)。

(图自:参考8)

(图自:参考9)

为什么通过降维来检测异常值? 如果减小维数,是否会丢失一些信息,包括异常值? 答案是一旦确定了主要模式,就可以发现异常值。 许多基于距离的技术(例如KNN)在计算整个特征空间中每个数据点的距离时会遭受维度诅咒,高尺寸必须减少。有趣的是,在降维过程中,发现了异常值。可以说离群检测是降维的副产品。

(图自:参考1)

有一个n维的输入x,编码器f(x)=h将x压缩成m维的形式h,其中m<n。解码器将试图把数据恢复到原来的维数g(h)=~x。衡量重建的忠实度(faithfulness)是损失函数L(x ,g(f(x)))的值,它越小,~x就越接近x。

按照这个思路,当我们在系统中定义了正确的事件以达到模型训练的目的时,模型应该从这些事件中提取特征,并根据这些特征对事件进行一些近似的重现。当模型中出现异常事件时,由于数据的特征不同,重建误差应该会明显增大。


(图自:参考3)
自动编码器是一种特殊类型的神经网络,它将输入值复制到输出值,如上图所示。它不像传统的Y那样需要目标变量,因此它被归类为无监督学习。你可能会问,如果输出值设置为等于输入值,我们为什么要训练模型呢?事实上,我们对输出层并不那么感兴趣。我们感兴趣的是隐藏的核心层。如果隐藏层的神经元数量少于输入层,隐藏层将提取输入值的基本信息。这个条件迫使隐藏层学习数据中最多的模式,忽略 “噪音”。所以在自动编码器模型中,隐藏层的维度必须比输入层或输出层的维度少。如果隐藏层的神经元数量比输入层的神经元数量多,神经网络就会被赋予过多的能力来学习数据。在极端情况下,它可能只是简单地将输入值复制到输出值,包括噪声,而不提取任何基本信息

(图自:参考2)

由于自动编码器从来没有见过大象,更重要的是,从来没有受过重建大象的训练,所以MSE会非常高。如果重建的MSE很高,那么很可能有一个异常值。


对于自动编码器用于异常检测,可以参考论文:Variational Autoencoder based Anomaly Detection using Reconstruction Probability(论文原文(2015),论文翻译)

清华和阿里团队2018年的论文:Unsupervised Anomaly Detection via Variational Auto-Encoder for Seasonal KPIs in Web Applications


Applications of Autoencoders

自动编码器的早期应用是降维。Geoffrey Hinton(2006年)的一篇里程碑式的论文显示,与PCA的前30个主成分相比,经过训练的自动编码器产生的误差更小,而且聚类的分离度更好。自动编码器在计算机视觉和图像编辑方面也有广泛的应用。在图像着色中,自动编码器用于将黑白图像转换为彩色图像。在图像降噪中,自动编码器用于去除噪声,例如:用于图像降噪的卷积自动编码器。


(图自:参考3)


Example Code 1

本例代码来自:参考 1

Step 1:Generate Dataset

构造一个具有15个特征的虚拟数据集,其中一个类将被视为异常,标准差为1.75。通过PCA降维到三维,并进行可视化。

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
from sklearn import datasets, decomposition, preprocessingx, y = datasets.make_blobs(n_samples=500,n_features=15,centers=2,center_box=(-4.0, 4.0),cluster_std=1.75,random_state=42)x = preprocessing.MinMaxScaler().fit_transform(x)
pca = decomposition.PCA(n_components=3)
pca_result = pca.fit_transform(x)
print(pca.explained_variance_ratio_)pca_df = pd.DataFrame(data=pca_result, columns=['pc_1', 'pc_2', 'pc_3'])
pca_df = pd.concat([pca_df, pd.DataFrame({'label': y})], axis=1)ax = Axes3D(plt.figure(figsize=(8, 8)))
ax.scatter(xs=pca_df['pc_1'], ys=pca_df['pc_2'], zs=pca_df['pc_3'], c=pca_df['label'], s=25)
ax.set_xlabel("pc_1")
ax.set_ylabel("pc_2")
ax.set_zlabel("pc_3")
plt.show()

生成的虚拟数据经过PCA降维后的结果为:

Step 2:Autoencoder in Keras

# set seed for reproducibility
seed = 42
np.random.seed(seed)
tf.random.set_seed(seed)n_samples = 1000
n_features = 15# generate random data
x, y = datasets.make_blobs(n_samples=n_samples,n_features=n_features,centers=2,center_box=(-4.0, 4.0),cluster_std=1.75,random_state=seed)

使用Pandas构建一个包含测试数据的DataFrame。缩放后,将其中的20%用于验证。

# prepare data
df = pd.concat([pd.DataFrame(x), pd.DataFrame({'anomaly': y})], axis=1)
normal_events = df[df['anomaly'] == 0]
abnormal_events = df[df['anomaly'] == 1]normal_events = normal_events.loc[:, normal_events.columns != 'anomaly']
abnormal_events = abnormal_events.loc[:, abnormal_events.columns != 'anomaly']# scaling
scaler = preprocessing.MinMaxScaler()
scaler.fit(df.drop('anomaly', 1))scaled_data = scaler.transform(normal_events)# 80% percent of dataset is designated to training
train_data, test_data = model_selection.train_test_split(scaled_data, test_size=0.2)

对于一些模型及其解决的问题(如 CNN 分类),增加深度可以帮助从数据中提取更多信息。太深的自动编码器会学习将X复制到Y中,而不构建它们的压缩表示,这也是我们关心的。在我们的例子中,值得检查的是,当增加深度和减少神经元数量时,MSE将如何变化

encoder = models.Sequential(name='encoder')
encoder.add(layer=layers.Dense(units=10, activation=activations.relu, input_shape=[n_features]))
encoder.add(layer=layers.Dense(units=5, activation=activations.relu))
encoder.add(layer=layers.Dense(units=2, activation=activations.relu))decoder = models.Sequential(name='decoder')
decoder.add(layer=layers.Dense(units=5, activation=activations.relu, input_shape=[2]))
decoder.add(layer=layers.Dense(units=10, activation=activations.relu))
decoder.add(layer=layers.Dense(units=n_features, activation=activations.sigmoid))autoencoder = models.Sequential([encoder, decoder])autoencoder.compile(loss=losses.MSE,optimizer=optimizers.Adam(),metrics=[metrics.mean_squared_error])# train model
EPOCHS = 100
history = autoencoder.fit(x=train_data, y=train_data, epochs=EPOCHS, validation_data=[test_data, test_data])
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('Model Loss')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend(['Train', 'Test'], loc='upper left')
plt.show()


该模型训练了100多轮。 高于该值并没有改善的趋势,结果稳定在0.017-0.018 MSE。

plot_samples = 100
# normal event
real_x = test_data[:plot_samples].reshape(plot_samples, n_features)
predicted_x = autoencoder.predict(x=real_x)
normal_events_mse = losses.mean_squared_error(real_x, predicted_x)
normal_events_df = pd.DataFrame({'mse': normal_events_mse,'n': np.arange(0, plot_samples),'anomaly': np.zeros(plot_samples)})# abnormal event
abnormal_x = scaler.transform(abnormal_events)[:plot_samples].reshape(plot_samples, n_features)
predicted_x = autoencoder.predict(x=abnormal_x)
abnormal_events_mse = losses.mean_squared_error(abnormal_x, predicted_x)
abnormal_events_df = pd.DataFrame({'mse': abnormal_events_mse,'n': np.arange(0, plot_samples),'anomaly': np.ones(plot_samples)})mse_df = pd.concat([normal_events_df, abnormal_events_df])
plot = sns.lineplot(x=mse_df.n, y=mse_df.mse, hue=mse_df.anomaly)line = lines.Line2D(xdata=np.arange(0, plot_samples),ydata=np.full(plot_samples, 0.035),color='#CC2B5E',linewidth=1.5,linestyle='dashed')plot.add_artist(line)
plt.show()


绘制截止阈值 [threshold= 0.035],超过该阈值事件将被分类为可疑事件。 MSMSE≥阈值范围内的数据都将被发送到需要分析的可疑事件的专用队列中进行分析。其余的将由标准流程处理。

在例子中,我使用了一个人工生成的数据集进行聚类。两个类的数据的特征之间含有明显的离散性,这有助于模型在训练过程中发现差异。在实际情况下,只有部分特征会偏离常态。在评估一个事件时,自动编码器是可用的可能性之一,应该和其他算法一起使用。


Example Code 2

  • Timeseries anomaly detection using an Autoencoder

    • TF.Keras 官方教程
    • Date created: 2020/05/31;Last modified: 2020/05/31

Load the data

我们将使用Numenta异常基准(NAB)数据集。 它提供了包含标记的异常行为周期的人工时间序列数据。 数据是有序的,带有时间戳的单值指标。

import numpy as np
import pandas as pd
from tensorflow import keras
from tensorflow.keras import layers
from matplotlib import pyplot as pltmaster_url_root = "https://raw.githubusercontent.com/numenta/NAB/master/data/"df_small_noise_url_suffix = "artificialNoAnomaly/art_daily_small_noise.csv"
df_small_noise_url = master_url_root + df_small_noise_url_suffix
df_small_noise = pd.read_csv(df_small_noise_url, parse_dates=True, index_col="timestamp"
)df_daily_jumpsup_url_suffix = "artificialWithAnomaly/art_daily_jumpsup.csv"
df_daily_jumpsup_url = master_url_root + df_daily_jumpsup_url_suffix
df_daily_jumpsup = pd.read_csv(df_daily_jumpsup_url, parse_dates=True, index_col="timestamp"
)

Prepare training data

从训练时间序列数据文件中获取数据值并标准化值数据。采样周期为5分钟,共14天数据(for every 5 mins for 14 days)。

  • 24 * 60 / 5 = 288 timesteps per day
  • 288 * 14 = 4032 data points in total
# Normalize and save the mean and std we get,
# for normalizing test data.
training_mean = df_small_noise.mean()
training_std = df_small_noise.std()
df_training_value = (df_small_noise - training_mean) / training_std
print("Number of training samples:", len(df_training_value))

Create sequences

TIME_STEPS = 288# Generated training sequences for use in the model.
def create_sequences(values, time_steps=TIME_STEPS):output = []for i in range(len(values) - time_steps):output.append(values[i : (i + time_steps)])return np.stack(output)x_train = create_sequences(df_training_value.values)
print("Training input shape: ", x_train.shape)

Training input shape: (3744, 288, 1)

Build a model

我们将建立卷积重建自动编码器模型。该模型的输入形状为(batch_size,sequence_length,num_features),并返回相同形状的输出。在这种情况下,sequence_length=288,num_features=1。

model = keras.Sequential([layers.Input(shape=(x_train.shape[1], x_train.shape[2])),layers.Conv1D(filters=32, kernel_size=7, padding="same", strides=2, activation="relu"),layers.Dropout(rate=0.2),layers.Conv1D(filters=16, kernel_size=7, padding="same", strides=2, activation="relu"),layers.Conv1DTranspose(filters=16, kernel_size=7, padding="same", strides=2, activation="relu"),layers.Dropout(rate=0.2),layers.Conv1DTranspose(filters=32, kernel_size=7, padding="same", strides=2, activation="relu"),layers.Conv1DTranspose(filters=1, kernel_size=7, padding="same"),]
)
model.compile(optimizer=keras.optimizers.Adam(learning_rate=0.001), loss="mse")
model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
conv1d (Conv1D)              (None, 144, 32)           256
_________________________________________________________________
dropout (Dropout)            (None, 144, 32)           0
_________________________________________________________________
conv1d_1 (Conv1D)            (None, 72, 16)            3600
_________________________________________________________________
conv1d_transpose (Conv1DTran (None, 144, 16)           1808
_________________________________________________________________
dropout_1 (Dropout)          (None, 144, 16)           0
_________________________________________________________________
conv1d_transpose_1 (Conv1DTr (None, 288, 32)           3616
_________________________________________________________________
conv1d_transpose_2 (Conv1DTr (None, 288, 1)            225
=================================================================
Total params: 9,505
Trainable params: 9,505
Non-trainable params: 0
_________________________________________________________________

Train the model

history = model.fit(x_train,x_train,epochs=50,batch_size=128,validation_split=0.1,callbacks=[keras.callbacks.EarlyStopping(monitor="val_loss", patience=5, mode="min")],
)

绘制损失曲线

plt.plot(history.history["loss"], label="Training Loss")
plt.plot(history.history["val_loss"], label="Validation Loss")
plt.legend()
plt.show()

Detecting anomalies

我们将通过确定模型重建输入数据的程度来检测异常。

  • 1.在训练样本上找到MAE损失
  • 2.查找最大MAE损失值。 这是模型在尝试重建样本时最糟糕的情况。 我们将其作为异常检测的阈值
  • 3.如果样本的重建损失大于此阈值,那么可以推断出该模型正在看到它不熟悉的模式。将这个样本标记为异常。
# Get train MAE loss.
x_train_pred = model.predict(x_train)
train_mae_loss = np.mean(np.abs(x_train_pred - x_train), axis=1)plt.hist(train_mae_loss, bins=50)
plt.xlabel("Train MAE loss")
plt.ylabel("No of samples")
plt.show()# Get reconstruction loss threshold.
threshold = np.max(train_mae_loss)
print("Reconstruction error threshold: ", threshold)

Reconstruction error threshold: 0.06655808810755175

让我们看看模型是如何重构第一个样本的。这是训练数据集第1天起的288个时间步。

# Checking how the first sequence is learnt
plt.plot(x_train[0])
plt.plot(x_train_pred[0])
plt.show()


Prepare test data

def normalize_test(values, mean, std):values -= meanvalues /= stdreturn valuesdf_test_value = (df_daily_jumpsup - training_mean) / training_std
fig, ax = plt.subplots()
df_test_value.plot(legend=False, ax=ax)
plt.show()# Create sequences from test values.
x_test = create_sequences(df_test_value.values)
print("Test input shape: ", x_test.shape)# Get test MAE loss.
x_test_pred = model.predict(x_test)
test_mae_loss = np.mean(np.abs(x_test_pred - x_test), axis=1)
test_mae_loss = test_mae_loss.reshape((-1))plt.hist(test_mae_loss, bins=50)
plt.xlabel("test MAE loss")
plt.ylabel("No of samples")
plt.show()# Detect all the samples which are anomalies.
anomalies = test_mae_loss > threshold
print("Number of anomaly samples: ", np.sum(anomalies))
print("Indices of anomaly samples: ", np.where(anomalies))

Test input shape: (3744, 288, 1)
Number of anomaly samples: 411
Indices of anomaly samples: (array([ 217, …])

Plot anomalies

# data i is an anomaly if samples [(i - timesteps + 1) to (i)] are anomalies
anomalous_data_indices = []
for data_idx in range(TIME_STEPS - 1, len(df_test_value) - TIME_STEPS + 1):if np.all(anomalies[data_idx - TIME_STEPS + 1 : data_idx]):anomalous_data_indices.append(data_idx)df_subset = df_daily_jumpsup.iloc[anomalous_data_indices]
fig, ax = plt.subplots()
df_daily_jumpsup.plot(legend=False, ax=ax)
df_subset.plot(legend=False, ax=ax, color="r")
plt.show()


Example Code 3

该示例代码来自参考10

from keras.models import Model, load_model
from keras.layers import Input, Dense, Dropout
from keras.callbacks import ModelCheckpoint, TensorBoard
from keras import regularizersinput_dim = X_train.shape[1] # the # features
encoding_dim = 8 # first layer
hidden_dim = int(encoding_dim / 2) #hideen layernb_epoch = 30
batch_size = 128
learning_rate = 0.1input_layer = Input(shape=(input_dim, ))
encoder = Dense(encoding_dim, activation="tanh", activity_regularizer=regularizers.l1(10e-5))(input_layer)
encoder = Dense(hidden_dim, activation="relu")(encoder)
decoder = Dense(encoding_dim, activation='relu')(encoder)
decoder = Dense(input_dim, activation='tanh')(decoder)
autoencoder = Model(inputs=input_layer, outputs=decoder)# ----- some data omitted --------- #history = autoencoder.fit(X_train, X_train,epochs=nb_epoch,batch_size=batch_size,shuffle=True,validation_data=(X_test, X_test),verbose=1,callbacks=[checkpointer, tensorboard]).history
#encode all the data
encoded_seqs = encode_sequence_list(seqs_ds.iloc[:,0])
#scale it
scaled_data = MinMaxScaler().fit_transform(encoded_seqs)
#predict it
predicted = autoencoder.predict(scaled_data)
#get the error term
mse = np.mean(np.power(scaled_data - predicted, 2), axis=1)
#now add them to our data frame
seqs_ds['MSE'] = mse

我们需要做的第一件事就是确定阈值,这通常取决于我们的数据和领域知识。有人会说异常是一个数据点,例如,其误差项高于数据的95%。如果我们预计5%的数据将是异常的,那将是一个适当的阈值。 但是,回想一下,我们向25,000个完全格式化的序列列表中注入了5个异常,这意味着只有0.02%的数据是异常的,因此我们希望将阈值设置为高于数据的99.98%(或0.9998个百分位数) 。 因此,首先让我们找到此阈值:



我们发现6个离群值,其中5个是“真实”离群值。

完整代码:GitHub


Other Example Code

因为目前暂未用到图像相关的异常检测,所以本文不再赘述,现在对在查阅过程中发现的比较好的文章总结如下。

  1. Building Autoencoders in Keras

    • Keras官方教程(2017最后更新,支持Keras2.0)
    • 使用自动编码器 对 mnist 数据集进行异常检测。

  1. Machine learning for anomaly detection and condition monitoring
    轴承失效

  1. Anomaly Detection with Auto-Encoders
    信用卡欺诈检测

参考:

  1. Anomaly detection with Autoencoders
  2. Anomaly detection with Keras, TensorFlow, and Deep Learning
  3. Anomaly Detection with Autoencoders Made Easy
  4. 对基于深度神经网络的Auto Encoder用于异常检测的一些思考
  5. 基于变分自编码器(VAE)利用重建概率的异常检测
  6. Anomaly Detection with Auto-Encoders
  7. Timeseries anomaly detection using an Autoencoder
  8. Autoencoders — Deep Learning bits #1
  9. https://hackernoon.com/latent-space-visualization-deep-learning-bits-2-bd09a46920df
  10. A Keras-Based Autoencoder for Anomaly Detection in Sequences

使用AutoEncoder进行异常检测相关推荐

  1. 自编码器AutoEncoder解决异常检测问题

    自编码器AutoEncoder解决异常检测问题 一. 自编码器(Auto-Encoder)介绍 1. AE算法的原理 2. AE算法的作用 3. AE算法的优缺点 二. 自编码器AutoEncoder ...

  2. 14种异常检测方法汇总

    今天给大家分享一篇关于异常检测的文章,重点介绍了14种公开网络上一些常见的异常检测方法(附资料来源和代码). 一.基于分布的方法 1. 3sigma 基于正态分布,3sigma准则认为超过3sigma ...

  3. 异常检测方法梳理,看这篇就够了!

    本文收集整理了网络上一些常见的异常检测方法(附资料来源和代码),可以说是非常全面了,内容有点长,不着急,先收藏起来,每天学习一点点就是领先的开始. 一.基于分布的方法 1. 3sigma 基于正态分布 ...

  4. 【机器学习】异常检测

    前言 异常检测实际案例:网络安全中的攻击检测,金融交易欺诈检测,疾病侦测,和噪声数据过滤等.时间序列的异常又分为点异常和模式异常. 对于一个新观测值进行判断: 离群点检测: 训练数据包含离群点,即远离 ...

  5. 14种异常检测方法汇总(附代码)!

    公众号:尤而小屋 作者:Ai 编辑:Peter 今天给大家分享一篇关于异常检测的文章,重点介绍了14种公开网络上一些常见的异常检测方法(附资料来源和代码). 一.基于分布的方法 1. 3sigma 基 ...

  6. 14种异常检测方法理论和代码总结

    作者丨Ai 来源丨宅码 编辑丨极市平台 导读 本文收集整理了公开网络上一些常见的异常检测方法(附资料来源和代码). 本文收集整理了公开网络上一些常见的异常检测方法(附资料来源和代码).不足之处,还望批 ...

  7. 14种异常检测方法总结

    作者丨Ai 来源丨宅码 编辑丨极市平台 本文收集整理了公开网络上一些常见的异常检测方法(附资料来源和代码).不足之处,还望批评指正. 一.基于分布的方法 1. 3sigma 基于正态分布,3sigma ...

  8. 不用再找了,这就是全网最全的异常检测方法总结

    大家好,今天正好趁着周末,收集整理全网最常使用的异常检测方法(附资料来源和代码),喜欢记得收藏.点赞.关注. 注:技术交流文末获取 一.基于分布的方法 1. 3sigma 基于正态分布,3sigma准 ...

  9. 自动编码(Autoencoder)器异常检测(outlier detection)实战

    自动编码(Autoencoder)器异常检测实战 异常点检测(Outlier detection),又称为离群点检测,是找出与预期对象的行为差异较大的对象的一个检测过程.这些被检测出的对象被称为异常点 ...

最新文章

  1. 2021-2027年中国市医疗电子场投资分析及前景预测报告
  2. ubuntu11.04中如何像其他版本一样快速回到桌面
  3. python 之GUI设计:Entry组件
  4. drf实现常用数据缓存
  5. sql远程mysql服务器查询_sql server 使用链接服务器远程查询
  6. rtl support
  7. 【模拟】Biotech
  8. IntelliJ IDEA forMac 如何生成项目的javadoc(API文档)
  9. cmd中输入net start mysql 提示:服务名无效或者MySQL正在启动 MySQL无法启动
  10. C#初学的一些注意点
  11. python-requests数据驱动延伸
  12. 编程语言中的常量折叠(const folding)
  13. sql server利用开窗函数over() 进行分组统计
  14. 安装CentOS报错dracut-initqueue timeout
  15. 华为ICT大赛2016模拟题
  16. 模拟退火算法求解--顺序约束的路由部署问题
  17. 慕课java工程师2020版_中国大学慕课2020Java程序设计答案大全
  18. 合肥学院ACM集训队第一届暑假友谊赛 B FYZ的求婚之旅 D 计算机科学家 F 智慧码 题解...
  19. CSS笔记 —— 美化网页
  20. 美的微晶冰箱以云数据为驱动,实现智能保鲜冰箱智慧新升级

热门文章

  1. 数据结构之线性结构(应用实例)
  2. python 链表分割
  3. 广州翰智软件有限公司
  4. linux复制文件夹中前N个文件到其他目录下
  5. boolean 类型不建议用 is 开头
  6. matlab模拟三体运动_三体运动的matlab演示.docx
  7. PLS-00172: 字符串常值太长
  8. gddr6速率_美光宣布GDDR6显存完工 速率高达14Gbps
  9. Linux如何上线和下线CPU
  10. 【Java闭关修炼】SpringBoot项目-贪吃蛇对战小游戏-配置git环境和项目创建