0%

代码所需数据
聚类就是根据数据之间的相似度将数据集划分为多个类别或组,使类别内的数据相似度较大而类别间的数据相似度较小。如下图所示,左边是原始数据,右边是聚类之后的效果,不同的颜色代表不同的类别。
在这里插入图片描述

对于本次代码聚类步骤如下(聚类算法大体步骤,可根据需求进行修改):

1.设置初始类别中心和类别数,初始化是要注意在题目所给数据的x、y的最小值和最大值进行。
2.根据类别中心对全部数据进行类别划分:每个点分到离自己距离最小的那个类
3.重新计算当前类别划分下每个类的中心:例如可以取每个类别里所有的点的平均值作为新的中心。如何求多个点的平均值? 分别计算X坐标的平均值,y坐标的平均值,从而得到新的点。注意:类的中心可以不是真实的点,虚拟的点也不影响。
4.在新的类别中心下继续进行类别划分;

如果连续两次的类别划分结果不变则停止算法; 否则循环2~5。例如当类的中心不再变化时,跳出循环。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import numpy as np
import matplotlib.pyplot as plt
%matplotlib

data = np.loadtxt('Lab4.dat')

def calSSE(X, cidx, ctrs) :
SSE = 0
for i, ctr in enumerate(ctrs) :
SSE += np.sum(np.square(X[np.where(cidx == i + 1)] - ctr))

return SSE / X.shape[0]

def kmeans(X, K) :
center_point = []
for i in range(K) :
point_x = np.random.uniform(np.min(X, axis = 0)[0], np.max(X, axis = 0)[0])#随机初始化簇心
point_y = np.random.uniform(np.min(X, axis = 0)[1], np.max(X, axis = 0)[1])
center_point.append([point_x, point_y])
center_point = np.array(center_point)
cluter = np.zeros(X.shape[0]).astype(np.int32)#建立簇类初始化为0
item = 5
while item > 0:#迭代
for i in range(X.shape[0]) :#计算每一组数据与每个簇心的欧氏距离,距离最小者记为此组数据为所标类别
distance = center_point
distance = np.sum(np.square(distance - X[i]), axis = 1)#注意x, y都计算所以要求和,注意求和维度
cluter[i] = np.argmin(distance) + 1#最小值的下标

New_center_point = np.zeros((K, 2))

for i in range(K) :#更新簇心,取每一簇类的平均值作为新簇心
New_center_point[i][0] = np.mean(X[np.where(cluter == i + 1), 0])
New_center_point[i][1] = np.mean(X[np.where(cluter == i + 1), 1])
if (New_center_point - center_point < 1e-7).all() :#当新簇心与之前的簇心近似相等时退出迭代
break
center_point = New_center_point
item -= 1
return cluter, center_point#返回每一组数据所对应的簇类和簇心

SSE = []
mark = [ 'r', 'c', 'y', 'k', 'm', 'g']

plt.ion()
for K in range(2, 7) :
cidx, ctrs = kmeans(data, K)
ctrs_set.append(ctrs)
print(f'K为{K}时的簇心 : \n {ctrs}')
SSE.append(calSSE(data, cidx, ctrs))#手肘法求最好分类的K值

plt.subplot(2, 3, K - 1)
for i in range(K) :
plt.scatter(data[np.where(cidx == i + 1), 0], data[np.where(cidx == i + 1), 1], marker = '.', color = mark[i])#作图
plt.scatter(ctrs[ : , 0], ctrs[ : , 1], marker = '*', color = 'g')#做出簇心
plt.title(f'K is {K}')
plt.tight_layout()
plt.xticks([]), plt.yticks([])


plt.figure()
plt.plot(list(range(2, 7)), SSE, '+--')
plt.ioff()
plt.show()
阅读全文 »

分别用平均滑动窗口、指数滑动窗口、SG滤波法对含有奇异值和高斯噪声的两列数据进行去奇异值和降噪,最终拟合曲线推测函数表达式。去噪方法理论知识参考
对第一列数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import matplotlib.pyplot as plt
import numpy as np
from scipy import optimize
import scipy.io as scio
%matplotlib
#防止中文乱码
plt.rcParams["font.sans-serif"] = ["Simhei"]
plt.rcParams["axes.unicode_minus"] = False
data = scio.loadmat('2 data_preprocess_practice.mat')

yy3 = data["yy3"]
x = np.arange(0, 20001, 1)
#去除奇异值
def Noise_reduction(data_col) :
lst = []
i = 0
#此处用的是3sigema的方法
while i + 12 < 20001 :
lst1 = data_col[i : i + 12]
mean = np.mean(lst1)
std = np.std(lst1)
for value in lst1 :
if (value - mean) >= -3 * std and (value - mean) <= 3 * std :
lst.append(value)
i += 12
lst1 = []
return lst

#平均滑动去噪
#滑动平均法适用于,噪声的均值为0,真实值变化不大或线性变化的场景
def Average_sliding_denoising(arr, window_size) :
#对数组进首尾扩展,以滑动窗口可以处理到首尾点,思想与图片滤波算子相似
New_arr = arr[ : ]
window_size = (window_size - 1) // 2
for step in range(window_size) :
arr.insert(step, sum(arr[ : window_size]) / window_size)
arr.insert(len(arr) - step, sum(arr[len(arr) - window_size : len(arr)]) / window_size)
for i in range(window_size, len(arr) - window_size) :
New_arr[i - window_size] = (sum(arr[i - window_size : i + window_size + 1])) / (2 * window_size + 1)
return New_arr

#指数平均滑动去噪
#当误差不受观测值大小影响的话,指数滑动平均比滑动平均好;当误差随观测值大小变化时,滑动平均比指数滑动平均更好。
def Exponential_sliding_denoising(arr, weight = 0.01) :
for i in range(1, len(arr)) :
arr[i] = weight * arr[i] + (1 - weight) * arr[i - 1]
return arr

#Savitzky-Golay平滑去噪
#SG滤波法对于数据的观测信息保持的更好,在一些注重数据变化的场合会比较适用。
def create_x(size, rank):
x = []
for i in range(2 * size + 1):
m = i - size
row = [m ** j for j in range(rank)]
x.append(row)
x = np.mat(x)
return x

def Savgol_Denosing(arr, window_size, rank) :
New_arr = arr[ : ]
m = (window_size - 1) // 2
# 处理边缘数据,用边缘值首尾增加m个首尾项
for step in range(m) :
arr.insert(step, arr[0])
arr.insert(len(arr) - step, arr[len(arr) - 1])
# 创建X矩阵
X = create_x(m, rank)
# 计算加权系数矩阵B
B = (X * (X.T * X).I) * X.T
#只用更新第m个点,因此只需取B系数矩阵的第m行即可
A0 = B[m].T
# 计算平滑修正后的值
narr = []
for i in range(len(New_arr)):
y = [arr[i + j] for j in range(window_size)]
y1 = np.mat(y) * A0
y1 = float(y1)
narr.append(y1)
return narr

#可视化不同去噪方法的效果
def Mapping(lst, arr, arr1, arr2) :
x = np.array(list(range(0, len(arr), 1)))
fig = plt.figure(figsize=(15, 5))
fig.set(alpha = 0.2)
plt.subplot2grid((1,4), (0, 0))
plt.plot(x, arr, label = 'Average_sliding_denoising')
plt.legend(loc = 1)
plt.subplot2grid((1, 4), (0, 1))
plt.plot(x, arr1, 'g-', label = 'Exponential_sliding_denoising')
plt.legend(loc = 1)
plt.subplot2grid((1, 4), (0, 2))
plt.plot(x, arr2, 'r-', label = 'Savgol_Denosing')
plt.legend(loc = 1)
plt.subplot2grid((1, 4), (0, 3))
plt.plot(x, lst, 'b-', x, arr, 'pink', x, arr1, 'g', x, arr2, 'r')
plt.legend(['Before Denoising', 'Exponential_sliding_denoising', 'Average_sliding_denoising', 'Savgol_Denosing'], loc = 1)
plt.show()

