1. 程式人生 > 其它 >Logistic Regression with a Neural Network mindset

Logistic Regression with a Neural Network mindset

文章內容為吳恩達深度學習第二週的程式設計作業

**ipynbg格式程式碼及資料集-->陳能豆 **
密碼: o1bn

#!/usr/bin/env python
# coding: utf-8

# # 吳恩達深度學習第二週程式設計作業

# ## 題目部分

# 先來看一下 英文的題目部分

# Logistic Regression with a Neural Network mindset
# Welcome to your first (required) programming assignment! You will build a logistic regression classifier to recognize cats. This assignment will step you through how to do this with a Neural Network mindset, and so will also hone your intuitions about deep learning.
# 
# Instructions:
# 
# Do not use loops (for/while) in your code, unless the instructions explicitly ask you to do so.
# You will learn to:
# 
# Build the general architecture of a learning algorithm, including:
# Initializing parameters
# Calculating the cost function and its gradient
# Using an optimization algorithm (gradient descent)
# Gather all three functions above into a main model function, in the right order.

# ### 簡單解釋一下要求  
# 要求我們建議一個邏輯迴歸分類器來識別貓的圖片  
# 
# #### 要求如下:  
# * 不要在程式碼中使用迴圈(for/while),除非指令明確要求您這樣做。  
# 
# * 演算法的架構如下:  
# 1. 引數初始化  
# 2. 成本函式及梯度的計算  
# 3. 優化演算法  
# 
# 你需要編寫上面提到的方法,並進行組合,成為一個模型
# 
# #### 資料集概述
# 這裡會提供給我們一個數據集,名字為”data.h5“(和下面程式碼用的是同一個資料集,不過名字改成了”train_catvnoncat.h5“)  
# 裡面包含了相關資料集,更具體的可以看程式碼的資料匯入方法。 
# 主要包括:  
# 1. 標籤設定好的訓練集,標記是否為cat(0/1)  
# 2. 標籤設定好的測試集  
# 3. 圖片的形狀為(64, 64, 3)  
# 
# 
# 資料集及程式碼附上鍊接--> [陳能豆](https://pan.baidu.com/s/1VMCuVU8IKWLycKM6B20O_g)  
# 提取密碼:q73d
# 
# #### ok  下面看程式碼
# 

# In[98]:


# pip --version   # 這裡看一下python的版本  ,3.6 以及別的版本應該也是可行的   


# ### 程式碼部分

# #### 程式碼段後面附上相關重點提示 
# #### 相關函式用法 不會的百度

# In[197]:


import numpy as np
import matplotlib.pyplot as plt
import h5py
import random
# 下面兩個用於測試模型 
from PIL import Image
import imageio


# 匯入相關包

# In[198]:


# 匯入資料函式
def load_datasets():
    
    train_datasets = h5py.File('datasets/train_catvnoncat.h5',"r")
    train_set_x_origi = np.array(train_datasets["train_set_x"][:])
    train_set_y_origi = np.array(train_datasets["train_set_y"][:])
    # 讀取訓練集
    
    
    test_datasets = h5py.File('datasets/test_catvnoncat.h5',"r")
    test_set_x_origi = np.array(test_datasets["test_set_x"][:])
    test_set_y_origi = np.array(test_datasets["test_set_y"][:])
    # 測試集
    
    
    classes = np.array(test_datasets["list_classes"][:])
    # 儲存可能的結果   0 non-cat  1  cat
    
    # 初始化矩陣格式
    train_set_y_origi = train_set_y_origi.reshape( (1,train_set_y_origi.shape[0]) )
    test_set_y_origi = test_set_y_origi.reshape( (1,test_set_y_origi.shape[0]) )
    
    return train_set_x_origi,train_set_y_origi,test_set_x_origi,test_set_y_origi,classes
    
    


# 從資料集中匯入資料  其中classes 用於儲存可能的結果  
# classes: array([b'non-cat', b'cat'], dtype='|S7')

# In[199]:


# 讀入資料
train_set_x_origi,train_set_y,test_set_x_origi,test_set_y,classes = load_datasets()


# In[200]:


# 顯示一下訓練集的資料
index = random.randint(1,train_set_y.shape[1])

