0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

講解隨機梯度下降、類別數據編碼、Vowpal Wabbit機器學習庫

zhKF_jqr_AI ? 來源:未知 ? 作者:李倩 ? 2018-07-17 09:11 ? 次閱讀

編者按:機器學習開放課程第八課,Mail.Ru數據科學家Yury Kashnitsky講解了隨機梯度下降、類別數據編碼、Vowpal Wabbit機器學習庫。

這一課我們將從理論和實踐的角度介紹Vowpal Wabbit訓練速度非同尋常的原因,在線學習和哈希技巧。我們將在新聞、影評、StackOverflow問題上嘗試Vowpal Wabbit。

概覽

隨機梯度下降和在線學習

SGD

在線學習方法

類別數據處理

標簽編碼

獨熱編碼

哈希技巧

Vowpal Wabbit

新聞:二元分類

新聞:多元分類

IMDB影評

分類StackOverflow問題

相關資源

1. 隨機梯度下降和在線學習

1.1 隨機梯度下降

回顧一下,梯度下降的想法是通過在下降最快的方向上小步前進,以最小化某個函數。這一方法得名于以下微積分的事實:函數f(x) = f(x1, ..., xn)的偏導數向量

指向函數增長最快的方向。這意味著,向相反方向移動(逆梯度),可能以最快的速度降低函數值。

俄羅斯最受歡迎的冬季度假勝地——謝列格什滑雪場,踩著滑雪板的人為本文作者

除了宣傳美麗的風光,上面的照片描繪了梯度下降的概念。如果你想滑得盡可能快,你需要選擇最陡峭的下降路徑。計算逆梯度可以看成評估不同點的坡度。

例子

我們將通過梯度下降求解一個成對回歸問題(paired regression problem)。讓我們根據一個變量預測另一個變量:根據體重預測身高。我們將假定這些變量是線性相關的。另外,我們將使用的是SOCR數據集。

首先我們導入數據,并繪制散布圖:

import warnings

warnings.filterwarnings('ignore')

import os

import re

import numpy as np

import pandas as pd

from tqdm import tqdm_notebook

from sklearn.datasets import fetch_20newsgroups, load_files

from sklearn.preprocessing importLabelEncoder, OneHotEncoder

from sklearn.model_selection import train_test_split

from sklearn.linear_model importLogisticRegression

from sklearn.metrics import classification_report, accuracy_score, log_loss

from sklearn.metrics import roc_auc_score, roc_curve, confusion_matrix

from scipy.sparse import csr_matrix

import matplotlib.pyplot as plt

%matplotlib inline

import seaborn as sns

PATH_TO_ALL_DATA = '../../data/'

data_demo = pd.read_csv(os.path.join(PATH_TO_ALL_DATA,

'weights_heights.csv'))

plt.scatter(data_demo['Weight'], data_demo['Height']);

plt.xlabel('Weight in lb')

plt.ylabel('Height in inches');

我們有一個l維向量x(每個人的體重,也就是訓練樣本)和向量y(包含數據集中每個人的身高)。

我們要完成的任務是:找到滿足以下條件的權重w0和w1,使預測身高yi= w0+ w1xi最小化以下平方誤差(等效于最小化均方誤差,因為1/l并不會帶來什么不同):

我們將使用梯度下降,利用SE(w0, w1)在權重w0和w1上的偏導數。以下簡單的更新公式定義了迭代訓練過程:

展開偏導數后,我們得到:

在數據量不大的情況下,上面的數學效果不錯(我們這里不討論局部極小值、鞍點、學習率選擇、動量等問題,請參考《深度學習》一書的數值計算那一章)。批量梯度下降有一個問題——梯度演算需要累加訓練集中所有對象的值。換句話說,該算法需要大量迭代,而每次迭代重新計算權重的過程中都包含累加整個訓練集的運算。如果我們有數十億訓練樣本,怎么辦?

這正是隨機梯度下降的動機!簡單來說,我們扔掉累加符號,僅僅根據單個訓練樣本或一小部分訓練樣本更新權重:

這個方法無法保證我們在每次迭代中以最佳的方向移動。因此,我們可能需要更多的迭代,不過我們的權重更新會快很多。

吳恩達的機器學習課程很好地講解了這一點。讓我們來看一下。

這是某個函數的等值線圖,我們想要找出該函數的全局最小值。紅線展示了權重變動(圖中的θ0和θ1相當于我們的w0和w1)。根據梯度的性質,每點的變動方向垂直于等值線。隨機梯度下降時,權重以更難預測的方式變動(紫線),我們甚至可以看到,有些步驟是錯誤的,正遠離最小值;然而,梯度下降和隨機梯度下降這兩個過程均收斂于同一解。

1.2 在線學習方法

