如何将相关系数指定为keras中的损失函数

时间:2017-10-07 11:59:31

标签: python machine-learning tensorflow keras

我第一次使用keras + tensorflow。我想指定correlation coefficient作为损失函数。对它进行平方是有意义的,它是一个介于0和1之间的数字,其中0表示不好,1表示良好。

我的基本代码目前如下:

<?php
require_once 'C:/xampp/htdocs/json/pcrov/vendor/autoload.php';
use \pcrov\JsonReader\JsonReader;
ini_set("max_execution_time", 0);
$reader = new JsonReader();
$reader->open("jsonfile.json");
$fo = fopen("csvfile.csv", "w" );
fputs($fo, "name, companyID, ultimateHoldingCompany".PHP_EOL);
while ($reader->read(strpos($key, "foo__"))) {
    // I want to loop through the key that contains foo_ and print the key name
    $companyID = null;
    $entityName = null;
    $uhc = null;
    $companyID = $key
    $entityName = $reader->value();
    $UltimateHoldingCompany = $reader['ultimateHoldingCompany']['name']-
    >value;
    fputs($fo, 
    $entityName.",".$companyID.",".$UltimateHoldingCompany.PHP_EOL);
   }
  $reader->close();
  ?>

如何更改此值以便优化以最小化平方相关系数?

我尝试了以下内容:

def baseline_model():
        model = Sequential()
        model.add(Dense(4000, input_dim=n**2, kernel_initializer='normal', activation='relu'))
        model.add(Dense(1, kernel_initializer='normal'))
        # Compile model
        model.compile(loss='mean_squared_error', optimizer='adam')
        return model

estimators = []
estimators.append(('standardize', StandardScaler()))
estimators.append(('mlp', KerasRegressor(build_fn=baseline_model, epochs=100, batch_size=32, verbose=2)))
pipeline = Pipeline(estimators)
kfold = KFold(n_splits=10, random_state=0)
results = cross_val_score(pipeline, X, Y, cv=kfold)
print("Standardized: %.2f (%.2f) MSE" % (results.mean(), results.std()))

但是这会崩溃:

def correlation_coefficient(y_true, y_pred):
    pearson_r, _ = tf.contrib.metrics.streaming_pearson_correlation(y_pred, y_true)
    return 1-pearson_r**2

def baseline_model():
# create model
        model = Sequential()
        model.add(Dense(4000, input_dim=n**2, kernel_initializer='normal', activation='relu'))
#        model.add(Dense(2000, kernel_initializer='normal', activation='relu'))
        model.add(Dense(1, kernel_initializer='normal'))
        # Compile model
        model.compile(loss=correlation_coefficient, optimizer='adam')
        return model

更新1

按照下面的答案,代码现在运行。不幸的是,Traceback (most recent call last): File "deeplearning-det.py", line 67, in <module> results = cross_val_score(pipeline, X, Y, cv=kfold) File "/home/user/.local/lib/python3.5/site-packages/sklearn/model_selection/_validation.py", line 321, in cross_val_score pre_dispatch=pre_dispatch) File "/home/user/.local/lib/python3.5/site-packages/sklearn/model_selection/_validation.py", line 195, in cross_validate for train, test in cv.split(X, y, groups)) File "/home/user/.local/lib/python3.5/site-packages/sklearn/externals/joblib/parallel.py", line 779, in __call__ while self.dispatch_one_batch(iterator): File "/home/user/.local/lib/python3.5/site-packages/sklearn/externals/joblib/parallel.py", line 625, in dispatch_one_batch self._dispatch(tasks) File "/home/user/.local/lib/python3.5/site-packages/sklearn/externals/joblib/parallel.py", line 588, in _dispatch job = self._backend.apply_async(batch, callback=cb) File "/home/user/.local/lib/python3.5/site-packages/sklearn/externals/joblib/_parallel_backends.py", line 111, in apply_async result = ImmediateResult(func) File "/home/user/.local/lib/python3.5/site-packages/sklearn/externals/joblib/_parallel_backends.py", line 332, in __init__ self.results = batch() File "/home/user/.local/lib/python3.5/site-packages/sklearn/externals/joblib/parallel.py", line 131, in __call__ return [func(*args, **kwargs) for func, args, kwargs in self.items] File "/home/user/.local/lib/python3.5/site-packages/sklearn/externals/joblib/parallel.py", line 131, in <listcomp> return [func(*args, **kwargs) for func, args, kwargs in self.items] File "/home/user/.local/lib/python3.5/site-packages/sklearn/model_selection/_validation.py", line 437, in _fit_and_score estimator.fit(X_train, y_train, **fit_params) File "/home/user/.local/lib/python3.5/site-packages/sklearn/pipeline.py", line 259, in fit self._final_estimator.fit(Xt, y, **fit_params) File "/home/user/.local/lib/python3.5/site-packages/keras/wrappers/scikit_learn.py", line 147, in fit history = self.model.fit(x, y, **fit_args) File "/home/user/.local/lib/python3.5/site-packages/keras/models.py", line 867, in fit initial_epoch=initial_epoch) File "/home/user/.local/lib/python3.5/site-packages/keras/engine/training.py", line 1575, in fit self._make_train_function() File "/home/user/.local/lib/python3.5/site-packages/keras/engine/training.py", line 960, in _make_train_function loss=self.total_loss) File "/home/user/.local/lib/python3.5/site-packages/keras/legacy/interfaces.py", line 87, in wrapper return func(*args, **kwargs) File "/home/user/.local/lib/python3.5/site-packages/keras/optimizers.py", line 432, in get_updates m_t = (self.beta_1 * m) + (1. - self.beta_1) * g File "/home/user/.local/lib/python3.5/site-packages/tensorflow/python/ops/math_ops.py", line 856, in binary_op_wrapper y = ops.convert_to_tensor(y, dtype=x.dtype.base_dtype, name="y") File "/home/user/.local/lib/python3.5/site-packages/tensorflow/python/framework/ops.py", line 611, in convert_to_tensor as_ref=False) File "/home/user/.local/lib/python3.5/site-packages/tensorflow/python/framework/ops.py", line 676, in internal_convert_to_tensor ret = conversion_func(value, dtype=dtype, name=name, as_ref=as_ref) File "/home/user/.local/lib/python3.5/site-packages/tensorflow/python/framework/constant_op.py", line 121, in _constant_tensor_conversion_function return constant(v, dtype=dtype, name=name) File "/home/user/.local/lib/python3.5/site-packages/tensorflow/python/framework/constant_op.py", line 102, in constant tensor_util.make_tensor_proto(value, dtype=dtype, shape=shape, verify_shape=verify_shape)) File "/home/user/.local/lib/python3.5/site-packages/tensorflow/python/framework/tensor_util.py", line 364, in make_tensor_proto raise ValueError("None values not supported.") ValueError: None values not supported. correlation_coefficient函数给出了彼此不同的值,我不确定它们是否与1- scipy.stats.pearsonr()[0] *相同* 2。

  