#小结,单纯从可视化效果来看,指数平均化动的效果是最好的

#数据重新拟合,推测函数
def Polynomial_fitting(lst) :
x1 = np.arange(0, len(lst), 1).astype(float)
z1 = np.polyfit(x1, lst, 11)
# print(np.poly1d(z1))
x_points = np.linspace(0, 19973, 19973)
y_point = np.polyval(z1, x_points)
fig1 = plt.figure()
plt.plot(x1, lst, x_points, y_point, 'r')
plt.legend(['Before fitting', 'After fitting'], loc = 1)
plt.show()


data_col1 = []
data_col2 = []
for line in yy3 :
data_col1.append(line[0])
data_col2.append(line[1])

data_col1 = np.array(data_col1)
data_col2 = np.array(data_col2)

lst1 = Noise_reduction(data_col1)
lst1_A = Average_sliding_denoising(Noise_reduction(data_col1), 61)
lst1_E = Exponential_sliding_denoising(Noise_reduction(data_col1))
lst1_S = Savgol_Denosing(Noise_reduction(data_col1), 59, 2)
Mapping(lst1, lst1_A, lst1_E, lst1_S)
Polynomial_fitting1(lst1_A)

效果:
在这里插入图片描述

对第二列数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def Polynomial_fitting2(lst) :
x1 = np.arange(0, len(lst), 1).astype(float)
z1 = np.polyfit(x1, lst, 50)
x_points = np.linspace(0, 19973, 19973)
y_point = np.polyval(z1, x_points)
fig1 = plt.figure()
plt.plot(x1, lst, x_points, y_point, 'r')
plt.legend(['Before fitting', 'After fitting'], loc = 1)
plt.show()
lst2 = Noise_reduction(data_col2)
lst2_A = Average_sliding_denoising(Noise_reduction(data_col2), 61)
lst2_E = Exponential_sliding_denoising(Noise_reduction(data_col2))
lst2_S = Savgol_Denosing(Noise_reduction(data_col2), 59, 2)
Mapping(lst2, lst2_E, lst2_A, lst2_S)
Polynomial_fitting2(lst2_A)
阅读全文 »

前言

  在生成对抗网络(Generative Adversarial Network,简称 GAN)发明之前,变分自编码器(VAE)被认为是理论完备,实现简单,使用神经网络训练起来很稳定,生成的图片逼近度也较高,但是人眼还是可以很轻易地分辨出真实图片与机器生成的图片。但在2014年GAN被提出之后,在之后的几年里面里迅速发展,生成的图片越来越逼真。

1 GAN

1.1 相关介绍

  GAN模型的核心思想就是博弈思想,是生成器(造假者)和判别器(鉴别者)之间的博弈,在提出GAN的原始论文中,作者举了货币制造的例子。即像一台验钞机和一台制造假币的机器之间的博弈,两者不断博弈,博弈的结果假币越来越像真币,直到验钞机无法识别一张货币是假币还是真币为止。

阅读全文 »

前言

  目前我们可以通过爬虫等方式获取海量的样本数据𝒙,如照片、语音、文本等,是相对容易的,但困难的是获取这些数据所对应的标签信息,例如机器翻译,除了收集源语言的对话文本外,还需要待翻译的目标语言文本数据。数据的标注工作目前主要还是依赖人的先验知识来完成。因此,面对海量的无标注数据,我们需要从中学习到数据的分布𝑃(𝒙)的算法,而无监督算法模型就是针对这类问题而发展的。特别地,如果算法把𝒙作为监督信号来学习,这类算法称为自监督学习,本博客介绍的自编码器就属于自监督学习范畴。

