1.jumpyter基本操作
shift+enter执行程序
2.向量化和非向量化的区别
import numpy as np
a=np.array([1,2,3,4])#创建一个数组
print(a)
输出:
[1 2 3 4]
下面用一个计算来比较向量化和非向量化的计算时差
import time
a=np.random.rand(1000000)#创造一个100万维度的向量
b=np.random.rand(1000000)
tic=time.time()#用于记录时间的
c=np.dot(a,b)
toc=time.time()
print(c)
print("向量化计算时间:"+str(1000*(toc-tic))+"ms")
#非向量化
c=0
tic=time.time()
for i in range(1000000):
c+=a[i]*b[i]
toc=time.time()
print(c)
print("for循环遍历用时:"+str(1000*(toc-tic))+"ms")
输出结果:
249886.21472148108
向量化计算时间:1.9955635070800781ms
249886.21472147264
for循环遍历用时:574.5570659637451ms
从上述结果可以看出,向量化之后计算效率大大提高。
3.python中的广播
- 已知这四种食物,苹果,牛肉,鸡蛋,土豆的三种组成成分中的卡路里含量如下,计算每个成分的卡路里占比。
import numpy as np
A=np.array([[56.0,0.0,4.4,68.0],
[1.2,104.0,52.0,8.0],
[1.8,135.0,99.0,0.9]])
print(‘A=’A)
cal=A.sum(axis=0)#这里axis=0指在矩阵的竖直方向求和,水平轴相加是axis=1
print(‘cal=’cal)
percentage=100*A/cal.reshape(1,4)#让A这个3*4的矩阵去除以一个1*4的矩阵即cal这个矩阵,
#这里的reshape是确保cal是个1*4的矩阵,用于改变矩阵的形状的,这里用A这个矩阵去除以cal这个矩阵就是用了python中的广播cal自动复制成3*4的再相除
print(‘percentage=’percentage)
输出:
A=[[ 56. 0. 4.4 68. ]
[ 1.2 104. 52. 8. ]
[ 1.8 135. 99. 0.9]]
cal=[ 59. 239. 155.4 76.9]
percentage=[[94.91525424 0. 2.83140283 88.42652796]
[ 2.03389831 43.51464435 33.46203346 10.40312094]
[ 3.05084746 56.48535565 63.70656371 1.17035111]]
从上面的代码中我们可以看到python的广播现象,这里用一个3×4的矩阵去除以一个1×4的矩阵,python自动把1×4的矩阵展开成3×4的矩阵再进行运算
4.尽量避免使用数组
import numpy as np
a=np.random.randn(5)#这么定义是返回一个一维的数组
print(a)
print(a.shape)#他的结构是个一维的数组,里面有5个数
print(a.T)#打印他的转置发现跟之前一样的
print(np.dot(a,a.T))#这样计算出来是个数相当于行*列
a=np.random.randn(5,1)#推荐使用这种定义一个5*1的矩阵
print(a)
print(a.T)#转置成行矩阵
print(np.dot(a,a.T))#列×行变成一个矩阵
输出:
[ 1.44911213 -0.39818701 0.10252206 0.40489787 -2.25696121]
(5,)
[ 1.44911213 -0.39818701 0.10252206 0.40489787 -2.25696121
7.526805807262495
[[-1.32924057]
[-0.17809059]
[ 1.32048081]
[-0.55105694]
[-0.2069648 ]]
[[-1.32924057 -0.17809059 1.32048081 -0.55105694 -0.2069648 ]]
[[ 1.76688048 0.23672524 -1.75523666 0.73248723 0.27510601]
[ 0.23672524 0.03171626 -0.23516521 0.09813806 0.03685848]
[-1.75523666 -0.23516521 1.74366958 -0.72766011 -0.27329305]
[ 0.73248723 0.09813806 -0.72766011 0.30366375 0.11404939]
[ 0.27510601 0.03685848 -0.27329305 0.11404939 0.04283443]]
ps:当不确定一个向量的具体维度是多少的时候,用assert()去验证一下
assert(a.shape==(5,1))
上面这行代码,如果a不是5×1的矩阵那么就会报错,用于确认这个矩阵多少维的
第二周练习题:
一、选择题
1.请考虑以下代码段:一开始选的C 正确答案D
a = np.random.randn(3, 3)
b = np.random.randn(3, 1)
c = a * b
c
的维度是什么?
A.这会触发广播机制,b
会被复制3次变成(3*3),而*
操作是元素乘法,所以c.shape = (3, 3)
B.这会触发广播机制,b
会被复制3次变成(3*3),而*
操作是矩阵乘法,所以c.shape = (3, 3)
C.这个操作将一个3x3矩阵乘以一个3x1的向量,所以c.shape = (3, 1)
D.这个操作会报错,因为你不能用*
对这两个矩阵进行操作,你应该用np.dot(a, b)
这里python是不能用两个矩阵直接相乘的,只能用遍历一个一个算,在numpy中可以使用向量化来算
即np.dot(a, b)
举例:
- 普通方法
def matrix_multiply(matrix1,matrix2):
new_matrix = [[0 for i in range(len(matrix1))] for j in range(len(matrix1))]
for i in range(len(matrix1)):
for j in range(len(matrix1)):
for x in range(len(matrix1)):
new_matrix[i][j] += matrix1[i][x]*matrix2[x][j]
return new_matrix
matrix1 = [[1,2,3], [4,5,6], [7,8,9]]
matrix2 = [[2,2,2], [3,3,3], [4,4,4]]
new_matrix = matrix_multiply(matrix1, matrix2)
print(new_matrix) # [[20, 20, 20], [47, 47, 47], [74, 74, 74]]
- 用numpy
import numpy as np
matrix1 = [[1,2,3], [4,5,6], [7,8,9]]
matrix2 = [[2,2,2], [3,3,3], [4,4,4]]
print(np.dot(matrix1,matrix2))
"""
[[20 20 20]
[47 47 47]
[74 74 74]]
"""
二、编程题
搭建一个能够识别猫的简单的神经网络
环境:在jumpter上编程
步骤:
1.导入数据集
从我们下载的数据集可以看到他是一个.h5的文件,我们导入数据集的时候会用到一个包叫h5py。
- 查看是否安装了h5py这个包,conda的优势就体现出来了。
- 输入conda list 查看包
如图可以看到有这个包
- 导入数据的代码
#导入数据
import h5py
#导入训练数据
train_data=h5py.File(r'C:\Users\Administrator\Desktop\【吴恩达课后编程作业】第二周 - PA1 - 具有神经网络思维的Logistic回归\datasets/train_catvnoncat.h5','r')
test_data=h5py.File(r'C:\Users\Administrator\Desktop\【吴恩达课后编程作业】第二周 - PA1 - 具有神经网络思维的Logistic回归\datasets/test_catvnoncat.h5','r')
首先导入数据的格式为:
train_data=h5py.File(r’文件路径’,‘r’) 这行代码中:
- train_data是名字,自己定义的
- h5py.File(‘文件路径’,‘r’)是固定格式,后面的r代表读取文件
- 之所以在括号里面文件路径之前还要加个r是因为\Users,\u表示其后是UNICODE编码,所以在前面加个r来避免python把\误认为是转义字符。
2.看一下导入的数据有什么
因为h5格式的文件跟字典类似是有键值对的,所以我们可以通过遍历他的键值对来看看里面有什么东西。
2.1首先查看训练集:
for key in train_data.keys():
print(key)
输出:
list_classes
train_set_x
train_set_y
分析输出的这三个健是什么意思:
- list_classes指的是真实的类别标签【是猫,不是猫】
- train_set_x指的是输入的图片
- train_set_y分类标签
下面来分别查看一下这三个数据
- 查看train_set_x的维度:
train_data['train_set_x'].shape
输出:
(209, 64, 64, 3)
可以看到输出是个4×1的矩阵,这四个数字代表的意思是:
- 209代表训练集有209张图片
- 后面三个数代表图片的三个通道
- 查看train_set_y的维度:
train_data['train_set_y'].shape#标签刚好是209,每个样本对应一个标签
(209,)
2.2 查看测试集
list(test_data.keys())#这行代码也用于输出test_data里面所有的key值
输出:
['list_classes', 'test_set_x', 'test_set_y']
- 查看test_set_x的维度:
test_data['test_set_x'].shape
输出:
(50, 64, 64, 3)
代表测试集有50张图片,每张图片的保存格式是64×64×3
- 查看test_set_y的维度
test_data['test_set_y'].shape
输出:
(50,)
这里标签也跟测试集的输入图片数量对应
2.3取出训练集和测试集的数据
现在训练集的数据和测试集的数据还都存在train_set_x或者test_set_x里面,如果调用的话可以这么写:
plt.imshow(train_data['train_set_x'][148])#这句话的意思是取出train_data数据中的训练集里面的209张图片中的第149张图片显示出来。
明显这么写很麻烦,那么我们就把所有的数据都取出来再另外给个简单的名字
#取出训练集
train_data_org=train_data['train_set_x'][:]#这行代码的意思是,把train_data中test_set_x这个键中的数据都取出来命名为train_data_org
#[:]代表把所有的行和列都取出来
train_labels_org=train_data['train_set_y'][:]#取出训练集的标签
#取出测试集数据
test_data_org=test_data['test_set_x'][:]
test_labels_org=test_data['test_set_y'][:]
我们来查看一下图片;
#查看图片
import matplotlib.pyplot as plt #专门用于显示图片的包
%matplotlib inline
#这行代码执行以后可以在线显示图片
plt.imshow(train_data['train_set_x'][148])
- 在执行这段代码的时候碰到了一个问题
如图所示,一开始把注释写在了%matplotlib inline的后面发现报错,去查了很久才解决,其实看一看他的提示:
UsageError: unrecognized arguments: #这行代码执行以后可以在线显示图片
无法识别”#这行代码执行以后可以在线显示图片“这行语句,你把注释删了就可以了,先看错误再去查。
3.进行数据维度和标签维度的处理
3.1数据维度处理
- 分别把训练集和测试集的数据变成n*m的矩阵其中n是特征,m是样本数量
#数据维度的处理
m_train=train_data_org.shape[0]#这里是取出训练集的样本数209
m_test=test_data_org.shape[0]#取出测试集的样本数50
train_data_tran=train_data_org.reshape(m_train,-1).T#这行代码的意思是把train_data_org这个本来维度是(209,64,64,3)的一个张量,我把它变成行为m_train,也就是209,列我不知道多少列的一个矩阵,然后再转置.
test_data_tran=test_data_org.reshape(m_test,-1).T
print(train_data_tran.shape,test_data_tran.shape)#这样就变成了一个n*m的矩阵,n是特征,m是样本数量
输出:
(12288, 209) (12288, 50)
从输出结果来看,训练集和测试集数据都变成了12288行的这样一个二维矩阵
3.2标签维度处理
把标签从一个列表变成一个行向量
#接下来进行标签处理
import numpy as np
train_labels_tran=train_labels_org[np.newaxis,:]#这行代码的意思是,我本来train_labels_org是存放标签的,他的维度是(209,)意思是一个长为209的列表,所以我们要想办法把他变成一个(1,209)的行向量.
#[np.newaxis,:]指增加一个维度变成1行多少列(这里是209),那么如果我写成[:,np.newaxis]就代表我把他变成一个多少行1列的这样一个维度
test_labels_tran=test_labels_org[np.newaxis,:]
print(train_labels_tran.shape,test_labels_tran.shape)
输出:
(1, 209) (1, 50)
4.标准化数据
这里为了减小误差,我把0-255的数据归一化成1以内的数据
#标准化数据
print(train_data_tran[:9,:9])#打印出9*9列的数据可以看出来,因为图片保存的数据是0-255之间的,从输出来看,这些数据分布不均匀,我们把他们按照量程区间归一化减小误差
输出:
[[ 17 196 82 1 9 84 56 19 63]
[ 31 192 71 22 9 79 57 22 68]
[ 56 190 68 2 5 50 23 2 61]
[ 22 193 89 1 10 84 52 23 64]
[ 33 186 83 14 9 79 55 26 68]
[ 59 182 83 2 6 51 19 2 60]
[ 25 188 100 1 9 77 43 27 68]
[ 35 179 98 13 9 72 53 29 71]
[ 62 174 104 1 6 44 17 2 58]]
train_data_sta=train_data_tran/255 #这里我想把他们归一化到0-1区间本来是train_data_tran-min/(max-min),
#这里最小值为0,最大值为255简化之后就是代码这么写
test_data_sta=test_data_tran/255
print(train_data_sta[:9,:9])
输出;
[[0.06666667 0.76862745 0.32156863 0.00392157 0.03529412 0.32941176
0.21960784 0.0745098 0.24705882]
[0.12156863 0.75294118 0.27843137 0.08627451 0.03529412 0.30980392
0.22352941 0.08627451 0.26666667]
[0.21960784 0.74509804 0.26666667 0.00784314 0.01960784 0.19607843
0.09019608 0.00784314 0.23921569]
[0.08627451 0.75686275 0.34901961 0.00392157 0.03921569 0.32941176
0.20392157 0.09019608 0.25098039]
[0.12941176 0.72941176 0.3254902 0.05490196 0.03529412 0.30980392
0.21568627 0.10196078 0.26666667]
[0.23137255 0.71372549 0.3254902 0.00784314 0.02352941 0.2
0.0745098 0.00784314 0.23529412]
[0.09803922 0.7372549 0.39215686 0.00392157 0.03529412 0.30196078
0.16862745 0.10588235 0.26666667]
[0.1372549 0.70196078 0.38431373 0.05098039 0.03529412 0.28235294
0.20784314 0.11372549 0.27843137]
[0.24313725 0.68235294 0.40784314 0.00392157 0.02352941 0.17254902
0.06666667 0.00784314 0.22745098]]
5.实现反向传播、梯度下降以及优化
- 主要用到的公式
- 代码:
#定义sigmoid函数
def sigmoid(z):
a=1/(1+np.exp(-z))
return a
#初始化参数
n_dim=train_data_sta.shape[0]#定义n_dim是训练集的属性个数
print(n_dim)#这个维度应该是12288
w=np.zeros((n_dim,1))#把w这个权值定义成n行1列的矩阵,初始化为0
b=0
#定义前向传播函数、代价函数以及梯度下降
def propagate(w,b,x,Y):
#1.前向传播函数
z = np.dot(w.T,X)+b
A=sigmoid(z)
#2.代价函数
#m=X.shape[1]
J=-1/m * np.sum(Y * np.log(A)+(1-Y) * np.log(1-A))#这里np。sum()这个函数默认按列求和,这里刚好是按列排列的,
#如果想按行求和那就在后面加个axis=1
#3.梯度下降
dw=1/m * np.dot(X,(A-Y).T)
db=1/3 * np.sum(A-Y)
grands={'dw':dw,'db':db}#这里因为dw和db一般是放在一起用的,这里把他们放在一个字典中好看一些
return grands,J
- 优化部分
#优化部分
def optimise(w,b,x,y,alpha,n_iters,print_cost):#这里的x,y是指单个标签
#这里alpha代表学习速率、n_iters代表迭代次数
costs=[ ]#这个列表用于存放代价函数值,方便后面画图
for i in range(n_iters):#迭代n_iters次
grands,J= propagate(w,b,x,y)#调用函数把dw,db,J求出来
dw=grands['dw']
db=grands['db']
#梯度下降
w = w - alpha * dw
b = b - alpha * db
if i % 100 ==0:#每隔100次输出一下代价函数的值
costs.append(J)
if print-cost:#这里可以动态选择是否输出,方便后续查看,这是从后面优化来的
print('n_iters is ',i,'cost is',J)
grands = {'dw':dw,'db':db} #为了返回方便
params = {'w':w,'b':b}
return grands,params,costs
6.预测部分
#预测部分
def predict(w,b,X_test):
Z = np.dot(w.T,X_test)+b
A=sigmoid(Z)
m = X_test.shape[1]#获取测试集样本数
y_pred = np.zeros((1,m))#这个矩阵用于存放预测值
for i in range(m):
if A[:,i]>0.5:
y_pred[:,i]=1
else:
y_pred[:,i]=0
return y_pred
7.模型整合
#模型整合
def model(w,b,x_train,y_train,x_test,y_test,alpha,n_iters,print_cost):
grands,params,costs = optimise(w,b,x_train,y_train,alpha,n_iters,print_cost)
w = params['w']
b = params['b']
y_pred_train = predict(w,b,x_train)#这里既对训练集做预测,也对测试集做预测
y_pred_test = predict(w,b,x_test)
print('the train accuracy is',np.mean(y_pred_train == y_train)*100,'%')
#这里准确率的计算思想为,我看一下有多少预测值等于真实值,然后把这些预测值除以总的预测个数。
print('the test accuracy is',np.mean(y_pred_test == y_test) * 100,'%')
b = {
'w' : w,
'b' : b,
'y_pred_train': y_pred_train,
'y_pred_test': y_pred_test,
'alpha':alpha
}
return b
8.函数调用
model(w,b,train_data_sta,train_labels_tran,test_data_sta,test_labels_tran,alpha=0.005,n_iters=2000,print_cost=True)
输出:
9.画出代价函数的图像
plt.plot(b['costs'])
plt.xlabel('per hundred iters')
plt.ylabel('costs')
输出
10.单个样本测试
#取一副具体的图片看一下预测结果和真实值之间的差距,并且把图片显示出来
index = 40
print('y is ',test_labels_tran[0,index])#打印真实值
print('y prediction is ',int(b['y_pred_test'][0,index]))#打印预测值
输出:
y is 1
y prediction is 1
- 打印图片
plt.imshow(test_data_org[index])
- 比较模型学习率对模型预测的影响
#比较模型的学习率alpha对模型预测的影响
alphas = [0.01,0.001,0.0001]
for i in alphas:
print('alpha = ',i)
d=model(w,b,train_data_sta,train_labels_tran,test_data_sta,test_labels_tran,alpha=i,n_iters=2000,print_cost=False)
print('==========================')
plt.plot(d['costs'],label=str(i))
plt.xlabel('per hundred iters')
plt.ylabel('cost')
plt.legend()#这行主要是用于显示那个label=str(i),也就是学习率alpha这个标签
输出;
11.在网上下载图片测试
- 读取图片
debug:
fname = 'C:\Users\Administrator\Desktop\猫样本测试.jpg'#这样报错
image = plt.imread(fname)
plt.imshow(image)
输出:
File "<ipython-input-346-849d95c632be>", line 1
fname = 'C:\Users\Administrator\Desktop\猫样本测试.jpg'
^
SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 2-3: truncated \UXXXXXXXX escape
正确写法:
fname = 'C:\\Users\Administrator\Desktop\猫样本测试.jpg'
#或者fname = r'C:\\Users\Administrator\Desktop\猫样本测试.jpg'
image = plt.imread(fname)
plt.imshow(image)
输出:
- 看一下下载图片的大小,这里不符合我们的要求
image.shape
输出:
(640, 1020, 3)
- 更改图片大小
from skimage import transform#可以改变图片的尺寸
image_tran = transform.resize(image,(64,64,3)).reshape(64*64*3,1)
image_tran.shape
输出;
(12288, 1)
- 调用预测函数进行预测
y=predict(d['w'],d['b'],image_tran)
print(int(y))
输出:
1