神经网络实现中的溢出错误
我正在尝试自己实现神经网络的反向传播算法。到目前为止,我写的训练代码是这样的:
def train(x,labels,n):
lam = 0.5
w1 = np.random.uniform(0,0.01,(20,120)) #weights
w2 = np.random.uniform(0,0.01,20)
for i in xrange(n):
w1 = w1/np.linalg.norm(w1)
w2 = w2/np.linalg.norm(w2)
for j in xrange(x.shape[0]):
y1 = np.zeros((600)) #output
d1 = np.zeros((20))
p = np.mat(x[j,:])
a = np.dot(w1,p.T) #activation
z = 1/(1 + np.exp((-1)*a))
y1[j] = np.dot(w2,z)
for k in xrange(20):
d1[k] = z[k]*(1 - z[k])*(y1[j] - labels[j])*np.sum(w2) #delta update rule
w1[k,:] = w1[k,:] - lam*d1[k]*x[j,:] #weight update
w2[k] = w2[k] - lam*(y1[j]-labels[j])*z[k]
E = 1/2*pow((y1[j]-labels[j]),2) #mean squared error
print E
return 0
输入单元数量 - 120,
隐藏单元数量 - 20,
输出单元数量 - 1,
训练样本数量 - 600
x 是一个 600*120 的训练集,数据经过处理,使得均值为零,方差为1,最大值为3.28,最小值为-4.07。前200个样本属于类别1,接下来的200个样本属于类别2,最后200个样本属于类别3。标签是分配给每个样本的类别标签,n 是收敛所需的迭代次数。每个样本有120个特征。
我已经将权重初始化在0到0.01之间,并且输入数据经过缩放,使得方差为1,均值为零,但代码仍然抛出了溢出警告,导致'a'(即激活值)变成了NaN。我不明白问题出在哪里。
每个样本有120个元素。x的一个样本行:
[ 0.80145231 1.29567936 0.91474224 1.37541992 1.16183938 1.43947296
1.32440357 1.43449479 1.32742415 1.40533852 1.28817561 1.37977183
1.2290933 1.34720161 1.15877069 1.29699635 1.05428735 1.21923531
0.92312685 1.1061345 0.66647463 1.00044203 0.34270708 1.05589558
0.28770958 1.21639524 0.31522575 1.32862243 0.42135899 1.3997094
0.5780146 1.44444501 0.75872771 1.47334256 0.95372771 1.48878048
1.13968139 1.49119962 1.33121905 1.47326017 1.47548571 1.4450047
1.58272343 1.39327328 1.62929132 1.31126604 1.62705274 1.21790335
1.59951034 1.12756958 1.56253815 1.04096709 1.52651382 0.95942134
1.48875633 0.87746762 1.45248623 0.78782313 1.40446404 0.68370011
2 个回答
0
这段代码是用来重复pytorch中的sigmoid函数。
import numpy as np
def sigmoid(x : np.ndarray) -> np.ndarray:
positives = x >= 0
negatives = ~positives
exp_x_neg = np.exp(x[negatives])
y = x.copy()
y[positives] = 1 / (1 + np.exp(-x[positives]))
y[negatives] = exp_x_neg / (1 + exp_x_neg)
return y
用pytorch进行测试
import torch
values = np.random.randint(-500000, 500000,
size=(1,3,512,512)).astype(np.float32) / 100.0
x_np = sigmoid(values)
x_t = torch.sigmoid(torch.tensor(values))
err_per_element = np.abs((x_np - x_t.cpu().numpy())).sum() / np.prod(values.shape)
print(err_per_element) # 6.039030965114082e-12
29
溢出问题
在使用NumPy时,逻辑 sigmoid 函数在信号强度增加时容易出现溢出问题。你可以尝试添加以下代码:
np.clip( signal, -500, 500 )
这段代码会限制NumPy矩阵中的值在一个特定的范围内。这样可以防止sigmoid函数中的精度溢出。我发现+-500是一个比较合适的信号饱和水平。
>>> arr
array([[-900, -600, -300],
[ 0, 300, 600]])
>>> np.clip( arr, -500, 500)
array([[-500, -500, -300],
[ 0, 300, 500]])
实现方法
这是我在项目中使用的代码片段:
def sigmoid_function( signal ):
# Prevent overflow.
signal = np.clip( signal, -500, 500 )
# Calculate activation signal
signal = 1.0/( 1 + np.exp( -signal ))
return signal
#end
为什么Sigmoid函数会溢出?
随着训练的进行,激活函数的精度会提高。sigmoid信号会在接近完美的准确度时,从下方趋近于1,或从上方趋近于0。例如,可能会变成0.99999999999...或者0.00000000000000001...
因为NumPy专注于进行高精度的数值运算,所以它会保持尽可能高的精度,这样就可能导致溢出错误。
注意:你可以通过设置以下代码来忽略这个错误信息:
np.seterr( over='ignore' )