1 自编码器

1.1 原理

  自编码器是通过对输入$x$进行编码后得到一个低维的向量$z$,然后根据 这个向量还原出输入$x$。通过对比$x$与$\bar{x}$的误差,再利用神经网络去训练使得误差逐渐减小,从而达到非监督学习的目的。结构如下图所示。
在这里插入图片描述
  其中我们将数据𝒙本身作为监督信号来指导网络的训练,即希望神经网络能够学习到映射${𝑓_θ}$: $x$ → $x$,我们把网络𝑓𝜃切分为两个部分,前面的子网络尝试学习映射关系:$g_{θ1}$: $x$ → $z$,后面的子网络尝试学习映射关系:$h_{θ2}$:$z$ → $x$。我们把$g_{θ1}$看成一个数据编码(Encode)的过程,作用就是将输入$x$编码成低纬度的隐藏变量$z$,$h_{θ2}$看成一个数据解码(Dncode)的过程,作用是将隐藏变量$z$重塑成高纬度的$x$。编码器和解码器共同完成了输入数据$x$的编码和解码过程,我们把整个网路模型${𝑓_θ}$叫做自动编码器(Auto-Encoder),如果网络含有多个隐藏层,则称为深度自编码器(Deep Auto-encoder)。在这里插入图片描述
  自编码器的编码器通过编码器压缩得到的隐藏变量$z$重塑$\bar{x}$,我们希望解码器的输出能够完美地或者近似恢复出原来的输入,即$x$约等于$\bar{x}$,则自编码器的损失函数可定义为

阅读全文 »

Canny 算子和 Marr(LoG)边缘检测方法类似,也属于是先平滑后求导数的方法John Canny研究了最优边缘检测方法所需的特性,给出了评价边缘检测性能优劣的三个指标:

  • 好的信噪比,即将非边缘点判定为边缘点的概率要低,将边缘点判为非边缘点的概率要低;
  • 高的定位性能,即检测出的边缘点要尽可能在实际边缘的中心;
  • 对单一边缘仅有唯一响应,即单个边缘产生多个响应的概率要低,并且虚假响应边缘应该得到最大抑制。

步骤:

  • 减少噪音:由于边缘检测易受图像中的噪声影响,因此第一步是使用5x5高斯滤波器去除图像中的噪声.
    在这里插入图片描述
  • 计算图像梯度:对平滑后的图像使用sobel算子在水平与竖直方向上计算一阶导数,得到图像梯度(Gx和Gy)。根据梯度图找到边界梯度和方向
    在这里插入图片描述
    根据角度对幅值进行非极大值抑制:将模糊的边界变得清晰(sharp)
  • 将其梯度方向近似为以下值中的一个(0,45,90,135,180,225,270,315)(即上下左右和45度方向);
  • 比较该像素点,和其梯度方向正负方向的像素点的梯度强度;
  • 如果该像素点梯度强度最大则保留,否则抑制(删除,即置为0)。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    edge = cv2.Canny(image, threshold1, threshold2) 必要参数:
  • 第一个参数是需要处理的原图像,该图像必须为单通道的灰度图;
  • 第二个参数是阈值1;
  • 第三个参数是阈值2。

代码实现:

阅读全文 »

