吴恩达深度学习作业编程1【识别猫片】

it2025-04-19  22

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
最新回复(0)