Skip to content

Update release branch #3333

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 73 commits into from
Apr 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
3663320
Bump master to 1.1 and 0.13 (#3091)
shauheen Mar 26, 2019
70c6418
Binary LR samples using T4 templates (#3099)
zeahmed Mar 28, 2019
233bc2d
Created samples for 'FeaturizeText' API. (#3120)
zeahmed Mar 28, 2019
ee5fbe0
Created sample for 'TokenizeIntoCharactersAsKeys' API. (#3123)
zeahmed Mar 28, 2019
617f0f6
Fix grammar in exception message. (#3122)
codemzs Mar 28, 2019
e95f31d
Pass weighting value from ProduceWordBags to WordBagEstimator constru…
MarcinJuraszek Mar 29, 2019
0a2ec3a
Fix missing ExampleWeightColumnName in the advanced Options for some …
abgoswam Mar 29, 2019
21b5bb4
Created sample for 'ApplyWordEmbedding' API. (#3142)
zeahmed Apr 1, 2019
f93e973
Created sample for text normalizing API. (#3133)
zeahmed Apr 1, 2019
e5cbca7
Update VBuffer documentation (#3136)
TomFinley Apr 1, 2019
d2bf3e7
Restore OVA ability to preserve key names on predicted label (#3101)
Ivanidzo4ka Apr 1, 2019
41a6308
Updating .tt file due to renaming of LbfgsPoissonRegression. (#3140)
zeahmed Apr 1, 2019
fde1ab7
Move Normalizer extension method from experimental to stable nuget an…
codemzs Apr 2, 2019
0ce5618
Disable push to myget (#3157)
shauheen Apr 2, 2019
51fc8b2
Adding release notes for RC1 (#3176)
shauheen Apr 2, 2019
950f133
Created samples for TokenizeIntoWords and RemoveStopWords APIs. (#3156)
zeahmed Apr 2, 2019
1412ce1
Fix NuGet badge on README to show pre-release (#3189)
eerhardt Apr 3, 2019
9a80b78
Fix IncludeBuildNumberInPackageVersion for official builds (#3182)
eerhardt Apr 3, 2019
a7bcdda
Multi-column mapping API for normalizer estimators. (#3172)
codemzs Apr 3, 2019
ac53748
Samples and unit test for image-related transform estimators (#3165)
abgoswam Apr 3, 2019
e285889
Conversion catalog samples (#3167)
sfilipi Apr 4, 2019
dfa38ab
Key type documentation. (#3194)
TomFinley Apr 4, 2019
e54f295
Update Readme
shauheen Apr 4, 2019
24645ff
Created samples for 'ProduceWordBags' and 'ProduceHashedWordBags' API…
zeahmed Apr 4, 2019
9d79ab3
Samples for categorical transform estimators (#3179)
abgoswam Apr 4, 2019
b8a70ac
Fix a value-mapping bug (#3180)
wschin Apr 4, 2019
a8915f4
Created sample for 'LatentDirichletAllocation' API. (#3191)
zeahmed Apr 5, 2019
854f154
Created samples for 'ProduceNgrams' and 'ProduceHashedNgrams' APIs. (…
zeahmed Apr 5, 2019
8130567
Samples for FeatureSelection transform estimators (#3184)
abgoswam Apr 5, 2019
b291d95
TimeSeriesStatics naming. (#3215)
codemzs Apr 5, 2019
a5f0977
Fixing namespace for image samples (#3208)
abgoswam Apr 5, 2019
68640bb
Update description about key type and add one more reference (#3170)
wschin Apr 5, 2019
7e0cc46
Add loadable attribute for LinearMulticlassModelParameters (#3217)
Ivanidzo4ka Apr 5, 2019
d9df721
Rename sample methods to Example (#3212)
codemzs Apr 5, 2019
b2ac8e0
Fix marshalling of bool flags in MF (#3210)
wschin Apr 5, 2019
8e5c0bb
remove unused files. (#3223)
sfilipi Apr 5, 2019
2679f14
Add minor doc strings to some internal functions (#3102)
wschin Apr 5, 2019
073a33b
Renaming OptimizationTolerance to fix a spelling error. (#3199)
rogancarr Apr 5, 2019
fc89745
Refactoring related to namespaces and public input/output classes. (#…
zeahmed Apr 5, 2019
f19b560
Added OneVersusAll and PairwiseCoupling samples. (#3159)
ganik Apr 5, 2019
7a0d395
Multi column MapKeyToValue and MapValueToKey (#3187)
sfilipi Apr 7, 2019
8a03cf9
Fix bug in ONNX scorer sample. (#3230)
codemzs Apr 8, 2019
fdd24cf
Polish marshalling of MF model and MF problem and enable 32-bit tests…
wschin Apr 8, 2019
1724da8
Fix DNN Featurizer sample bug. (#3237)
codemzs Apr 8, 2019
36cad67
Fix LightGBM Ranking sample runtime exception. (#3257)
codemzs Apr 9, 2019
a57ad10
Fix SDCA sample runtime exception. (#3259)
codemzs Apr 9, 2019
ee14339
Fix runtime exception in ImageClassification. (#3249)
codemzs Apr 9, 2019
ad99bc7
Key to binary samples for documentation (#3211)
sfilipi Apr 9, 2019
3065a8f
Remove Microsoft.ML prefix from namespaces in samples binary. (#3267)
codemzs Apr 9, 2019
304170a
Samples for CustomMapping, IndicateMissingValues, ReplaceMissingValue…
artidoro Apr 10, 2019
6723bb6
Updated sample for Concatenate API. (#3262)
zeahmed Apr 10, 2019
e0c029c
Update Permutation Feature Importance Samples (#3247)
rogancarr Apr 10, 2019
947b3f8
Updated CopyColumns, DropColumns and SelectColumns samples. (#3268)
zeahmed Apr 10, 2019
f8c78d0
Ensable the uses of SSE and OpenMP in LIBMF (#3265)
wschin Apr 10, 2019
55d911d
Remove Console.Readline at the end of the samples. (#3278)
codemzs Apr 11, 2019
b6e602a
Add doc string to explain matrix-vector product's SSE code and a test…
wschin Apr 11, 2019
ef0302a
Time Series samples for stateful prediction engine. (#3213)
codemzs Apr 11, 2019
a4fb9a8
Update tt files to have Microsoft.ML prefix for SampleUtils. (#3285)
codemzs Apr 11, 2019
6f576de
Update Feature Contribution Calculation Samples (#3241)
rogancarr Apr 11, 2019
1e27ead
Fix runtime exception in MapKeyToVector sample. (#3287)
codemzs Apr 11, 2019
c601b77
Update Documents Index README.md (#3289)
tauheedul Apr 11, 2019
9c03a1c
Update IDataView principles, type system documentation. (#3288)
TomFinley Apr 11, 2019
bf4d605
Prior trainer should accept label column type of boolean ONLY. (#3291)
codemzs Apr 11, 2019
29ca1f8
Baseline test for MultiClassNaiveBayes. (#3113)
codemzs Apr 11, 2019
a602476
Try buid LIBMF with OpenMP again (#3297)
wschin Apr 11, 2019
41ba426
Fix runtime exception in Prior trainer sample and update the sample o…
codemzs Apr 11, 2019
89a1fb9
Add a sample for one class matrix factorization (#3282)
wschin Apr 12, 2019
663e939
Fix runtime exception in MapKeyToVectorMultiColumn.cs. (#3305)
codemzs Apr 12, 2019
43d4c18
Fix of #3822 to address some inadvertently omitted fixes on VectorDat…
TomFinley Apr 12, 2019
326727f
Simple IDataView implementation sample. (#3302)
TomFinley Apr 12, 2019
37ed336
Put product version with git commit into model.zip/version.txt (#3173)
Ivanidzo4ka Apr 12, 2019
e37e5b1
Extend Gam Samples (#3281)
rogancarr Apr 12, 2019
2dfcb57
Merge branch 'master' into RC2
Apr 13, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ Along with these ML capabilities, this first release of ML.NET also brings the f

## Installation

[![NuGet Status](https://img.shields.io/nuget/v/Microsoft.ML.svg?style=flat)](https://www.nuget.org/packages/Microsoft.ML/)
[![NuGet Status](https://img.shields.io/nuget/vpre/Microsoft.ML.svg?style=flat)](https://www.nuget.org/packages/Microsoft.ML/)

ML.NET runs on Windows, Linux, and macOS using [.NET Core](https://github.com/dotnet/core), or Windows using .NET Framework. 64 bit is supported on all platforms. 32 bit is supported on Windows, except for TensorFlow, LightGBM, and ONNX related functionality.

The current release is 0.11. Check out the [release notes](docs/release-notes/0.11/release-0.11.md) to see what's new.
The current release is 1.0.0-preview. Check out the [release notes](docs/release-notes/1.0.0-preview/release-1.0.0-preview.md) to see what's new.

First, ensure you have installed [.NET Core 2.1](https://www.microsoft.com/net/learn/get-started) or later. ML.NET also works on the .NET Framework 4.6.1 or later, but 4.7.2 or later is recommended.

Expand Down Expand Up @@ -86,7 +86,7 @@ var model = learningPipeline.Fit(data);
Now from the model we can make inferences (predictions):

```C#
var predictionEngine = model.CreatePredictionEngine<SentimentData, SentimentPrediction>(mlContext);
var predictionEngine = mlContext.Model.CreatePredictionEngine<SentimentData, SentimentPrediction>(model);
var prediction = predictionEngine.Predict(new SentimentData
{
SentimentText = "Today is a great day!"
Expand Down
25 changes: 24 additions & 1 deletion THIRD-PARTY-NOTICES.TXT
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,27 @@ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

License notice for SharpZipLib
------------------------------

https://github.com/icsharpcode/SharpZipLib

Copyright © 2000-2018 SharpZipLib Contributors

Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
16 changes: 15 additions & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,23 @@ Project Docs
- [Strong Name Signing](https://github.com/dotnet/corefx/blob/master/Documentation/project-docs/strong-name-signing.md)
- [Public Signing](https://github.com/dotnet/corefx/blob/master/Documentation/project-docs/public-signing.md)
- [Project NuGet Dependencies](https://github.com/dotnet/buildtools/blob/master/Documentation/project-nuget-dependencies.md)
- [ML.NET Roadmap](https://github.com/dotnet/machinelearning/blob/master/README.md)
- [ML.NET Cookbook](code/MlNetCookBook.md)
- [ML.NET API Reference Documentation](https://docs.microsoft.com/en-us/dotnet/api/?view=ml-dotnet)

Building from Source
====================

- [Building ML.NET on Linux and OS X](building/unix-instructions.md)
- [Building ML.NET on Windows](building/windows-instructions.md)
- [Building ML.NET on Windows](building/windows-instructions.md)

Repo of Samples
====================

- [ML.NET Samples](https://github.com/dotnet/machinelearning-samples/blob/master/README.md)

Extensions for ML.NET
====================

- [Infer.NET - Bayesian / Probabilistic inference for ML.NET](https://github.com/dotnet/infer/blob/master/README.md)
- [NimbusML - Python bindings for ML.NET](https://github.com/Microsoft/NimbusML/blob/master/README.md)
182 changes: 106 additions & 76 deletions docs/code/IDataViewDesignPrinciples.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ directly address distributed data and computation, but is suitable for single
node processing of data partitions belonging to larger distributed data sets.

IDataView is the data pipeline machinery for ML.NET. Microsoft teams consuming
this library have implemented libraries of IDataView related components
(loaders, transforms, savers, trainers, predictors, etc.) and have validated
the performance, scalability and task flexibility benefits.
this library have implemented libraries of IDataView related components (data
loaders, transformers, estimators, trainers, etc.) and have validated the
performance, scalability and task flexibility benefits.

The name IDataView was inspired from the database world, where the term table
typically indicates a mutable body of data, while a view is the result of a
Expand Down Expand Up @@ -128,10 +128,9 @@ The IDataView system design does *not* include the following:
view.

* **Efficient indexed row access**: There is no standard way in the IDataView
system to request the values for a specific row number. While the
`IRowCursor` interface has a `MoveMany(long count)` method, it only supports
moving forward `(count > 0)`, and is not necessarily more efficient than
calling `MoveNext()` repeatedly. See [here](#row-cursor).
system to request the values for a specific row number. Rather, like
enumerators, one can only move forward with `MoveNext()`. See
[here](#row-cursor) for more information.

* **Data file formats**: The IDataView system does not dictate storage or
transport formats. It *does* include interfaces for loader and saver
Expand Down Expand Up @@ -167,15 +166,15 @@ there is a precisely defined set of standard types including:
* Single and Double precision floating point
* Signed integer values using 1, 2, 4, or 8 bytes
* Unsigned integer values using 1, 2, 4, or 8 bytes
* Unsigned 16 byte values for ids and probabilistically unique hashes
* Values for ids and probabilistically unique hashes, using 16 bytes
* Date time, date time zone, and timespan
* Key types
* Vector types

The set of standard types will likely be expanded over time.

The IDataView type system is specified in a separate document, *IDataView Type
System Specification*.
The IDataView type system is specified in a separate document, [IDataView Type
System Specification](IDataViewTypeSystem.md).

IDataView provides a general mechanism for associating semantic annotations with
columns, such as designating sets of score columns, names associated with the
Expand Down Expand Up @@ -235,56 +234,85 @@ with a key type.
## Components

The IDataView system includes several standard kinds of components and the
ability to compose them to produce efficient data pipelines. A loader
represents a data source as an `IDataView`. A transform is applied to an
`IDataView` to produce a derived `IDataView`. A saver serializes the data
produced by an `IDataView` to a stream, in some cases in a format that can be
read by a loader. There are other more specific kinds of components defined
and used by the ML.NET code base, for example, scorers, evaluators, joins, and
caches. While there are several standard kinds of components, the set of
component kinds is open.

### Transforms

Transforms are a foundational kind of IDataView component. Transforms take an
IDataView as input and produce an IDataView as output. Many transforms simply
"add" one or more computed columns to their input schema. More precisely,
their output schema includes all the columns of the input schema, plus some
additional columns, whose values are computed from some of the input column
values. It is common for an added column to have the same name as an input
column, in which case, the added column hides the input column. Both the
original column and new column are present in the output schema and available
for downstream components (in particular, savers and diagnostic tools) to
inspect. For example, a normalization transform may, for each slot of a
vector-valued column named Features, apply an offset and scale factor and
bundle the results in a new vector-valued column, also named Features. From
the user's perspective (which is entirely based on column names), the Features
column was "modified" by the transform, but the original values are available
downstream via the hidden column.

Some transforms require training, meaning that their precise behavior is
determined automatically from some training data. For example, normalizers and
dictionary-based mappers, such as the TermTransform, build their state from
training data. Training occurs when the transform is instantiated from user-
provided parameters. Typically, the transform behavior is later serialized.
When deserialized, the transform is not retrained; its behavior is entirely
determined by the serialized information.
ability to compose them to produce efficient data pipelines:

Estimators and transformers. The langauge is derived from a similar idiom in
[Spark](https://spark.apache.org/).

A data loader allows data sources to be read as an `IDataView`. A transformer
is applied via its `Transform` method to an `IDataView` to produce a derived
`IDataView`. A saver serializes the data produced by an `IDataView` to a
stream, in some cases in a format that can be read by a loader. There are
other more specific kinds of components defined and used by the ML.NET code
base, for example, scorers, evaluators, joins, and caches, but most of the
aforementioned are internal. While there are several standard kinds of
components, the set of component kinds is open. In the following sections we
discuss the most important types of components in the public API of ML.NET.

### Transformers

Transformers are a foundational kind of IDataView component. They have two
primary responsibilities, from a user's point of view.

As the name suggests, the primary method is `Transform`, which takes
`IDataView` as input and produce an `IDataView` as output, using the
`ITransformer.Transform` method. Many transformers simply "add" one or more
computed columns to their input schema. More precisely, their output schema
includes all the columns of the input schema, plus some additional columns,
whose values are computed from some of the input column values. It is common
for an added column to have the same name as an input column, in which case,
the added column hides the input column. Both the original column and new
column are present in the output schema and available for downstream
components (in particular, savers and diagnostic tools) to inspect. For
example, a data view that comes from a normalization transformer may, for each
slot of a vector-valued column named `"Features"`, apply an offset and scale
factor and bundle the results in a new vector-valued column, also named
`"Features"`. From the user's perspective (which is entirely based on column
names), the Features column was "modified" by the transform, but the original
values are available downstream via the hidden column.

Transformers, being identified as central to our concept of a "model," are
serializable. When deserialized, the transformer should behave identically to
its serialized version.

### Estimators

Many transformers require training, meaning that their precise behavior is
determined from some training data. For example, normalizers and
dictionary-based mappers, such as the `ValueToKeyMappingTransformer`, build
their state from training data.

This training occurs with another structure generally parallel to
`ITransformer` called `IEstimator` configured using user parameters, that
returns an `ITransformer` once it is `Fit`. For example,
`NormalizingEstimator` implements `IEstimator<NormalizingTransformer>`, so the
return value of `Fit` is `NormalizingTransformer`.

### Composition Examples

Multiple primitive transforms may be applied to achieve higher-level
semantics. For example, ML.NET's `CategoricalTransform` is the composition of
two more primitive transforms, `TermTransform`, which maps each term to a key
value via a dictionary, and `KeyToVectorTransform`, which maps from key value
to indicator vector. Similarly, `CategoricalHashTransform` is the composition
of `HashTransform`, which maps each term to a key value via hashing, and
`KeyToVectorTransform`.

Similarly, `WordBagTransform` and `WordHashBagTransform` are each the
composition of three transforms. `WordBagTransform` consists of
`WordTokenizeTransform`, `TermTransform`, and `NgramTransform`, while
`WordHashBagTransform` consists of `WordTokenizeTransform`, `HashTransform`,
and `NgramHashTransform`.
semantics. For example, ML.NET's `OneHotEncodingTransformer` is the
composition of two more primitive transforms, `ValueToKeyMappingTransformer`,
which maps each term to a key value via a dictionary, and
`KeyToVectorMappingTransformer`, which maps from key value to indicator
vector. Similarly, `OneHotHashEncodingTransformer` is the composition of
`HashingTransformer`, which maps each term to a key value via hashing, and
`ValueToKeyMappingTransformer`.

### Schema Propagation

Because the act of fitting an estimator or transforming data is often
extremely expensive proposition, it is useful for pipelines to know *what*
they will produce and produce some at least preliminary validation on whether
a pipeline can actually work before one goes through doing this.

For this reason, both `ITransformer` and `IEstimator` have methods
`GetOutputSchema`, which respectively take and return `DataViewSchema` and
`SchemaShape`. In this way, programmatically a pipeline can be checked, at
least to some extent, before considerable time might be wasted on an
ultimately futile action is spent in the `Fit` method, since "downstream"
components were configured incorrectly with the wrong types, wrong names, or
some other issue.

## Cursoring

Expand All @@ -294,8 +322,7 @@ To access the data in a view, one gets a row cursor from the view by calling
the `GetRowCursor` method. The row cursor is a movable window onto a single
row of the view, known as the current row. The row cursor provides the column
values of the current row. The `MoveNext()` method of the cursor advances to
the next row. There is also a `MoveMany(long count)` method, which is
semantically equivalent to calling `MoveNext()` repeatedly, `count` times.
the next row.

Note that a row cursor is not thread safe; it should be used in a single
execution thread. However, multiple cursors can be active simultaneously on
Expand All @@ -318,10 +345,11 @@ column and row directions.
A row cursor has a set of active columns, determined by arguments passed to
`GetRowCursor`. Generally, the cursor, and any upstream components, will only
perform computation or data movement necessary to provide values of the active
columns. For example, when `TermTransform` builds its term dictionary from its
input `IDataView`, it gets a row cursor from the input view with only the term
column active. Any data loading or computation not required to materialize the
term column is avoided. This is lazy computation in the column direction.
columns. For example, when `ValueToKeyMappingTransformer` builds its term
dictionary from its input `IDataView`, it gets a row cursor from the input
view with only the term column active. Any data loading or computation not
required to materialize the term column is avoided. This is lazy computation
in the column direction.

Generally, creating a row cursor is a very cheap operation. The expense is in
the data movement and computation required to iterate over the rows. If a
Expand Down Expand Up @@ -360,17 +388,19 @@ encourage parallel execution. If the view is a transform that can benefit from
parallelism, it requests from its input view, not just a cursor, but a cursor
set. If that view is a transform, it typically requests from its input view a
cursor set, etc., on up the transformation chain. At some point in the chain
(perhaps at a loader), a component, called the splitter, determines how many
cursors should be active, creates those cursors, and returns them together
with a consolidator object. At the other end, the consolidator is invoked to
marshal the multiple cursors back into a single cursor. Intervening levels
simply create a cursor on each input cursor, return that set of cursors as
well as the consolidator.

The ML.NET code base includes transform base classes that implement the
minimal amount of code required to support this batch parallel cursoring
design. Consequently, most transform implementations do not have any special
code to support batch parallel cursoring.
(perhaps at a loader), a component determines how many cursors should be
active, creates those cursors, and returns them. These cursors can be either
independently processed in different threads, or else an internal utility
method is invoked to marshal the multiple cursors back into a single cursor.
Intervening levels simply create a cursor on each input cursor, return that
set of cursors as well as the consolidator.

The ML.NET code base includes internal `IDataView` implementations that
implement the minimal amount of code required to support this batch parallel
cursoring design, most notably by the `IDataView` implementors returned from
`ITransformer` implementations that that are also one-to-one mappers.
Consequently, most transformer implementations do not have any special code to
support batch parallel cursoring.

### Memory Efficiency

Expand Down Expand Up @@ -415,9 +445,9 @@ the random number generator. Serving rows from disk in a random order is quite
difficult to do efficiently (without seeking for each row). The binary .idv
loader has some shuffling support, favoring performance over attempting to
provide a uniform distribution over the permutation space. This level of
support has been validated to be sufficient for machine learning goals (for example,
in recent work on SA-SDCA algorithm). When the data is all in memory, as it is
when cached, randomizing is trivial.
support has been validated to be sufficient for machine learning goals (for
example, in recent work on SA-SDCA algorithm). When the data is all in memory,
as it is when cached, randomizing is trivial.

## Appendix: Comparison with LINQ

Expand Down
Loading