Marr算子: Laplacian of a Gaussian(LOG)

  • Marr算子是在Laplacian算子的基础上实现的,它得益于对人的视觉机理的研究,有一定的生物学和生理学意义。
  • 由于Laplacian算子对噪声比较敏感,为了减少噪声影响,提出了将高斯滤
    波和拉普拉斯检测算子结合在一起进行边缘检测的方法:先对图像进行平滑,然后再用Laplacian算子检测边缘。
  • 平滑函数应能反映不同远近的周围点对给定像素具有不同的平滑作用,因此,平滑函数采用正态分布的高斯函数,即:
    在这里插入图片描述
    卷积操作具有结合律,因此我们先将高斯平滑滤波器与拉普拉斯滤波器进行卷积,然后利用得到的混合滤波器去对图片进行卷积以得到所需的结果。
    两个优点:
  • 由于高斯和拉普拉斯核通常都比图像小得多,所以这种方法通常只需要很少的算术运算。
  • LoG (‘ Laplacian of Gaussian’)内核的参数可以预先计算,因此在运行时只需要对图像执行一遍的卷积即可。
    在这里插入图片描述算法步骤如下:
  • 滤波:首先对图像f(x,y)进行平滑滤波,其滤波函数根据人类视觉特性选为高斯函数,
  • 增强:对平滑图像进行拉普拉斯运算,
  • 检测:利用二阶导数算子过零点的性质,可确定图像中阶跃边缘的位置

由于的平滑性质能减少噪声的影响,所以当边缘模糊或噪声较大时,利用检测过零点能提供较可靠的边缘位置。在该算子中,σ 的选择很重要, σ 小时边缘位置精度高,但边缘细节变化多; σ 大时平滑作用大,但细节损失大,边缘点定位精度低。应根据噪声水平和边缘点定位精度要求适当选取 σ。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
## Marr算子:Lalpacian of Gaussion(LOG)
#cv2.GuassianBlur(img, ksize,sigmaX,sigmaY),sigmaX和sigmaY表示x和y方向上的高斯核标准差
gaussion = cv.GaussianBlur(img_clean, (3, 3), 0)#先用高斯滤波对图像进行平滑处理
dst = cv.Laplacian(gaussion, cv.CV_16S, ksize = 3)#再用拉普拉斯算子进行边缘检测,第二个参数CV_16s表示图像中的数据是16位无符号整数
log = cv.convertScaleAbs(dst) #convertScaleAbs函数是一个位深转化函数,可将任意类型的数据转化为CV_8UC1
# (0)CV_8UCV1表示8位无符号整数,且通道为一
# (1). 对于src*alpha+beta的结果如果是负值且大于-255,则直接取绝对值;
# (2). 对于src*alpha+beta的结果如果大于255,则取255;
# (3). 对于src*alpha+beta的结果是负值,且小于-255,则取255;
# (4). 对于src*alpha+beta的结果如果在0-255之间,则保持不变;

fig = plt.figure(figsize = (10, 5))#作图
fig.set(alpha = 0.2)
plt.subplot2grid((1, 2), (0, 0))
plt.imshow(img_clean, 'gray')

plt.subplot2grid((1, 2), (0, 1))
plt.imshow(log, 'gray')

在这里插入图片描述

阅读全文 »

Kirsch算子是R.Kirsch提出来一种边缘检测算法,它采用8个模板对图像上的每一个像素点进行卷积求导数,这8个模板代表8个方向,对图像上的8个特定边缘方向作出最大响应,运算中取最大值作为图像的边缘输出。
在这里插入图片描述
在这里插入图片描述
Kirsch算子特点
• 在计算边缘强度的同时可以得到边缘的方向
• 各方向间的夹角为45º

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
%matplotlib
#kirsch算子
#自定义卷积核,八个方向
m1 = np.array([[5, 5, 5], [-3,0,-3], [-3,-3,-3]])
m2 = np.array([[-3, 5,5], [-3,0,5], [-3,-3,-3]])
m3 = np.array([[-3,-3,5], [-3,0,5], [-3,-3,5]])
m4 = np.array([[-3,-3,-3], [-3,0,5], [-3,5,5]])
m5 = np.array([[-3, -3, -3], [-3,0,-3], [5,5,5]])
m6 = np.array([[-3, -3, -3], [5,0,-3], [5,5,-3]])
m7 = np.array([[5, -3, -3], [5,0,-3], [5,-3,-3]])
m8 = np.array([[5, 5, -3], [5,0,-3], [-3,-3,-3]])