在隨機梯度下降的實踐指導下,我們可以在多達數百GB的數據上訓練分類器和回歸器。

考慮成對回歸的情形,我們可以將訓練數據集(X, y)保存在硬盤上,而不是將整個訓練數據集載入內存(內存放不下),然后逐個讀取數據,更新模型的權重:

在處理完整個訓練數據集后,我們的損失函數會下降,不過通常需要幾十個epoch之后損失函數的值才足夠小。

這一學習的方法稱為在線學習,早在機器學習MOOC成為主流之前,這一術語就出現了。

這里我們沒有討論SGD的很多細節(jié)。如果你想要深入這一理論,我強烈推薦Stephen Boyd寫的《Convex Optimization》一書?,F在,我們將介紹Vowpal Wabbit庫,感謝隨機優(yōu)化和特征哈希,它非常擅長在大規(guī)模數據集上訓練簡單模型。

在scikit-learn中,基于SGD訓練的分類器和回歸器稱為SGDClassifier和SGDRegressor(見sklearn.linear_model)。這些是很好的SGD實現,不過我們將使用VW,因為在許多方面,它的性能比sklean的SGD模型要好。

2. 類別數據處理

2.1 標簽編碼

許多分類算法和回歸算法基于歐幾里得空間運作,這意味著數據表示為由實數組成的向量。然而,真實數據中我們常常碰到具有離散值的類別變量,比如是/否,一月/二月/.../十二月。下面我們將討論如何處理這類數據,特別是配合線性模型使用的情況下。

讓我們探索一下UCI bank marketing數據集,其中大部分特征是類別特征。

df = pd.read_csv(os.path.join(PATH_TO_ALL_DATA, 'bank_train.csv'))

labels = pd.read_csv(os.path.join(PATH_TO_ALL_DATA,

'bank_train_target.csv'), header=None)

df.head()

你可以看到,大部分特征并不由數字表示。這就帶來了一個問題,我們無法直接使用大多數機器學習方法(至少就那些scikit-learn實現的而言)。

讓我們深入查看一下“教育”特征。

df['education'].value_counts().plot.barh();

最直截了當的方案是將這一特征的每個值映射為唯一的數字。例如,我們可以將university.degree映射為0,basic.9y映射為1,等等。我們可以使用sklearn.preprocessing.LabelEncoder進行這一映射。

label_encoder = LabelEncoder()

mapped_education = pd.Series(label_encoder.fit_transform(

df['education']))

mapped_education.value_counts().plot.barh()

print(dict(enumerate(label_encoder.classes_)))

輸出:

{0: 'basic.4y', 1: 'basic.6y', 2: 'basic.9y', 3: 'high.school', 4: 'illiterate', 5: 'professional.course', 6: 'university.degree', 7: 'unknown'}

df['education'] = mapped_education

df.head()

同樣,我們轉換其他列:

categorical_columns = df.columns[df.dtypes

== 'object'].union(['education'])

for column in categorical_columns:

df[column] = label_encoder.fit_transform(df[column])

df.head()

這種方法的主要問題是我們現在引入了一些可能并不存在的相對順序。

例如,我們隱式地引入了職業(yè)特征的代數,我們現在可以從客戶一的職業(yè)中減去客戶二的職業(yè):

df.loc[1].job - df.loc[2].job # -1.0

這樣的操作有意義嗎?沒有。讓我們嘗試基于這一特征轉換訓練邏輯回歸。

def logistic_regression_accuracy_on(dataframe, labels):

features = dataframe.as_matrix()

train_features, test_features, train_labels, test_labels =

train_test_split(features, labels)

logit = LogisticRegression()

logit.fit(train_features, train_labels)

return classification_report(test_labels,

logit.predict(test_features))

print(logistic_regression_accuracy_on(df[categorical_columns],

labels))

我們可以看到,邏輯回歸從未預測分類1. 為了在類別特征上使用線性模型,我們需要使用一種不同的方法:獨熱編碼(One-Hot Encoding)。

2.2 獨熱編碼

假設某項特征可能有10個唯一值。獨熱編碼為每個唯一值創(chuàng)建一個新特征,這10個特征中,除了一個特征以外,所有特征的值為零。

sklearn.preprocessing的OneHotEncoder類實現了獨熱編碼。默認情況下,OneHotEncoder將數據轉換為一個稀疏矩陣,以節(jié)約內存空間。不過,在這一特定問題中,我們沒有碰到內存問題,所以我們將使用“密集”矩陣表示。

onehot_encoder = OneHotEncoder(sparse=False)

encoded_categorical_columns =

pd.DataFrame(onehot_encoder.fit_transform(

df[categorical_columns]))

encoded_categorical_columns.head()

轉換維獨熱編碼之后,就可以使用線性模型了:

print(logistic_regression_accuracy_on(encoded_categorical_columns, labels))