为什么损失功能会产生错误的输出以及它们如何产生   更正为提供与correlation_coefficient_loss相同的值?

这是完全自包含的代码,应该只运行:

1 -
  scipy.stats.pearsonr()[0]**2

更新2

我放弃了import numpy as np import sys import math from scipy.stats import ortho_group from scipy.stats import pearsonr import matplotlib.pyplot as plt from keras.models import Sequential from keras.layers import Dense from keras.wrappers.scikit_learn import KerasRegressor from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.pipeline import Pipeline import tensorflow as tf from keras import backend as K def permanent(M): n = M.shape[0] d = np.ones(n) j = 0 s = 1 f = np.arange(n) v = M.sum(axis=0) p = np.prod(v) while (j < n-1): v -= 2*d[j]*M[j] d[j] = -d[j] s = -s prod = np.prod(v) p += s*prod f[0] = 0 f[j] = f[j+1] f[j+1] = j+1 j = f[0] return p/2**(n-1) def correlation_coefficient_loss(y_true, y_pred): x = y_true y = y_pred mx = K.mean(x) my = K.mean(y) xm, ym = x-mx, y-my r_num = K.sum(xm * ym) r_den = K.sum(K.sum(K.square(xm)) * K.sum(K.square(ym))) r = r_num / r_den return 1 - r**2 def correlation_coefficient(y_true, y_pred): pearson_r, update_op = tf.contrib.metrics.streaming_pearson_correlation(y_pred, y_true) # find all variables created for this metric metric_vars = [i for i in tf.local_variables() if 'correlation_coefficient' in i.name.split('/')[1]] # Add metric variables to GLOBAL_VARIABLES collection. # They will be initialized for new session. for v in metric_vars: tf.add_to_collection(tf.GraphKeys.GLOBAL_VARIABLES, v) # force to update metric values with tf.control_dependencies([update_op]): pearson_r = tf.identity(pearson_r) return 1-pearson_r**2 def baseline_model(): # create model model = Sequential() model.add(Dense(4000, input_dim=no_rows**2, kernel_initializer='normal', activation='relu')) # model.add(Dense(2000, kernel_initializer='normal', activation='relu')) model.add(Dense(1, kernel_initializer='normal')) # Compile model model.compile(loss=correlation_coefficient_loss, optimizer='adam', metrics=[correlation_coefficient]) return model no_rows = 8 print("Making the input data using seed 7", file=sys.stderr) np.random.seed(7) U = ortho_group.rvs(no_rows**2) U = U[:, :no_rows] # U is a random orthogonal matrix X = [] Y = [] print(U) for i in range(40000): I = np.random.choice(no_rows**2, size = no_rows) A = U[I][np.lexsort(np.rot90(U[I]))] X.append(A.ravel()) Y.append(-math.log(permanent(A)**2, 2)) X = np.array(X) Y = np.array(Y) estimators = [] estimators.append(('standardize', StandardScaler())) estimators.append(('mlp', KerasRegressor(build_fn=baseline_model, epochs=100, batch_size=32, verbose=2))) pipeline = Pipeline(estimators) X_train, X_test, y_train, y_test = train_test_split(X, Y, train_size=0.75, test_size=0.25) pipeline.fit(X_train, y_train) 功能,现在只使用下面JulioDanielReyes给出的correlation_coefficient。然而,要么这仍然是错误的,要么keras显然过度拟合。即使我有:

correlation_coefficient_loss

例如,在100个时期之后我损失了0.6653但是当我测试训练模型时损失了0.857。

  

如何过度拟合中的这么少数量的节点   隐藏层?

3 个答案:

答案 0 :(得分:15)

根据keras documentation,您应该将平方相关系数作为函数而不是字符串'mean_squared_error'传递。

该功能需要接收2个张量(y_true, y_pred)。你可以看一下keras source code的灵感。

在tensorflow上还实现了一个函数tf.contrib.metrics.streaming_pearson_correlation。请注意参数的顺序,它应该是这样的:

更新1:根据此issue

初始化局部变量
import tensorflow as tf
def correlation_coefficient(y_true, y_pred):
    pearson_r, update_op = tf.contrib.metrics.streaming_pearson_correlation(y_pred, y_true, name='pearson_r'
    # find all variables created for this metric
    metric_vars = [i for i in tf.local_variables() if 'pearson_r'  in i.name.split('/')]

    # Add metric variables to GLOBAL_VARIABLES collection.
    # They will be initialized for new session.
    for v in metric_vars:
        tf.add_to_collection(tf.GraphKeys.GLOBAL_VARIABLES, v)

    # force to update metric values
    with tf.control_dependencies([update_op]):
        pearson_r = tf.identity(pearson_r)
        return 1-pearson_r**2

...

model.compile(loss=correlation_coefficient, optimizer='adam')

更新2 :即使您无法直接使用scipy功能,也可以查看implementation并使用keras backend将其移植到您的代码中。

更新3:张力流函数可能不是可微分的,你的损失函数必须是这样的:(请检查数学)

from keras import backend as K
def correlation_coefficient_loss(y_true, y_pred):
    x = y_true
    y = y_pred
    mx = K.mean(x)
    my = K.mean(y)
    xm, ym = x-mx, y-my
    r_num = K.sum(tf.multiply(xm,ym))
    r_den = K.sqrt(tf.multiply(K.sum(K.square(xm)), K.sum(K.square(ym))))
    r = r_num / r_den

    r = K.maximum(K.minimum(r, 1.0), -1.0)
    return 1 - K.square(r)

更新4:两个函数的结果都不同,但correlation_coefficient_lossscipy.stats.pearsonr的结果相同: 以下是测试它的代码:

import tensorflow as tf
from keras import backend as K
import numpy as np
import scipy.stats

inputa = np.array([[3,1,2,3,4,5],
                    [1,2,3,4,5,6],
                    [1,2,3,4,5,6]])
inputb = np.array([[3,1,2,3,4,5],
                    [3,1,2,3,4,5],
                    [6,5,4,3,2,1]])

with tf.Session() as sess:
    a = tf.placeholder(tf.float32, shape=[None])
    b = tf.placeholder(tf.float32, shape=[None])
    f1 = correlation_coefficient(a, b)
    f2 = correlation_coefficient_loss(a, b)

    sess.run(tf.global_variables_initializer())

    for i in range(inputa.shape[0]):

        f1_result, f2_result = sess.run([f1, f2], feed_dict={a: inputa[i], b: inputb[i]})
        scipy_result =1- scipy.stats.pearsonr(inputa[i], inputb[i])[0]**2
        print("a: "+ str(inputa[i]) + " b: " + str(inputb[i]))
        print("correlation_coefficient: " + str(f1_result))
        print("correlation_coefficient_loss: " + str(f2_result))
        print("scipy.stats.pearsonr:" + str(scipy_result))

结果:

a: [3 1 2 3 4 5] b: [3 1 2 3 4 5]
correlation_coefficient: -2.38419e-07
correlation_coefficient_loss: 0.0
scipy.stats.pearsonr:0.0
a: [1 2 3 4 5 6] b: [3 1 2 3 4 5]
correlation_coefficient: 0.292036
correlation_coefficient_loss: 0.428571
scipy.stats.pearsonr:0.428571428571
a: [1 2 3 4 5 6] b: [6 5 4 3 2 1]
correlation_coefficient: 0.994918
correlation_coefficient_loss: 0.0
scipy.stats.pearsonr:0.0

答案 1 :(得分:1)

以下代码是tensorflow 2.0版中相关系数的实现

import tensorflow as tf

def correlation(x, y):    
    mx = tf.math.reduce_mean(x)
    my = tf.math.reduce_mean(y)
    xm, ym = x-mx, y-my
    r_num = tf.math.reduce_mean(tf.multiply(xm,ym))        
    r_den = tf.math.reduce_std(xm) * tf.math.reduce_std(ym)
    return = r_num / r_den

它返回与numpy的corrcoef函数相同的结果。

答案 2 :(得分:0)

r = scipy.stats.pearsonr(inputa[i], inputb[i])[0] 

r是相关性,那么为什么对r取平方?

scipy_result = 1 - scipy.stats.pearsonr(inputa[i], inputb[i])[0]**2

rscipy_result之间的关系是什么?