Code
library(tidyverse)
<- iris[ , -5] %>%
x_train scale(center = TRUE, scale = TRUE) %>% # 标准化
as.data.frame()
Rui
June 10, 2023
最简单的自编码器(AE)形式是一个前馈的、非循环的神经网络,类似于多层感知器(MLP)中的单层感知器,用一层或多层隐藏层链接输入和输出。输出层具有与输入层相同数量的节点(神经元)。输出层节点数和输入层一致。其目的是重构输入(最小化输入和输出之间的差异),而不是在给定输入 \(X\) 的情况下预测目标值 \(Y\), 所以自编码器属于无监督学习。
\[ \phi :{\mathcal {X}}\rightarrow {\mathcal {F}} \\ \]
\[ \psi :{\mathcal {F}}\rightarrow {\mathcal {X}} \\ \]
\[ \phi, \psi ={\underset {\phi, \psi }{\operatorname {argmin} }}\|{\mathcal {X}}-(\psi \circ \phi ){\mathcal {X}}\|^{2} \]
在最简单的情况下,给定一个隐藏层,自编码器的编码阶段接受输入 \({\displaystyle \mathbf {x} \in \mathbb {R} ^{d}={\mathcal {X}}}\) 并将其映射到 \({\displaystyle \mathbf {h} \in \mathbb {R} ^{p}={\mathcal {F}}}\):\({\displaystyle \mathbf {h} =\sigma (\mathbf {Wx} +\mathbf {b})}\)。 \({\displaystyle \mathbf {h}}\) 通常表示编码、潜变量或潜在表示。 \(\sigma\) 是一个逐元素的激活函数(例如 sigmoid
函数或线性整流函数)。 \({\mathbf {W}}\)是权重矩阵,\(\mathbf {b}\) 是偏置向量。 权重和偏置通常随机初始化,并在训练期间通过反向传播迭代更新。 自编码器的解码阶段映射 \({\displaystyle \mathbf {h}}\) 到重构 \({\displaystyle \mathbf {x'}}\)(与 \(\mathbf {x}\) 形状一致):\({\displaystyle \mathbf {x'} =\sigma '(\mathbf {W'h} +\mathbf {b'} )}\) 其中解码器部分的 \({\displaystyle \mathbf {\sigma '} ,\mathbf {W'} ,\mathbf {b'}}\) 可能与编码器部分的 \({\displaystyle \mathbf {\sigma } ,\mathbf {W} ,\mathbf {b}}\) 无关。
自编码器被训练来最小化重建误差(如平方误差),通常被称为 “损失”:
\[ {\displaystyle {\mathcal {L}}(\mathbf {x} ,\mathbf {x'})=\|\mathbf {x} -\mathbf {x'} \|^{2}=\|\mathbf {x} -\sigma '(\mathbf {W'} (\sigma (\mathbf {Wx} +\mathbf {b} ))+\mathbf {b'} )\|^{2}} \]
当特征空间 \(\mathcal {F}\) 的维度比输入空间 \(\mathcal {X}\) 低时,特征向量 \(\phi (x)\) 可以看作时输入 \(\mathbf {x}\) 的压缩表示,这就是不完备自动编码(undercomplete autoencoders)的情况。 如果隐藏层大于(过完备)或等于输入层的数量,或者隐藏单元的容量足够大,自编码器就可能学会恒等函数而变得无用。
本例中自编码器将使用 keras
包构建。与任何神经网络一样,自编码器的构建具有很大的灵活性,例如隐藏层的数量和每个隐藏层中节点的数量。每个隐藏层都会尝试在数据中找到新的结构。大部分情况下,自编码器是对称的,中间层是瓶颈层(bottleneck)。自编码器的前半部分被称为编码器(encoder),后半部分被称为解码器(decoder)。
建立神经网络模型之前对数据进行标准化往往可以加速模型收敛。
Sepal.Length | Sepal.Width | Petal.Length | Petal.Width |
---|---|---|---|
-0.8976739 | 1.0156020 | -1.335752 | -1.311052 |
-1.1392005 | -0.1315388 | -1.335752 | -1.311052 |
-1.3807271 | 0.3273175 | -1.392399 | -1.311052 |
-1.5014904 | 0.0978893 | -1.279104 | -1.311052 |
-1.0184372 | 1.2450302 | -1.335752 | -1.311052 |
-0.5353840 | 1.9333146 | -1.165809 | -1.048667 |
# autoencoder in keras
library(keras)
# set training data
x_train <- as.matrix(x_train)
# set model
model <- keras_model_sequential()
model %>%
layer_dense(units = 4, activation = "tanh", input_shape = ncol(x_train)) %>%
layer_dense(units = 2, activation = "tanh", name = "bottleneck") %>%
layer_dense(units = 4, activation = "tanh") %>%
layer_dense(units = ncol(x_train))
# view model layers
summary(model)
## Model: "sequential"
## ________________________________________________________________________________
## Layer (type) Output Shape Param #
## ================================================================================
## dense_2 (Dense) (None, 4) 20
## bottleneck (Dense) (None, 2) 10
## dense_1 (Dense) (None, 4) 12
## dense (Dense) (None, 4) 20
## ================================================================================
## Total params: 62
## Trainable params: 62
## Non-trainable params: 0
## ________________________________________________________________________________
可以看出,在降维的同时,AE 并没有丢失 iris
数据集中的类别特征。
---
title: "非线性降维AE"
author: "Rui"
date: "2023-06-10"
categories: [R, Keras]
image: "CrocusSativus.jpg"
format:
html:
code-fold: true
code-tools: true
---
```{r setup, include = FALSE}
# 设置默认参数
knitr::opts_chunk$set(
echo = TRUE,
fig.align = "center",
message = FALSE,
warning = FALSE,
collapse = TRUE
)
```
```{=html}
<iframe frameborder="no" border="0" marginwidth="0" marginheight="0" width=450 height=100 src="//music.163.com/outchain/player?type=2&id=1377642003&auto=1&height=66"></iframe>
```
## Autoencoder
最简单的自编码器(AE)形式是一个前馈的、非循环的神经网络,类似于多层感知器(MLP)中的单层感知器,用一层或多层隐藏层链接输入和输出。输出层具有与输入层相同数量的节点(神经元)。输出层节点数和输入层一致。其目的是重构输入(最小化输入和输出之间的差异),而不是在给定输入 $X$ 的情况下预测目标值 $Y$, 所以自编码器属于无监督学习。
![](Autoencoder_structure.png)
$$
\phi :{\mathcal {X}}\rightarrow {\mathcal {F}} \\
$$
$$
\psi :{\mathcal {F}}\rightarrow {\mathcal {X}} \\
$$
$$
\phi, \psi ={\underset {\phi, \psi }{\operatorname {argmin} }}\|{\mathcal {X}}-(\psi \circ \phi ){\mathcal {X}}\|^{2}
$$
在最简单的情况下,给定一个隐藏层,自编码器的编码阶段接受输入 ${\displaystyle \mathbf {x} \in \mathbb {R} ^{d}={\mathcal {X}}}$ 并将其映射到 ${\displaystyle \mathbf {h} \in \mathbb {R} ^{p}={\mathcal {F}}}$:${\displaystyle \mathbf {h} =\sigma (\mathbf {Wx} +\mathbf {b})}$。 ${\displaystyle \mathbf {h}}$ 通常表示编码、潜变量或潜在表示。 $\sigma$ 是一个逐元素的激活函数(例如 `sigmoid` 函数或线性整流函数)。 ${\mathbf {W}}$是权重矩阵,$\mathbf {b}$ 是偏置向量。 权重和偏置通常随机初始化,并在训练期间通过反向传播迭代更新。 自编码器的解码阶段映射 ${\displaystyle \mathbf {h}}$ 到重构 ${\displaystyle \mathbf {x'}}$(与 $\mathbf {x}$ 形状一致):${\displaystyle \mathbf {x'} =\sigma '(\mathbf {W'h} +\mathbf {b'} )}$ 其中解码器部分的 ${\displaystyle \mathbf {\sigma '} ,\mathbf {W'} ,\mathbf {b'}}$ 可能与编码器部分的 ${\displaystyle \mathbf {\sigma } ,\mathbf {W} ,\mathbf {b}}$ 无关。
自编码器被训练来最小化重建误差(如平方误差),通常被称为 "损失":
$$
{\displaystyle {\mathcal {L}}(\mathbf {x} ,\mathbf {x'})=\|\mathbf {x} -\mathbf {x'} \|^{2}=\|\mathbf {x} -\sigma '(\mathbf {W'} (\sigma (\mathbf {Wx} +\mathbf {b} ))+\mathbf {b'} )\|^{2}}
$$
当特征空间 $\mathcal {F}$ 的维度比输入空间 $\mathcal {X}$ 低时,特征向量 $\phi (x)$ 可以看作时输入 $\mathbf {x}$ 的压缩表示,这就是不完备自动编码(undercomplete autoencoders)的情况。 如果隐藏层大于(过完备)或等于输入层的数量,或者隐藏单元的容量足够大,自编码器就可能学会恒等函数而变得无用。
本例中自编码器将使用 `keras` 包构建。与任何神经网络一样,自编码器的构建具有很大的灵活性,例如隐藏层的数量和每个隐藏层中节点的数量。每个隐藏层都会尝试在数据中找到新的结构。大部分情况下,自编码器是对称的,中间层是瓶颈层(bottleneck)。自编码器的前半部分被称为编码器(encoder),后半部分被称为解码器(decoder)。
## 数据预处理
建立神经网络模型之前对数据进行标准化往往可以加速模型收敛。
```{r}
library(tidyverse)
x_train <- iris[ , -5] %>%
scale(center = TRUE, scale = TRUE) %>% # 标准化
as.data.frame()
```
```{r}
x_train %>% head() %>% knitr::kable()
```
## 建立自动编码器
### 建立模型
```{r}
# autoencoder in keras
library(keras)
# set training data
x_train <- as.matrix(x_train)
# set model
model <- keras_model_sequential()
model %>%
layer_dense(units = 4, activation = "tanh", input_shape = ncol(x_train)) %>%
layer_dense(units = 2, activation = "tanh", name = "bottleneck") %>%
layer_dense(units = 4, activation = "tanh") %>%
layer_dense(units = ncol(x_train))
# view model layers
summary(model)
```
### 编译模型
```{r}
# compile model
model %>% compile(
loss = "mean_squared_error",
optimizer = "adam"
)
# fit model
model %>% fit(
x = x_train,
y = x_train,
epochs = 2000,
verbose = 0
)
# evaluate the model
evaluate(model, x_train, x_train)
```
### 提取出中间层
```{r}
intermediate_layer_model <- keras_model(inputs = model$input, outputs = get_layer(model, "bottleneck")$output)
intermediate_output <- predict(intermediate_layer_model, x_train)
```
### 可视化
```{r}
ggplot(data.frame(node1 = intermediate_output[, 1], node2 = intermediate_output[, 2]), aes(x = node1, y = node2, col = iris$Species)) +
geom_point() +
guides(color=guide_legend(title = "Species")) +
theme_bw()
```
可以看出,在降维的同时,AE 并没有丢失 `iris` 数据集中的类别特征。