filterlist = [m1, m2, m3, m4, m5, m6, m7, m8]#将各个方向的卷积核放到一起便于统一操作
filtered_list = np.zeros((8, img_clean.shape[0], img_clean.shape[1]))#建立三维数组,第0维表示各个方向卷积后的值

for k in range(8) :
out = cv.filter2D(img_clean, cv.CV_16S, filterlist[k])#自定义卷积,其实里面的步骤跟Sobel算子是差不多的
filtered_list[k] = out

final = np.max(filtered_list, axis = 0)#取八个方向中的最大值,也就是取第0维的最大值作为图像该点,滤波之后的新的像素值
final[ np.where(final >= 255)] = 255#令像素值大于255的点等于255
final[ np.where(final < 255) ] = 0#令像素值小于255的点等于0

fig = plt.figure(figsize = (10, 5))#显示图像
fig.set(alpha = 0.2)
plt.subplot2grid((1, 2), (0, 0))
plt.imshow(img_clean, 'gray')

plt.subplot2grid((1, 2), (0, 1))
plt.imshow(final, 'gray')

在这里插入图片描述

数据预处理分析,最后面附有决策树算法的实现
原始数据:
原数据地址
在这里插入图片描述
计算第一次决策如果
分别对在14天各个属性下是否进行施肥的统计情况且计算该属性的基尼指数,同一种属性不同表现的基尼指数表示为M,加权平均之后为节点的基尼指数,用N表示
天气:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#encoding = utf-8
import pandas as pd

Base_file = pd.read_excel('Data.xlsx')
Base_file.head(15)
#Base_file.head()
Weather_Sunny = Base_file[Base_file['天气'] == '晴天']['是否施肥'].value_counts()
#print(Weather_Sunny)['否' '否' '否' '是' '是']
Weather_Rainy = Base_file[Base_file['天气'] == '雨天']['是否施肥'].value_counts()
Weather_Overcast = Base_file[Base_file['天气'] == '阴天']['是否施肥'].value_counts()
Weather_Overcast['否'] = 0
Weather_df = pd.DataFrame([
pd.Series([Weather_Sunny['是'], Weather_Sunny['否']], index = ['是', '否']),
pd.Series([Weather_Rainy['是'], Weather_Rainy['否']], index = ['是', '否']),
pd.Series([Weather_Overcast['是'], Weather_Overcast['否']], index = ['是', '否'])
], index=['晴天', '雨天', '阴天'])
Weather_df.head()

在这里插入图片描述
晴天:M1 = 2 2/5 (1 - 2/5) = 0.444444445
雨天:M2 = 2 3/5 (1 - 3/5) = 0.48
阴天:M3 = 0
N1 = 5/14 M1 + 5/14 M2 = 0.343
温度:

1
2
3
4
5
6
7
8
9
Hot = Base_file[Base_file['温度'] == '炎热']['是否施肥'].value_counts()
Cool = Base_file[Base_file['温度'] == '温']['是否施肥'].value_counts()
Cold = Base_file[Base_file['温度'] == '冷']['是否施肥'].value_counts()
Temperature_df = pd.DataFrame([
pd.Series([Hot['是'], Hot['否']], index = ['是', '否']),
pd.Series([Cool['是'], Cool['否']], index = ['是', '否']),
pd.Series([Cold['是'], Cold['否']], index = ['是', '否'])
], index = ['炎热', '温', '冷'])
Temperature_df.head()

在这里插入图片描述
炎热:M1 = 2 2/4 (1 - 2/4) = 0.5
温 : M2 = 2 2/6 (1 - 2/6) = 0.44444445
冷: M3 = 2 3/4 (1 - 3/4) = 0.375
N2 = 4/14 M1 + 6/14 M2 + 4/14 * M3 = 0.440

阅读全文 »

1 Transformer