2.3 哈希技巧

真實數據可能是易變的,意味著我們無法保證類別特征不會出現新值。這一問題阻礙了訓練好的模型在新數據上的應用。除此以外,LabelEncoder需要對整個數據集進行初步分析,并將構建的映射保存在內存中,這使得在大型數據集上運用標簽編碼變得困難。

有一個基于哈希的向量化類別數據的簡單方法,毫不意外地,它被稱為哈希技巧。

哈希函數可以幫助我們?yōu)椴煌奶卣髦嫡业轿ㄒ坏木幋a,例如:

for s in ('university.degree', 'high.school', 'illiterate'):

print(s, '->', hash(s))

結果:

university.degree -> -6241459093488141593

high.school -> 7728198035707179500

illiterate -> -7360093633803373451

我們不打算使用負值,或者數量級很大的值,所以我們將限制哈希值的范圍:

hash_space = 25

for s in ('university.degree', 'high.school', 'illiterate'):

print(s, '->', hash(s) % hash_space)

university.degree -> 7

high.school -> 0

illiterate -> 24

想象下我們的數據集包含一個單身學生,他在周一接到一個電話。他的特征向量會類似于通過獨熱編碼創(chuàng)建的向量:

hashing_example = pd.DataFrame([{i: 0.0for i in range(hash_space)}])

for s in ('job=student', 'marital=single', 'day_of_week=mon'):

print(s, '->', hash(s) % hash_space)

hashing_example.loc[0, hash(s) % hash_space] = 1

hashing_example

job=student -> 20

marital=single -> 23

day_of_week=mon -> 9

我們哈希的不是特征值,而是特征名 + 特征值對。這樣我們就可以區(qū)分不同特征的相同值。

使用哈希編碼可能會遇到碰撞嗎?當然有可能,不過只要哈??臻g足夠大,碰撞很罕見。即使碰撞真的發(fā)生了,回歸或分類表現也不會受多大影響。在這一情形下,哈希碰撞就像是一種正則化的形式。

你也許會說“尼瑪這什么玩意?”;哈希看起來就違背直覺。然而,事實上,有時這是唯一可行的處理類別數據的方法。而且,這一技術已被證實就是好使。等你處理了足夠多的數據之后,你可能自己意識到這一點。

3. Vowpal Wabbit

Vowpal Wabbit(VW)是業(yè)界使用最廣泛的機器學習庫之一。它的訓練速度很快,支持許多訓練模式,特別是在大數據和高維數據方面表現出色。同時,由于VM實現了哈希技巧,它是一個處理文本數據的完美選擇。

VW可以作為命令行工具使用。輸入以下命令訪問VW的幫助頁面:

vw --help

vw可以從文件或stdin讀取數據,數據格式如下:

[Label] [Importance] [Tag]|NamespaceFeatures |NamespaceFeatures ... |NamespaceFeatures

Namespace=String[:Value]

Features=(String[:Value] )*

其中,[]表示可選元素,(...)*表示接受多個輸入。

Label(標簽)是一個數字。在分類問題中,它通常是1或-1;在回歸問題中,它是一個實數(浮點數)。

Importance(重要性)是一個數字。它指明了樣本的權重。處理失衡數據時,設定Importance很有用。

Tag(標記)是不含空格的字符串。它是樣本的“名稱”。

Namespace(命名空間)用于創(chuàng)建不同的特征空間。

Features是給定Namespace中的特征。特征默認權重為1.0,但可以調整,例如feature:0.1

例如,以下字符串匹配VW格式:

11.0 |Subject WHAT car isthis |OrganizationUniversity of Maryland:0.5CollegePark

我們可以將其傳給vw:

echo '1 1.0 |Subject WHAT car is this |Organization University of Maryland:0.5 College Park' | vw

VW是一個非常棒的處理文本數據的工具。我們將通過20newsgroups數據集展示這一點,該數據集包含來自20種不同新聞組的信息。

3.1 新聞:二元分類

使用sklearn函數加載數據:

newsgroups = fetch_20newsgroups(PATH_TO_ALL_DATA)

newsgroups['target_names']

新聞組的20項主題為:

['alt.atheism',

'comp.graphics',

'comp.os.ms-windows.misc',

'comp.sys.ibm.pc.hardware',

'comp.sys.mac.hardware',

'comp.windows.x',

'misc.forsale',

'rec.autos',

'rec.motorcycles',

'rec.sport.baseball',

'rec.sport.hockey',

'sci.crypt',

'sci.electronics',

'sci.med',

'sci.space',

'soc.religion.christian',

'talk.politics.guns',

'talk.politics.mideast',

'talk.politics.misc',

'talk.religion.misc']

讓我們看下第一封消息:

text = newsgroups['data'][0]

