[MRG] Switch BernoulliRBM to CSR format
diff --git a/sklearn/neural_network/rbm.py b/sklearn/neural_network/rbm.py
index 88250abb02851..323a20f15b78a 100644
--- a/sklearn/neural_network/rbm.py
+++ b/sklearn/neural_network/rbm.py
@@ -16,6 +16,7 @@
 from ..utils import check_arrays
 from ..utils import check_random_state
 from ..utils import gen_even_slices
+from ..utils import issparse
 from ..utils.extmath import safe_sparse_dot
 from ..utils.extmath import logistic_sigmoid
 
@@ -48,8 +49,10 @@ class BernoulliRBM(BaseEstimator, TransformerMixin):
         Number of iterations/sweeps over the training dataset to perform
         during training.
 
-    verbose : bool, optional
-        The verbosity level.
+    verbose : int, optional
+        The verbosity level. Enabling it (with a non-zero value) will compute 
+        the log-likelihood of each mini-batch and hence cause a runtime overhead
+        in the order of 10%.
 
     random_state : integer or numpy.RandomState, optional
         A random number generator instance to define the state of the
@@ -112,7 +115,7 @@ def transform(self, X):
         h : array, shape (n_samples, n_components)
             Latent representations of the data.
         """
-        X, = check_arrays(X, sparse_format='csc', dtype=np.float)
+        X, = check_arrays(X, sparse_format='csr', dtype=np.float)
         return self._mean_hiddens(X)
 
     def _mean_hiddens(self, v):
@@ -185,9 +188,9 @@ def _free_energy(self, v):
         free_energy : array-like, shape (n_samples,)
             The value of the free energy.
         """
-        return - np.dot(v, self.intercept_visible_) - np.log(1. + np.exp(
-            safe_sparse_dot(v, self.components_.T) + self.intercept_hidden_)) \
-            .sum(axis=1)
+        return (- safe_sparse_dot(v, self.intercept_visible_)
+                - np.log(1. + np.exp(safe_sparse_dot(v, self.components_.T)
+                            + self.intercept_hidden_)).sum(axis=1))
 
     def gibbs(self, v):
         """Perform one Gibbs sampling step.
@@ -262,7 +265,10 @@ def score_samples(self, v):
         rng = check_random_state(self.random_state)
         fe = self._free_energy(v)
 
-        v_ = v.copy()
+        if issparse(v):
+            v_ = v.toarray()
+        else:
+            v_ = v.copy()
         i_ = rng.randint(0, v.shape[1], v.shape[0])
         v_[np.arange(v.shape[0]), i_] = 1 - v_[np.arange(v.shape[0]), i_]
         fe_ = self._free_energy(v_)
@@ -282,7 +288,7 @@ def fit(self, X, y=None):
         self : BernoulliRBM
             The fitted model.
         """
-        X, = check_arrays(X, sparse_format='csc', dtype=np.float)
+        X, = check_arrays(X, sparse_format='csr', dtype=np.float)
         n_samples = X.shape[0]
         rng = check_random_state(self.random_state)
 
diff --git a/sklearn/neural_network/tests/test_rbm.py b/sklearn/neural_network/tests/test_rbm.py
index 34d50e53e7c0f..64eaa2dd60852 100644
--- a/sklearn/neural_network/tests/test_rbm.py
+++ b/sklearn/neural_network/tests/test_rbm.py
@@ -1,7 +1,7 @@
 import sys
+import re
 
 import numpy as np
-
 from numpy.testing import assert_almost_equal, assert_array_equal
 
 from sklearn.datasets import load_digits
@@ -121,3 +121,24 @@ def test_rbm_verbose():
         rbm.fit(Xdigits)
     finally:
         sys.stdout = old_stdout
+
+
+def test_sparse_and_verbose():
+    """
+    Make sure RBM works with sparse input when verbose=True
+    """
+    old_stdout = sys.stdout
+    sys.stdout = StringIO()
+    from scipy.sparse import csc_matrix
+    X = csc_matrix([[0.], [1.]])
+    rbm = BernoulliRBM(n_components=2, batch_size=2, n_iter=1,
+                       random_state=42, verbose=True)
+    try:
+        rbm.fit(X)
+        s = sys.stdout.getvalue()
+        # make sure output is sound
+        assert(re.match(r"Iteration 0, pseudo-likelihood = -?(\d)+(\.\d+)?",
+                        s))
+    finally:
+        sio = sys.stdout
+        sys.stdout = old_stdout

While taking a look at Issue #2455, I've noticed that `BernoulliRBM`  enforces CSC format for sparse data. However it accesses the data row-wise (it trains in Minibatches of `batch_size` rows). Thus CSR format seems like a much more natural choice.

I ran some short tests on a 2000x100000 sparse matrix with 95% sparsity on an RBM with 128 components, and saw a speedup of ~ 5% when switching from CSC to CSR matrices... (I'd expect the speedup to be larger on larger matrices).
