简单的 ANN 模型以 tanh(x) 作为激活函数收敛,但不以 leaky ReLu 收敛
Simple ANN model converges with tanh(x) as the activation function, but it doesn't with leaky ReLu
我正在训练一个简单的 ANN 模型 (MLP),将其用作激活函数 tanh(x)
,经过一些交互后,它会收敛,误差等于 10^-5,这是我的完整代码:
import numpy as np
import pandas as pd
# Base de dados a ser treinada
x = pd.DataFrame(
[[1],
[2],
[3]],
columns=['valores x'])
d = pd.DataFrame(
[[5],
[4],
[3]],
columns=['valores desejados'])
# Convertendo o dataframe em array e normalizando os valores desejados para ficar entre 0 e +1.
x = x.to_numpy()
d = d/(1.05*d.max())
d = d.to_numpy()
# Derivada de tanh(x) = sech²(x) = 1 - (tanh(x))²
def df(x):
y = 1 - np.power(np.tanh(x), 2)
return y
#def rede_mlp(n, x, d, net, k, precisao):
# Construindo a rede de duas camadas
# net = número de neurônios na primeira camada
# n = taxa de aprendizagem
# precisao = precisão do erro quadrático médio
net=3
n = 0.1
precisao=0.00001
w1 = np.random.rand(net,len(x[0]))
w2 = np.random.rand(1,net)
E_M=1
epocas=0
while E_M>precisao:
E_M=0
errofinal=0
for i in range(0,len(x)):
# FOWARD
i1 = np.matmul(w1, x[i].reshape(len(x[i]),1))
y1 = np.tanh(i1)
i2 = np.matmul(w2, y1)
y2 = np.tanh(i2)
# erro com o valor desejado
erro = d[i].reshape(len(d[i]),1) - y2
# BACKPROPAGATION
delta_2 = erro*df(i2)
w2 = w2 + n*(np.matmul(delta_2, y1.reshape(1, net)))
delta_1 = (np.matmul(w2.T, delta_2))*df(i1)
w1 = w1 + n*(np.matmul(delta_1, x[i].reshape(1, len(x[i]))))
errofinal = errofinal + 0.5*erro**2
E_M = errofinal/len(x)
epocas+=1
print(E_M)
之后我尝试将激活函数改成leaky ReLu,但是没有收敛。学习率n
改了好几次了,还是误差很大。它大约是 7.95,这对我的数据来说很大。这是我的尝试:
import numpy as np
import pandas as pd
# Base de dados a ser treinada
x = pd.DataFrame(
[[1],
[2],
[3]],
columns=['valores x'])
d = pd.DataFrame(
[[5],
[4],
[3]],
columns=['valores desejados'])
# Convertendo o dataframe em array e normalizando os valores desejados para ficar entre 0 e +1.
x = x.to_numpy()
d = d.to_numpy()
def df(x):
x = np.array(x)
x[x<=0] = 0.01
x[x>0] = 1
return x
def f(x):
return(np.where(x > 0, x, x * 0.01))
#def rede_mlp(n, x, d, net, k, precisao):
# Construindo a rede de duas camadas
# net = número de neurônios na primeira camada
# n = taxa de aprendizagem
# precisao = precisão do erro quadrático médio
net=3
n = 1e-4
precisao=0.0001
w1 = np.random.rand(net,len(x[0]))
w2 = np.random.rand(1,net)
E_M=20
epocas=0
while E_M>precisao:
E_M=0
errofinal=0
for i in range(0,len(x)):
# FOWARD
i1 = np.matmul(w1, x[i].reshape(len(x[i]),1))
y1 = f(i1)
i2 = np.matmul(w2, y1)
y2 = f(i2)
# erro com o valor desejado
erro = d[i].reshape(len(d[i]),1) - y2
# BACKPROPAGATION
delta_2 = erro*df(i2)
w2 = w2 + n*(np.matmul(delta_2, y1.reshape(1, net)))
delta_1 = (np.matmul(w2.T, delta_2))*df(i1)
w1 = w1 + n*(np.matmul(delta_1, x[i].reshape(1, len(x[i]))))
errofinal = errofinal + 0.5*erro**2
#E_M = errofinal/len(x)
E_M = errofinal
epocas+=1
print(E_M)
编辑:
经过一些修改,这是我的ReLu代码(但错误仍然很高~7.77):
import numpy as np
import pandas as pd
# Base de dados a ser treinada
x = pd.DataFrame(
[[1],
[2],
[3]],
columns=['valores x'])
d = pd.DataFrame(
[[5],
[4],
[3]],
columns=['valores desejados'])
# Convertendo o dataframe em array e normalizando os valores desejados para ficar entre 0 e +1.
x = x.to_numpy()
d = d.to_numpy()
def df(x):
return(np.where(x <= 0, 0.01, 1))
def f(x):
return(np.where(x > 0, x, x * 0.01))
#def rede_mlp(n, x, d, net, k, precisao):
# Construindo a rede de duas camadas
# net = número de neurônios na primeira camada
# n = taxa de aprendizagem
# precisao = precisão do erro quadrático médio
net=3
n = 1e-3
precisao=0.1
w1 = np.random.rand(net,len(x[0]))
w2 = np.random.rand(1,net)
E_M=20
epocas=0
while E_M>precisao:
E_M=0
errofinal=0
for i in range(0,len(x)):
# FOWARD
i1 = np.matmul(w1, x[i].reshape(len(x[i]),1))
y1 = f(i1)
i2 = np.matmul(w2, y1)
y2 = f(i2)
# erro com o valor desejado
erro = d[i].reshape(len(d[i]),1) - y2
# BACKPROPAGATION
delta_2 = erro*df(i2)
delta_1 = (np.matmul(w2.T, delta_2))*df(i1)
w2 = w2 + n*(np.matmul(delta_2, y1.reshape(1, net)))
w1 = w1 + n*(np.matmul(delta_1, x[i].reshape(1, len(x[i]))))
errofinal = errofinal + 0.5*erro**2
#E_M = errofinal/len(x)
E_M = errofinal
epocas+=1
print(E_M)
您需要为网络添加偏差。
您尝试建模的方程是 y = 6 - x
,如果您可以使用 6
作为截距(偏差),这是微不足道的,但我认为如果不这样做实际上是不可能的。
添加偏差后,许多函数更容易表示,这就是为什么包含一个偏差是标准做法。这个Q&A on the role of bias in NNs解释的比较透彻
我修改了你的代码以添加偏差,并遵循更典型的命名约定,它对我来说收敛了。
net = 3
n = 1e-3
precisao = 0.0001
w1 = np.random.rand(net, len(x[0]))
bias1 = np.random.rand()
w2 = np.random.rand(1, net)
bias2 = np.random.rand()
E_M = 20
epocas = 0
while E_M > precisao:
E_M = 0
errofinal = 0
for i in range(0,len(x)):
a0 = x[i].reshape(-1, 1)
targ = d[i].reshape(-1, 1)
z1 = np.matmul(w1, a0) + bias1
a1 = f(z1)
z2 = np.matmul(w2, a1) + bias2
a2 = f(z2)
erro = a2 - targ
# BACKPROPAGATION
delta_2 = erro * df(z2)
delta_1 = np.matmul(w2.T, delta_2) * df(z1)
bias2 -= n * delta_2
bias1 -= n * delta_1
w2 -= n * np.matmul(delta_2, a1.T)
w1 -= n * np.matmul(delta_1, a0.T)
errofinal = errofinal + 0.5*erro**2
#E_M = errofinal/len(x)
E_M = errofinal
epocas += 1
if epocas % 1000 == 0:
print(epocas, E_M)
我提高了学习率,所以收敛得更快。
1000 [[0.14401507]]
2000 [[0.00028834]]
较早的错误修复建议
您将导数设置为始终等于 1。
def df(x):
x = np.array(x)
x[x<=0] = 0.01
x[x>0] = 1
return x
行x[x<=0] = 0.01
将所有非正值设置为1/100
,一个正值。之后每个值都是正值,因为已经为正值的值不受影响,而负值或零值只是变为正值。所以下一行 x[x>0] = 1
将所有导数设置为 1
.
试试这个:
def df(x):
return np.where(np.array(x) <= 0, 0.01, 1)
我正在训练一个简单的 ANN 模型 (MLP),将其用作激活函数 tanh(x)
,经过一些交互后,它会收敛,误差等于 10^-5,这是我的完整代码:
import numpy as np
import pandas as pd
# Base de dados a ser treinada
x = pd.DataFrame(
[[1],
[2],
[3]],
columns=['valores x'])
d = pd.DataFrame(
[[5],
[4],
[3]],
columns=['valores desejados'])
# Convertendo o dataframe em array e normalizando os valores desejados para ficar entre 0 e +1.
x = x.to_numpy()
d = d/(1.05*d.max())
d = d.to_numpy()
# Derivada de tanh(x) = sech²(x) = 1 - (tanh(x))²
def df(x):
y = 1 - np.power(np.tanh(x), 2)
return y
#def rede_mlp(n, x, d, net, k, precisao):
# Construindo a rede de duas camadas
# net = número de neurônios na primeira camada
# n = taxa de aprendizagem
# precisao = precisão do erro quadrático médio
net=3
n = 0.1
precisao=0.00001
w1 = np.random.rand(net,len(x[0]))
w2 = np.random.rand(1,net)
E_M=1
epocas=0
while E_M>precisao:
E_M=0
errofinal=0
for i in range(0,len(x)):
# FOWARD
i1 = np.matmul(w1, x[i].reshape(len(x[i]),1))
y1 = np.tanh(i1)
i2 = np.matmul(w2, y1)
y2 = np.tanh(i2)
# erro com o valor desejado
erro = d[i].reshape(len(d[i]),1) - y2
# BACKPROPAGATION
delta_2 = erro*df(i2)
w2 = w2 + n*(np.matmul(delta_2, y1.reshape(1, net)))
delta_1 = (np.matmul(w2.T, delta_2))*df(i1)
w1 = w1 + n*(np.matmul(delta_1, x[i].reshape(1, len(x[i]))))
errofinal = errofinal + 0.5*erro**2
E_M = errofinal/len(x)
epocas+=1
print(E_M)
之后我尝试将激活函数改成leaky ReLu,但是没有收敛。学习率n
改了好几次了,还是误差很大。它大约是 7.95,这对我的数据来说很大。这是我的尝试:
import numpy as np
import pandas as pd
# Base de dados a ser treinada
x = pd.DataFrame(
[[1],
[2],
[3]],
columns=['valores x'])
d = pd.DataFrame(
[[5],
[4],
[3]],
columns=['valores desejados'])
# Convertendo o dataframe em array e normalizando os valores desejados para ficar entre 0 e +1.
x = x.to_numpy()
d = d.to_numpy()
def df(x):
x = np.array(x)
x[x<=0] = 0.01
x[x>0] = 1
return x
def f(x):
return(np.where(x > 0, x, x * 0.01))
#def rede_mlp(n, x, d, net, k, precisao):
# Construindo a rede de duas camadas
# net = número de neurônios na primeira camada
# n = taxa de aprendizagem
# precisao = precisão do erro quadrático médio
net=3
n = 1e-4
precisao=0.0001
w1 = np.random.rand(net,len(x[0]))
w2 = np.random.rand(1,net)
E_M=20
epocas=0
while E_M>precisao:
E_M=0
errofinal=0
for i in range(0,len(x)):
# FOWARD
i1 = np.matmul(w1, x[i].reshape(len(x[i]),1))
y1 = f(i1)
i2 = np.matmul(w2, y1)
y2 = f(i2)
# erro com o valor desejado
erro = d[i].reshape(len(d[i]),1) - y2
# BACKPROPAGATION
delta_2 = erro*df(i2)
w2 = w2 + n*(np.matmul(delta_2, y1.reshape(1, net)))
delta_1 = (np.matmul(w2.T, delta_2))*df(i1)
w1 = w1 + n*(np.matmul(delta_1, x[i].reshape(1, len(x[i]))))
errofinal = errofinal + 0.5*erro**2
#E_M = errofinal/len(x)
E_M = errofinal
epocas+=1
print(E_M)
编辑:
经过一些修改,这是我的ReLu代码(但错误仍然很高~7.77):
import numpy as np
import pandas as pd
# Base de dados a ser treinada
x = pd.DataFrame(
[[1],
[2],
[3]],
columns=['valores x'])
d = pd.DataFrame(
[[5],
[4],
[3]],
columns=['valores desejados'])
# Convertendo o dataframe em array e normalizando os valores desejados para ficar entre 0 e +1.
x = x.to_numpy()
d = d.to_numpy()
def df(x):
return(np.where(x <= 0, 0.01, 1))
def f(x):
return(np.where(x > 0, x, x * 0.01))
#def rede_mlp(n, x, d, net, k, precisao):
# Construindo a rede de duas camadas
# net = número de neurônios na primeira camada
# n = taxa de aprendizagem
# precisao = precisão do erro quadrático médio
net=3
n = 1e-3
precisao=0.1
w1 = np.random.rand(net,len(x[0]))
w2 = np.random.rand(1,net)
E_M=20
epocas=0
while E_M>precisao:
E_M=0
errofinal=0
for i in range(0,len(x)):
# FOWARD
i1 = np.matmul(w1, x[i].reshape(len(x[i]),1))
y1 = f(i1)
i2 = np.matmul(w2, y1)
y2 = f(i2)
# erro com o valor desejado
erro = d[i].reshape(len(d[i]),1) - y2
# BACKPROPAGATION
delta_2 = erro*df(i2)
delta_1 = (np.matmul(w2.T, delta_2))*df(i1)
w2 = w2 + n*(np.matmul(delta_2, y1.reshape(1, net)))
w1 = w1 + n*(np.matmul(delta_1, x[i].reshape(1, len(x[i]))))
errofinal = errofinal + 0.5*erro**2
#E_M = errofinal/len(x)
E_M = errofinal
epocas+=1
print(E_M)
您需要为网络添加偏差。
您尝试建模的方程是 y = 6 - x
,如果您可以使用 6
作为截距(偏差),这是微不足道的,但我认为如果不这样做实际上是不可能的。
添加偏差后,许多函数更容易表示,这就是为什么包含一个偏差是标准做法。这个Q&A on the role of bias in NNs解释的比较透彻
我修改了你的代码以添加偏差,并遵循更典型的命名约定,它对我来说收敛了。
net = 3
n = 1e-3
precisao = 0.0001
w1 = np.random.rand(net, len(x[0]))
bias1 = np.random.rand()
w2 = np.random.rand(1, net)
bias2 = np.random.rand()
E_M = 20
epocas = 0
while E_M > precisao:
E_M = 0
errofinal = 0
for i in range(0,len(x)):
a0 = x[i].reshape(-1, 1)
targ = d[i].reshape(-1, 1)
z1 = np.matmul(w1, a0) + bias1
a1 = f(z1)
z2 = np.matmul(w2, a1) + bias2
a2 = f(z2)
erro = a2 - targ
# BACKPROPAGATION
delta_2 = erro * df(z2)
delta_1 = np.matmul(w2.T, delta_2) * df(z1)
bias2 -= n * delta_2
bias1 -= n * delta_1
w2 -= n * np.matmul(delta_2, a1.T)
w1 -= n * np.matmul(delta_1, a0.T)
errofinal = errofinal + 0.5*erro**2
#E_M = errofinal/len(x)
E_M = errofinal
epocas += 1
if epocas % 1000 == 0:
print(epocas, E_M)
我提高了学习率,所以收敛得更快。
1000 [[0.14401507]]
2000 [[0.00028834]]
较早的错误修复建议
您将导数设置为始终等于 1。
def df(x):
x = np.array(x)
x[x<=0] = 0.01
x[x>0] = 1
return x
行x[x<=0] = 0.01
将所有非正值设置为1/100
,一个正值。之后每个值都是正值,因为已经为正值的值不受影响,而负值或零值只是变为正值。所以下一行 x[x>0] = 1
将所有导数设置为 1
.
试试这个:
def df(x):
return np.where(np.array(x) <= 0, 0.01, 1)