target = newsgroups['target_names'][newsgroups['target'][0]]

print('-----')

print(target)

print('-----')

print(text.strip())

print('----')

輸出:

-----

rec.autos

-----

From: lerxst@wam.umd.edu (where's my thing)

Subject: WHAT car is this!?

Nntp-Posting-Host: rac3.wam.umd.edu

Organization: University of Maryland, College Park

Lines: 15

I was wondering if anyone out there could enlighten me on this car I saw

the other day. It was a 2-door sports car, looked to be from the late 60s/

early 70s. It was called a Bricklin. The doors were really small. In addition,

the front bumper was separate from the rest of the body. This is

all I know. If anyone can tellme a model name, engine specs, years

of production, where this car is made, history, or whatever info you

have on this funky looking car, please e-mail.

Thanks,

- IL

---- brought to you by your neighborhood Lerxst ----

----

現在我們將把數據轉換為Vowpal Wabbit可以理解的格式。我們將丟棄所有短于3個符號的單詞。這里,我們跳過了一些重要的NLP步驟,像是詞干提取和詞形還原;不過,我們之后將看到,即使沒有這些步驟,VW仍然解決了問題。

def to_vw_format(document, label=None):

return str(label or'') + ' |text ' + ' '.join(re.findall('w{3,}',

document.lower())) + ' '

to_vw_format(text, 1if target == 'rec.autos'else -1)

輸出:

'1 |text from lerxst wam umd edu where thing subject what car this nntp posting host rac3 wam umd edu organization university maryland college park lines was wondering anyone out there could enlighten this car saw the other day was door sports car looked from the late 60s early 70s was called bricklin the doors were really small addition the front bumper was separate from the rest the body this all know anyone can tellme model name engine specs years production where this car made history whatever info you have this funky looking car please mail thanks brought you your neighborhood lerxst '

我們將數據集分為訓練集和測試集,并將其分別寫入不同的文件。如果一份文檔和rec.autos相關,那么我們就將它視作正面樣本。所以,我們正構建一個模型,區(qū)分出汽車有關的文章:

all_documents = newsgroups['data']

all_targets = [1if newsgroups['target_names'][target] == 'rec.autos'

else -1for target in newsgroups['target']]

train_documents, test_documents, train_labels, test_labels =

train_test_split(all_documents, all_targets, random_state=7)

with open(os.path.join(PATH_TO_ALL_DATA, '20news_train.vw'), 'w') as vw_train_data:

for text, target in zip(train_documents, train_labels):

vw_train_data.write(to_vw_format(text, target))

with open(os.path.join(PATH_TO_ALL_DATA, '20news_test.vw'), 'w') as vw_test_data:

for text in test_documents:

vw_test_data.write(to_vw_format(text))

現在,我們將創(chuàng)建的訓練文件傳給Vowpal Wabbit。我們通過鉸鏈(hinge)損失函數(線性SVM)求解這一分類問題。訓練好的模型將保存在20news_model.vw文件中:

vw -d $PATH_TO_ALL_DATA/20news_train.vw

--loss_function hinge -f $PATH_TO_ALL_DATA/20news_model.vw

輸出:

final_regressor = ../../data//20news_model.vw

Num weight bits = 18

learning rate = 0.5

initial_t = 0

power_t = 0.5

usingno cache

Reading datafile = ../../data//20news_train.vw

num sources = 1

average since example example current current current

loss last counter weight label predict features

1.0000001.000000 1 1.0 -1.0000 0.0000 157

0.9112760.822551 2 2.0 -1.0000 -0.1774 159

0.6057930.300311 4 4.0 -1.0000 -0.3994 92

0.4195940.233394 8 8.0 -1.0000 -0.8167 129

0.3139980.208402 16 16.0 -1.0000 -0.6509 108

0.1960140.078029 32 32.0 -1.0000 -1.0000 115

0.1831580.170302 64 64.0 -1.0000 -0.7072 114

0.2610460.338935 128 128.0 1.0000 -0.7900 110

0.2629100.264774 256 256.0 -1.0000 -0.6425 44

0.2166630.170415 512 512.0 -1.0000 -1.0000 160

0.1767100.136757 1024 1024.0 -1.0000 -1.0000 194

0.1345410.092371 2048 2048.0 -1.0000 -1.0000 438

0.1044030.074266 4096 4096.0 -1.0000 -1.0000 644

0.0813290.058255 8192 8192.0 -1.0000 -1.0000 174

finished run

number of examples per pass = 8485

passes used = 1

weighted example sum = 8485.000000

weighted label sum = -7555.000000

average loss = 0.079837

best constant = -1.000000

best constant's loss = 0.109605

total feature number = 2048932

VW在訓練時會打印很多信息(你可以通過--quiet參數讓VW少輸出信息)。關于VW輸出信息的說明,可以參考GitHub上的文檔。就目前而言,我們可以看到,隨著訓練的進行,平均損失下降了。VW使用之前未見的樣本計算損失,所以VW的平均損失通常比較準確?,F在,我們將訓練好的模型應用于測試集,并將預測保存到由-p指定的文件:

vw -i $PATH_TO_ALL_DATA/20news_model.vw -t -d $PATH_TO_ALL_DATA/20news_test.vw

-p $PATH_TO_ALL_DATA/20news_test_predictions.txt

現在我們加載預測,計算AUC,并繪制ROC曲線:

with open(os.path.join(PATH_TO_ALL_DATA,

'20news_test_predictions.txt')) as pred_file:

test_prediction = [float(label)

for label in pred_file.readlines()]

auc = roc_auc_score(test_labels, test_prediction)

roc_curve = roc_curve(test_labels, test_prediction)

with plt.xkcd():

plt.plot(roc_curve[0], roc_curve[1]);

plt.plot([0,1], [0,1])

plt.xlabel('FPR'); plt.ylabel('TPR');

plt.title('test AUC = %f' % (auc));

plt.axis([-0.05,1.05,-0.05,1.05]);

可以看到,我們達到了很高的分類質量。

3.2 新聞:多元分類

我們仍將使用之前的新聞組數據集。不過,這次我們將解決一個多元分類問題。VW要求標簽從1開始,而sklearn的LabelEncoder的標簽則從0開始。因此,我們需要在LabelEncoder的編碼上加1:

all_documents = newsgroups['data']

topic_encoder = LabelEncoder()

all_targets_mult = topic_encoder.fit_transform(newsgroups['target']) + 1

仍然像之前一樣,我們切分訓練集和測試集,并保存到不同文件。

train_documents, test_documents, train_labels_mult, test_labels_mult =

train_test_split(all_documents, all_targets_mult, random_state=7)

with open(os.path.join(PATH_TO_ALL_DATA,

'20news_train_mult.vw'), 'w') as vw_train_data:

for text, target in zip(train_documents, train_labels_mult):

vw_train_data.write(to_vw_format(text, target))

with open(os.path.join(PATH_TO_ALL_DATA,

'20news_test_mult.vw'), 'w') as vw_test_data:

for text in test_documents:

vw_test_data.write(to_vw_format(text))

我們將在多元分類模式下訓練Vowpal Wabbit,在oaa參數中傳入分類的數目。同時,讓我們看下模型的一些參數(更多信息可以在Vowpal Wabbit的官方教程中找到):

學習率(-l,默認0.5)每步權重改變的比率

學習率衰減(--power_t,默認0.5)實踐表明,如果學習率隨著隨機梯度下降的推進而下降,我們能更好地逼近損失的最小值

損失函數(--loss_function)整個訓練算法取決于損失函數的選擇??梢詤⒖紦p失函數的文檔。

正則化(-l1)注意VW為每個對象計算正則化。所以我們通常將正則值設為10-20左右。

此外,你也可以嘗試使用Hyperopt自動調整Vowpal Wabbit參數。

vw — oaa 20 $PATH_TO_ALL_DATA/20news_train_mult.vw -f $PATH_TO_ALL_DATA/20news_model_mult.vw

— loss_function=hinge

vw -i $PATH_TO_ALL_DATA/20news_model_mult.vw -t -d $PATH_TO_ALL_DATA/20news_test_mult.vw

-p $PATH_TO_ALL_DATA/20news_test_predictions_mult.txt

讓我們看看結果如何:

with open(os.path.join(PATH_TO_ALL_DATA,

'20news_test_predictions_mult.txt')) as pred_file:

test_prediction_mult = [float(label)

for label in pred_file.readlines()]

accuracy_score(test_labels_mult, test_prediction_mult)

輸出:

0.8734535171438671

在測試集上的精確度超過87%,還不錯。

3.3 IMDB影評

這一節(jié)中,我們將對IMDB影評進行二元分類。影評數據可從Google網盤下載

https://drive.google.com/file/d/1xq4l5c0JrcxJdyBwJWvy0u9Ad_pvkJ1l/view

我們使用sklearn.datasets的load_files函數加載影評。數據集已經分為訓練集、測試集兩部分,各包含12500好評、12500差評。首先,我們將分割文本和標簽:

import pickle

path_to_movies = os.path.expanduser('imdb_reviews')

reviews_train = load_files(os.path.join(path_to_movies, 'train'))

text_train, y_train = reviews_train.data, reviews_train.target

reviews_test = load_files(os.path.join(path_to_movies, 'test'))

text_test, y_test = reviews_test.data, reviews_train.target

查看一些影評的例子和相應的標簽:

text_train[0]

輸出:

b"Zero Day leads you to think, even re-think why two boys/young men would do what they did - commit mutual suicide via slaughtering their classmates. It captures what must be beyond a bizarre mode of being for two humans who have decided to withdraw from common civility in order to define their own/mutual world via coupled destruction.

It is not a perfect movie but given what money/time the filmmaker and actors had - it is a remarkable product. In terms of explaining the motives and actions of the two young suicide/murderers it is better than 'Elephant' - in terms of being a film that gets under our 'rationalistic' skin it is a far, far better film than almost anything you are likely to see.

Flawed but honest with a terrible honesty."

這是好評還是差評?

y_train[0]

輸出:

1

看來是好評。

再看一條:

text_train[1]

輸出:

b'Words can't describe how bad this movie is. I can't explain it by writing only. You have too see it for yourself to get at grip of how horrible a movie really can be. Not that I recommend you to do that. There are so many clichxc3xa9s, mistakes (and all other negative things you can imagine) here that will just make you cry. To start with the technical first, there are a LOT of mistakes regarding the airplane. I won't list them here, but just mention the coloring of the plane. They didn't even manage to show an airliner in the colors of a fictional airline, but instead used a 747 painted in the original Boeing livery. Very bad. The plot is stupid and has been done many times before, only much, much better. There are so many ridiculous moments here that i lost count of it really early. Also, I was on the bad guys' side all the time in the movie, because the good guys were so stupid. "Executive Decision" should without a doubt be you're choice over this one, even the "Turbulence"-movies are better. In fact, every other movie in the world is better than this one.'

這條是好評還是差評?

y_train[1]

輸出:

0

嗯,這條是差評。

如前所述,數據集已經分成訓練集和測試集兩部分?,F在我們再從訓練集中切分30%出來作為驗證集。

train_share = int(0.7 * len(text_train))

train, valid = text_train[:train_share], text_train[train_share:]

train_labels, valid_labels = y_train[:train_share], y_train[train_share:]

同樣,我們將它們保存到文件:

with open(os.path.join(PATH_TO_ALL_DATA, 'movie_reviews_train.vw'), 'w') as vw_train_data:

for text, target in zip(train, train_labels):

vw_train_data.write(to_vw_format(str(text), 1if target == 1else -1))

with open(os.path.join(PATH_TO_ALL_DATA, 'movie_reviews_valid.vw'), 'w') as vw_train_data:

for text, target in zip(valid, valid_labels):

vw_train_data.write(to_vw_format(str(text), 1if target == 1else -1))

with open(os.path.join(PATH_TO_ALL_DATA, 'movie_reviews_test.vw'), 'w') as vw_test_data:

for text in text_test:

vw_test_data.write(to_vw_format(str(text)))

然后運行Vowpal Wabbit(我們仍然使用鉸鏈損失,不過你可以試驗其他算法):

vw -d $PATH_TO_ALL_DATA/movie_reviews_train.vw --loss_function hinge -f $PATH_TO_ALL_DATA/movie_reviews_model.vw --quiet

訓練完成后,讓我們在留置的驗證集上測試一下表現:

vw -i $PATH_TO_ALL_DATA/movie_reviews_model.vw -t

-d $PATH_TO_ALL_DATA/movie_reviews_valid.vw -p $PATH_TO_ALL_DATA/movie_valid_pred.txt --quiet

從文件讀取預測,并估計精確度和AUC。

with open(os.path.join(PATH_TO_ALL_DATA, 'movie_valid_pred.txt')) as pred_file:

valid_prediction = [float(label)

for label in pred_file.readlines()]

print("Accuracy: {}".format(round(accuracy_score(valid_labels,

[int(pred_prob > 0) for pred_prob in valid_prediction]), 3)))

print("AUC: {}".format(round(roc_auc_score(valid_labels, valid_prediction), 3)))

輸出:

Accuracy: 0.885

AUC: 0.942

在測試集上如法炮制:

vw -i $PATH_TO_ALL_DATA/movie_reviews_model.vw -t -d $PATH_TO_ALL_DATA/movie_reviews_test.vw -p $PATH_TO_ALL_DATA/movie_test_pred.txt --quiet

with open(os.path.join(PATH_TO_ALL_DATA, 'movie_test_pred.txt')) as pred_file:

test_prediction = [float(label)

for label in pred_file.readlines()]

print("Accuracy: {}".format(round(accuracy_score(y_test,

[int(pred_prob > 0) for pred_prob in test_prediction]), 3)))

print("AUC: {}".format(round(roc_auc_score(y_test, test_prediction), 3)))

和我們期望的一樣,精確度和AUC幾乎和驗證集上一樣:

Accuracy: 0.88

AUC: 0.94

讓我們嘗試下n元語法,看看能不能提高精確度:

vw -d $PATH_TO_ALL_DATA/movie_reviews_train.vw --loss_function hinge --ngram 2 -f $PATH_TO_ALL_DATA/movie_reviews_model2.vw --quiet

vw -i$PATH_TO_ALL_DATA/movie_reviews_model2.vw -t -d $PATH_TO_ALL_DATA/movie_reviews_valid.vw -p $PATH_TO_ALL_DATA/movie_valid_pred2.txt --quiet

vw -i $PATH_TO_ALL_DATA/movie_reviews_model2.vw -t -d $PATH_TO_ALL_DATA/movie_reviews_test.vw -p $PATH_TO_ALL_DATA/movie_test_pred2.txt --quiet

效果不錯:

# 驗證集

Accuracy: 0.894

AUC: 0.954

# 測試集

Accuracy: 0.888

AUC: 0.952

3.4 分類StackOverflow問題

現在,讓我們看看Vowpal Wabbit在大型數據集上的表現。我們將使用一個10GB的StackOverflow問答數據集:

https://drive.google.com/file/d/1ZU4J3KhJDrHVMj48fROFcTsTZKorPGlG/view?usp=sharing

原始數據集由一千萬問題組成,每個問題有多個標簽。數據相當整潔,所以別叫它“大數據”,即使是在酒館中。:)

我們僅僅選取了10個標簽:javascript、java、python、ruby、php、c++、c#、go、scala、swift。讓我們解決這一十元分類問題:我們想根據問題的文本預測這個問題的標簽是10個流行的編程語言中的哪一個。

選取10個標簽后,我們得到了一個4.7G的數據集,并將其切分為訓練集和測試集。

我們將用Vowpal Wabbit處理訓練集(3.1 GiB):

vw --oaa 10 -d $PATH_TO_STACKOVERFLOW_DATA/stackoverflow_train.vw -f vw_model1_10mln.vw -b 28 --random_seed 17 --quiet

其中,--oaa 10表示我們有10個分類,-b 28表示我們將使用28位哈希,也就是228特征空間,--random_seed 17固定隨機數種子,以便復現。

訓練完成之后,看看模型在測試集上的表現:

vw -t -i vw_model1_10mln.vw -d $PATH_TO_STACKOVERFLOW_DATA/stackoverflow_test.vw -p vw_test_pred.csv --random_seed 17 --quiet

vw_pred = np.loadtxt(os.path.join(PATH_TO_STACKOVERFLOW_DATA,

'vw_test_pred.csv'))

test_labels = np.loadtxt(os.path.join(PATH_TO_STACKOVERFLOW_DATA,

'stackoverflow_test_labels.txt'))

