计算神经网络的参数量
对于全连接层来说,其单层的参数量为 (输入维度 + 1) * 该层神经元个数
。这是因为全连接层的每个神经元都需要一个 权重向量
和一个 偏置值
来计算其输出,权重向量
的长度就是 输入维度
,偏置值
是一个标量。
若当前 network
有 hidden_layers
层 hidden layer
,其中每层 hidden_layer
有 hidden_dim
维,则有:
T o t a l _ p a r a m s = ( i n p u t _ d i m + 1 ) ∗ h i d d e n _ d i m + ( h i d d e n _ d i m + 1 ) ∗ h i d d e n _ d i m ∗ ( h i d d e n _ l a y e r s − 1 ) + ( h i d d e n _ d i m + 1 ) ∗ o u t p u t _ d i m Total\_params = (input\_dim + 1) * hidden\_dim + (hidden\_dim + 1) * hidden\_dim * (hidden\_layers - 1) + (hidden\_dim + 1) * output\_dim Total_params=(input_dim+1)∗hidden_dim+(hidden_dim+1)∗hidden_dim∗(hidden_layers−1)+(hidden_dim+1)∗output_dim
对于一个神经网络来说,其总参数量就是所有全连接层的参数量之和。例如,如果我们有一个神经网络,它有一个输入层(输入维度为 4),一个隐藏层(隐藏层神经元个数为 5),和一个输出层(输出维度为 3),那么它的总参数量就是:
输入层到隐藏层的全连接层:
(
4
+
1
)
∗
5
=
25
(4 + 1) * 5 = 25
(4+1)∗5=25
隐藏层到输出层的全连接层:
(
5
+
1
)
∗
3
=
18
(5 + 1) * 3 = 18
(5+1)∗3=18
总参数量:
25
+
18
=
43
25 + 18 = 43
25+18=43
创建多隐藏层的网络
那么该如何创建多隐藏层的网络,顺便打印参数量呢?
这里举个例子说明:
import torch.nn as nn
input_dim = 8
hidden_dim = 16
hidden_layers = 2
output_dim = 8
# 为了简洁,舍去了 Relu()
network = nn.Sequential(
nn.Linear(input_dim, hidden_dim),
# 在函数的调用中,一个 * 表示将一个序列展开为单独的位置参数,这一行代码是列表推导,最终的表现是重复生成多个 hidden layer
*[nn.Linear(hidden_dim, hidden_dim) for _ in range(hidden_layers-1)],
nn.Linear(hidden_dim, output_dim)
)
# 打印总参数量
total_params = (
(input_dim+1) * hidden_dim +
(hidden_dim + 1) * hidden_dim * (hidden_layers - 1) +
(hidden_dim + 1) * output_dim
)
print(f'Total params: {total_params}')
>> Total params: 552
当然,实际上你可以直接使用 pytorch 中的函数进行打印
total_params = sum(param.numel() for param in network.parameters())
print(f'Total params: {total_params}')
>> Total params: 552
进一步的,如果你想查看各层分别的参数量,你可以使用以下代码
for name, param in network.named_parameters():
print(name, param.numel())
0.weight 128
0.bias 16
1.weight 256
1.bias 16
2.weight 128
2.bias 8
其中 weight
对应的是权重,bias
是偏差。
构建总参数量接近的神经网络
这个视频片段能够让你更好的了解 Deep Network 和 Shallow network 的差异:Why Deep Learning?
已知神经网络的总参数量由下式给出:
T
o
t
a
l
_
p
a
r
a
m
s
=
(
i
n
p
u
t
_
d
i
m
+
1
)
∗
h
i
d
d
e
n
_
d
i
m
+
(
h
i
d
d
e
n
_
d
i
m
+
1
)
∗
h
i
d
d
e
n
_
d
i
m
∗
(
h
i
d
d
e
n
_
l
a
y
e
r
s
−
1
)
+
(
h
i
d
d
e
n
_
d
i
m
+
1
)
∗
o
u
t
p
u
t
_
d
i
m
Total\_params = (input\_dim + 1) * hidden\_dim + (hidden\_dim + 1) * hidden\_dim * (hidden\_layers - 1) + (hidden\_dim + 1) * output\_dim
Total_params=(input_dim+1)∗hidden_dim+(hidden_dim+1)∗hidden_dim∗(hidden_layers−1)+(hidden_dim+1)∗output_dim
为了符号简便,做以下简写:
- i = i n p u t _ d i m i = input\_dim i=input_dim
- o = o u t p u t _ d i m o = output\_dim o=output_dim
- l = h i d d e n _ l a y e r s l = hidden\_layers l=hidden_layers
- d = h i d d e n _ d i m d = hidden\_dim d=hidden_dim
有:
T
o
t
a
l
_
p
a
r
a
m
s
=
(
i
+
1
)
∗
d
+
(
d
+
1
)
∗
d
∗
(
l
−
1
)
+
(
d
+
1
)
∗
o
Total\_params = (i + 1) * d + (d + 1) * d * (l - 1) + (d + 1) * o
Total_params=(i+1)∗d+(d+1)∗d∗(l−1)+(d+1)∗o
进一步的,将其化成一元二次方程的形式,其中
d
d
d 为自变量:
T
o
t
a
l
_
p
a
r
a
m
s
=
(
l
−
1
)
∗
d
2
+
(
i
+
o
+
l
)
∗
d
+
o
Total\_params = (l - 1) * d^2 + (i + o + l) * d + o
Total_params=(l−1)∗d2+(i+o+l)∗d+o
假设 i , o , l , d i, o, l, d i,o,l,d 均为已知量,现在需要求:在输入输出维度不变的情况下,当 d e s t _ h i d d e n _ l a y e r s dest\_hidden\_layers dest_hidden_layers 给定时,隐藏层的维数等于多少才能让两个网络的总参数量接近?( d e s t dest dest 代指我们要计算的目标网络)
同样的,做以下简写:
- l d = d e s t _ h i d d e n _ l a y e r s l_d = dest\_hidden\_layers ld=dest_hidden_layers
- d d = d e s t _ h i d d e n _ d i m d_d = dest\_hidden\_dim dd=dest_hidden_dim
则有:
d
e
s
t
_
T
o
t
a
l
_
p
a
r
a
m
s
=
(
l
d
−
1
)
∗
d
d
2
+
(
i
+
o
+
l
d
)
∗
d
d
+
o
dest\_Total\_params = (l_d - 1) * d_d^2 + (i + o + l_d) * d_d + o
dest_Total_params=(ld−1)∗dd2+(i+o+ld)∗dd+o
令
d
e
s
t
_
T
o
t
a
l
_
p
a
r
a
m
s
=
T
o
t
a
l
_
p
a
r
a
m
s
dest\_Total\_params = Total\_params
dest_Total_params=Total_params:
(
l
d
−
1
)
∗
d
d
2
+
(
i
+
o
+
l
d
)
∗
d
d
+
o
=
(
l
−
1
)
∗
d
2
+
(
i
+
o
+
l
)
∗
d
+
o
⇓
(
l
d
−
1
)
∗
d
d
2
+
(
i
+
o
+
l
d
)
∗
d
d
−
(
l
−
1
)
∗
d
2
−
(
i
+
o
+
l
)
∗
d
=
0
(l_d - 1) * d_d^2 + (i + o + l_d) * d_d + o = (l - 1) * d^2 + (i + o + l) * d + o\\\Downarrow\\ (l_d - 1) * d_d^2 + (i + o + l_d) * d_d - (l - 1) * d^2 - (i + o + l) * d = 0
(ld−1)∗dd2+(i+o+ld)∗dd+o=(l−1)∗d2+(i+o+l)∗d+o⇓(ld−1)∗dd2+(i+o+ld)∗dd−(l−1)∗d2−(i+o+l)∗d=0
这实际上是一个一元二次方程,其中
d
d
d_d
dd 为自变量,其余均已知,可当作常数看待。令
a
=
l
d
−
1
,
b
=
i
+
o
+
l
d
,
c
=
−
(
l
−
1
)
∗
d
2
−
(
i
+
o
+
l
)
∗
d
a = l_d - 1,\\ b = i + o + l_d,\\ c = - (l - 1) * d^2 - (i + o + l) * d
a=ld−1,b=i+o+ld,c=−(l−1)∗d2−(i+o+l)∗d
则上式可化成
a
∗
d
d
2
+
b
∗
d
d
+
c
=
0
a * d_d^2 + b *d_d + c = 0
a∗dd2+b∗dd+c=0
由一元二次方程的求根公式
y
=
−
b
±
b
2
−
4
a
c
2
a
y = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}
y=2a−b±b2−4ac
有
d
d
=
−
(
i
+
o
+
l
d
)
±
(
i
+
o
+
l
d
)
2
−
4
(
l
d
−
l
)
(
−
(
(
l
−
1
)
∗
d
2
−
(
i
+
o
+
l
)
∗
d
)
)
2
(
l
d
−
l
)
d_d = \frac{-(i+o+l_d) \pm \sqrt{(i+o+l_d)^2 - 4(l_d-l)(-((l - 1) * d^2 - (i + o + l) * d))}}{2(l_d-l)}
dd=2(ld−l)−(i+o+ld)±(i+o+ld)2−4(ld−l)(−((l−1)∗d2−(i+o+l)∗d))
你可以通过调用下方代码中的 get_dest_dim()
获取目标网络隐藏层应该设置的维度。
def get_dest_dim(input_dim, output_dim, hidden_layers, dest_hidden_layers, hidden_dim):
'''获取目标网络隐藏层的维度(总参数量接近于原网络)'''
# 计算一元二次方程的系数 a,b,c
a = dest_hidden_layers - 1 # a = l_d - 1
b = input_dim + output_dim + dest_hidden_layers # b = i + o + l_d
c = - (hidden_layers - 1) * (hidden_dim ** 2) - (input_dim + output_dim + hidden_layers) * hidden_dim # c = - (l - 1) * (d ** 2) - (i + o + l) * d
# 计算分子中的平方根部分,即 b^2-4ac
sqrt_part = (b ** 2) - 4 * a * c
# 计算两个解,一个是加号,一个是减号,即(-b±√(b^2-4ac))/(2a)
d_d_plus = (-b + sqrt_part**(0.5)) / (2 * a)
d_d_minus = (-b - sqrt_part**(0.5)) / (2 * a)
# 返回两个解的元组
return (d_d_plus, d_d_minus)
# 设置你想要的目标网络隐藏层数量
dest_hidden_layers = 2
# 获取对应的维数
dest_hidden_dim, _ = get_dest_dim(input_dim, output_dim, hidden_layers, dest_hidden_layers, hidden_dim)
print(f"若将隐藏层网络层数改为: {dest_hidden_layers},则维数应当改为: {round(dest_hidden_dim)}",)