plt.imshow(train_set_x_origi[index])
# 列印圖片

# 列印結果
print( "The picture number is " +str(index) + "  The ans is " +classes[ np.squeeze(train_set_y[:,index])].decode("utf-8") )

print("使用np.squeeze:" + str(np.squeeze(train_set_y[:,index])) )
print("不使用np.squeeze: " + str(train_set_y[:,index])  )


# 顯示的是資料集中隨機的一張圖片及結果
# 可改為指定編號  
# squeeze 函式的作用為壓縮維度  
# 是否使用squeeze的區別見程式碼
# 

# In[201]:


# 檢視矩陣維數
im_number_train = train_set_y.shape[1]
im_number_test = test_set_y.shape[1]
im_size = train_set_x_origi.shape[1]

# 列印
print("訓練集圖片數量: "+str(im_number_train))
print("測數集圖片數量: "+str(im_number_test))
print("圖片寬度高度為: "+str(im_size))
print("每張圖片大小為" +str(im_size)+","+str(im_size)+",3")
print("訓練集x維數為 "+str(train_set_x_origi.shape))
print("訓練集y維數為 "+str(train_set_y.shape))
print("測試集x維數為 "+str(test_set_x_origi.shape))
print("測試集y維數為 "+str(test_set_y.shape))


# shaape 函式 返回矩陣維數  
# 返回資料型別為n元組   可通過下標引用

# In[202]:


# 降維  資料預處理
train_set_x_flatten = train_set_x_origi.reshape(train_set_x_origi.shape[0],-1).T
test_set_x_flatten = test_set_x_origi.reshape(test_set_x_origi.shape[0],-1).T

# 列印降維後的維數

print("訓練集降維後的維數為 "+str(train_set_x_flatten.shape))
print("測試集降維後的維數為 "+str(test_set_x_flatten.shape))


# reshape 函式用於改變矩陣維數  
# -1 表示 自動計算下一維度   

# In[203]:


# 核對維數
print("訓練集x的位數為 "+str(train_set_x_flatten.shape))
print("訓練集y維數為 "+str(train_set_y.shape))
print("測試集x的維數為 "+str(test_set_x_flatten.shape))
print("測試集y維數為 "+str(test_set_y.shape))


# In[204]:


# 資料標準化
# 圖片儲存的值為畫素值    0-255
# 例如資料集中
print(np.amax(train_set_x_flatten))
print(np.amin(train_set_x_flatten))

train_set_x = train_set_x_flatten/255
test_set_x = test_set_x_flatten/255


# In[205]:


def sigmoid(z):
    # 引數為z陣列
    
    # 返回s = sigmoid(z)
    
    s = 1/(1+np.exp(-z))
    
    return s


# 啟用函式有很多種    
# ![image.png](attachment:image.png "啟用函式")

# In[206]:


# 測試siggmod 函式 是否符合預期
print( "sigmoid(0) = "+str(sigmoid(0)))
print( "sigmoid(1) = "+str(sigmoid(1)))
print( "sigmoid(10) = "+str(sigmoid(10)))
print( "sigmoid(-1) = "+str(sigmoid(-1)))
print( "sigmoid(-10) = "+str(sigmoid(-10)))


# In[207]:


def initialize_zeros_vector(size): 
    # 函式作用 生成 並返回一個(size,1) 的0向量  同時初始化 b=0
    
    
    w = np.zeros( (size,1) )
    b = 0
    
    # 斷言確保維數
    assert( w.shape== (size,1) )
    assert( isinstance(b,float) or isinstance(b,int) )
    
    return (w , b)

    


# In[208]:


def  two_way_propogate(W,b,X,Y ):
    # 實現正向傳播和反向傳播
    
    m = X.shape[1]
    
    # 正向傳播 
    
    A = sigmoid(np.dot(W.T,X )+b)
    cost = (-1/m)*np.sum(Y*np.log(A)  + (1-Y)*np.log(1-A))
    
    # 反向傳播
    dw = (1/m)* np.dot(X,(A-Y).T)
    db = (1/m)* np.sum(A-Y)
    
    assert(dw.shape==W.shape)
    assert(db.dtype == float)
    cost = np.squeeze(cost)
    
    # 儲存dw db
    grads = {
        "dw":dw,
        "db":db
    }
    
    return grads, cost

    
    


