文主要介紹通過DashVector和ModelScope中的Chinese Clip模型實現文搜圖、圖搜圖等功能,同時結合DashText SDK實現sparse vector+dense vector混合檢索,熟悉sparse vector的使用方法,提高檢索效率。
pip install dashvector
pip install dashtext
pip install modelscope
由于安裝ModelScope SDK需要一些依賴,繼續安裝,安裝的時間有點長,請耐心等待~~~~~
pip install decord
pip install torch torchvision opencv-python timm librosa fairseq transformers unicodedata2 zhconv rapidfuzz
由于本教程中,會使用DashText的sdk生成稀疏向量,生成稀疏向量過程中會先下載一個詞包,下載過程比較長。所以可以預先下載。
wget https://dashvector-data.oss-cn-beijing.aliyuncs.com/public/sparsevector/bm25_zh_default.json
好啦,SDK和依賴都安裝完了,下面簡單介紹一下多模態搜索的過程。
[{
"query_id": "54372",
"query": "金屬產品打印",
"image_id": "813904",
"image": <PIL.PngImagePlugin.PngImageFile image mode=RGB size=224x224 at 0x7F8EB1F39DB0>
},
{
"query_id": "78633",
"query": "夾棉帽子",
"image_id": "749842",
"image": <PIL.PngImagePlugin.PngImageFile image mode=RGB size=224x224 at 0x7F8EB0AFFF70>
}]
from dashvector import Client
# 如下填寫您在1.2 準備工作中獲取的DashVector API-KEY
DASHVECTOR_API_KEY='{YOUR DashVector API-KEY}'
# 如下填寫您在1.2 準備工作中獲取的DashVector中Cluster中的Endpoint
DASHVECTOR_END_POINT='{YOUR DashVector Endpoint}'
# 初始化DashVector 的client
client=Client(api_key=DASHVECTOR_API_KEY, endpoint=DASHVECTOR_END_POINT)
response=client.create(
# Collection的名稱,名稱可自定義。這里暫時定義為:ImageTextSearch
name='ImageTextSearch',
# 創建Collection的維度,注意一定是1024維。因為后面我們會使用Chinese Clip模型進行embedding,Chinese Clip模型的輸出維度是1024維。
dimension=1024,
# 距離度量方式一定為dotproduct,因為稀疏向量只支持dotproduc這種度量方式。
metric='dotproduct',
dtype=float,
# 定義schema,通過schema可以定義Collection中包含哪些字段,以及字段的類型,以便實現更快速的搜索。這里定義了image_id、query和query_id三個schema。
# 關于Schema的詳細使用請參考:https://help.aliyun.com/document_detail/2510228.html
fields_schema={'image_id': int, 'query': str, 'query_id': int}
)
print(response)
好啦,Collection創建成功了。
# 首先import一大堆東西
from modelscope.msdatasets import MsDataset
from modelscope.utils.constant import Tasks
from modelscope.pipelines import pipeline
import base64
import io
from dashvector import Client, Doc, DashVectorCode, DashVectorException
from dashtext import SparseVectorEncoder
# load 數據集,選取modelscope中的muge數據集,取數據集中validation部分
# muge數據集的格式為:
# [{
# "query_id": "54372",
# "query": "金屬產品打印",
# "image_id": "813904",
# "image": <PIL.PngImagePlugin.PngImageFile image mode=RGB size=224x224 at 0x7F8EB1F39DB0>
# },
# {
# "query_id": "78633",
# "query": "夾棉帽子",
# "image_id": "749842",
# "image": <PIL.PngImagePlugin.PngImageFile image mode=RGB size=224x224 at 0x7F8EB0AFFF70>
# }]
# 首次load muge數據集有點慢,請耐心等待。
datasets=MsDataset.load("muge", split="validation")
# 獲取數據集的長度,也就是數據集中有多少個這樣的數據
datasets_len=len(datasets)
# 初始化ModelScope推理pipeline,本教程使用Chinese Clip作為embedding模型。由于圖片的Embedding比較消耗計算資源,所以推薦使用GPU進行推理加速。
# 請參考:https://modelscope.cn/models/iic/multi-modal_clip-vit-huge-patch14_zh/summary
pipeline=pipeline(task=Tasks.multi_modal_embedding,
model='damo/multi-modal_clip-vit-huge-patch14_zh', model_revision='v1.0.0')
# 初始化稀疏向量編碼器,用于對muge數據集中的query進行稀疏向量編碼,中文編碼。詳情請參考:https://help.aliyun.com/document_detail/2546039.html
encoder=SparseVectorEncoder()
# encoder初始化的時間比較長,主要原因在于稀疏向量編碼器需要加載一個json文件,該文件比較大,需要下載。我們可以先下載完,保存在本地,直接加載,速度會快很多。
# 下載鏈接:https://dashvector-data.oss-cn-beijing.aliyuncs.com/public/sparsevector/bm25_zh_default.json
# 也可以使用:wget https://dashvector-data.oss-cn-beijing.aliyuncs.com/public/sparsevector/bm25_zh_default.json,直接下載到本地。
# 下載完成后,放在本機目錄中,本教程已經下載完成,放在根目錄下。
encoder_path='bm25_zh_default.json'
encoder.load(encoder_path)
# 如下填寫您在1.2 準備工作中獲取的DashVector API-KEY
DASHVECTOR_API_KEY='{YOUR DashVector API-KEY}'
# 如下填寫您在1.2 準備工作中獲取的DashVector中Cluster中的Endpoint
DASHVECTOR_END_POINT='{YOUR DashVector Endpoint}'
# 初始化dashvector的Client,用于訪問dashvector服務
# 請參考:https://help.aliyun.com/document_detail/2510240.html
client=Client(api_key=DASHVECTOR_API_KEY, endpoint=DASHVECTOR_END_POINT)
# 將圖片轉成字符串,用于將圖片存儲在dashvector中
def image_to_str(image):
image_byte_arr=io.BytesIO()
image.save(image_byte_arr, format='PNG')
image_bytes=image_byte_arr.getvalue()
return base64.b64encode(image_bytes).decode()
# 通過Chinese Clip提取圖片特征,并轉成向量
def image_vector(image):
# 通過Chinese Clip提取圖片特征,返回為一個tensor
img_embedding=pipeline.forward({'img': image})['img_embedding']
# 將返回的tensor轉成向量,向量需要轉存到cpu中
img_vector=img_embedding.detach().cpu().numpy()
return img_vector if isinstance(image, list) else img_vector[0]
# 通過Chinese Clip提取文本特征,并轉成向量
def text_vector(text):
# 通過Chinese Clip提取文本特征,返回為一個tensor
text_embedding=pipeline.forward({'text': text})['text_embedding']
# 將返回的tensor轉成向量,向量需要轉存到cpu中
text_vector=text_embedding.detach().cpu().numpy()
return text_vector if isinstance(text, list) else text_vector[0]
# 通過dashtext對文本生成稀疏向量。注意,本函數為生成入庫的稀疏向量,而不是query的稀疏向量
def sparse_vector_documents(text):
# 通過dashtext生成稀疏向量
sparse_vector=encoder.encode_documents(text)
return sparse_vector if isinstance(text, list) else sparse_vector
# 插入向量數據,batch_size默認為10,最大不超過20
def insert_docs(collection_name: str, partition='default', batch_size=10):
idx=0
while idx < datasets_len:
# 獲取batch range數據
batch_range=range(idx, idx + batch_size) if idx + batch_size < datasets_len else range(idx, datasets_len)
# 獲取image信息
images=[datasets[i]['image'] for i in batch_range]
# 通過Chinese Clip提取圖片特征,返回為一個vector
images_vector=image_vector(images)
# 獲取query信息
texts=[datasets[i]['query'] for i in batch_range]
# 生成稀疏向量
documents_sparse_vector=sparse_vector_documents(texts)
# 獲取圖片ID和query ID
images_ids=[datasets[i]['image_id'] for i in batch_range]
query_ids=[datasets[i]['query_id'] for i in batch_range]
# 獲取Collection
collection=client.get(collection_name)
# 批量插入
response=collection.upsert(
[
Doc(
id=image_id,
vector=img_vector,
sparse_vector=document_sparse_vector,
fields={
# 由于在創建Collection時,image_id和query_id都是int類型,所以這里需要轉換為int類型
'image_id': int(image_id),
'query_id': int(query_id),
'query': query,
# 將Image格式轉成字符串,用于存儲在dashvector中
'image': image_to_str(image)
}
) for img_vector, document_sparse_vector, image_id, query_id, image, query in
zip(images_vector, documents_sparse_vector, images_ids, query_ids, images, texts)
]
)
print(response)
idx +=batch_size
return response
if __name__=='__main__':
# 插入數據
response=insert_docs(collection_name='ImageTextSearch', batch_size=20)
# 老規矩,先import一堆東西
from modelscope.utils.constant import Tasks
from modelscope.preprocessors.image import load_image
from modelscope.pipelines import pipeline
from PIL import Image
import base64
import io
from dashvector import Client, Doc, DashVectorCode, DashVectorException
from dashtext import SparseVectorEncoder, combine_dense_and_sparse
from urllib.parse import urlparse
# 初始化ModelScope推理pipeline,本教程使用Chinese Clip作為embedding模型。由于圖片的Embedding比較消耗計算資源,所以推薦使用GPU進行推理加速。
# 請參考:https://modelscope.cn/models/iic/multi-modal_clip-vit-huge-patch14_zh/summary
pipeline=pipeline(task=Tasks.multi_modal_embedding,
model='damo/multi-modal_clip-vit-huge-patch14_zh', model_revision='v1.0.0')
# 初始化稀疏向量編碼器,用于對muge數據集中的query進行稀疏向量編碼,中文編碼。詳情請參考:https://help.aliyun.com/document_detail/2546039.html
encoder=SparseVectorEncoder()
# encoder初始化的時間比較長,主要原因在于稀疏向量編碼器需要加載一個json文件,該文件比較大,需要下載。我們可以先下載完,保存在本地,直接加載,速度會快很多。
# 下載鏈接:https://dashvector-data.oss-cn-beijing.aliyuncs.com/public/sparsevector/bm25_zh_default.json
# 也可以使用:wget https://dashvector-data.oss-cn-beijing.aliyuncs.com/public/sparsevector/bm25_zh_default.json,直接下載到本地。
# 下載完成后,放在本機目錄中,本教程已經下載完成,放在根目錄下。
encoder_path='bm25_zh_default.json'
encoder.load(encoder_path)
# 如下填寫您在1.2 準備工作中獲取的DashVector API-KEY
DASHVECTOR_API_KEY='{YOUR DashVector API-KEY}'
# 如下填寫您在1.2 準備工作中獲取的DashVector中Cluster中的Endpoint
DASHVECTOR_END_POINT='{YOUR DashVector Endpoint}'
# 初始化dashvector的Client,用于訪問dashvector服務
# 請參考:https://help.aliyun.com/document_detail/2510240.html
client=Client(api_key=DASHVECTOR_API_KEY, endpoint=DASHVECTOR_END_POINT)
# 將字符串轉為圖片
def str2image(image_str):
image_bytes=base64.b64decode(image_str)
return Image.open(io.BytesIO(image_bytes))
# 判斷是否為URL
def is_url(url):
try:
result=urlparse(url)
return all([result.scheme, result.netloc])
except ValueError:
return False
# 通過Chinese Clip提取圖片特征,并轉成向量
def image_vector(image):
# 通過Chinese Clip提取圖片特征,返回為一個tensor
img_embedding=pipeline.forward({'img': image})['img_embedding']
# 將返回的tensor轉成向量,向量需要轉存到cpu中
img_vector=img_embedding.detach().cpu().numpy()
return img_vector if isinstance(image, list) else img_vector[0]
# 通過Chinese Clip提取文本特征,并轉成向量
def text_vector(text):
# 通過Chinese Clip提取文本特征,返回為一個tensor
text_embedding=pipeline.forward({'text': text})['text_embedding']
# 將返回的tensor轉成向量,向量需要轉存到cpu中
text_vector=text_embedding.detach().cpu().numpy()
return text_vector if isinstance(text, list) else text_vector[0]
# 通過dashtext對文本生成稀疏向量。注意,本函數為query的稀疏向量,而不是入庫的稀疏向量
def sparse_vector_queries(text):
# 通過dashtext生成稀疏向量
sparse_vector=encoder.encode_queries(text)
return sparse_vector if isinstance(text, list) else sparse_vector
# 通過文本和圖片搜索圖片,返回搜索結果。其中,文本會轉換為稀疏向量,圖片會轉換成稠密向量,并通過alpha值控制稠密向量和稀疏向量的權重,alpha=1.0則全部使用稠密向量搜索,alpha=0.0則全部使用稀疏向量搜索
def serach_by_imageAndtext(query_text, query_image, collection_name, partition='default', top_k=10, alpha=0.5):
if is_url(query_image):
query_image=load_image(query_image)
image_embedding=image_vector(query_image)
query_sparse_embedding=sparse_vector_queries(query_text)
scaled_dense_vector, scaled_sparse_vector=combine_dense_and_sparse(image_embedding, query_sparse_embedding, alpha)
try:
collection=client.get(name=collection_name)
# 搜索
docs=collection.query(
vector=scaled_dense_vector,
sparse_vector=scaled_sparse_vector,
partition=partition,
topk=top_k,
output_fields=['image', 'query', 'image_id']
)
image_list=list()
for doc in docs:
image_str=doc.fields['image']
# print(doc.score)
# print(doc.fields['query'])
# print(doc.fields['image_id'])
image_list.append(str2image(image_str))
return image_list
except DashVectorException as e:
print(e)
return []
# 通過文本搜索圖片,返回搜索結果,并將文本變成對應的稀疏向量和稠密向量,稀疏向量用來控制文本中是否包含該關鍵詞,稠密向量用于控制圖片中是否包含此信息。可通過alpha值控制稠密向量和稀疏向量的權重,alpha=1.0則全部使用稠密向量搜索,alpha=0.0則全部使用稀疏向量搜索
def search_by_text(query_text, collection_name, partition='default', top_k=10, alpha=0.5):
query_embedding=text_vector(query_text)
print(query_embedding)
print(type(query_embedding))
print(query_embedding.dtype)
query_sparse_embedding=sparse_vector_queries(query_text)
scaled_dense_vector, scaled_sparse_vector=combine_dense_and_sparse(query_embedding, query_sparse_embedding, alpha)
try:
collection=client.get(name=collection_name)
# 搜索
docs=collection.query(
vector=scaled_dense_vector,
sparse_vector=scaled_sparse_vector,
partition=partition,
topk=top_k,
output_fields=['image', 'query', 'image_id']
)
image_list=list()
for doc in docs:
image_str=doc.fields['image']
# print(doc.score)
# print(doc.fields['query'])
# print(doc.fields['image_id'])
image_list.append(str2image(image_str))
return image_list
except DashVectorException as e:
print(e)
return []
if __name__=='__main__':
query_text='女士帽子'
query_image='https://cbu01.alicdn.com/img/ibank/O1CN01XjQLIb2JjMX6sVhn7_!!2217497569457-0-cib.jpg?__r__=1711033209457'
# response=search_by_text(query_text=query_text, collection_name='ImageTextSearch', alpha=1.0)
response=serach_by_imageAndtext(query_text=query_text, query_image=query_image, collection_name='ImageTextSearch',
top_k=20, alpha=0.8)
for image in response:
image.show()
譯:張逸
校對:馮羽
本文約2804字,建議閱讀7分鐘。
當你在Keras中選擇好最合適的深度學習模型,就可以用它在新的數據實例上做預測了。但是很多初學者不知道該怎樣做好這一點,我經常能看到下面這樣的問題:
“我應該如何用Keras對我的模型作出預測?”
在本文中,你會學到如何使用Keras這個Python庫完成深度學習模型的分類與回歸預測。
看完這篇教程,你能掌握以下幾點:
現在就讓我們開始吧
本文結構
教程共分為三個部分,分別是:
模型確定
在做預測之前,首先得訓練出一個最終的模型。你可能選擇k折交叉驗證或者簡單劃分訓練/測試集的方法來訓練模型,這樣做的目的是為了合理估計模型在樣本集之外數據上的表現(新數據)
當評估完成,這些模型存在的目的也達到了,就可以丟棄他們。接下來,你得用所有的可用數據訓練出一個最終的模型。關于這方面的內容,你可以在下面這個文章中得到更多的信息:
https://machinelearningmastery.com/train-final-machine-learning-model/
分類預測
對于分類問題,模型學習的是一個輸入特征到輸出特征之間的映射,這里的輸出即為一個標簽。比如“垃圾郵件”和“非垃圾郵件”
下邊是Keras中為簡單的二分類問題開發的神經網絡模型的一個例子。如果說你以前沒有接觸過用Keras開發神經網絡模型的話,不妨先看看下邊這篇文章:
https://machinelearningmastery.com/tutorial-first-neural-network-python-keras/
# 訓練一個最終分類的模型
from keras.models import Sequential
from keras.layers import Dense
from sklearn.datasets.samples_generator import make_blobs
from sklearn.preprocessing import MinMaxScaler
# 生成一個二分類問題的數據集
X, y=make_blobs(n_samples=100, centers=2, n_features=2, random_state=1)
scalar=MinMaxScaler()
scalar.fit(X)
X=scalar.transform(X)
# 定義并擬合模型
model=Sequential()
model.add(Dense(4, input_dim=2, activation='relu'))
model.add(Dense(4, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam')
model.fit(X, y, epochs=200, verbose=0)
建立好這個模型后,可能需要將它保存到文件中(比如通過Keras的相關API)。以后你就可以隨時加載這個模型,并用它進行預測了。有關這方面的示例,可以參考下邊的文章:
https://machinelearningmastery.com/save-load-keras-deep-learning-models/
為了本文的結構更簡潔,我們的例子中省去了這個步驟。
繼續說回到分類預測的問題。我們希望最終得到的模型能進行兩種預測:一是判斷出類別,二是給出屬于相應類別概率。
一個類別預測會給定最終的模型以及若干數據實例,我們利用模型來判斷這些實例的類別。對于新數據,我們不知道輸出的是什么結果,這就是為什么首先需要一個模型。
在Keras中,可以利用predict_class()函數來完成我們上述所說的內容----即利用最終的模型預測新數據樣本的類別。
需要注意的是,這個函數僅適用于Sequential模型,不適于使用功能式API開發的模型。(not those models developed using the functional API.)
比如,我們在名為Xnew的數組中有若干個數據實例,它被傳入predict_classes()函數中,用來對這些數據樣本的類別進行預測。
Xnew=[[...], [...]]
ynew=model.predict_classes(Xnew)
讓我們用一個更具體的例子來說明:
# 建立一個新的分類模型
from keras.models import Sequential
from keras.layers import Dense
from sklearn.datasets.samples_generator import make_blobs
from sklearn.preprocessing import MinMaxScaler
# 生成二分類數據集
X, y=make_blobs(n_samples=100, centers=2, n_features=2, random_state=1)
scalar=MinMaxScaler()
scalar.fit(X)
X=scalar.transform(X)
# 定義并擬合最終模型
model=Sequential()
model.add(Dense(4, input_dim=2, activation='relu'))
model.add(Dense(4, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam')
model.fit(X, y, epochs=500, verbose=0)
# 新的未知數據實例
Xnew, _=make_blobs(n_samples=3, centers=2, n_features=2, random_state=1)
Xnew=scalar.transform(Xnew)
# 作出預測
ynew=model.predict_classes(Xnew)
# 顯示輸入和輸出
for i in range(len(Xnew)):
print("X=%s, Predicted=%s" % (Xnew[i], ynew[i]))
下面是對三個實例預測的結果,我們將數據和預測結果一并輸出:
X=[0.89337759 0.65864154], Predicted=[0]
X=[0.29097707 0.12978982], Predicted=[1]
X=[0.78082614 0.75391697], Predicted=[0]
如果你只有一個新的實例,那就需要將它包裝一下,變成一個數組的形式。以便傳給predict_classes()函數,比如這樣:
from keras.models import Sequential
from keras.layers import Dense
from sklearn.datasets.samples_generator import make_blobs
from sklearn.preprocessing import MinMaxScaler
from numpy import array
# 生成一個二分類數據集
X, y=make_blobs(n_samples=100, centers=2, n_features=2, random_state=1)
scalar=MinMaxScaler()
scalar.fit(X)
X=scalar.transform(X)
# 定義并擬合最終的新模型
model=Sequential()
model.add(Dense(4, input_dim=2, activation='relu'))
model.add(Dense(4, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam')
model.fit(X, y, epochs=500, verbose=0)
# 未知的新實例
Xnew=array([[0.89337759, 0.65864154]])
# 作出預測
ynew=model.predict_classes(Xnew)
# 顯示輸入輸出
print("X=%s, Predicted=%s" % (Xnew[0], ynew[0]))
運行上邊這個例子,會得到對這個單獨實例的預測結果
X=[0.89337759 0.65864154], Predicted=[0]
準備數據時,應該將其中的類別標簽轉換為整數表示(比如原始數據類別可能是一個字符串),這時候你就可能會用到sklearn中的LabelEncoder。
http://scikitlearn.org/stable/modules/generated/sklearn.preprocessing.LabelEncoder.html#sklearn.preprocessing.LabelEncoder
當然,在我們使用LabelEcoder中的函數inverse_transform()時,還可以將那些整數表示的類別標簽轉換回去。
因為這個原因,在擬合最終模型時,你可能想要保存用于編碼y值的LabelEncoder結果。
概率預測
另外一種是對數據實例屬于某一類的可能性進行預測。它被稱為“概率預測”,當給定一個新的實例,模型返回該實例屬于每一類的概率值。(0-1之間)
在Keras中,我們可以調用predict_proba()函數來實現。舉個例子:
Xnew=[[...], [...]]
ynew=model.predict_proba(Xnew)
在二分類問題下,Sigmoid激活函數常被用在輸出層,預測概率是數據對象屬于類別1的可能性,或者屬于類別0的可能性(1-概率)
在多分類問題下,則是softmax激活函數常被用在輸出層。數據對象屬于每一個類別的概率作為一個向量返回。
下邊的例子對Xnew數據數組中的每個樣本進行概率預測。
from keras.models import Sequential
from keras.layers import Dense
from sklearn.datasets.samples_generator import make_blobs
from sklearn.preprocessing import MinMaxScaler
# 生成二分類數據集
X, y=make_blobs(n_samples=100, centers=2, n_features=2, random_state=1)
scalar=MinMaxScaler()
scalar.fit(X)
X=scalar.transform(X)
# 定義并擬合出最終模型
model=Sequential()
model.add(Dense(4, input_dim=2, activation='relu'))
model.add(Dense(4, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam')
model.fit(X, y, epochs=500, verbose=0)
# 新的未知數據
Xnew, _=make_blobs(n_samples=3, centers=2, n_features=2, random_state=1)
Xnew=scalar.transform(Xnew)
# 做預測
ynew=model.predict_proba(Xnew)
# 顯示輸入輸出
for i in range(len(Xnew)):
print("X=%s, Predicted=%s" % (Xnew[i], ynew[i]))
我們運行這個實例,并將輸入數據及這些實例屬于類別1的概率打印出來:
X=[0.89337759 0.65864154], Predicted=[0.0087348]
X=[0.29097707 0.12978982], Predicted=[0.82020265]
X=[0.78082614 0.75391697], Predicted=[0.00693122]
回歸預測
回歸預測是一個監督學習問題,該模型學習一個給定輸入樣本到輸出數值的映射。比如會輸出0.1或0.2這樣的數字。
下邊是一個Keras回歸的模型。
# 訓練一個回歸模型的例子
from keras.models import Sequential
from keras.layers import Dense
from sklearn.datasets import make_regression
from sklearn.preprocessing import MinMaxScaler
# 生成回歸數據集
X, y=make_regression(n_samples=100, n_features=2, noise=0.1, random_state=1)
scalarX, scalarY=MinMaxScaler(), MinMaxScaler()
scalarX.fit(X)
scalarY.fit(y.reshape(100,1))
X=scalarX.transform(X)
y=scalarY.transform(y.reshape(100,1))
# 定義并擬合模型
model=Sequential()
model.add(Dense(4, input_dim=2, activation='relu'))
model.add(Dense(4, activation='relu'))
model.add(Dense(1, activation='linear'))
model.compile(loss='mse', optimizer='adam')
model.fit(X, y, epochs=1000, verbose=0)
我們可以在最終的模型中調用predict()函數進行數值的預測。該函數以若干個實例組成的數組作為輸入參數。
下面的例子演示了如何對未知的多個數據實例進行回歸預測。
from keras.models import Sequential
from keras.layers import Dense
from sklearn.datasets import make_regression
from sklearn.preprocessing import MinMaxScaler
# 生成回歸數據集
X, y=make_regression(n_samples=100, n_features=2, noise=0.1, random_state=1)
scalarX, scalarY=MinMaxScaler(), MinMaxScaler()
scalarX.fit(X)
scalarY.fit(y.reshape(100,1))
X=scalarX.transform(X)
y=scalarY.transform(y.reshape(100,1))
# 定義并擬合模型
model=Sequential()
model.add(Dense(4, input_dim=2, activation='relu'))
model.add(Dense(4, activation='relu'))
model.add(Dense(1, activation='linear'))
model.compile(loss='mse', optimizer='adam')
model.fit(X, y, epochs=1000, verbose=0)
# 未知的新數據
Xnew, a=make_regression(n_samples=3, n_features=2, noise=0.1, random_state=1)
Xnew=scalarX.transform(Xnew)
# 作出預測
ynew=model.predict(Xnew)
# 顯示輸入輸出
for i in range(len(Xnew)):
print("X=%s, Predicted=%s" % (Xnew[i], ynew[i]))
運行上面那個多分類預測實例,然后將輸入和預測結果并排打印,進行對比。
X=[0.29466096 0.30317302], Predicted=[0.17097184]
X=[0.39445118 0.79390858], Predicted=[0.7475489]
X=[0.02884127 0.6208843 ], Predicted=[0.43370453]
同樣的,這個函數可以用于單獨實例的預測,前提是它們包裝成適當的格式。
舉例說明:
from keras.models import Sequential
from keras.layers import Dense
from sklearn.datasets import make_regression
from sklearn.preprocessing import MinMaxScaler
from numpy import array
# 生成回歸數據集
X, y=make_regression(n_samples=100, n_features=2, noise=0.1, random_state=1)
scalarX, scalarY=MinMaxScaler(), MinMaxScaler()
scalarX.fit(X)
scalarY.fit(y.reshape(100,1))
X=scalarX.transform(X)
y=scalarY.transform(y.reshape(100,1))
# 定義并擬合模型
model=Sequential()
model.add(Dense(4, input_dim=2, activation='relu'))
model.add(Dense(4, activation='relu'))
model.add(Dense(1, activation='linear'))
model.compile(loss='mse', optimizer='adam')
model.fit(X, y, epochs=1000, verbose=0)
# 新的數據
Xnew=array([[0.29466096, 0.30317302]])
# 作出預測
ynew=model.predict(Xnew)
# 顯示輸入輸出
print("X=%s, Predicted=%s" % (Xnew[0], ynew[0]))
運行實例并打印出結果:
X=[0.29466096 0.30317302], Predicted=[0.17333156]
延伸閱讀
這部分提供了一些相關的資料,如果你想更深入學習的話可以看一看。
How to Train a Final Machine Learning Model:
https://machinelearningmastery.com/train-final-machine-learning-model/
Save and Load Your Keras Deep Learning Models:
https://machinelearningmastery.com/save-load-keras-deep-learning-models/
Develop Your First Neural Network in Python With Keras Step-By-Step:
https://machinelearningmastery.com/tutorial-first-neural-network-python-keras/
The 5 Step Life-Cycle for Long Short-Term Memory Models in Keras:
https://machinelearningmastery.com/5-step-life-cycle-long-short-term-memory-models-keras/
How to Make Predictions with Long Short-Term Memory Models in Keras:
https://machinelearningmastery.com/make-predictions-long-short-term-memory-models-keras/
總結:
在本教程中,你知道了如何使用Keras庫通過最終的深度學習模型進行分類和回歸預測。
具體來說,你了解到:
對本文的內容有什么問題嗎?在下面的評論中提出來,我將盡我所能來回答。
原文鏈接:
https://machinelearningmastery.com/how-to-make-classification-and-regression-predictions-for-deep-learning-models-in-keras/
譯者簡介
張逸,中國傳媒大學大三在讀,主修數字媒體技術。對數據科學充滿好奇,感慨于它創造出來的新世界。目前正在摸索和學習中,希望自己勇敢又熱烈,學最有意思的知識,交最志同道合的朋友。
自Medium
機器之心編譯
參與:Nurhachu、蔣思源、吳攀
無監督學習是深度學習的圣杯。它的目的是希望能夠用極少量且不需要標注的數據訓練通用系統。本文將從無監督學習的基本概念開始再進一步簡述無監督學習的各個基礎算法及其優缺點。本文作者為專注機器人與視覺研究的 e-Lab 的研究者 Eugenio Culurciello。
如今深度學習模型都需要在大規模的監督數據集上訓練。這意味著對于每一個數據,都會有一個與之對應的標簽。在很流行的 ImageNet 數據集中,其共有一百萬張帶人工標注的圖片,即 1000 類中的每一類都有 1000 張。創建這么一個數據集是需要一番功夫的,可能需要很多人花數月的功夫完成。假定現在要創建一個有一百萬類的數據集,那么就必須給總共 1 億幀視頻數據集中的每一幀做標注,這基本是無法實現的。
現在,回想一下在你很小的時候,自己是如何得到教導的。沒錯,我們的確受到了一些監督,但是當你的父母告訴你這是一只「貓」之后,他們不會在日后的生活中每一次觀察到貓時都告訴你這是「貓」!而如今的監督式學習是這樣的:我一次又一次地告訴你「貓」是什么樣的,也許會重復一百萬次。然后你的深度學習模型就領會了關于貓的知識。
理想情況下,我們希望有一個更像我們的大腦一樣去運行得模型。它僅僅需要很少的一些標簽就能夠理解現實世界中的很多類事物。在現實世界中,我指的類是物體類別、動作類別、環境類別、物體的部分的類別,諸如此類還有很多很多。
正如你會在這篇評論中看到的一樣,最成功的模型就是那些能夠預測視頻中即將出現的畫面的模型。很多這類技術面臨并正嘗試解決的一個問題,即為了達到良好的全局表現,訓練要在視頻上進行,而不是靜態的圖片上。這是將學習到的表征應用在實際任務中的唯一途徑。
基本概念
無監督學習研究的主要目標就是要預訓練出能夠用于其他任務的模型(即鑒別器或者編碼器)。編碼器的特點應該盡可能的通用,以便可以用在分類任務中(如在 ImageNet 上進行訓練),并且提供盡可能像監督模型一樣好的結果。
最新的監督模型總是表現得比無監督預訓練模型更好。那是因為,監督會允許模型能夠更好的編碼數據集上的特征。但是當模型應用在其他的數據集上時,監督會衰減。在這方面,無監督訓練有希望提供更加通用的特性來執行任何任務。
如果以實際生活中的應用為目標,例如無人駕駛、動作識別、目標檢測和實時提取中的識別,那么算法需要在視頻上訓練。
自編碼器
UC Davis 的 Bruno Olshausen 和康奈爾大學的 David Field 于 1996 年的發表的論文《Sparse Coding with an Overcomplete Basis Set: A Strategy by V1?》(論文鏈接:http://redwood.psych.cornell.edu/papers/olshausen_field_1997.pdf) 表明,編碼理論可以被用在視覺皮層的接收域中。他們證明了我們大腦中的基本視覺旋渦 (V1) 使用稀疏性原理來創建一個能夠被用于重建輸入圖像的基本功能的最小集合。
下面的鏈接是 2014 年倫敦微軟 Bing 團隊的 Piotr Mirowski 關于自動編碼器的一個很好的綜述。
鏈接:https://piotrmirowski.files.wordpress.com/2014/03/piotrmirowski_2014_reviewautoencoders.pdf
Yann LeCun 的團隊也從事這個領域的研究。在鏈接網頁中的 demo 中,你可以看到像 V1 一樣的濾波器是如何學習的。(鏈接:http://www.cs.nyu.edu/~yann/research/deep/)
通過重復貪婪逐層訓練的過程,堆棧式自編碼器(Stacked-auto encoder)也被使用了。
自動編碼器方法也被稱為直接映射方法。
自動編碼器/稀疏編碼/堆疊式自動編碼的優點和缺點
優點:
簡單的技術:重建輸入
多層可堆疊
直觀和基于神經科學的研究
缺點
每一層都被貪婪地(greedily)訓練
沒有全局優化
比不上監督學習地性能
多層失效
對通用目標地表征而言,重建輸入可能不是理想的指標
聚類學習
它是用 k-means 聚類在多層中學習濾波器的一種技術。
我們組把這項技術命名為:聚類學習(見論文:Clustering Learning for Robotic Vision)、聚類連接 (見論文:An Analysis of the Connections Between Layers of Deep Neural Networks),以及卷積聚類 (見論文:Convolutional Clustering for Unsupervised Learning)。就在最近,這項技術在流行地無監督學習數據集 STL-10 上實現了非常好的結果。
我們在這個領域的研究和 Adam Coates 與 Andrew Ng 在基于 k-means 學習特征表示 ( Learning Feature Representations with K-means ) 中發表的研究成果是獨立的。
眾所周知,由于在求解配分函數時的數值問題,受限波爾茲曼機(RBM),深波爾茲曼機(DBM),深度信念網絡(DBN/參見 Geoffrey E. Hinton 等人的研究:A fast learning algorithm for deep belief net)等模型已經很難去訓練了。因此,它們沒有廣泛應用于解決問題中。
聚類學習的優缺點:
優點:
簡單的技術:得到相似群集的輸出
多層可堆疊
直觀和基于神經科學的研究
缺點:
每一層都被貪婪地訓練
沒有全局優化
在某些情況下可以和監督學習的性能媲美
多層遞增式失效==性能回報遞減
生成對抗網絡模型
生成對抗網絡嘗試通過鑒別器和生成器的對抗而得來一個優良的生成模型,該網絡希望能夠生成足以騙過鑒別器的逼真圖像。生成模型這一領域近年來十分優秀的生成對抗網絡正是由 Ian Goodfellow 和 Yoshua Bengio 等人在論文《Generative Adversarial Nets》中提出。這里還有 OpenAI 的研究員 Ian 在 2016 年底做的關于生成對抗網絡 (GANS) 的總結,視頻鏈接:https://channel9.msdn.com/Events/Neural-Information-Processing-Systems-Conference/Neural-Information-Processing-Systems-Conference-NIPS-2016/Generative-Adversarial-Networks。
由 Alec Radford、 Luke Metz 以及 Soumith Chintala 等人實例化的一個被稱作 DCGAN 的生成對抗模型取得了非常好的結果。他們的研究發表在論文:Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks。
Vincent Dumoulin 和 Ishmael Belghazi 等人對這個模型做了一個比較好的解釋(鏈接:https://ishmaelbelghazi.github.io/ALI/)。
DCGAN 鑒別器被設計來判斷一副輸入圖片是真實的(來源于某個數據集的真實圖片)或虛假的(來源于某個生成器)。生成器將隨機地噪聲向量(例如 1024 個數值)作為輸入,并生成一副圖片。
在 DCGAN 中,生成器網絡如下:
盡管這個鑒別器是一個標準的神經網絡。具體的細節可以參考下文提及的代碼。
關鍵是要并行地去訓練這兩個網絡,同時不要完全過擬合,因此才會復制數據集。學習到的特征需要泛化在未知的樣本上,所以學習數據集將不會有用。
在 Torch7 上訓練 DCGAN 的代碼(https://github.com/soumith/dcgan.torch)也被提供了。這需要大量的實驗,相關內容 Yann LeCun 在 Facebook 中也分享過:https://www.facebook.com/yann.lecun/posts/10153269667222143
當生成器和鑒別器都被訓練之后,你可以同時使用兩者。主要的目標就是訓練出一個能夠被用于其他任務的鑒別器網絡,例如在其他數據集上可以分類。生成器可以用來從隨機向量中生成圖片。這些圖片有著非常有趣的屬性。首先,它們從輸入空間中提供了平滑的變換。如下所示的例子展示了在 9 個隨機輸入向量中移動而生成的圖片:
輸入向量空間也提供了數學屬性,證明學習到的特征是按照相似性來組織的,如下圖所示:
生成器學習到的平滑空間啟示鑒別器也要有類似的屬性,這使得鑒別器在編碼圖像時成了一個很棒的通用特征提取器。這有助于解決 CNN 在訓練不連續圖像的時候由于對抗噪聲而造成的失敗(詳見 Christian Szegedy 等人的文章《Intriguing properties of neural networks》,https://arxiv.org/abs/1312.6199)。
GAN 最新的進展,在僅有 1000 個標簽樣本的 CIFAR-10 數據集上實現了 21% 的錯誤率,參見 OpenAI 的 Tim Salimans 等人的論文《Improved Techniques for Training GANs》,論文鏈接:https://arxiv.org/pdf/1606.03498v1.pdf。
最近關于 infoGAN 的論文《InfoGAN: Interpretable Representation Learning by Information Maximizing Generative Adversarial Nets》(鏈接:https://arxiv.org/abs/1606.03657)中,能夠產生特征非常清晰的圖像,并且這些圖像具有更加有趣的意義。然而,他們并沒有公布學習到的特征在某項任務或某個數據集中的性能對比。
在如下所示的博客和網站中也有關于生成對抗模型的總結,參見 OpenAI 的技術博客 https://blog.openai.com/generative-models/ 和網頁 https://code.facebook.com/posts/1587249151575490/a-path-to-unsupervised-learning-through-adversarial-networks/。
另一個非常有趣的例子如下,在例子中,作者用生成對抗訓練去學習從文本描述中生成圖像。參見論文《Generative Adversarial Text to Image Synthesis》,鏈接:https://arxiv.org/abs/1605.05396。
我最欣賞這項工作的地方在于它所使用的網絡用文本描述作為生成器的輸入,而不是隨機向量,這樣就可以精確地控制生成器的輸出。網絡模型結構如下圖所示:
生成對抗模型的缺點和優點
優點:
對整個網絡的全局訓練
易于編程和實現
缺點:
難以訓練和轉換問題
在某些情況下可以比得上監督學習的性能
需要提升可用性(這是所有無監督學習算法面臨的問題)
可以從數據中學習的模型
通過設計不需要標簽的無監督學習任務和旨在解決這些任務的學習算法,這些模型直接從無標簽的數據中學習。
在視覺表征中通過解決拼圖問題來進行無監督學習確實是一個聰明的技巧。作者將圖像分割成了拼圖,并且訓練深度網絡來解決拼圖問題。最終得到的網絡的表現足以比肩最好的預訓練網絡。詳見論文《Unsupervised Learning of Visual Representations by Solving Jigsaw Puzzles》,鏈接:https://arxiv.org/abs/1603.09246
在視覺表征中通過圖像補丁和布局來進行無監督學習也是一個聰明的技巧。他們讓同一幅圖像上的兩個補丁緊密分布。這些補丁在統計上來講是同一個物體。第三個補丁選擇隨機的圖像,并且布局在隨機的位置,從統計上來講與前兩個補丁并不是同一類物體。然后訓練一個深度網絡來區分兩個屬于同一類的補丁和另一個不同類別的補丁。最終得到的網絡具有和最高性能精調網絡之一相同的性能。詳情參見論文《Learning visual groups from co-occurrences in space and time》,鏈接:https://arxiv.org/abs/1511.06811。
從立體圖像重建中進行的無監督學習模型采用立體圖像作為輸入,例如圖像一幀的左半部分,然后重建出圖像的右半部分。雖然這項工作并不針對無監督學習,但是它可以用作無監督學習。這種方法也可以用來從靜態圖片生成 3D 電影。參見論文《Deep3D: Fully Automatic 2D-to-3D Video Conversion with Deep Convolutional Neural Networks》,鏈接:https://arxiv.org/abs/1604.03650,github 上的 Python 源碼:https://github.com/piiswrong/deep3d。
利用替代類別的無監督學習視覺表征使用圖像不行來創建非常大的替代類。這些圖像補丁然后被增強,然后被用來訓練基于增強替代類的監督網絡。這在無監督特征學習中給出了最好的結果。詳情參見論文《Discriminative Unsupervised Feature Learning with Exemplar Convolutional Neural Networks》,鏈接:https://arxiv.org/abs/1406.6909。
使用視頻的無監督學習視覺表征采用了基于 LSTM 的編碼器-解碼器對。編碼 LSTM 運行在視頻幀的序列上以生成一個內部表征。隨后這些表征通過另一個 LSTM 被解碼以生成一個目標序列。為了使這個變成無監督的,一種方法是預測與輸入相同的序列。另一種方式是預測未來的幀。詳情參見論文《Unsupervised Learning of Visual Representations using Videos》,鏈接:https://arxiv.org/abs/1505.00687。
另一篇使用視頻的文章出自 MIT 的 Vondrick 和 Torralba 等人(http://arxiv.org/abs/1504.08023),有著非常惹人注目的結果。這項工作背后的思想是從視頻輸入中預測未來幀的表示。這是一種優雅的方法。使用的模型如下:
這項技術的一個問題就是:一個訓練在靜態圖像幀上的神經網絡被用來解釋視頻輸入。這種網絡不會學習到視頻的時間動態變化以及在空間運動的物體的平滑變換。所以我們認為這個網絡并不適合用來預測未來視頻中的畫面。
為了克服這個問題,我們團隊創建了一個大型的視頻數據集 eVDS(https://engineering.purdue.edu/elab/eVDS/),可用來直接從視頻數據上訓練新的(遞歸和反饋)網絡模型。
PredNet
PredNet 是被設計來預測視頻中未來幀的網絡。在這個博客中可以看到一些例子,博客鏈接:https://coxlab.github.io/prednet/。
PredNet 是一個非常聰明的神經網絡型,在我們看來,它將在將來的神經網絡中起著重要的作用。PredNet 學習到了超越監督式 CNN 中的單幀圖片的神經表征。
PredNet 結合了生物啟發的雙向 [人腦模型](詳見論文《Unsupervised Pixel-prediction》,https://papers.nips.cc/paper/1083-unsupervised-pixel-prediction.pdf)。它使用了 [預測編碼和神經模型中的反饋連接](詳見論文《Neural Encoding and Decoding with Deep Learning for Dynamic Natural Vision》,http://arxiv.org/abs/1608.03425)。下面是 PredNet 模型以及一個具有兩個堆疊層的例子:
PredNet 結合了生物啟發的雙向人腦模型
這個模型有以下這幾個優點:
可使用無標簽的數據來訓練
在每一層嵌入了損失函數來計算誤差
具有執行在線學習的能力,通過監控錯誤信號,當模型不能預測輸出的時候,它會知道需要學習誤差信號
PredNet 存在的一個問題是,對第一層的一些簡單的基于運動的濾波器而言,預測未來輸入的幀是相對容易的。在我們所做的 PredNet 的實驗中,PredNet 在重建輸入幀的時候學會了在重建輸入幀時達到很好的效果,但是更高層不會學到較好的表征。事實上,在實驗中更高層連簡單的分類任務都解決不了。
事實上,預測未來的幀是不必要的。我們愿意做的就是去預測下一幀的表征,就像 Carl Vondrick 做的一樣。詳見論文《Anticipating Visual Representations from Unlabeled Video》,鏈接:https://arxiv.org/abs/1504.08023。
通過觀察物體的運動來學習特征
最近的這篇論文通過觀察視頻中物體的運動來訓練無監督模型(《Learning Features by Watching Objects Move》,https://people.eecs.berkeley.edu/~pathak/unsupervised_video/)。運動以光流的形式被提取出來,并被用作運動物體的分割模板。盡管光流信號并沒有提供任何一個接近良好的分割模板,但是在大規模數據集上的平均效果使得最終的網絡會表現良好。例子如下所示:
這項工作是非常激動人心的,因為它遵循關于人類視覺皮層如何學習分割運動物體的神經學理論。參見論文《Development of human visual function》,鏈接:http://www.sciencedirect.com/science/article/pii/S004269891100068X。
未來
未來需要你們來創造。
無監督訓練仍然還是一個有待發展的主題,你可以通過以下方式做出較大的貢獻:
創建一個新的無監督任務去訓練網絡,例如:解決拼圖問題、對比圖像補丁、生成圖像等......
想出能夠創造很棒的無監督功能的任務,例如:像我們人類視覺系統的工作方式一樣,理解立體圖像和視頻中什么是物體、什么是背景。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。