Transformer是Sequence-toSequence(Seq2Seq)的一个模型,我们之前在作一些实验的时候,当我们输入一个Sequence时,我们的输出也会是一个Sequence,而输入和输出结果的长度是一样的,当我们不知道输出结果是有多长时,我们便要机器自己决定要输出多长,这就会用到Seq2Seq,特别是在语音辨识及机器翻译中。
在这里插入图片描述
一般的Seq2Seq模型是由Encoder和Decoder组成,Encoder接受外界的输入,然后把输出的结果丢给Decoder,再由Decoder决定要输出的Sequence的大小在这里插入图片描述
Seq2seq最早在14年的时候就有了,那时是长的很眉清目秀,后面就变得一言难尽了
在这里插入图片描述
在这里插入图片描述

Encoder

Encoder要做的事情就是输入一排向量然后输出一排长度相同向量,这个用RNN或者CNN都能做得到,Encoder用的是self-attention(在我第四篇笔记中有记录到,欢迎大家指正)在这里插入图片描述
现在的Encoder会被分成很多个block,每一个block先做一个self-attention,接受一排向量的输入,考虑全部的资讯,然后输出一排向量,再把结果丢到全连接层再输出一排向量,这就是每一个block的输出,在这里插入图片描述
实际上原来的transformer中,block做的事情更加复杂,在经过self-attention得到一排向量之后,并不会直接丢给全连接层,而是将输入加进来得到新的向量,当成新的output,这种架构叫做residual connection,再将得到的新output做layer normalization(不需要考虑batch),layer normalization在同一个feature中计算不同维度的mean,standard,用公式x’i = (xi - mean)/ std归一化,得到要输入到全连接层的结果,在这里插入图片描述
同样的,全连接层里面也有residual connection的架构和normalization,然后才得到一个block的输出

Decoder

阅读全文 »

1 RNN 的缺点

  我在上一篇博客中跟大家一步一步探索了 RNN 模型的网络结构,最后面也介绍了 RNN 的应用场景。但在实际应用中,标准 RNN 训练的优化算法面临一个很大的难题,就是长期依赖问题——由于网络结构的变深使得模型丧失了学习到先前信息的能力,通俗的说,标准的 RNN 虽然有了记忆,但很健忘,也即标准 RNN 只有短时记忆。循环神经网络在处理较长的句子时,往往只能够理解有限长度内的信 息,而对于位于较长范围类的有用信息往往不能够很好的利用起来。我们把这种现象叫做短时记忆。
  针对标准 RNN 短时记忆的问题,最直接的想法就是延长这种短时记忆,使得 RNN 可以有效利用较大范围内的训练数据,从而提升性能。这时,一种基于 RNN 改进的新型网络模型——LSTM 该登场了。同时在上篇博客的最后面谈到了 RNN 的梯度消失问题,LSTM 模型可以有效地解决这个问题。

2 LSTM

  1997 年,瑞士人工智能科学家 Jürgen Schmidhuber 提出了 长短时记忆网络(Long Short-Term Memory,简称 LSTM)。LSTM 相对于基础的 RNN 网络来说,记忆能力更强,更擅长处理较长的序列信号数据,LSTM 提出后,被广泛应用在序列预测、自然语言处理等任务中,几乎取代了基础的 RNN 模型。
  首先回顾一下基础的 RNN 网络结构:
在这里插入图片描述

上一个时间戳的状态向量 $\boldsymbol{h_{t-1}}$ 与当前时间戳的输入 $\boldsymbol{x_t}$ 经过线性变换后,通过激活函数 $\boldsymbol{tanh}$ 后得到新的状态向量 $\boldsymbol{h_{t}}$。相对于基础的 RNN,网络只有一个状态向量 $\boldsymbol{h_{t}}$,LSTM 新增了一个状态向量 $\boldsymbol{C_{t}}$,同时引入了 门控(Gate)机制,通过门控单元来控制信息的遗忘和刷新:在这里插入图片描述

阅读全文 »