周报(8.5-8.12)
本周工作
犯傻分享
标准化值域和激活函数值域不符
我之前在复现InversionNet网络代码的过程中,因为我的设备内存不足,所以重写了Dataset类,实现分段加载数据来缓解内存压力。在写数据处理部分的代码时,为了模型更好的拟合,我是用了我更熟悉的标准化对数据进行了处理。标准化的公式为:
Z
=
X
−
μ
σ
Z = \frac{X-μ}{σ}
Z=σX−μ
其中
μ
μ
μ是原始数据的均值,
σ
σ
σ是原始数据的标准差。经过公式处理之后,
Z
Z
Z是一个均值为0,标准差为1的量,那么速度模型的值域就较为平均落到了横轴的附近,能够满足模型训练和预测中需要。
但在实际经过训练InversionNet之后,我发现我的模型收敛的较早,性能也离师兄师姐训练出来的模型还有一段差距,找了好一会原因,最后发现是InversionNet模型最后的Tanh激活函数的问题。
因为Tanh是一个值域为[-1, 1]的函数,把Tanh放到最后的模型只能拟合[-1, 1]的结果。但是数据经标准差后只能保证约68%的大部分数据落到[-1, 1]的区间内,还有部分数据会超过这个范围,这些超出[-1, 1]范围的数据是无法被网络拟合的,所以训练到最后模型里最佳结果会有一段无法缩小的距离。
师兄的DD-Net里的示例代码是对数据进行了归一化的处理,公式为:
Z
=
X
−
X
m
i
n
X
m
a
x
−
X
m
i
n
Z = \frac{X-X_{min}}{X_{max}-X_{min}}
Z=Xmax−XminX−Xmin
归一化操作的值域就一定能落在[-1, 1]之间,也能被Tanh拟合。但是标准化仍然有着一定优势,如数据
[
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
,
9
,
20
]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 20]
[1,2,3,4,5,6,7,8,9,20]
平均值为6.5。
归一化后数据为
[
0
,
0.0526
,
0.1053
,
0.1579
,
0.2105
,
0.2632
,
0.3158
,
0.3684
,
0.4211
,
1
]
[0, 0.0526, 0.1053, 0.1579, 0.2105,0.2632, 0.3158, 0.3684, 0.4211, 1]
[0,0.0526,0.1053,0.1579,0.2105,0.2632,0.3158,0.3684,0.4211,1]
归一化后平均值为0.2895,有9个数据落入了以0.5为分界线的前半个区间,前9个数据的标准差为0.1359,最后数据离平均点的距离为0.7105。
标准化后数据为
[
−
1.0735
,
−
0.8783
,
−
0.6831
,
−
0.4880
,
−
0.2928
,
−
0.0976
,
0.0976
,
0.2928
,
0.4880
,
2.6349
]
[-1.0735, -0.8783, -0.6831, -0.4880, -0.2928, -0.0976, 0.0976, 0.2928, 0.4880, 2.6349]
[−1.0735,−0.8783,−0.6831,−0.4880,−0.2928,−0.0976,0.0976,0.2928,0.4880,2.6349]
标准化后有6个数据落入了以0为分界线的前半个区间,前9个数据的标准差为0.5040,最后数据离平均点的距离为2.6349。
上述数据可以这样理解:
-
在20这个离群点的作用下,前9个数据在归一化中被压缩的很近,丧失了区分度。
如果使用标准差,前9个数据虽然也被压缩了,但是程度远没有归一化那么大(0.1359与0.5040)。
结论是数据更能保存自己的特征。
-
看最后一个元素,受限于[-1, 1]的值域空间,归一化中离群点离平均点的距离为0.7105,而最小元素离平均点的距离为0.2895,约等于原始数据到平均点的距离的比例:[5.5: 13.5]。
但如果使用了标准差,最大元素和最小元素到平均值点的距离为[1.0735: 2.6349],这个比例实际上大于了原始的比例。
结论是标准差更能体现不同值到平均点的距离关系。
综上所述,使用标准差处理的数据更具区分度,距离越远的元素标准差后距离会更远,这两点都有利于网络的训练,标准化也有缩放数据的功能。但需要注意的是标准差的值域不止[-1, 1],不能用tanh。
显存爆炸
在训练过程中,从训练InversionNet到FCNVMB的过程中,保持原有的batch_size后训练时报出out of memery的问题。为了节省显存,我对pytorch的显存占用机制进行了探索。
探索显存占用
工具:Pytorch-Memory-Utils:https://github.com/Oldpan/Pytorch-Memory-Utils/
测试:训练使用FlatVel_A、batch_size为10的FCNVMB修改版网络
测试结果:
-
0-110.6的增长是加载模型的内存占用。
-
110.6-124.0的增长是加载地层数据。
-
124.0-124.2的增长是加载速度模型数据。
-
124.2-1905.2的增长是训练过程中产生的梯度数据。
-
1979.2-1905.2的差值是残差连接和其他临时数据。
-
1905.2-124.3的差值是loss.backward()后被删除的梯度数据。
-
124.3-456.1是optimizer.step()后产生的数据。
-
456.1-456.1是重新读取新的数据时的数据。
-
456.1-345.5是optimizer.zero_grad()后减少的数据。
同时之后每次读取数据后,内存占用也为456.1。
显存占用的结论
- 由上文1-3步得知,模型及数据集共计占用124.2Mb,只占显存最高占用中很少的一部分。
- 由上文第4步得知,占用显存最大的一部分为模型前向计算时pytorch自动计算的用于反向传播的梯度数据。
- 由上文第5步得知,跳跃连接/残差连接保留的特征图像会占用极少一部分显存,基本不需要担心跳跃连接本身产生的显存问题,但跳跃连接仍可能产生更多的梯度?这里需要进一步验证。
- 在loss.backward()反向传播后梯度显存被释放。
- 7-9步,优化器会占用一部分显存,暂时不了解这部分显存用于何种用途。
减少显存的方法
-
由结论3可得,使用del及时删除不再使用的变量,如残差连接中的梯度等。
-
由结论2可得,要想降低前向计算时产生的梯度数据,要么调整模型本身,要么减小batch_size。但很多时候我们无法减少模型复杂度,只能调低batch_size。
-
同样由结论2得知,pytorch可以使用
with torch.no_grad()
来避免梯度的计算。停止计算梯度,可以用于验证集loss的计算,加快运行速度,减少显存占用,但不能用于训练过程,包括pad,剪裁图片仍然改变了输入输出,过程中会产生梯度变化,因此这个过程中也不能使用直接赋值的方式进行剪裁,这种方式仍然会丢失梯度。torch.no_grad()与model.eval()
torch.no_grad(): 停止梯度计算
model.eval():使模型停用dropout、bn等操作
使用更好的函数
在进行数据处理时,部分操作的速度过慢,部分操作出现报错,经查,是由于一下问题导致的:
- 在读取OpenFWI时使用的是numpy数据结构,训练时使用的是Tensor数据结构。
Tensor(list(ndarryObject1, ndarryObject2))
非常慢,使用Tensor(list(float1, float2))
会报错,改用Tensor.from_numpy(numpy(list(ndarryObject1, ndarryObject2)))
可以大大加快转换速度。 Tensor(ndarryObject)
会造成数据复制,造成双倍内存占用,减慢运行效率。Tensor.from_numpy(ndarryObject)
是就地操作,Tensor会共用numpy数据结构内的原始数据。
正演学习
学习了地震正演技术,但仍需加强学习
上周已得到的用于正演的二维声波方程:
1
v
2
∂
2
U
∂
t
2
=
∂
2
U
∂
x
2
+
∂
2
U
∂
z
2
\frac{1}{v^2}\frac{∂^2U}{∂t^2}=\frac{∂^2U}{∂x^2}+\frac{∂^2U}{∂z^2}
v21∂t2∂2U=∂x2∂2U+∂z2∂2U
我们需要对该过程进行二维差分,二维差分相当于获取周围点的信息,并将连续的公式离散化,获得以下公式
1
v
2
U
k
+
1
−
2
U
k
+
U
k
−
1
Δ
t
2
=
U
i
+
1
,
j
k
−
2
U
i
,
j
k
+
U
i
−
1
,
j
k
Δ
x
2
+
U
i
+
1
,
j
k
−
2
U
i
,
j
k
+
U
i
−
1
,
j
k
Δ
z
2
+
\frac{1}{v^2} \frac{U^{k+1}−2U^k+U^{k−1}}{Δt^2}= \frac{U_{i+1,j}^k−2U_{i,j}^k+U_{i−1,j}^k}{Δx^2}+ \frac{U_{i+1,j}^k−2U_{i,j}^k+U_{i−1,j}^k}{Δz^2}+
v21Δt2Uk+1−2Uk+Uk−1=Δx2Ui+1,jk−2Ui,jk+Ui−1,jk+Δz2Ui+1,jk−2Ui,jk+Ui−1,jk+
其中,k表示时间序列,我们可以在已知k和k-1时间序列的情况下求出k+1的波动情况,进而模拟波的传播。
下周任务
- 选择具体方向,开展研究。
- 继续学习地震正演原理,数学原理。
- 继续学习地震反演原理,深度学习原理。