2020.4.22
首先來總結 李宏毅2020機器學習 Logistic Regression部分
(小部分內容摘抄自:
the github page is: https://Sakura-gh.github.io/ML-notes)
視頻加思考總共兩邊纔算有所理解。
上一次結束時,提出了問題,有沒有可能找到一個不那麼麻煩的方法找到w和b。
使用最大似然估計的思想,將各個樣本出現的概率相乘然後求得最大值即可。將這個式子化簡之後,就到得了一個新的loss function:
這個式子的意義在直觀上也很好理解,就是當訓練樣本的標記值爲1時,括號內前一項起作用,當訓練樣本的標記值爲0時,則是後一項起作用。作用在ln之內的,其實就是sigmoid函數,也就是表示這件事情出現的概率,概率越小則數值越大,也就意味着要輔助的代價就越大,反之則相反。
這個式子其實就是交叉熵,表示的是兩個分佈有多接近。
再使用梯度下降法就可以進行數據更新,然後找到最合適的w和b了。有趣的是,對這裏的loss function求導,得到的結果和線性迴歸中的導數是一樣的,說明二者有相同的參數更新方式。
這裏是二者的比較:
再來思考一個問題,爲什麼對數機率迴歸要使用交叉熵來作爲loss function而不像線性迴歸一樣使用方差的和來作爲loss function。可以先假設使用方差和的情況,這種情況下對loss function求導,得到的結果如下:
這個式子明顯是有問題的,如果第n個點的目標target是1,則,此時如果function的output 爲1的話,說明現在離target很接近了,於是得到的微分會變成0,這件事情是很合理的;但是當function的output爲 0的時候,說明離target還很遙遠,但是由於在上中求出來的update表達式中有一個f(x),因此這個時候也會導致得到的微分變成0。
也就是說,這種情況下有着極大的誤差,應該使用極大的代價來彌補,所以在梯度下降中,這一步應該邁得很大,但是若果是上式,這種情況則無法下降。所以我們要使用交叉熵而不是方差和。
上一次學習的分類方法叫Generative,就是需要求出mu和sigma的那個方法。這次學習的方法叫Discriminative,不需要求出mu和sigma便可求出w和b。二者有什麼區別呢?
這裏首先要提到的概念叫‘腦補’,意思是你看到一件事,你也許就很依靠自己的想象來補齊這件事的前因後果,正常人其實應該都有體會。二者的區別其實就在於此,Discriminative其實就是完全按照現有數據就行學習,來找到最佳的w和b,而Generative則是要根據現有數據,通過學習腦補出來一個數據的分佈,然後再得到mu和sigma,再求出w和b。這一塊根據二者的推導過程,很容易明白。
所以,對於數據量較大的樣本總體來說,就可以使用Discriminative的方法,因爲數據量已經足夠大,很能反映樣本的真實分佈了,不需要再去腦補什麼。而對於樣本總量較小的樣本總體來說,腦補就顯得很關鍵,因爲樣本總體不能很好地反映樣本的分佈情況,Generative的方法效果會更好。
所以,Generative model和discriminative model的差別就在於,Generative的model它有做了某些假設,假設你的data來自於某個概率模型;而Discriminative的model是完全不作任何假設的。
多分類問題直接參見 https://Sakura-gh.github.io/ML-notes
老師還提到,對數機率迴歸其實使用侷限性的,李宏毅老師也指出了一個Feature Transformation的方法,具體也參見 https://Sakura-gh.github.io/ML-notes,但是在吳恩達老師講解的機器學習中,可以使用更爲複雜的決策邊界來稍稍克服這一個問題。
然後將很多對數機率迴歸連載一起,就是構成了神經網絡(從對數機率迴歸推導過來的過程還是不是很理解)
後面就是深度學習!
2020.4.23
昨天的Python沒寫,今天一起寫了
學習了《Python編程 從入門到實踐》 第七章
第七章的內容是用戶輸入和while循環
input函數的使用方法如下,注意input函數返回的是字符串
name=input('tell me your name:')
#可使用int(),str()來轉換數據類型
while循環基本內容和其他的語言類似,break爲退出循環,continue爲重新執行循環。
while處理列表
names=['zhao','qian','sun','li','zhou']
while names:
...
#當列表非空則判斷爲True,可以一個一個取出,直到爲空
while 'qian' in names
...
#上面這個也可以循環,因爲他的判斷爲True
學習了《Python編程 從入門到實踐》 第八章
這一章的內容是函數
def hello()
...
def Hello(name)
...
def Hello(name,age)
...
#這些都是定義函數和向其傳遞參數的方法
傳遞參數時又分爲按位置傳遞和關鍵字傳遞:
def hello(name,age)
...
hello(name='su',age='25')#關鍵字傳遞
hello('su','25')#位置傳遞
設定默認值:
def hello(name='su',age='26')
...
設定返回值
def hello(name)
...
return sth
message=hello('su')
#返回的值可以使字符串、數,也可以是列表、字典
讓參數變爲可選參數
def hello(name,age,sex='')
...#後面加上對最後一個參數的if判斷即可
#python中默認空字符串爲False
傳遞任意數量的實參:
def hello(*toppings)
...
#*toppings 其實就是創建名爲toppings的空元祖
#也可以用**toppings創建一個空字典
後面還學習了導入模塊
import time
import time as t #這是給time模塊重新命名
掌握這兩種足以。
2020.4.24
學習了《Python編程 從入門到實踐》 第九章
類。
個人覺得,類的功能和第三方庫的功能是很像的,存儲在別的文件中也是使用import調用,下面是練習用的一段程序:
class Restaurant():
def __init__(self,r_name,r_type):
self.r_name=r_name
self.r_type=r_type
self.r_num=0
def describer(self):
print('name: '+self.r_name)
print('type: '+self.r_type)
print('people: '+str(self.r_num))
def openr(self):
print('the restuarant is opening')
def set_num(self,n):
self.r_num=n
def add_num(self,n):
if self.r_num+n >= 100:
more=self.r_num+n-100
print('more than 100 people,'+str(more)+' people should get out')
else:
self.r_num=self.r_num+n
class Ice(Restaurant):
def __init__(self,r_name,r_type):
super().__init__(r_name,r_type)
self.flavor='a'
def inf(self):
print('name: '+self.r_name)
print('type: '+self.r_type)
print('people: '+str(self.r_num))
print('ice flavor: '+self.flavor)
r= Ice('okk','chuancai')
r.set_num(44)
r.add_num(60)
r.inf()
執行的結果是:
more than 100 people,4 people should get out
name: okk
type: chuancai
people: 44
ice flavor: a
對其中的程序進行說明,首先是使用class來定義一個類,其中的第一個函數必須是初始化函數,在這裏使用前後雙下劃線的命名方式來定義這個初始化函數,是一種約定俗成的方式,初始化函數在創建一個類時會自動運行。形參self必不可少,切必須在第一位,self由系統自動傳遞參數,他是一個指向實例本身的引用。剩下的函數就和定義普通函數一樣,但是要加入self。
下一段是一個繼承類,也就是一個子類。定義時括號內要寫入父類的名稱。初始化時要加入super()函數,定義方法見代碼。super()的用途就是繼承父類。創建子類時,子類必須在父類的後面。
這一部分對於我來說是新內容,所以後面還會再挑時間去深究、熟練。
2020.4.26
學習了《Python編程 從入門到實踐》 第十章
這一章的主要內容是用python處理文件和異常。
首先是打開文件和讀取文件:
with open('pi.txt') as file_obj:
c=file_obj.read()
print(c)
#引號內可以使相對路徑也可以是絕對路徑
#使用關鍵字with,python可以在你不需要文件時將它自動關閉,省心一些
#.read()是將文件讀取爲一個長字符串
以行的形式讀取文件:
with open('pi.txt') as file_obj:
for line in file_obj:
print(line)
或者
with open('pi.txt') as file_obj:
c=file_obj.readlines()
for line in c:
print(line.strip())
#第一個方法是直接for循環遍歷文件,這裏的for遍歷是按行遍歷的
#第二種方法是將文件按行存儲在一個列表中
接下來使寫入文件:
with open('pi.txt','w') as file_obj:
file_obj.write('ni hao')
#程序是向pi.txt中寫入ni hao
#‘w’是寫標誌,除此之外還有:‘r’讀,‘a’附加,‘r+’讀寫
#注意,修改已有文件不能用‘w’ 要用‘a’
接下來是異常處理部分:
#通常使用try&except
a=4
b=0
try:
f=a/b
except:
print('you cant divide by zero!')
else:
print(f)
#這樣出現錯誤時,就會顯示你自己設定的提示了
此外還學習了一個函數split(),他可以把文本按空格分割成元素,然後儲存到列表中。
如果在處理異常時,想要得到‘失敗時一聲不吭’的效果,那麼這樣做:
a=4
b=0
try:
f=a/b
except:
#print('you cant divide by zero!')
pass
else:
print(f)
接下來是存儲數據的部分:
import json
num=[2,3,4]
filename='nums.json'
with open(filename,'w') as f_obj:
json.dump(num,f_obj)
#創建一個叫nums的文件,然後把num寫入
import json
filename='nums.json'
with open(filename) as f_obj:
nums=json.load(f_obj)
#這樣就把num.json中的文件讀取到nums中了