所有代码以及PPT:https://github.com/nicktming/code/tree/dev/machine_learning/Artificial_neural_network
dev分支
初了解
这是一张典型神经网络的图,如果看不懂没关系,继续往下看.我们先从导数开始了解.
导数
该函数曲线在这一点上的切线斜率
有些函数在每个点的斜率都是一样的比如f(x)=3x
,但是有些函数在每个点的函数可能都不一样比如f(x)=3x^2+4x+5
.
补充一下我个人对于导数的理解,几何含义是
f(x)
在点x
的斜率,我理解为在点x
的导数是在此处对f(x)
的影响有多大.
比如f(x)=10x
那么f'(x) = 10
,意味着f(x)
的变化是x
变化的10
倍, 比如f(1)=10;f(1.01)=10.1
,x
变化了0.01
然而f(x)
变化了10
倍.
复合函数的导数
复合函数对自变量的导数,等于已知函数对中间变量的导数,乘以中间变量对自变量的导数.
偏导
每个变量的导数
梯度
例子1: f(x) = 3x^2 + 4x + 5
代码 :
gradient_test_1.py
给出一个起点(start_x)和步长(step),如何利用梯度下降法寻找到可以使
f(x)
变小.
导数:
dx = f'(x) = 6x + 4; x := x - step * f'(x)
import numpy as np
import matplotlib.pyplot as plt
# init some data
x_data = np.arange(-10, 11).reshape([21, 1])
y_data = np.square(x_data)*3 + x_data * 4 + 5
# for polt picture
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.plot(x_data, y_data, lw=3)
plt.ion()
plt.show()
start_x = 10
step = 0.1
current_x = start_x
current_y = 3 * current_x * current_x + 4 * current_x + 5
print("(loop_count, current_x, current_y)")
for i in range(10):
print(i, current_x, current_y)
derivative_f_x = 6 * current_x + 4
current_x = current_x - step * derivative_f_x
current_y = 3 * current_x * current_x + 4 * current_x + 5
ax.scatter(current_x, current_y)
plt.pause(0.1)
结果:
结果可以看到
(current_x)
从10
一直在逼近f(x)
的中轴线使得f(x)
最小值.可以运行代码(需要安装python,numpy,matplotlib
)进行查看,会有动画的效果,对于理解梯度下降会比较有帮助.
例子2: f(x,y) = 3x^2 + 4y^2 + 5
代码 :
gradient_test_3.py
相对于例子1,例子2是二维, 因此对
x,y
需要求偏导,意味对各个维度的斜线.
给出一个起点(start_x, start_y) 和步长(step),如何利用梯度下降法去寻找到可以使f(x, y)变小?
导数:
dx = 6x dy = 8y
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# init some data
x_data = np.arange(-4, 4, 0.25)
y_data = np.arange(-4, 4, 0.25)
f_data = np.square(x_data)*3 + np.square(y_data) * 4 + 5
X, Y = np.meshgrid(x_data, y_data)
Z = np.sqrt(f_data)
fig = plt.figure()
ax = Axes3D(fig)
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap='rainbow')
plt.ion()
plt.show()
start_x = 10
start_y = 10
step = 0.01
current_x = start_x
current_y = start_y
current_f = 3 * current_x * current_x + 4 * current_y + 5
print("(loop_count, current_x, current_y, current_f)")
for i in range(100):
print(i, current_x, current_y, current_f)
### derivatives of x and y
derivative_f_x = 6 * current_x
derivative_f_y = 8 * current_y
### update x, y
current_x = current_x - step * derivative_f_x
current_y = current_y - step * derivative_f_y
### current f
current_f = 3 * current_x * current_x + 4 * current_y + 5
ax.scatter(np.meshgrid(current_x), np.meshgrid(current_y), np.sqrt(current_f))
plt.pause(0.1)
结果:
可以看到
f(x, y) = current_f
在一直越来越小,对应的图就是下图,可以看到(x,y)
一直在趋近于f(x, y)
的最低点. (可以去运行代码,会有动画的效果,便于理解)
计算图的导数
代码:
gradient_test_5.py
目标:如何改变a,b,c使得J小于
0.1
?
答案当然还是梯度下降法
step = 0.1
a = 5
b = 3
c = 2
u = b * c
v = a + u
J = 3 * v
while not J < 0.1 :
print("J:", J)
# derivatives of variables
derivative_J_v = v
derivative_v_a = 1
derivative_v_u = 1
derivative_u_b = c
derivative_u_c = b
derivative_J_a = derivative_J_v * derivative_v_a
derivative_J_b = derivative_J_v * derivative_v_u * derivative_u_b
derivative_J_c = derivative_J_v * derivative_v_u * derivative_u_c
#update variables
a = a - step * derivative_J_a
b = b - step * derivative_J_b
c = c - step * derivative_J_c
u = b * c
v = a + u
J = 3 * v
最终可以看到
J
已经小于0.1
了,这个例子的展示有联合求导的情况,而且可以把a,b,c
类比为神经网络中的参数.
讨论Wx + b
代码:
gradient_test_6.py
最简单的
f(x) = w1 * x + b1
现在是坐标系中给出一些散点,然后希望用找到一条线可以最大程度拟合这些点.
那如何才是最大程度拟合了这些点呢?我们可以设置我们自己的损失函数,在这里我们把
cost_function = Least squares(最小平方法)
当做损失函数,也就是所有点到这条线的距离和,这个距离和越小越好,那好了我们已经弄明白了也就是说如何改变w1,b1
使得cost_function
最小,是不是和上面的例子有点像,答案也是一样就是梯度下降法.
首先就是需要求
cost_function
对w1,b1
的导数.
cost_function = 1/2m * ((w1*x1 + b1 - y1)^2 + (w1*x2 + b1 - y2)^2 + ... + (w1*xn + b1 - yn)^2)
Dcost_function/dw1 = 1/m * (x1*(w1*x1 + b1 - y1) + x2*(w1*x2 + b1 - y2) + ... + xn*(w1*xn + b1 - yn))
===>Dcost_function/dw1 = 1/m * sum(yi_predict_yi)*xi
同理b1
一样.
import numpy as np
import matplotlib.pyplot as plt
m = 20
# init some data
x_data = np.arange(1, m + 1).reshape([m, 1])
y_data = x_data*3 + 5
# for polt picture
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.scatter(x_data, y_data)
plt.ion()
plt.show()
w1 = 0
b1 = 0
step = 0.01
def cost_function(y_prediction):
return 1.0/(2 * m) * np.sum(np.square(y_prediction - y_data))
y_prediction = x_data * w1 + b1
ax.plot(x_data, y_prediction, 'black', lw=3)
print("(i, cost_function)")
for i in range(250):
print(i, cost_function(y_prediction))
derivative_f_w1 = 1.0/m * np.sum(np.multiply(y_prediction - y_data, x_data))
derivative_f_b1 = 1.0/m * np.sum(y_prediction - y_data)
w1 = w1 - step * derivative_f_w1
b1 = b1 - step * derivative_f_b1
y_prediction = x_data * w1 + b1
try:
ax.lines.remove(lines[0])
except Exception:
pass
lines = ax.plot(x_data, y_prediction, 'r-', lw=3)
plt.pause(0.1)
print('w1:', w1, 'b1:', b1)
结果:
可以看到
cost_function
越来越小,黑线是初始w1=0,b1=0
是线的位置,最终生成的红线是最终的线(w1=3.19,b1=2.32)
. (可以运行代码,代码会有线是如何模拟从初始位置到最终位置的)
外层再加入一个Sigmoid
函数
h'(x) = h(x) * (1 - h(x))
目标还是改变
w1,b1
使cost_function
变小,所以还是求cost_function
关于w1,b1
的偏导,加了一个函数,利用联合求导的方式还是可以求出答案.
代码没有写了,感兴趣的人可以自己写一下哈(一样的道理)
激励函数
一般都是非线性函数
为什么需要非线性函数?
如果是线性激励函数的话,整个网络还是线性方程.可以表示成:
(参数)x1 + (参数)x2 + … + (参数)xn
ANN: Artificial neural network
例子1: num_of_samples=1
代码:
gradient_test_2.py
cost_function
为最小平方法, 有3
个输入包括x1
,x2
和x3
. 有两个输出yo1
和yo2
.
y1 = W11*x1 + W21*x2 + W31*x3
y2 = W12*x2 + W22*x2 + W32*x3
yo1 = sigmod(y1)
yo2 = sigmod(y2)
Cost_function = 1/2 * [(yo1 - y)^2 + (yo2-y)^2]
原始数据:
[[ 1. 1. 1.]]
[[ 0.56553902 0.46432009]]
('start:', 0.19409408548266943)
数据集x1=1,x2=1,x3=1
输出集yt1=0.56553902, yt2=0.46432009
原始基于参数Wcost_function=0.19409408548266943
目标还是一致,希望可以通过改变
W11,W12,W21,W22,W31,W32
来使cost_function
越来越小,因此需要求出cost_function
关于这些参数的偏导.
import numpy as np
m = 10
step = 0.01
def sigmoid(x):
return 1/(1+np.exp(-x))
def derivative_sigmoid(x):
return np.multiply(1 - sigmoid(x), sigmoid(x))
def cost_function(yo, Y):
return 1./(2*m) * np.sum(np.square(np.subtract(yo, Y)))
#shape 1*3
X = np.ones((m, 3))
Y = np.random.rand(m, 2)
#shape 3*2
W = np.ones((3, 2))
#shape 1*2
y = np.dot(X, W)
#shape 1*2
yo = sigmoid(y)
cost = cost_function(yo, Y)
print("start:", cost)
cnt = 0;
while not cost < 0.1 :
derivative_c_y = np.subtract(yo, Y) / m
derivative_yo_y = derivative_sigmoid(y)
dw = np.dot(X.T, np.multiply(derivative_c_y, derivative_yo_y))
W = W - step * dw
y = np.dot(X, W)
yo = sigmoid(y)
cost = cost_function(yo, Y)
cnt += 1
print("end:", cost)
print("cnt:", cnt)
结果:
例子2:num_of_samples=m
其实中间过程还是一样,需要求各个参数的偏导.我只是想说明一下当
num_of_samples>1
时,代码还是一样.
数据集:
X = [[ 1. 1. 1.]
[ 1. 1. 1.]
[ 1. 1. 1.]
[ 1. 1. 1.]
[ 1. 1. 1.]
[ 1. 1. 1.]
[ 1. 1. 1.]
[ 1. 1. 1.]
[ 1. 1. 1.]
[ 1. 1. 1.]]
Y = [[ 0.51100414 0.05743273]
[ 0.69833688 0.47127458]
[ 0.08897891 0.78770351]
[ 0.55291883 0.78184918]
[ 0.94388284 0.4277488 ]
[ 0.50303774 0.10330091]
[ 0.07714834 0.1860604 ]
[ 0.2438794 0.55412802]
[ 0.32615948 0.25536064]
[ 0.26345809 0.2665332 ]]
用tensorflow
实现一个简单的神经网络
import tensorflow as tf
import numpy as np
x_data = np.float32(np.random.rand(2, 100))
y_data = np.dot([0.100, 0.200], x_data) + 0.300
b = tf.Variable(tf.zeros([1]))
W = tf.Variable(tf.random_uniform([1, 2], -1.0, 1.0))
y = tf.matmul(W, x_data) + b
loss = tf.reduce_mean(tf.square(y - y_data))
optimizer = tf.train.GradientDescentOptimizer(0.5)
train = optimizer.minimize(loss)
init = tf.initialize_all_variables()
sess = tf.Session()
sess.run(init)
for step in xrange(0, 201):
sess.run(train)
if step % 20 == 0:
print step, sess.run(W), sess.run(b)
下一篇将会用代码进一步分析多层是如何传递错误的,也就是用代码理解反向
传播,通过代码理解反向传播(backpropagation)
参考
1.网易云课堂: 深度学习-吴恩达
2.博客:https://www.jianshu.com/p/c7e642877b0e
3.tensorflow官网