8

Gần đây tôi đã cố gắng tìm hiểu Apache Spark như một sự thay thế cho Scikit Learn, tuy nhiên dường như với tôi ngay cả trong những trường hợp đơn giản, Scikit cũng hội tụ với một mô hình chính xác nhanh hơn Spark. Ví dụ tôi tạo ra 1000 điểm dữ liệu cho một hàm tuyến tính rất đơn giản (z = x + y) với kịch bản sau đây:Apache Spark có kém chính xác hơn Scikit Learn?

from random import random 

def func(in_vals): 
    '''result = x (+y+z+w....)''' 
    result = 0 
    for v in in_vals: 
     result += v 
    return result 

if __name__ == "__main__": 
    entry_count = 1000 
    dim_count = 2 
    in_vals = [0]*dim_count 
    with open("data_yequalsx.csv", "w") as out_file: 
     for entry in range(entry_count): 
      for i in range(dim_count): 
       in_vals[i] = random() 
      out_val = func(in_vals) 
      out_file.write(','.join([str(x) for x in in_vals])) 
      out_file.write(",%s\n" % str(out_val)) 

sau đó tôi chạy kịch bản Scikit sau:

import sklearn 
from sklearn import linear_model 

import numpy as np 

data = [] 
target = [] 
with open("data_yequalsx.csv") as inFile: 
    for row in inFile: 
     vals = row.split(",") 
     data.append([float(x) for x in vals[:-1]]) 
     target.append(float(vals[-1])) 

test_samples= len(data)/10 

train_data = [0]*(len(data) - test_samples) 
train_target = [0]*(len(data) - test_samples) 
test_data = [0]*(test_samples) 
test_target = [0]*(test_samples) 
train_index = 0 
test_index = 0 
for j in range(len(data)): 
    if j >= test_samples: 
     train_data[train_index] = data[j] 
     train_target[train_index] = target[j] 
     train_index += 1 
    else: 
     test_data[test_index] = data[j] 
     test_target[test_index] = target[j] 
     test_index += 1 

model = linear_model.SGDRegressor(n_iter=100, learning_rate="invscaling", eta0=0.0001, power_t=0.5, penalty="l2", alpha=0.0001, loss="squared_loss") 
model.fit(train_data, train_target) 
print(model.coef_) 
print(model.intercept_) 

result = model.predict(test_data) 
mse = np.mean((result - test_target) ** 2) 
print("Mean Squared Error = %s" % str(mse)) 

Và sau đó kịch bản Spark này: (với spark-gửi, không có đối số khác)

from pyspark.mllib.regression import LinearRegressionWithSGD, LabeledPoint 
from pyspark import SparkContext 

sc = SparkContext (appName="mllib_simple_accuracy") 

raw_data = sc.textFile ("data_yequalsx.csv", minPartitions=10) #MinPartitions doesnt guarantee that you get that many partitions, just that you wont have fewer than that many partitions 
data = raw_data.map(lambda line: [float(x) for x in line.split (",")]).map(lambda entry: LabeledPoint (entry[-1], entry[:-1])).zipWithIndex() 
test_samples= data.count()/10 

training_data = data.filter(lambda (entry, index): index >= test_samples).map(lambda (lp,index): lp) 
test_data = data.filter(lambda (entry, index): index < test_samples).map(lambda (lp,index): lp) 

model = LinearRegressionWithSGD.train(training_data, step=0.01, iterations=100, regType="l2", regParam=0.0001, intercept=True) 
print(model._coeff) 
print(model._intercept) 

mse = (test_data.map(lambda lp: (lp.label - model.predict(lp.features))**2).reduce(lambda x,y: x+y))/test_samples; 
print("Mean Squared Error: %s" % str(mse)) 

sc.stop() 

Kỳ lạ thay, mặc dù lỗi do tia lửa là một thứ tự tầm quan trọng lớn hơn do Scikit (0.185 và 0.045 tương ứng) mặc dù hai mô hình có thiết lập gần như giống nhau (theo như tôi có thể biết) Tôi hiểu rằng điều này đang sử dụng SGD với rất ít lần lặp lại và kết quả có thể khác nhau nhưng tôi không nghĩ rằng nó sẽ ở bất cứ nơi nào gần một sự khác biệt lớn như vậy hoặc một lỗi lớn như vậy, đặc biệt là với dữ liệu đặc biệt đơn giản.


Có điều gì tôi hiểu nhầm trong Spark? Nó có được cấu hình đúng không? Chắc chắn tôi sẽ nhận được một lỗi nhỏ hơn thế?

+1

Tôi đề nghị bạn cung cấp giới hạn lỗi bằng cách lặp lại thí nghiệm nhiều lần với các hạt giống ngẫu nhiên khác nhau và kiểm tra xem bạn có nhận được kết quả tương tự hay không, 1000 điểm dữ liệu và 100 lần lặp lại không nhiều lắm, ngoài ra, sklearn và mllib sử dụng cùng một tốc độ học tập cho SGD, bạn sử dụng invscaling cho sklearn. giống nhau? –

Trả lời

2

Vì Spark được song song, mỗi nút cần có khả năng hoạt động độc lập với các nút khác khi tính toán đang được tiến hành để tránh các khoảng thời gian đắt tiền giữa các nút. Do đó, nó sử dụng một thủ tục gọi là Stochastic Gradient Descent để đạt đến mức tối thiểu, theo sau các gradient cục bộ xuống dưới.

Cách 'chính xác' để giải quyết vấn đề hồi qui [đơn giản, nhỏ nhất] liên quan đến việc giải phương trình ma trận. Đây có lẽ là những gì Scikit-Learn đang làm, vì vậy trong trường hợp này nó sẽ chính xác hơn.

Sự cân bằng là giải phương trình ma trận thường có tỷ lệ N^3 cho ma trận vuông cỡ N, nhanh chóng trở nên không khả thi đối với các tập dữ liệu lớn. Spark hoán đổi độ chính xác cho công suất tính toán. Như với bất kỳ quy trình học máy nào, bạn nên xây dựng trong LOTS của kiểm tra sanity trong suốt các thuật toán của bạn để đảm bảo rằng kết quả của bước trước đó có ý nghĩa gì.

Hy vọng điều này sẽ hữu ích!

3

SGD, viết tắt của Stochastic Gradient Descent, là thuật toán tối ưu hóa lồi trực tuyến và do đó rất khó để song song, vì nó làm cho một bản cập nhật cho mỗi lần lặp lại (có các biến thể thông minh hơn như SGD với các lô nhỏ, nhưng vẫn không Mặt khác, các thuật toán lô, chẳng hạn như L-BFGS, hwich tôi khuyên bạn nên sử dụng với Spark (LogigisticRegressionWithLBFGS), có thể dễ dàng song song, vì nó làm cho việc lặp lại trên mỗi kỷ nguyên (nó cần xem tất cả các điểm dữ liệu, tính toán giá trị và độ dốc của hàm mất của mỗi điểm, sau đó thực hiện tổng hợp để tính toán độ dốc đầy đủ)

Python được chạy trong một máy duy nhất, do đó SGD hoạt động tốt.

Bằng cách này, nếu bạn nhìn vào mã MLlib, tương đương với scikit học của lambda là lambda/kích thước của tập dữ liệu (mllib tối ưu hóa 1/n*sum(l_i(x_i,f(y_i)) + lambda khi scikit học tối ưu hóa sum(l_i(x_i,f(y_i)) + lambda

Các vấn đề liên quan