accuracy_score(test_labels, vw_pred)

結果:

0.91728604842865913

模型的訓練和預測在不到1分鐘內就完成了(我使用的是2015年中期的MacBook Pro,2.2 GHz Intel Core i7,16GB RAM)。精確度差不多達到了92%。我們沒有使用什么Hadoop集群就做到了這一點。:) 令人印象深刻,不是嗎?

4. 相關資源

VW的官方文檔

Deep Learning(《深度學習》)一書的數值計算那一章

Stephen Boyd寫的Convex Optimization一書

Adam Drake寫的博客文章Command-line Tools can be 235x Faster than your Hadoop Cluster

GitHub上的多種ML算法在Criteo 1TB數據集上的評測rambler-digital-solutions/criteo-1tb-benchmark

FastML博客上VW分類的帖子

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯系本站處理。 舉報投訴
  • 函數
    +關注

    關注

    3

    文章

    4259

    瀏覽量

    62227
  • 機器學習
    +關注

    關注

    66

    文章

    8321

    瀏覽量

    132165
  • 數據集
    +關注

    關注

    4

    文章

    1197

    瀏覽量

    24590

原文標題:機器學習開放課程(八):使用Vowpal Wabbit高速學習大規(guī)模數據集

文章出處:【微信號:jqr_AI,微信公眾號:論智】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    分享一個自己寫的機器學習線性回歸梯度下降算法

    單變量線性回歸算法,利用Batch梯度梯度下降算法迭代計算得到誤差最小的代價函數theta0,theta1。調節(jié)學習率a可以觀察擬合得到的函數和代價函數誤差收斂情況。
    發(fā)表于 10-02 21:48

    機器學習新手必學的三種優(yōu)化算法(牛頓法、梯度下降法、最速下降法)

    法、梯度下降法、最速下降法)進行了介紹和比較,并結合算法的數學原理和實際案例給出了優(yōu)化算法選擇的一些建議。閱讀本文的基礎準備線性代數多變量微積分對凸函數的基本知識我們都知道,機器
    發(fā)表于 05-07 08:30

    數據編碼技術

    2.2  數據編碼技術2.2.1  數字數據的數字信號編碼2.2.2  數字數據的模擬信號編碼2.2.3&nb
    發(fā)表于 06-27 21:45 ?0次下載

    隨機并行梯度下降圖像匹配方法性能研究及優(yōu)化_李松洋

    隨機并行梯度下降圖像匹配方法性能研究及優(yōu)化_李松洋
    發(fā)表于 03-14 08:00 ?0次下載

    機器學習隨機梯度下降和批量梯度下降算法介紹

    隨機梯度下降(Stochastic gradient descent) 批量梯度下降(Batch gradient descent)
    發(fā)表于 11-28 04:00 ?8779次閱讀
    <b class='flag-5'>機器</b><b class='flag-5'>學習</b>:<b class='flag-5'>隨機</b><b class='flag-5'>梯度</b><b class='flag-5'>下降</b>和批量<b class='flag-5'>梯度</b><b class='flag-5'>下降</b>算法介紹

    一文看懂常用的梯度下降算法

    編輯:祝鑫泉 一 概述 梯度下降算法( Gradient Descent Optimization )是神經網絡模型訓練最常用的優(yōu)化算法。對于深度學習模型,基本都是采用梯度
    發(fā)表于 12-04 18:17 ?1758次閱讀

    機器學習梯度下降法的過程

    梯度下降法是一個用于尋找最小化成本函數的參數值的最優(yōu)化算法。當我們無法通過分析計算(比如線性代數運算)求得函數的最優(yōu)解時,我們可以利用梯度下降法來求解該問題。
    發(fā)表于 04-26 16:44 ?3388次閱讀

    梯度下降算法及其變種:批量梯度下降,小批量梯度下降隨機梯度下降

    現在我們來討論梯度下降算法的三個變種,它們之間的主要區(qū)別在于每個學習步驟中計算梯度時使用的數據量,是對每個參數更新(
    的頭像 發(fā)表于 05-03 15:55 ?2.1w次閱讀

    機器學習之感知機python是如何實現的

    算法選擇,最終的目標是求損失函數的最小值,利用機器學習中最常用的梯度下降GD或者隨機梯度
    發(fā)表于 03-30 09:36 ?950次閱讀
    <b class='flag-5'>機器</b><b class='flag-5'>學習</b>之感知機python是如何實現的

    基于分布式編碼的同步隨機梯度下降算法

    基于數據并行化的異步隨機梯度下降(ASGD)算法由于需要在分布式計算節(jié)點之間頻繁交換梯度數據,從而影響算法執(zhí)行效率。提出基于分布式
    發(fā)表于 04-27 13:56 ?2次下載
    基于分布式<b class='flag-5'>編碼</b>的同步<b class='flag-5'>隨機</b><b class='flag-5'>梯度</b><b class='flag-5'>下降</b>算法

    梯度下降法在機器學習中的應用

    梯度下降法沿著梯度的反方向進行搜索,利用了函數的一階導數信息。
    的頭像 發(fā)表于 05-18 09:20 ?1276次閱讀
    <b class='flag-5'>梯度</b><b class='flag-5'>下降</b>法在<b class='flag-5'>機器</b><b class='flag-5'>學習</b>中的應用

    PyTorch教程12.4之隨機梯度下降

    電子發(fā)燒友網站提供《PyTorch教程12.4之隨機梯度下降.pdf》資料免費下載
    發(fā)表于 06-05 14:58 ?0次下載
    PyTorch教程12.4之<b class='flag-5'>隨機</b><b class='flag-5'>梯度</b><b class='flag-5'>下降</b>

    PyTorch教程12.5之小批量隨機梯度下降

    電子發(fā)燒友網站提供《PyTorch教程12.5之小批量隨機梯度下降.pdf》資料免費下載
    發(fā)表于 06-05 15:00 ?0次下載
    PyTorch教程12.5之小批量<b class='flag-5'>隨機</b><b class='flag-5'>梯度</b><b class='flag-5'>下降</b>

    PyTorch教程-12.4。隨機梯度下降

    12.4。隨機梯度下降? Colab [火炬]在 Colab 中打開筆記本 Colab [mxnet] Open the notebook in Colab Colab [jax
    的頭像 發(fā)表于 06-05 15:44 ?410次閱讀
    PyTorch教程-12.4。<b class='flag-5'>隨機</b><b class='flag-5'>梯度</b><b class='flag-5'>下降</b>

    PyTorch教程-12.5。小批量隨機梯度下降

    12.4 節(jié)一次處理一個訓練示例以取得進展。它們中的任何一個都有其自身的缺點。當數據非常相似時,梯度下降并不是特別有效。隨機梯度
    的頭像 發(fā)表于 06-05 15:44 ?716次閱讀
    PyTorch教程-12.5。小批量<b class='flag-5'>隨機</b><b class='flag-5'>梯度</b><b class='flag-5'>下降</b>