Skip to content

396 convert regressors to num power 1#416

Open
apphp wants to merge 17 commits into
RubixML:3.0from
apphp:396-convert-regressors-to-num-power-1
Open

396 convert regressors to num power 1#416
apphp wants to merge 17 commits into
RubixML:3.0from
apphp:396-convert-regressors-to-num-power-1

Conversation

@apphp

@apphp apphp commented Jul 7, 2026

Copy link
Copy Markdown

No description provided.

@apphp
apphp requested a review from andrewdalpino July 7, 2026 08:25
@apphp apphp self-assigned this Jul 7, 2026
Comment thread src/Regressors/MLPRegressor.php Outdated
$this->holdOut = $holdOut;
$this->costFn = $costFn ?? new LeastSquares();
$this->metric = $metric ?? new RMSE();
$this->packSamples = $packSamples;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we autodetect whether we need to pack samples or not? If so I'd prefer we did that instead of passing it in at the constructor. What happens if someone passes in packed samples and then unpacked samples after that?

@apphp apphp Jul 9, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored with auto-detection of arrays, that need pack operation - see array_pack() function

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sweet! Nice work man

Comment thread src/Regressors/GradientBoost.php Outdated
public function featureImportances() : array
{
if (!isset($this->ensemble, $this->featureCount)) {
if (!$this->ensemble || !$this->featureCount) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This new lines is not the same as the old logic. Why did you change it?

@apphp apphp Jul 9, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My mistake - turned back.

Comment thread src/Regressors/Adaline.php Outdated
$this->network = new FeedForward(
new Placeholder1D($dataset->numFeatures()),
[new Dense(1, $this->l2Penalty, true, new Xavier2())],
[new Dense(1, $this->l2Penalty, true, new XavierUniform())],

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since XavierUniform implements Xavier1 initialization, this change is not equivalent to the old line. We'll need to implement Xavier2Uniform and rename XavierUniform to Xavier1Uniform.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed with Xavier2Uniform

Comment thread src/Classifiers/SoftmaxClassifier.php Outdated
$this->network = new FeedForward(
new Placeholder1D($dataset->numFeatures()),
[new Dense(count($classes), $this->l2Penalty, true, new Xavier1())],
[new Dense(count($classes), $this->l2Penalty, true, new XavierNormal())],

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

XavierNormal is not equivalent to Xavier1 which samples from a uniform distribution.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed with Xavier1Uniform

$hiddenLayers = $this->hiddenLayers;

$hiddenLayers[] = new Dense(count($classes), 0.0, true, new Xavier1());
$hiddenLayers[] = new Dense(count($classes), 0.0, true, new XavierNormal());

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

XavierNormal is not equivalent to Xavier1 which samples from a uniform distribution.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed with using Xavier1Uniform

Comment thread src/Classifiers/LogisticRegression.php Outdated
$this->network = new FeedForward(
new Placeholder1D($dataset->numFeatures()),
[new Dense(1, $this->l2Penalty, true, new Xavier1())],
[new Dense(1, $this->l2Penalty, true, new XavierNormal())],

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

XavierNormal is not equivalent to Xavier1 which samples from a uniform distribution.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed with using Xavier1Uniform

Comment thread src/Regressors/GradientBoost.php Outdated
Comment thread phpstan-bootstrap.php
andrewdalpino
andrewdalpino previously approved these changes Jul 20, 2026

@andrewdalpino andrewdalpino left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a

$this->validateFanInFanOut(fanIn: $fanIn, fanOut: $fanOut);

// Xavier-2 uses fourth-root scaling instead of standard square-root Xavier 1 scaling.
$limit = (6.0 / ($fanOut + $fanIn)) ** 0.25;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, yeah Xavier2 uses that fourth root instead of square root.

@andrewdalpino
andrewdalpino dismissed their stale review July 20, 2026 00:05

Found more potential issues

@andrewdalpino andrewdalpino left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok Xavier2 Uniform looks good. Did you want to add Xavier2 Normal just to match the Xavier1 Normal you added?

Nice work regarding array_pack, I like the idea of building the optimization into the function itself. It handles the case of a semi-packed array, an edge case, but bound to happen to someone - so this approach solves that.

I'm asking about the need for depth arguments in the comments. Let me know what you think.

Comment thread src/functions.php
* @param int $maxDepth
* @return array<mixed>
*/
function array_pack(array $samples, int $depth = 0, int $maxDepth = 100) : array

@andrewdalpino andrewdalpino Jul 20, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need the $depth and $maxDepth arguments?

"PHP arrays are finite trees (no circular references), so infinite recursion can't happen."

Do we need these arguments for anything beyond preventing infinite recursion? If not, then let's simplify the API. Example (untested) ...

function array_pack(array $samples): array
{
        if (!array_is_list($samples)) {
            $samples = array_values($samples);
        }
 
        return array_map(function ($item) {
            if (is_array($item)) {
                if (!array_is_list($item)) {
                    $item = array_values($item);
                }

                return array_pack($item);
            }
            
            return $item;
        }, $samples;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants