Neural Networks and Deep Learning:https://www.coursera.org/learn/neural-networks-deep-learning/home/week/3
这段时间会一直更深度学习的内容。
先明确说明代码不是我写的,我只是整理,来源于Cousera的代码,将代码大幅度缩短,补充说明。
还是分成三段,
-1是效果
0.代码
1.扩展和补充
import numpy as np
import matplotlib.pyplot as plt
import sklearn
import sklearn.datasets
import sklearn.linear_model
np.random.seed(1)
# 生成数据集X,Y
np.random.seed(1)
m = 400 # 数据量
N = int(m/2) # 每一个分类的point数量
D = 2 # 维度
X = np.zeros((m,D)) # 0向量 (400,2)
Y = np.zeros((m,1), dtype='uint8') # 标签 (0 for red,1 for blue) (400,1)
a = 4 # maximum ray of the flower
for j in range(2):
ix = range(N*j,N*(j+1))
t = np.linspace(j*3.12,(j+1)*3.12,N) + np.random.randn(N)*0.2 # theta
r = a*np.sin(4*t) + np.random.randn(N)*0.2 # radius
X[ix] = np.c_[r*np.sin(t), r*np.cos(t)]
Y[ix] = j
X = X.T # (2,400)
Y = Y.T # (1,400)
# 数据可视化
# 前两项是位置,c是标量用来配色,s大小,cmap配色方案
plt.scatter(X[0, :], X[1, :], c=Y.reshape(400), s=40, cmap=plt.cm.Spectral)
# logistic 预测
clf = sklearn.linear_model.LogisticRegressionCV()
clf.fit(X.T, Y.T)
def plot_decision_boundary(model, X, y):
x_min, x_max = X[0, :].min() - 1, X[0, :].max() + 1 # 填充的边界大于最外边的点,不+1会留白
y_min, y_max = X[1, :].min() - 1, X[1, :].max() + 1
h = 0.01
# 网格化
xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
# 对整个平面网格所在的位置的点进行预测分类
Z = model(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
# 绘制等值区域和训练集
plt.contourf(xx, yy, Z, cmap=plt.cm.Spectral)
plt.ylabel('x2')
plt.xlabel('x1')
plt.scatter(X[0, :], X[1, :], c=y, cmap=plt.cm.Spectral)
plot_decision_boundary(lambda x: clf.predict(x), X, Y.reshape(-1))
plt.title("Logistic Regression")
# logistic精度
LR_predictions = clf.predict(X.T)
print ('logistic 的精度: %d ' % float((np.dot(Y,LR_predictions) + np.dot(1-Y,1-LR_predictions))/float(Y.size)*100) +
'% ' + "(正确率)")
# 深度学习模块
sigmoid = lambda x:1/(1+np.exp(-x))
def nn_model(X, Y, n_h, num_iterations = 10000,learning_rate = 1.2,print_cost=False):
np.random.seed(3)
n_x = X.shape[0]
n_y = Y.shape[0]
# 参数初始化
np.random.seed(2)
W1 = np.random.randn(n_h, n_x)*0.01
b1 = np.zeros((n_h, 1))
W2 = np.random.randn(n_y, n_h)*0.01
b2 = np.zeros((n_y, 1))
parameters = {"W1": W1,"b1": b1,"W2": W2,"b2": b2}
for i in range(0, num_iterations):
# 前向传播
Z1 = np.dot(W1,X) + b1
A1 = np.tanh(Z1)
Z2 = np.dot(W2,A1) + b2
A2 = sigmoid(Z2)
# 计算损失函数
m = Y.shape[1] # number of example
logprobs = Y*np.log(A2)+(1-Y)*np.log(1-A2)
cost = - np.sum(logprobs)/m
cost = np.squeeze(cost) # 清除维度冗余 E.g., turns [[17]] into 17
# 反向传播
dZ2 = A2 - Y
dW2 = 1/m * np.dot(dZ2,A1.T)
db2 = 1/m * np.sum(dZ2,axis=1,keepdims=True)
dZ1 = np.dot(W2.T,dZ2)*(1-np.tanh(Z1)**2)
dW1 = 1/m * np.dot(dZ1,X.T)
db1 = 1/m * np.sum(dZ1,axis=1,keepdims=True)
# 参数更新
W1,W2 = W1 - learning_rate * dW1, W2 - learning_rate * dW2
b1,b2 = b1 - learning_rate * db1, b2 - learning_rate * db2
parameters = {"W1": W1,"b1": b1,"W2": W2,"b2": b2} # 完成一次参数更新并重新赋值
if print_cost and i % 1000 == 0:
print ("迭代 %i 次后cost: %f" %(i, cost))
return parameters
# 预测模块
def predict(parameters, X):
W1,W2 = parameters['W1'],parameters['W2']
b1,b2 = parameters['b1'],parameters['b2']
Z1 = np.dot(W1,X) + b1
A1 = np.tanh(Z1)
Z2 = np.dot(W2,A1) + b2
A2 = sigmoid(Z2)
return np.around(A2,0)
parameters = nn_model(X, Y, n_h = 4, num_iterations = 10000, print_cost=True)
# 绘制决策边界
plot_decision_boundary(lambda x: predict(parameters, x.T), X, Y.reshape(-1))
plt.title("Decision Boundary for hidden layer size " + str(4))
# 使用训练后的参数计算数据集
predictions = predict(parameters, X)
print ('预测精度: %d' % float((np.dot(Y,predictions.T) + np.dot(1-Y,1-predictions.T))/float(Y.size)*100) + '%')
# 隐藏大小层对精度的影响
# 隐藏层尺寸是一个超参
plt.figure(figsize=(16, 32))
hidden_layer_sizes = [1, 2, 3, 4, 5, 20, 50]
for i, n_h in enumerate(hidden_layer_sizes):
plt.subplot(5, 2, i+1) # 绘制子图
plt.title('Hidden Layer of size %d' % n_h)
parameters = nn_model(X, Y, n_h, num_iterations = 5000)
plot_decision_boundary(lambda x: predict(parameters, x.T), X, Y.reshape(-1)) # 绘制边界
predictions = predict(parameters, X)
accuracy = float((np.dot(Y,predictions.T) + np.dot(1-Y,1-predictions.T))/float(Y.size)*100)
print ("大小为{}的隐藏层,最后的精度: {} %".format(n_h, accuracy))
# 不同的数据集
def load_extra_datasets():
N = 200
noisy_circles = sklearn.datasets.make_circles(n_samples=N, factor=.5, noise=.3)
noisy_moons = sklearn.datasets.make_moons(n_samples=N, noise=.2)
blobs = sklearn.datasets.make_blobs(n_samples=N, random_state=5, n_features=2, centers=6)
gaussian_quantiles = sklearn.datasets.make_gaussian_quantiles(mean=None, cov=0.5, n_samples=N, n_features=2, n_classes=2, shuffle=True, random_state=None)
no_structure = np.random.rand(N, 2), np.random.rand(N, 2)
return noisy_circles, noisy_moons, blobs, gaussian_quantiles, no_structure
noisy_circles, noisy_moons, blobs, gaussian_quantiles, no_structure = load_extra_datasets()
datasets = {"noisy_circles": noisy_circles,
"noisy_moons": noisy_moons,
"blobs": blobs,
"gaussian_quantiles": gaussian_quantiles}
dataset = "gaussian_quantiles"
X, Y = datasets[dataset]
X, Y = X.T, Y.reshape(1, Y.shape[0])
# make blobs binary
if dataset == "blobs":
Y = Y%2
# 数据可视化
plt.scatter(X[0, :], X[1, :], c=Y.reshape(200), s=40, cmap=plt.cm.Spectral)
这次的代码里面用到了sklearn,np.random.seed
1.0
plt.scatter(X[0, :], X[1, :], c=Y.reshape(400), s=40, cmap=plt.cm.Spectral)
说明:X是绘制的点的位置,Y是这个点的标签,在这里面前200个对应Y里面的0,后200个对应Y里面的1,所以一旦绘图,就会因为01的标量值不同而呈现颜色不同。
具体:这里用了matplotlib的scatter用法。
plt.scatter(x, y, s=area, c=colors, alpha=0.5)
1.X.shape维度是(2, 400),前两项分别取了0行1行,表示坐标位置xy
2.c
为color类似于mayavi的标量,接受了一个Y.reshape(400),注意Y本身是array([[0, 0, 0, 0,......,1,1,1,1]])
,
Y.shape是(1,400)这个和(400,)是有区别的,所以做了一步reshape
,另外Y.reshape(400)
不如Y.reshape(-1)
,数据尺寸是变化的。
这里面全是01,具体是,前200项是0,后200项是1
3.cmap
是配色方案,等效于colormap,字面翻译就是光谱(怪不得这么眼熟。),这个参数去掉也不会报错的,采取默认配色。(BTW:c=np.random.rand(400)
是五颜六色的发发,炒鸡好看)
4.s
是大小,也是一个可省略参数。
1.1.
np.random.seed(1)
这个是产生随机数用的,只是如果加了这一句,下面产生的随机数就能固定下来,
举个栗子好了
np.random.seed(1)
这句下面有1句随机生成,
np.random.seed(20)
这句下面有2句随机生成,
按理说循环3次是生成不同的随机,但因为加了这句np.random.seed(1)
,所以下面的随机数被固定了下来。
注意到这3次循环,每次循环的最后一个随机和第2个随机是不同的,这是因为np.random.seed(20)
的作用范围是最近的一句。
1.2.
sklearn.linear_model.LogisticRegressionCV()
原代码中有这么一句:
clf = sklearn.linear_model.LogisticRegressionCV()
clf.fit(X.T, Y.T)
说明: 先对象化,再使用fit
方法,拟合。
详解: 文档在这里,
sklearn.linear_model.LogisticRegressionCV(Cs=10, fit_intercept=True, cv=’warn’, dual=False, penalty=’l2’, scoring=None, solver=’lbfgs’, tol=0.0001, max_iter=100, class_weight=None, n_jobs=None, verbose=0, refit=True, intercept_scaling=1.0, multi_class=’warn’, random_state=None)
这玩意的省略参数也不少,求解方式lbfgs,最大迭代次数都有的,详细看文档。
然后使用了一个fit
方法:
fit(X, y[, sample_weight])
根据训练集拟合
格式:
X : {array-like, sparse matrix}, shape (n_samples, n_features)
y : array-like, shape (n_samples,)
一般我们习惯把训练集数量记为m,特征数目为n,X的维度就是(m,n)
对应y的维度为(m,1)
注意我们开始得到的X.shape是(2, 400),为(n,m)结构,所以转置。
Y.shape是(1,400),(1,m)结构,所以同样转置。
后面还有一个
clf.predict(x)
,根据训练好的模型把X重新放进去进行测试。
1.3.
np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
这个是用来绘制网格的。
1.4
np.c_[xx.ravel(), yy.ravel()]
https://docs.scipy.org/doc/numpy/reference/generated/numpy.r_.html#numpy.r_
补充说明一下:
这段最容易让人看不懂的地方:
# 生成数据集X,Y
np.random.seed(1)
m = 400 # 数据量
N = int(m/2) # 每一个分类的point数量
D = 2 # 维度
X = np.zeros((m,D)) # 0向量 (400,2)
Y = np.zeros((m,1), dtype='uint8') # 标签 (0 for red,1 for blue) (400,1)
a = 4 # maximum ray of the flower
for j in range(2):
ix = range(N*j,N*(j+1)) # 0-199,200-399
t = np.linspace(j*3.14,(j+1)*3.14,N) + np.random.randn(N)*0.2 # theta
r = a*np.sin(4*t) + np.random.randn(N)*0.2 # radius
X[ix] = np.c_[r*np.sin(t), r*np.cos(t)]
Y[ix] = j
这段其实把随机去掉,绘图就很明显了。
for j in range(2):
ix = range(N*j,N*(j+1)) # 0-199,200-399
t = np.linspace(j*3.14,(j+1)*3.14,N)
r = a*np.sin(4*t)
X[ix] = np.c_[r*np.sin(t), r*np.cos(t)]
Y[ix] = j
就这个图案本身而言是用的参数方程画的,一个轨迹方程。然后它给这个轨迹加了很多随机。
{ x = 4 s i n 4 t ⋅ s i n t y = 4 s i n 4 t ⋅ c o s t \begin{cases} x=&4sin4t·sint\\ &&\\ y=&4sin4t·cost& \end{cases} ⎩⎪⎨⎪⎧x=y=4sin4t⋅sint4sin4t⋅cost
先说一下,和-2.无隐藏层识别猫不同
相对于无隐藏层,多一个隐藏层就多了很多超参Hyperparameters。
1.学习速率lr
2.迭代次数num_iterations
3.隐藏层的层数
4.每一个隐藏层的大小hidden_layer_sizes
取[1, 2, 3, 4, 5,… 20, 50]的识别精度是不同的,
大小为1的隐藏层,最后的精度: 67.5 %
大小为2的隐藏层,最后的精度: 67.25 %
大小为3的隐藏层,最后的精度: 90.75 %
大小为4的隐藏层,最后的精度: 90.5 %
大小为5的隐藏层,最后的精度: 91.25 %
大小为6的隐藏层,最后的精度: 90.25 %
大小为7的隐藏层,最后的精度: 91.25 %
大小为8的隐藏层,最后的精度: 91.0 %
大小为9的隐藏层,最后的精度: 90.0 %
大小为10的隐藏层,最后的精度: 90.25 %
大小为20的隐藏层,最后的精度: 90.0 %
大小为50的隐藏层,最后的精度: 90.75 %
到后面已经慢慢进入过拟合状态了,最好的时候是91.25%。