Skip to content
This repository has been archived by the owner on Sep 14, 2021. It is now read-only.

Commit

Permalink
Fix #60 - Can now handle datasets with dimensions > points
Browse files Browse the repository at this point in the history
Stop Math.floor calculations causing zeros & ddd test for points < dimensions. Pass this verbose from tsne to knn, and extra knn logging. (#63)
  • Loading branch information
bldrvnlw authored and Nicola Pezzotti committed Aug 9, 2018
1 parent 91c4bf6 commit f02553f
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 8 deletions.
6 changes: 4 additions & 2 deletions src/dataset_util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,8 @@ export function generateKNNClusterTexture(
numNeighbors: number): {knnGraph: WebGLTexture, dataShape: RearrangedData} {
// Computing data shape
const pointsPerRow =
Math.floor(Math.sqrt(numPoints * numNeighbors) / numNeighbors);
Math.max(1,
Math.floor(Math.sqrt(numPoints * numNeighbors) / numNeighbors));
const numRows = Math.ceil(numPoints / pointsPerRow);
const dataShape =
{numPoints, pixelsPerPoint: numNeighbors, numRows, pointsPerRow};
Expand Down Expand Up @@ -178,7 +179,8 @@ export function generateKNNLineTexture(numPoints: number, numNeighbors: number):
{knnGraph: WebGLTexture, dataShape: RearrangedData} {
// Computing data shape
const pointsPerRow =
Math.floor(Math.sqrt(numPoints * numNeighbors) / numNeighbors);
Math.max(1,
Math.floor(Math.sqrt(numPoints * numNeighbors) / numNeighbors));
const numRows = Math.ceil(numPoints / pointsPerRow);
const dataShape =
{numPoints, pixelsPerPoint: numNeighbors, numRows, pointsPerRow};
Expand Down
10 changes: 10 additions & 0 deletions src/knn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,9 @@ export class KNNEstimator {
initNeigh[(i * numNeighs + n) * 2 + 1] = 10e30;
}
}
this.log('knn-textureWidth', this.knnDataShape.pointsPerRow *
this.knnDataShape.pixelsPerPoint);
this.log('knn-textureHeight', this.knnDataShape.numRows);
this.knnTexture0 = gl_util.createAndConfigureTexture(
this.gpgpu.gl,
this.knnDataShape.pointsPerRow * this.knnDataShape.pixelsPerPoint,
Expand All @@ -154,13 +157,18 @@ export class KNNEstimator {
}

private initilizeCustomWebGLPrograms(distanceComputationSource: string) {
this.log('knn Create programs/buffers start');
this.copyDistancesProgram = knn_util.createCopyDistancesProgram(this.gpgpu);
this.log('knn Create indices program');
this.copyIndicesProgram = knn_util.createCopyIndicesProgram(this.gpgpu);

this.log('knn Create brute force knn program, numNeighs', this.numNeighs);
this.bruteForceKNNProgram = knn_util.createBruteForceKNNProgram(
this.gpgpu, this.numNeighs, distanceComputationSource);
this.log('knn Create random sampling force knn program');
this.randomSamplingKNNProgram = knn_util.createRandomSamplingKNNProgram(
this.gpgpu, this.numNeighs, distanceComputationSource);
this.log('knn Create descent program');
this.kNNDescentProgram = knn_util.createKNNDescentProgram(
this.gpgpu, this.numNeighs, distanceComputationSource);

Expand All @@ -170,8 +178,10 @@ export class KNNEstimator {
linesVertexId[i] = i;
}
}
this.log('knn Create static vertex start');
this.linesVertexIdBuffer = tf.webgl.webgl_util.createStaticVertexBuffer(
this.gpgpu.gl, linesVertexId);
this.log('knn Create programs/buffers done');
}

iterateBruteForce() {
Expand Down
3 changes: 2 additions & 1 deletion src/tensor_to_data_texture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ export async function tensorToDataTexture(tensor: tf.Tensor):
const numChannels = 4;
const pixelsPerPoint = Math.ceil(numDimensions / numChannels);
const pointsPerRow =
Math.floor(Math.sqrt(numPoints * pixelsPerPoint) / pixelsPerPoint);
Math.max(1,
Math.floor(Math.sqrt(numPoints * pixelsPerPoint) / pixelsPerPoint));
const numRows = Math.ceil(numPoints / pointsPerRow);

const tensorData = tensor.dataSync();
Expand Down
2 changes: 1 addition & 1 deletion src/tsne.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ export class TSNE {

this.knnEstimator = new KNNEstimator(
this.packedData.texture, this.packedData.shape, this.numPoints,
this.numDimensions, this.numNeighbors, false);
this.numDimensions, this.numNeighbors, this.verbose);

this.optimizer = new TSNEOptimizer(this.numPoints, false);
const exaggerationPolyline = [
Expand Down
3 changes: 2 additions & 1 deletion src/tsne_optimizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,8 @@ export class TSNEOptimizer {
indices: Uint32Array): Promise<void> {
// Computing the shape of the knnGraphTexture
const pointsPerRow =
Math.floor(Math.sqrt(numPoints * numNeighbors) / numNeighbors);
Math.max(1,
Math.floor(Math.sqrt(numPoints * numNeighbors) / numNeighbors));
const numRows = Math.ceil(numPoints / pointsPerRow);
const dataShape =
{numPoints, pixelsPerPoint : numNeighbors, numRows, pointsPerRow};
Expand Down
36 changes: 33 additions & 3 deletions src/tsne_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,9 @@ import * as tf_tsne from './tsne';

/**
* Returns a simple dataset for testing
* Defaults to numPoints = 300, numDimensions = 10
*/
function generateData() {
const numPoints = 300;
const numDimensions = 10;
function generateData(numPoints = 300, numDimensions = 10) {
const data = tf.tidy(() => {
return tf.linspace(0, 1, numPoints * numDimensions)
.reshape([ numPoints, numDimensions ])
Expand Down Expand Up @@ -79,3 +78,34 @@ describe('TSNE class', () => {
data.dispose();
});
});

describe('TSNE class', () => {
it('iterateKnn and iterate also work when the number of ' +
'dimensions is larger than the number of points',
async () => {
const data = generateData(100, 20000);
const testOpt = tf_tsne.tsne(data, {
perplexity : 15,
verbose : false,
knnMode : 'auto',
});

try {
await testOpt.iterateKnn(10);
} catch(e) {
fail('iterateKnn threw exception: ${e}');
}

try {
await testOpt.iterate(10);
} catch(e) {
fail('iterate threw exception: ${e}');
}

const coords = await testOpt.coordinates();
expect(coords.shape[0]).toBe(100);
expect(coords.shape[1]).toBe(2);
data.dispose();
return;
});
});

0 comments on commit f02553f

Please sign in to comment.