1.問題描述
有209張圖片作為訓練集,50張圖片作為測試集,圖片中有的是貓的圖片,有的不是。每張圖片的像素大小為64*64
吳恩達並沒有把原始的圖片提供給我們
而是把這兩個圖片集轉換成兩個.h5文件:train_catvnoncat.h5(訓練集),test_catvnoncat.h5(測試集)。
這三這個文件的下載地址:https://pan.baidu.com/s/1bL8SC3gNxbzL9Xo4C6ybow 提取碼: iaq7
這個h5文件是一種數據文件格式,關於它的寫入和讀取詳見: https://blog.csdn.net/csdn15698845876/article/details/73278120
這里並不需要我們自己來寫讀取方法,吳恩達已經給出了一個文件lr_utils.py來讀取這兩個.h5文件。
問題總結一下,我們的已知條件是這下圖的這兩個.h5文件和一個lr_utils.py文件,兩個.h5文件分別是訓練集和測試集,lr_utils.py用來解析兩個.h5文件的內容。

我們可以打開看看這個lr_utils.py文件看看:
import numpy as np import h5py def load_dataset(): train_dataset = h5py.File('datasets/train_catvnoncat.h5', "r") train_set_x_orig = np.array(train_dataset["train_set_x"][:]) # your train set features train_set_y_orig = np.array(train_dataset["train_set_y"][:]) # your train set labels test_dataset = h5py.File('datasets/test_catvnoncat.h5', "r") test_set_x_orig = np.array(test_dataset["test_set_x"][:]) # your test set features test_set_y_orig = np.array(test_dataset["test_set_y"][:]) # your test set labels classes = np.array(test_dataset["list_classes"][:]) # the list of classes train_set_y_orig = train_set_y_orig.reshape((1, train_set_y_orig.shape[0])) test_set_y_orig = test_set_y_orig.reshape((1, test_set_y_orig.shape[0])) return train_set_x_orig, train_set_y_orig, test_set_x_orig, test_set_y_orig, classes
可以看到它里面就一個函數 load_dataset(),
它的返回值有5個,分別對應
train_set_x_orig:訓練集的特征值(像素集合)
train_set_y_orig:訓練集的標簽(是不是貓)
test_set_x_orig:測試集的特征值(像素集合)
test_set_y_orig:測試集的標簽(0表示不是貓,1表示是貓),
classes:bytes:保存的兩個字符串數據。
我們可以把他們打印出來,看看里面的結構:
train_set_x_orig,train_set_y,test_set_x_orig,test_set_y,classes=lr_utils.load_dataset() print("===========train_set_x_orig========") print(train_set_x_orig.shape) print(train_set_x_orig) print("===========train_set_y========") print(train_set_y.shape) print(train_set_y) print("===========test_set_x_orig========") print(test_set_x_orig.shape) print(test_set_x_orig) print("===========test_set_y========") print(test_set_y.shape) print(test_set_y) print("===========classes========") print(classes.shape) print(classes)
得到的部分結果如下(太長就不全貼出來了):
===========train_set_x_orig======== (209, 64, 64, 3) [[[[ 17 31 56] [ 22 33 59] [ 25 35 62] ... [ 0 0 0] [ 0 0 0] [ 0 0 0]]]] ===========train_set_y======== (1, 209) [[0 0 1 0 0 0 0 1 0 0 0 1 0 1 1 0 0 0 0 1 0 0 0 0 1 1 0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 1 1 0 0 0 0 1 0 0 1 0 0 0 1 0 1 1 0 1 1 1 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 1 0 0 0 1 1 1 0 0 1 0 0 0 0 1 0 1 0 1 1 1 1 1 1 0 0 0 0 0 1 0 0 0 1 0 0 1 0 1 0 1 1 0 0 0 1 1 1 1 1 0 0 0 0 1 0 1 1 1 0 1 1 0 0 0 1 0 0 1 0 0 0 0 0 1 0 1 0 1 0 0 1 1 1 0 0 1 1 0 1 0 1 0 0 0 0 0 1 0 0 1 0 0 0 1 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0]] ===========test_set_x_orig======== (50, 64, 64, 3) [[[[158 104 83] [161 106 85] [162 107 84] ... [ 8 33 12] [ 13 35 18] [ 5 22 5]]]] ===========test_set_y======== (1, 50) [[1 1 1 1 1 0 1 1 1 1 1 1 1 0 0 1 0 1 1 1 1 0 0 1 1 1 1 0 1 0 1 1 1 1 0 0 0 1 0 0 1 1 1 0 0 0 1 1 1 0]] ===========classes======== (2,) [b'non-cat' b'cat']
2.模型
本文采用簡單的單層神經網絡模型:

![]()
![]()

3.問題分析
3.1 單個樣本的情況
(1)特征矩陣X
每個樣本是一張64*64像素的圖,買個像素由(R,G,B)三原色構成的,所以每個樣本的特征數為 64*64*3=12288
把它們列起來寫,單個樣本的特征記做一個矩陣X:

(2)系數W矩陣

(3)系數B
![]()
3.2 m個樣本的情況
以上的z和x加上一個上標即可,注意W和b不要加,系數只有一組,與樣本的數量無關!
它表示第i個樣本
m=209個樣本寫成矩陣就是:

4.寫代碼
4.1偽代碼
使用這m個樣本進行訓練N次,不斷更新參數w和b,迭代結束的條件是當兩次相鄰迭代的損失函數的變化值小於某個閾值,
為了防止死循環,還要設置一個最大迭代次數。

4.2寫代碼
(1)矩陣變換
還記得 我們的已知條件是這5個矩陣:
train_set_x_orig:訓練集的特征值(像素集合)
train_set_y_orig:訓練集的標簽(是不是貓)
test_set_x_orig:測試集的特征值(像素集合)
test_set_y_orig:測試集的標簽(0表示不是貓,1表示是貓),
classes:bytes類型保存的兩個字符串數據
訓練集_圖片的維數 : (209, 64, 64, 3)
訓練集_標簽的維數 : (1, 209)
測試集_圖片的維數: (50, 64, 64, 3)
測試集_標簽的維數: (1, 50)
首先我們將train_set_x_orig轉成如下的格式:

每一列是一個樣本,一共209個樣本,我們使用的是reshape函數:
train_x_tmp=train_set_x_orig.reshape(train_set_x_orig.shape(1),-1).T
注意它並不等價於 train_set_x_orig.reshape(-1,train_set_x_orig.shape(1)),不信你可以自己寫個小例子測試下。
使用同樣的方法,我們將test_set_x_orig做變換,使得他們滿足公式中的形式:
test_x_tmp=test_set_x_orig.reshape(test_set_x_orig.shape(1),-1).T
(2)標准化數據集:
為了收斂速度,我們還要將每個像素值除以255,這個技巧在吳恩達的視頻里面講到。
train_set_x = train_x_tmp / 255
test_set_x = test_x_tmp/ 255
(3)開始寫吧
以下是需要你寫的代碼,除了這個文件,還需要前面說的兩個.h5文件和一個lr_utils.py文件,文章一開頭已經給出了下載地址。
# -*- coding: utf-8 -*- import io import sys sys.stdout=io.TextIOWrapper(sys.stdout.buffer,encoding='utf8') import pylab import lr_utils import matplotlib.pyplot as plt import numpy as np import h5py train_set_x_orig,train_set_y,test_set_x_orig,test_set_y,classes=lr_utils.load_dataset() #轉換成12288*209的矩陣 train_x_tmp = train_set_x_orig.reshape(train_set_x_orig.shape[0],-1).T #標准化特征值 X = train_x_tmp / 255 Y = train_set_y #初始化W,B,Z,A,cost,Dy #W是一個12288*1的矩陣 #B是一個1*1的矩陣,使用廣播 #Z是一個1*209的矩陣 #A是一個1*209的矩陣 #Dy=A-Y costCur=0 cost=0 W = np.zeros(shape = (12288,1)) B = 0 Z = np.zeros(shape = (1,209)) A = np.zeros(shape = (1,209)) Dy= 0 #err是相鄰兩次迭代的成本函數的差值 err=0 #costTmp是成本損失矩陣 costTmp = np.zeros(shape = (1,209)) #學習率 learning=0.01 #最大迭代次數 Nmax=5000 #定義收斂閾值 min=0.01 #寫循環 N=0 while N<Nmax : Z=np.dot((W.T),X)+B A=1/(1 + np.exp(-Z)) #成本矩陣 costTmp = np.dot(Y,np.log(A).T)+np.dot((1-Y),np.log(1-A).T) #計算成本 cost=(-1/209)*np.squeeze(np.sum(costTmp)) err = abs(costCur-cost) if err < min : break cost=costCur #W是一個12288*1的矩陣 #A是一個1*209的矩陣 Dy=(1/209)*(A-Y) W=W-learning*np.dot(X,(Dy.T)) #更新W 一個12288*1的矩陣,這里容易出錯,注意是X與Dy的轉置相乘,可以根據矩陣的維數來判斷。 B=B-learning*np.sum(Dy) #更新B N += 1 print("iteration is over") print("iteration count: "+str(N)) print("w:"+str(W)) print("B:"+str(B)) #使用訓練集合測試准確率 Y_prediction_train = np.zeros((1,209)) for i in range(A.shape[1]): #將概率a [0,i]轉換為實際預測p [0,i] Y_prediction_train[0,i] = 1 if A[0,i] > 0.5 else 0 #使用測試集合測試准確率 #轉換成12288*50的矩陣 TEST_Y = test_set_y test_x_tmp = test_set_x_orig.reshape(test_set_x_orig.shape[0],-1).T #標准化特征值 TEST_X = test_x_tmp/ 255 TEST_Z=np.dot((W.T),TEST_X)+B TEST_A=1/(1 + np.exp(-TEST_Z)) Y_prediction_test = np.zeros((1,50)) for i in range(TEST_A.shape[1]): #將概率a [0,i]轉換為實際預測p [0,i] Y_prediction_test[0,i] = 1 if TEST_A[0,i] > 0.5 else 0 #打印結果 print("test accuracy: " , format(100 - np.mean(np.abs(Y_prediction_test - TEST_Y)) * 100) ,"%") print("train accuracy: " , format(100 - np.mean(np.abs(Y_prediction_train - Y)) * 100) ,"%")
打印結果中的迭代數目和准確率如下:
iteration count: 5000 test accuracy: 68.0 % train accuracy: 100.0 %
可以看到,迭代次數達到了5000,訓練集的准確率是100%,但測試集的准確率不高。
如何提高呢?本文的線性模型不行了,
繼續學習后面的課程,使用多層神經網絡,隱藏層不要使用線性激活函數,選擇合理的初始參數值等等,這就是后面的內容了。
