摘要:算法详解;代码;可视化查看超参数影响
目标:识别一张图是不是猫
数据集:训练数据209张64*64
测试数据50张 64*64
方案:二分分类法
算法:logistic回归 ,限定了你的输入(X),和做优化时,需要优化哪些量(W,b)
激活函数:sigmod
sigmod函数图像:
特点:所有输出y值都落在0-1之间
ps:logistic回归是算法,但其激活函数取sigmod,是因为,你想得到一个在(0-1)之间的值,所以,这才用到了sigmod函数。
损失函数:
成本函数:
成本函数的由来:假设第1张图真实值是1(第一张图本来就是猫),
预测时,认为
它是猫的概率是0.8,体现在sigmod函数输出0.8,(a=0.8)
则正确率
同理,如果假设某图不是只猫,其y=0,
其正确率
合并
得
log是一个单调递增的函数,可以变成一个凸函数,便于使用梯度下降进行优化
把上式log化
上式还不是成本函数,因为,上式值越大表明,越准确
按照习惯来说,需要成本函数越小,预测值与真实值越接近,越准确
所以,直接加个负号就行了
所以,成本函数就是
计算图
代码:
-
载入数据
-
处理数据(/255),缩小数据,因为1比255更好计算
-
初始化(w,b),w是一个n维列向量,b=0
-
建立sigmod函数
-
利用训练数据集 建立正反向传播函数,如计算图,并求梯度,以便使用梯度下降
-
建立优化(梯度下降)函数,利用好梯度,选取下降方向,另需选取学习率 ,迭代次数。这两个选取与过拟合,欠拟合息息相关
-
利用迭代num_iterations次后,出来的w,b。组装好sigmod函数,预测,测试集数据
-
测试/训练集 正确率输出,利于判断
-
可视化输出,比较出一个好的学习率 ,和迭代次数。(超参数选择,一个无法学习的东西
-
import numpy as np
-
import matplotlib.pyplot as plt
-
import h5py
-
import sys
-
sys.path.append(r'F:\study\assignment2')
-
from lr_utils import load_dataset
-
'''''
-
数据读取与标准化
-
读取的x数据是(209,64,64,3)的格式
-
需要将其平铺成(64*64*3,209)
-
'''
-
train_x_orig,train_y_orig,test_x_orig,test_y_orig,classes=load_dataset()
-
-
train_x_flatten=train_x_orig.reshape(train_x_orig.shape[0],-1).T
-
test_x_flatten=test_x_orig.reshape(test_x_orig.shape[0],-1).T
-
#上面一定要记得转置,因为reshape成了(m,n)的形式
-
#-1,是不用去考虑到底要转换成多少列了,只要是负数就行
-
-
#然后是将数据缩小,便于计算,因为1比255更好计算,反正也不影响计算机结果
-
#标准化数据 rgb值都小于255的
-
train_x=train_x_flatten / 255
-
test_x=test_x_flatten / 255
-
-
train_y=train_y_orig
-
test_y=test_y_orig
-
#上面就把数据整理好了
-
-
'''''
-
下面开始写函数了
-
'''
-
-
#建立sigmod函数
-
def sigmod(x):
-
return (1/(1+np.exp(-x)))
-
-
#初始化w,b, ps:w是一个列向量
-
-
def initialize(n_x):
-
w=np.zeros(shape=(n_x,1))
-
b=0
-
return(w,b)
-
-
-
#建立正反向传播函数
-
-
def propagate(w,b,X,Y):
-
"""
-
正向传播
-
"""
-
-
A=sigmod(np.dot(w.T,X)+b)
-
m=X.shape[1]
-
cost=(-1/m)*np.sum(Y * np.log(A)+(1-Y) * np.log(1-A))
-
''''' ps:尼玛不知道为什这个三点冒号也要按照缩进格式来
-
反向传播
-
'''
-
dw=np.dot(X,(A-Y).T)/m
-
db=np.sum(A-Y)/m
-
-
'''''
-
组装数据
-
'''
-
grads={'dw':dw,'db':db}
-
return (grads,cost)
-
-
#建立优化函数
-
-
def optimize(w,b,X,Y,num_iterations,learning_rate,print_cost):
-
costs=[]
-
for i in range(num_iterations):
-
grads,cost=propagate(w,b,X,Y)
-
dw=grads['dw']
-
db=grads['db']
-
-
w=w-learning_rate*dw
-
b=b-learning_rate*db
-
-
#记录误差
-
if i % 100==0:
-
costs.append(cost)
-
if print_cost and i%100==0:
-
print('迭代次数:%i.误差值:%f' %(i,cost))
-
#组装数据
-
params={'w':w,'b':b}
-
return (params,costs)
-
-
#建立预测函数
-
-
def predict(w,b,X):
-
value=sigmod(np.dot(w.T,X)+b)
-
Y_prediction=(value>0.5)+0
-
-
'''''
-
对于上一代码详解
-
value>0.5是个判断语句,>0.5会返回True
-
+0.是让布尔值转化成数字,1
-
-
'''
-
return Y_prediction
-
-
-
#下面是整合所有函数了
-
def model(X_train,Y_train,X_test,Y_test,num_iterations=2000,learning_rate=0.01,print_cost=False):
-
#先调用X_train,Y_train,来训练处w,b
-
m=X_train.shape[1]
-
w,b=initialize(X_train.shape[0])
-
params,costs=optimize(w,b,X_train,Y_train,num_iterations,learning_rate,print_cost)
-
w,b=params['w'],params['b']
-
-
#计算预测值
-
Y_prediction_train=predict(w,b,X_train)
-
Y_prediction_test=predict(w,b,X_test)
-
-
#比较
-
print('TrainRightRate:',format(100-np.mean(np.abs(Y_prediction_train-Y_train))*100),'%')
-
print('TestRightRate:',format(100-np.mean(np.abs(Y_prediction_test-Y_test))*100),'%')
-
-
'''''
-
上面代码详解
-
abs(Y_p-T_r),此处两相比较,相同,预测对了,则详减为0,预测错了,则为1或者-1
-
abs,全部取正
-
mean,平均值,即有多少个+-1在所有数据中,即在所有数据中错误的个数/总数据
-
我要的是正确率,所以前面要用100来减
-
'''
-
#数据组装
-
d={
-
'costs':costs,
-
'Y_prediction_train':Y_prediction_train,
-
'Y_prediction_test':Y_prediction_test,
-
'w':w,
-
'b':b,
-
'learning_rate':learning_rate,
-
'num_iterations':num_iterations}
-
return d
-
-
#d=model(train_x,train_y,test_x,test_y,num_iterations=2000,learning_rate=0.005,print_cost=True)
-
-
-
'''''
-
上面就算是整个模型搭建完了,下面是可视化
-
表示迭代次数,学习率,与成本函数的关系
-
'''
-
-
learning_rate=[0.01,0.001,0.0001]
-
models={}
-
for i in learning_rate:
-
print ("learning rate is: " + str(i))
-
models[str(i)]=model(train_x,train_y,test_x,test_y,num_iterations=500,learning_rate=i)
-
print ('\n' + "-------------------------------------------------------" + '\n')
-
for i in learning_rate:
-
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()
代码笔记
-
从另外一个文件中导入py文件中的某个函数
import sys
sys.path.append(r'path')
from lr_utils import load_datasert
-
记住X要组装成(n,m)矩阵,w是一个(n,1)的列向量
有利于记住使用np.dot()时,哪个放前面,哪个放后面,也 有利于广播时是否需要转置的判断
-
数据处理
本例子中是将每个元/255,让[0,255],的数据计算,变成了[0,1]的数据计算,加快计算
还有很多其他的数据处理方式,还没学到,多做多学
-
np.reshape(a,-1)中-1的妙用,只要把一个数组的行写出来了,列向量可以使用-1,让计算机自动计算分配,只要是负值就行
-
w-=learning_rate*dw 不知道为什么不能使用,需要常规操作,w=w-learning_rate*dw
-
A and B,两个判断,只要有一个是False,那整个语句就是错的,本例子,使用and来控制是否输出迭代次数与误差
-
布尔值转数字 让布尔值'+0'就行了,numpy对于判断语句,也是并行运行的
-
对于同类型的数据,多用字典dict组装,如梯度,初始值
-
np.squeeze()函数,将(5,1,1)转换成(5,)降维处理,有利于运行,也是可视化操作时,作为输入时,不可缺少的操作
>>> a=np.random.randn(10000,1,1,1,1)
>>> sys.getsizeof(a)
80160
>>> b=np.random.randn(10000)
>>> sys.getsizeof(b)
80096
-
可视化操作中,参数解释:loc:选择把线型说明放在哪个地方,shadow,是否加营养
frame.set_facecolor('0.9'),给说明的地方加了框之后,再选择填充框的透明度
-
使用'''作解释时,也需要遵循Python的缩进格式,否则会报错
-
空一行 print('\n')