# ### 這裡附上課程中求導計算過程中的部分截圖,便於理解  
# 向量化之前:   
# ![image.png](attachment:image.png)
# 向量化後:  
# ![image.png](attachment:image.png)

# In[209]:


# 測試 two_way_propogate 
# 隨便初始化一些引數
W ,b ,X, Y = np.array([ [2],[2] ]),2,np.array([ [1,0],[0,0] ]),np.array([0,0])
grabs, cost = two_way_propogate(W,b,X,Y)
print("dw = " + str(grabs["dw"]))
print("db = " + str(grabs["db"]))
print("cost = " + str(cost))
# 迭代一次 看效果如何
learning_rate = 0.1
W = W -learning_rate*grabs["dw"]
b= b- learning_rate * grabs["db"]
grads, cost = two_way_propogate(W,b,X,Y)
print("迭代一次後")
print("dw = " + str(grabs["dw"]))
print("db = " + str(grabs["db"]))
print("cost = " + str(cost))


# In[210]:


def optimize( W , b , X , Y , num_iteration , learning_rate , print_cost=False , print_frequency = 100):
    # 該函式作用 運用梯度下降優化W 和b
    # 引數描述放在下面 
    """
    此函式通過執行梯度下降演算法來優化w和b
    
    引數:
        w  - 權重,大小不等的陣列(num_px * num_px * 3,1)
        b  - 偏差,一個標量
        X  - 維度為(num_px * num_px * 3,訓練資料的數量)的陣列。
        Y  - 真正的“標籤”向量(如果非貓則為0,如果是貓則為1),矩陣維度為(1,訓練資料的數量)
        num_iterations  - 優化迴圈的迭代次數
        learning_rate  - 梯度下降更新規則的學習率
        print_cost  - 每100步列印一次損失值
    
    返回:
        params  - 包含權重w和偏差b的字典
        grads  - 包含權重和偏差相對於成本函式的梯度的字典
        成本 - 優化期間計算的所有成本列表,將用於繪製學習曲線。
    
    提示:
    我們需要寫下兩個步驟並遍歷它們:
        1)計算當前引數的成本和梯度,使用propagate()。
        2)使用w和b的梯度下降法則更新引數。
    """
    costs =[]
    for i in range(num_iteration):
        grads , cost = two_way_propogate( W , b, X , Y )
        
        dw = grads["dw"]
        db = grads["db"]
        W = W- dw * learning_rate
        b = b- db * learning_rate
        
        if(i%print_frequency==0):
            costs.append(cost)
        
        
        if(print_cost and i%print_frequency==0):
            print("迭代次數為:%i , 誤差值為:  %f" % (i,cost))
    
    
    params = {
        "W": W,
        "b": b
    }
    
    grads = {
        "dw": dw,
        "db": db
    }
    
    return (params , grabs , costs)



#         w  - 權重矩陣
#         b  - 偏差值  一個數
#         X  - 維度為 訓練集
#         Y  - 訓練標籤集 真正的“標籤”向量(如果非貓則為0,如果是貓則為1),矩陣維度為(1,訓練資料的數量)
#         num_iterations  - 優化迴圈的迭代次數
#         learning_rate  - 梯度下降更新規則的學習率
#         print_cost  - 是否列印cost
#         print_frequency - 列印頻率,迭代多少次列印一次cost

# In[211]:


# 測試 optimize
W, b, X, Y = np.array([[2], [3]]), 3, np.array([[0,1], [2,2]]), np.array([[0, 2]])
params , grads , costs = optimize(W , b , X , Y , num_iteration=100 , learning_rate = 0.009)
print ("w = " + str(params["W"]))
print ("b = " + str(params["b"]))
print ("dw = " + str(grads["dw"]))
print ("db = " + str(grads["db"]))


# In[212]:


def predict(W , b , X):
    
    # 根據引數 預測結果
    
    m = X.shape[1]
    
    # 這裡引數的維度假設是符合的  不需要判斷
    
    A = sigmoid( np.dot(W.T,X )+b)
    
    assert(A.shape==(1,m))
    for i in range(A.shape[1]):
        
        A[0,i] = 1 if A[0,i] >0.5  else 0
    # 預設0.5為臨界值 
    
    assert(A.shape==(1,m) )
    
    return A
    


# 這裡的0.5 可以修改為一個指定的臨界值    或設定為引數

# In[213]:


# 測試predict
w, b, X, Y = np.array([[1], [2]]), 2, np.array([[1,2], [3,4]]), np.array([[1, 0]])
print("predictions = " + str(predict(w, b, X)))


# In[214]:


def model ( X_train , Y_train , X_test , Y_test , num_iterations = 2000 , learning_rate = 0.5, print_cost = False , print_frequency = 100):
    
    
    W , b = initialize_zeros_vector(X_train.shape[0])
    parameters , grabs , costs = optimize(W , b , X_train , Y_train , num_iterations , learning_rate , print_cost, print_frequency)
    
                                          
    W , b = parameters["W"] , parameters["b"]
    # 預測測試集
    Y_prediction_tset = predict(W , b , X_test)
    Y_prediction_train = predict(W , b , X_train)
    
    # 列印準確性
    print("訓練集準確性: " , format(100 - np.mean(np.abs(Y_prediction_train - Y_train)) * 100 ) , "%")
    print("測試集準確性: " , format(100 - np.mean(np.abs(Y_prediction_tset - Y_test)) * 100 ) , "%")
    
    
    
    d = {
        "costs" : costs,
        "Y_prediction_test" : Y_prediction_tset,
        "Y_prediction_train" : Y_prediction_train,
        "W" : W,
        "b" : b,
        "learning_rate" : learning_rate,
        "num_iterations" : num_iterations
    }
    
    return d
     


# In[215]:


# 測數model
d = model(train_set_x,train_set_y,test_set_x,test_set_y,num_iterations=2000,learning_rate=0.005,print_cost=True)


# In[216]:


costs = np.squeeze( d["costs"] )
plt.plot(costs)
plt.ylabel("cost")
plt.xlabel("iterations(per 100)")
plt.title("Learning rate= "+ str(d["learning_rate"]))
plt.show


# In[217]:


# 測試不同的學習率

learning_rates = [0.01,0.001,0.0001]
models = {}
for i in learning_rates:
    print("learning_rate is: " + str(i))
    models[str(i)]=model(train_set_x,train_set_y,test_set_x,test_set_y,num_iterations=2000,learning_rate=i,print_cost=False)
    print("\n")
    

for i in learning_rates:
    plt.plot(np.squeeze(models[str(i)]["costs"]  ), label= str(models[str(i)]["learning_rate"]))


plt.ylabel('cost')
plt.xlabel('iterations')
legend = plt.legend(loc='upper center' , shadow=True )
frame = legend.get_frame()
frame.set_facecolor('0.90')
plt.show


# In[218]:


def test_my_image( my_image):
    image_name = my_image
    fname = "images/" + my_image  # 在當前目錄下有一個images資料夾  用於存放我們的圖片 
    image = np.array(imageio.imread(fname))

    my_image = Image.fromarray(image).resize(( im_size , im_size ))
    my_image = np.array(my_image).reshape((1, im_size * im_size * 3)).T

    my_predicted_image = predict(d["W"], d["b"], my_image)

    plt.imshow(image)
    print("image name is: "+image_name)
    print( "y = " + str(np.squeeze(my_predicted_image)) + ", your algorithm predicts a \"" + classes[int(np.squeeze(my_predicted_image)),].decode("utf-8") +  "\" picture.")

    


# 下面我們自己整一張圖片試一試

# In[220]:


my_image1 = "my_image1.jpg" 
# my_image2 = "my_image1.jpg"
# my_image3 = "my_image2.jpg"
# my_image4 = "my_image3.jpg"
# my_image5 = "my_image4.jpg"
test_my_image(my_image1)
# test_my_image(my_image2)
# test_my_image(my_image3)
# test_my_image(my_image4)
# test_my_image(my_image5)


# ####  宣告: 本人蔘考了[Kulbear](https://github.com/Kulbear/deep-learning-coursera) 的github上的文章 ,加以自己理解,編寫了本篇內容。盡力讓人輕鬆理解課程內容及作業