Commit 2ad7baf8 authored by Benjamin Thomas Graham's avatar Benjamin Thomas Graham
Browse files

detach; batch_size; data_ptr

parent 16e4df34
...@@ -16,7 +16,7 @@ void cuda_LeakyReLU_updateOutput(/*cuda float*/ at::Tensor &input_features, ...@@ -16,7 +16,7 @@ void cuda_LeakyReLU_updateOutput(/*cuda float*/ at::Tensor &input_features,
T alpha) { T alpha) {
output_features.resize_as_(input_features); output_features.resize_as_(input_features);
auto n = input_features.numel(); auto n = input_features.numel();
LeakyReLU_fp<T>(input_features.data<T>(), output_features.data<T>(), n, LeakyReLU_fp<T>(input_features.data_ptr<T>(), output_features.data_ptr<T>(), n,
alpha); alpha);
} }
...@@ -27,6 +27,6 @@ void cuda_LeakyReLU_updateGradInput( ...@@ -27,6 +27,6 @@ void cuda_LeakyReLU_updateGradInput(
/*cuda float*/ at::Tensor &d_output_features, T alpha) { /*cuda float*/ at::Tensor &d_output_features, T alpha) {
d_input_features.resize_as_(d_output_features); d_input_features.resize_as_(d_output_features);
auto n = d_input_features.numel(); auto n = d_input_features.numel();
LeakyReLU_bp<T>(input_features.data<T>(), d_input_features.data<T>(), LeakyReLU_bp<T>(input_features.data_ptr<T>(), d_input_features.data_ptr<T>(),
d_output_features.data<T>(), n, alpha); d_output_features.data_ptr<T>(), n, alpha);
} }
...@@ -29,8 +29,8 @@ void cuda_MaxPooling_updateOutput( ...@@ -29,8 +29,8 @@ void cuda_MaxPooling_updateOutput(
output_features.resize_({nActive, nPlanes}); output_features.resize_({nActive, nPlanes});
output_features.zero_(); output_features.zero_();
auto iF = input_features.data<T>() + nFeaturesToDrop; auto iF = input_features.data_ptr<T>() + nFeaturesToDrop;
auto oF = output_features.data<T>(); auto oF = output_features.data_ptr<T>();
cuda_MaxPooling_ForwardPass<T>(iF, oF, nPlanes, input_features.size(1), cuda_MaxPooling_ForwardPass<T>(iF, oF, nPlanes, input_features.size(1),
output_features.size(1), _rules); output_features.size(1), _rules);
} }
...@@ -50,10 +50,10 @@ void cuda_MaxPooling_updateGradInput( ...@@ -50,10 +50,10 @@ void cuda_MaxPooling_updateGradInput(
d_input_features.resize_as_(input_features); d_input_features.resize_as_(input_features);
d_input_features.zero_(); d_input_features.zero_();
auto iF = input_features.data<T>(); auto iF = input_features.data_ptr<T>();
auto oF = output_features.data<T>(); auto oF = output_features.data_ptr<T>();
auto diF = d_input_features.data<T>(); auto diF = d_input_features.data_ptr<T>();
auto doF = d_output_features.data<T>(); auto doF = d_output_features.data_ptr<T>();
cuda_MaxPooling_BackwardPass<T>(iF, diF, oF, doF, nPlanes, cuda_MaxPooling_BackwardPass<T>(iF, diF, oF, doF, nPlanes,
input_features.size(1), input_features.size(1),
d_output_features.size(1), _rules); d_output_features.size(1), _rules);
...@@ -73,8 +73,8 @@ void cuda_RandomizedStrideMaxPooling_updateOutput( ...@@ -73,8 +73,8 @@ void cuda_RandomizedStrideMaxPooling_updateOutput(
output_features.resize_({nActive, nPlanes}); output_features.resize_({nActive, nPlanes});
output_features.zero_(); output_features.zero_();
auto iF = input_features.data<T>() + nFeaturesToDrop; auto iF = input_features.data_ptr<T>() + nFeaturesToDrop;
auto oF = output_features.data<T>(); auto oF = output_features.data_ptr<T>();
cuda_MaxPooling_ForwardPass<T>(iF, oF, nPlanes, input_features.size(1), cuda_MaxPooling_ForwardPass<T>(iF, oF, nPlanes, input_features.size(1),
output_features.size(1), _rules); output_features.size(1), _rules);
} }
...@@ -94,10 +94,10 @@ void cuda_RandomizedStrideMaxPooling_updateGradInput( ...@@ -94,10 +94,10 @@ void cuda_RandomizedStrideMaxPooling_updateGradInput(
d_input_features.resize_as_(input_features); d_input_features.resize_as_(input_features);
d_input_features.zero_(); d_input_features.zero_();
auto iF = input_features.data<T>(); auto iF = input_features.data_ptr<T>();
auto oF = output_features.data<T>(); auto oF = output_features.data_ptr<T>();
auto diF = d_input_features.data<T>(); auto diF = d_input_features.data_ptr<T>();
auto doF = d_output_features.data<T>(); auto doF = d_output_features.data_ptr<T>();
cuda_MaxPooling_BackwardPass<T>(iF, diF, oF, doF, nPlanes, cuda_MaxPooling_BackwardPass<T>(iF, diF, oF, doF, nPlanes,
input_features.size(1), input_features.size(1),
d_output_features.size(1), _rules); d_output_features.size(1), _rules);
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
for (auto &r : _rules) \ for (auto &r : _rules) \
rbMaxSize = std::max(rbMaxSize, (Int)r.size()); \ rbMaxSize = std::max(rbMaxSize, (Int)r.size()); \
at::Tensor rulesBuffer = at::empty({rbMaxSize}, at::CUDA(at_kINT)); \ at::Tensor rulesBuffer = at::empty({rbMaxSize}, at::CUDA(at_kINT)); \
Int *rbB = rulesBuffer.data<Int>(); \ Int *rbB = rulesBuffer.data_ptr<Int>(); \
for (int k = 0; k < _rules.size(); ++k) { \ for (int k = 0; k < _rules.size(); ++k) { \
auto &r = _rules[k]; \ auto &r = _rules[k]; \
Int nHotB = r.size() / 2; \ Int nHotB = r.size() / 2; \
......
...@@ -23,7 +23,7 @@ void cuda_SparseToDense_updateOutput( ...@@ -23,7 +23,7 @@ void cuda_SparseToDense_updateOutput(
std::array<long, Dimension + 2> sz; std::array<long, Dimension + 2> sz;
sz[0] = m.grids.begin()->second.size(); // batch size sz[0] = m.grids.begin()->second.size(); // batch size
sz[1] = nPlanes; sz[1] = nPlanes;
long *in_sz = inputSize.data<long>(); long *in_sz = inputSize.data_ptr<long>();
for (Int i = 0; i < Dimension; ++i) for (Int i = 0; i < Dimension; ++i)
sz[i + 2] = in_sz[i]; sz[i + 2] = in_sz[i];
output_features.resize_(sz); output_features.resize_(sz);
...@@ -32,9 +32,9 @@ void cuda_SparseToDense_updateOutput( ...@@ -32,9 +32,9 @@ void cuda_SparseToDense_updateOutput(
if (input_features.ndimension() == 2) { if (input_features.ndimension() == 2) {
const auto &_rules = m.getSparseToDenseRuleBook(inputSize, true); const auto &_rules = m.getSparseToDenseRuleBook(inputSize, true);
Int _nPlanes = input_features.size(1); Int _nPlanes = input_features.size(1);
auto iF = input_features.data<T>(); auto iF = input_features.data_ptr<T>();
auto oF = output_features.data<T>(); auto oF = output_features.data_ptr<T>();
long spatialVolume = inputSize.prod().data<long>()[0]; long spatialVolume = inputSize.prod().data_ptr<long>()[0];
cuda_SparseToDense_ForwardPass<T>(iF, oF, _nPlanes, spatialVolume, _rules); cuda_SparseToDense_ForwardPass<T>(iF, oF, _nPlanes, spatialVolume, _rules);
} }
} }
...@@ -50,10 +50,10 @@ void cuda_SparseToDense_updateGradInput( ...@@ -50,10 +50,10 @@ void cuda_SparseToDense_updateGradInput(
if (input_features.ndimension() == 2) { if (input_features.ndimension() == 2) {
const auto &_rules = m.getSparseToDenseRuleBook(inputSize, true); const auto &_rules = m.getSparseToDenseRuleBook(inputSize, true);
long spatialVolume = inputSize.prod().data<long>()[0]; long spatialVolume = inputSize.prod().data_ptr<long>()[0];
Int _nPlanes = d_input_features.size(1); Int _nPlanes = d_input_features.size(1);
auto diF = d_input_features.data<T>(); auto diF = d_input_features.data_ptr<T>();
auto doF = d_output_features.data<T>(); auto doF = d_output_features.data_ptr<T>();
cuda_SparseToDense_BackwardPass<T>(diF, doF, _nPlanes, spatialVolume, cuda_SparseToDense_BackwardPass<T>(diF, doF, _nPlanes, spatialVolume,
_rules); _rules);
} }
......
...@@ -28,8 +28,8 @@ void cuda_UnPooling_updateOutput( ...@@ -28,8 +28,8 @@ void cuda_UnPooling_updateOutput(
output_features.resize_({nActive, input_features.size(1) - nFeaturesToDrop}); output_features.resize_({nActive, input_features.size(1) - nFeaturesToDrop});
output_features.zero_(); output_features.zero_();
auto iF = input_features.data<T>() + nFeaturesToDrop; auto iF = input_features.data_ptr<T>() + nFeaturesToDrop;
auto oF = output_features.data<T>(); auto oF = output_features.data_ptr<T>();
cuda_UnPooling_ForwardPass<T>(iF, oF, nPlanes, input_features.size(1), cuda_UnPooling_ForwardPass<T>(iF, oF, nPlanes, input_features.size(1),
output_features.size(1), _rules); output_features.size(1), _rules);
...@@ -47,8 +47,8 @@ void cuda_UnPooling_updateGradInput( ...@@ -47,8 +47,8 @@ void cuda_UnPooling_updateGradInput(
const auto &_rules = const auto &_rules =
m.getRuleBook(outputSize, inputSize, poolSize, poolStride, true); m.getRuleBook(outputSize, inputSize, poolSize, poolStride, true);
auto diF = d_input_features.data<T>() + nFeaturesToDrop; auto diF = d_input_features.data_ptr<T>() + nFeaturesToDrop;
auto doF = d_output_features.data<T>(); auto doF = d_output_features.data_ptr<T>();
cuda_UnPooling_BackwardPass<T>(diF, doF, nPlanes, d_input_features.size(1), cuda_UnPooling_BackwardPass<T>(diF, doF, nPlanes, d_input_features.size(1),
d_output_features.size(1), _rules); d_output_features.size(1), _rules);
......
...@@ -17,7 +17,7 @@ template <Int dimension> using Point = std::array<Int, dimension>; ...@@ -17,7 +17,7 @@ template <Int dimension> using Point = std::array<Int, dimension>;
template <Int dimension> template <Int dimension>
Point<dimension> LongTensorToPoint(/*long*/ at::Tensor &t) { Point<dimension> LongTensorToPoint(/*long*/ at::Tensor &t) {
Point<dimension> p; Point<dimension> p;
long *td = t.data<long>(); long *td = t.data_ptr<long>();
for (Int i = 0; i < dimension; i++) for (Int i = 0; i < dimension; i++)
p[i] = td[i]; p[i] = td[i];
return p; return p;
...@@ -27,10 +27,10 @@ Point<2 * dimension> TwoLongTensorsToPoint(/*long*/ at::Tensor &t0, ...@@ -27,10 +27,10 @@ Point<2 * dimension> TwoLongTensorsToPoint(/*long*/ at::Tensor &t0,
/*long*/ at::Tensor &t1) { /*long*/ at::Tensor &t1) {
Point<2 * dimension> p; Point<2 * dimension> p;
long *td; long *td;
td = t0.data<long>(); td = t0.data_ptr<long>();
for (Int i = 0; i < dimension; i++) for (Int i = 0; i < dimension; i++)
p[i] = td[i]; p[i] = td[i];
td = t1.data<long>(); td = t1.data_ptr<long>();
for (Int i = 0; i < dimension; i++) for (Int i = 0; i < dimension; i++)
p[i + dimension] = td[i]; p[i + dimension] = td[i];
return p; return p;
...@@ -41,13 +41,13 @@ Point<3 * dimension> ThreeLongTensorsToPoint(/*long*/ at::Tensor &t0, ...@@ -41,13 +41,13 @@ Point<3 * dimension> ThreeLongTensorsToPoint(/*long*/ at::Tensor &t0,
/*long*/ at::Tensor &t2) { /*long*/ at::Tensor &t2) {
Point<3 * dimension> p; Point<3 * dimension> p;
long *td; long *td;
td = t0.data<long>(); td = t0.data_ptr<long>();
for (Int i = 0; i < dimension; i++) for (Int i = 0; i < dimension; i++)
p[i] = td[i]; p[i] = td[i];
td = t1.data<long>(); td = t1.data_ptr<long>();
for (Int i = 0; i < dimension; i++) for (Int i = 0; i < dimension; i++)
p[i + dimension] = td[i]; p[i + dimension] = td[i];
td = t2.data<long>(); td = t2.data_ptr<long>();
for (Int i = 0; i < dimension; i++) for (Int i = 0; i < dimension; i++)
p[i + 2 * dimension] = td[i]; p[i + 2 * dimension] = td[i];
return p; return p;
......
...@@ -17,7 +17,7 @@ template <Int dimension> using Point = std::array<Int, dimension>; ...@@ -17,7 +17,7 @@ template <Int dimension> using Point = std::array<Int, dimension>;
template <Int dimension> template <Int dimension>
Point<dimension> LongTensorToPoint(/*long*/ at::Tensor &t) { Point<dimension> LongTensorToPoint(/*long*/ at::Tensor &t) {
Point<dimension> p; Point<dimension> p;
long *td = t.data<long>(); long *td = t.data_ptr<long>();
for (Int i = 0; i < dimension; i++) for (Int i = 0; i < dimension; i++)
p[i] = td[i]; p[i] = td[i];
return p; return p;
...@@ -27,10 +27,10 @@ Point<2 * dimension> TwoLongTensorsToPoint(/*long*/ at::Tensor &t0, ...@@ -27,10 +27,10 @@ Point<2 * dimension> TwoLongTensorsToPoint(/*long*/ at::Tensor &t0,
/*long*/ at::Tensor &t1) { /*long*/ at::Tensor &t1) {
Point<2 * dimension> p; Point<2 * dimension> p;
long *td; long *td;
td = t0.data<long>(); td = t0.data_ptr<long>();
for (Int i = 0; i < dimension; i++) for (Int i = 0; i < dimension; i++)
p[i] = td[i]; p[i] = td[i];
td = t1.data<long>(); td = t1.data_ptr<long>();
for (Int i = 0; i < dimension; i++) for (Int i = 0; i < dimension; i++)
p[i + dimension] = td[i]; p[i + dimension] = td[i];
return p; return p;
...@@ -41,13 +41,13 @@ Point<3 * dimension> ThreeLongTensorsToPoint(/*long*/ at::Tensor &t0, ...@@ -41,13 +41,13 @@ Point<3 * dimension> ThreeLongTensorsToPoint(/*long*/ at::Tensor &t0,
/*long*/ at::Tensor &t2) { /*long*/ at::Tensor &t2) {
Point<3 * dimension> p; Point<3 * dimension> p;
long *td; long *td;
td = t0.data<long>(); td = t0.data_ptr<long>();
for (Int i = 0; i < dimension; i++) for (Int i = 0; i < dimension; i++)
p[i] = td[i]; p[i] = td[i];
td = t1.data<long>(); td = t1.data_ptr<long>();
for (Int i = 0; i < dimension; i++) for (Int i = 0; i < dimension; i++)
p[i + dimension] = td[i]; p[i + dimension] = td[i];
td = t2.data<long>(); td = t2.data_ptr<long>();
for (Int i = 0; i < dimension; i++) for (Int i = 0; i < dimension; i++)
p[i + 2 * dimension] = td[i]; p[i + 2 * dimension] = td[i];
return p; return p;
......
...@@ -23,7 +23,7 @@ template <Int dimension> SparseGrid<dimension>::SparseGrid() : ctr(0) { ...@@ -23,7 +23,7 @@ template <Int dimension> SparseGrid<dimension>::SparseGrid() : ctr(0) {
} }
template <typename T> T *OptionalTensorData(at::Tensor &tensor) { template <typename T> T *OptionalTensorData(at::Tensor &tensor) {
return tensor.numel() ? tensor.data<T>() : nullptr; return tensor.numel() ? tensor.data_ptr<T>() : nullptr;
} }
template <Int dimension> template <Int dimension>
...@@ -37,10 +37,10 @@ void addPointToSparseGridMapAndFeatures(SparseGridMap<dimension> &mp, ...@@ -37,10 +37,10 @@ void addPointToSparseGridMapAndFeatures(SparseGridMap<dimension> &mp,
if (mapVal.second) { if (mapVal.second) {
nActive++; nActive++;
features.resize_({(int)nActive, nPlanes}); features.resize_({(int)nActive, nPlanes});
std::memcpy(features.data<float>() + (nActive - 1) * nPlanes, vec, std::memcpy(features.data_ptr<float>() + (nActive - 1) * nPlanes, vec,
sizeof(float) * nPlanes); sizeof(float) * nPlanes);
} else if (overwrite) { } else if (overwrite) {
std::memcpy(features.data<float>() + mapVal.first->second * nPlanes, vec, std::memcpy(features.data_ptr<float>() + mapVal.first->second * nPlanes, vec,
sizeof(float) * nPlanes); sizeof(float) * nPlanes);
} }
} }
...@@ -95,7 +95,7 @@ void Metadata<dimension>::setInputSpatialLocation( ...@@ -95,7 +95,7 @@ void Metadata<dimension>::setInputSpatialLocation(
Int &nActive = *inputNActive; Int &nActive = *inputNActive;
auto nPlanes = vec.size(0); auto nPlanes = vec.size(0);
addPointToSparseGridMapAndFeatures<dimension>( addPointToSparseGridMapAndFeatures<dimension>(
mp, p, nActive, nPlanes, features, vec.data<float>(), overwrite); mp, p, nActive, nPlanes, features, vec.data_ptr<float>(), overwrite);
} }
template <Int dimension> template <Int dimension>
void Metadata<dimension>::setInputSpatialLocations( void Metadata<dimension>::setInputSpatialLocations(
...@@ -113,8 +113,8 @@ void Metadata<dimension>::setInputSpatialLocations( ...@@ -113,8 +113,8 @@ void Metadata<dimension>::setInputSpatialLocations(
Point<dimension> p; Point<dimension> p;
Int &nActive = *inputNActive; Int &nActive = *inputNActive;
auto nPlanes = vecs.size(1); auto nPlanes = vecs.size(1);
long *l = locations.data<long>(); long *l = locations.data_ptr<long>();
float *v = vecs.data<float>(); float *v = vecs.data_ptr<float>();
if (locations.size(1) == dimension) { if (locations.size(1) == dimension) {
// add points to current sample // add points to current sample
...@@ -154,7 +154,7 @@ Metadata<dimension>::getSpatialLocations(/*long*/ at::Tensor &spatialSize) { ...@@ -154,7 +154,7 @@ Metadata<dimension>::getSpatialLocations(/*long*/ at::Tensor &spatialSize) {
Int batchSize = SGs.size(); Int batchSize = SGs.size();
auto locations = torch::zeros({(int)nActive, dimension + 1}, at::kLong); auto locations = torch::zeros({(int)nActive, dimension + 1}, at::kLong);
auto lD = locations.data<long>(); auto lD = locations.data_ptr<long>();
for (Int i = 0; i < batchSize; i++) { for (Int i = 0; i < batchSize; i++) {
auto mp = SGs[i].mp; auto mp = SGs[i].mp;
...@@ -169,6 +169,12 @@ Metadata<dimension>::getSpatialLocations(/*long*/ at::Tensor &spatialSize) { ...@@ -169,6 +169,12 @@ Metadata<dimension>::getSpatialLocations(/*long*/ at::Tensor &spatialSize) {
return locations; return locations;
} }
template <Int dimension> template <Int dimension>
Int
Metadata<dimension>::getBatchSize(/*long*/ at::Tensor &spatialSize) {
auto &SGs = getSparseGrid(spatialSize);
return SGs.size();
}
template <Int dimension>
void Metadata<dimension>::createMetadataForDenseToSparse( void Metadata<dimension>::createMetadataForDenseToSparse(
/*long*/ at::Tensor &spatialSize, /*long*/ at::Tensor &spatialSize,
/*long*/ at::Tensor &nz_, long batchSize) { /*long*/ at::Tensor &nz_, long batchSize) {
...@@ -178,7 +184,7 @@ void Metadata<dimension>::createMetadataForDenseToSparse( ...@@ -178,7 +184,7 @@ void Metadata<dimension>::createMetadataForDenseToSparse(
auto &nActive = *inputNActive; auto &nActive = *inputNActive;
nActive = nz_.size(0); nActive = nz_.size(0);
long *nz = nz_.data<long>(); long *nz = nz_.data_ptr<long>();
std::vector<Int> br(batchSize + 1); std::vector<Int> br(batchSize + 1);
if (batchSize == 1) { if (batchSize == 1) {
...@@ -219,8 +225,8 @@ void Metadata<dimension>::sparsifyMetadata(Metadata<dimension> &mOut, ...@@ -219,8 +225,8 @@ void Metadata<dimension>::sparsifyMetadata(Metadata<dimension> &mOut,
auto &sgsOut = mOut.grids[p]; auto &sgsOut = mOut.grids[p];
sgsOut.resize(sgsIn.size()); sgsOut.resize(sgsIn.size());
if (filter.ndimension() == 1) { if (filter.ndimension() == 1) {
auto f = filter.data<unsigned char>(); auto f = filter.data_ptr<unsigned char>();
auto cs = cuSum.data<long>(); auto cs = cuSum.data_ptr<long>();
auto nActive = cs[cuSum.numel() - 1]; auto nActive = cs[cuSum.numel() - 1];
mOut.nActive[p] = nActive; mOut.nActive[p] = nActive;
Int sample; Int sample;
...@@ -262,8 +268,8 @@ Metadata<dimension>::sparsifyCompare(Metadata<dimension> &mGT, ...@@ -262,8 +268,8 @@ Metadata<dimension>::sparsifyCompare(Metadata<dimension> &mGT,
auto p = LongTensorToPoint<dimension>(spatialSize); auto p = LongTensorToPoint<dimension>(spatialSize);
at::Tensor gt = torch::zeros({nActive[p]}, at::kByte); at::Tensor gt = torch::zeros({nActive[p]}, at::kByte);
at::Tensor ref_map = torch::empty({mGT.nActive[p]}, at::kLong); at::Tensor ref_map = torch::empty({mGT.nActive[p]}, at::kLong);
long *ref_map_ptr = ref_map.data<long>(); long *ref_map_ptr = ref_map.data_ptr<long>();
unsigned char *gt_ptr = gt.data<unsigned char>(); unsigned char *gt_ptr = gt.data_ptr<unsigned char>();
auto &sgsGT = mGT.grids[p]; auto &sgsGT = mGT.grids[p];
auto &sgsFull = grids[p]; auto &sgsFull = grids[p];
Int batchSize = sgsFull.size(); Int batchSize = sgsFull.size();
...@@ -299,9 +305,9 @@ void Metadata<dimension>::addSampleFromThresholdedTensor( ...@@ -299,9 +305,9 @@ void Metadata<dimension>::addSampleFromThresholdedTensor(
SGs.resize(SGs.size() + 1); SGs.resize(SGs.size() + 1);
auto &sg = SGs.back(); auto &sg = SGs.back();
auto tensor = tensor_.data<float>(); auto tensor = tensor_.data_ptr<float>();
auto offset = offset_.data<long>(); auto offset = offset_.data_ptr<long>();
auto spatialSize = spatialSize_.data<long>(); auto spatialSize = spatialSize_.data_ptr<long>();
long size[dimension + 1]; // IntList? long size[dimension + 1]; // IntList?
for (Int i = 0; i <= dimension; ++i) for (Int i = 0; i <= dimension; ++i)
size[i] = tensor_.size(i); // std::vector<long> size = tensor_.size(); size[i] = tensor_.size(i); // std::vector<long> size = tensor_.size();
...@@ -311,7 +317,7 @@ void Metadata<dimension>::addSampleFromThresholdedTensor( ...@@ -311,7 +317,7 @@ void Metadata<dimension>::addSampleFromThresholdedTensor(
volume *= size[i]; volume *= size[i];
features_.resize_({(int)(nActive + volume), nPlanes}); features_.resize_({(int)(nActive + volume), nPlanes});
// Increment pointers as we work through the data // Increment pointers as we work through the data
auto features = features_.data<float>() + nActive * nPlanes; auto features = features_.data_ptr<float>() + nActive * nPlanes;
// Active locations // Active locations
Point<dimension> point; Point<dimension> point;
...@@ -413,7 +419,7 @@ void Metadata<dimension>::inputLayer(/*long*/ at::Tensor &spatialSize, ...@@ -413,7 +419,7 @@ void Metadata<dimension>::inputLayer(/*long*/ at::Tensor &spatialSize,
assert(coords.ndimension() == 2); assert(coords.ndimension() == 2);
assert(coords.size(1) >= dimension and coords.size(1) <= dimension + 1); assert(coords.size(1) >= dimension and coords.size(1) <= dimension + 1);
setInputSpatialSize(spatialSize); setInputSpatialSize(spatialSize);
inputLayerRules<dimension>(*inputSGs, inputLayerRuleBook, coords.data<long>(), inputLayerRules<dimension>(*inputSGs, inputLayerRuleBook, coords.data_ptr<long>(),
coords.size(0), coords.size(1), batchSize, mode, coords.size(0), coords.size(1), batchSize, mode,
*inputNActive); *inputNActive);
} }
...@@ -425,7 +431,7 @@ void Metadata<dimension>::blLayer(/*long*/ at::Tensor &spatialSize, ...@@ -425,7 +431,7 @@ void Metadata<dimension>::blLayer(/*long*/ at::Tensor &spatialSize,
assert(coords.ndimension() == 3); assert(coords.ndimension() == 3);
assert(coords.size(2) == dimension); assert(coords.size(2) == dimension);
setInputSpatialSize(spatialSize); setInputSpatialSize(spatialSize);
blRules<dimension>(*inputSGs, blLayerRuleBook, coords.data<long>(), blRules<dimension>(*inputSGs, blLayerRuleBook, coords.data_ptr<long>(),
coords.size(0), coords.size(1), mode, *inputNActive); coords.size(0), coords.size(1), mode, *inputNActive);
} }
template <Int dimension> template <Int dimension>
...@@ -437,9 +443,9 @@ RuleBook &Metadata<dimension>::getSubmanifoldRuleBook( ...@@ -437,9 +443,9 @@ RuleBook &Metadata<dimension>::getSubmanifoldRuleBook(
if (rb.empty()) { if (rb.empty()) {
auto &SGs = grids[LongTensorToPoint<dimension>(spatialSize)]; auto &SGs = grids[LongTensorToPoint<dimension>(spatialSize)];
#if defined(ENABLE_OPENMP) #if defined(ENABLE_OPENMP)
openMP ? SubmanifoldConvolution_SgsToRules_OMP(SGs, rb, size.data<long>()) : openMP ? SubmanifoldConvolution_SgsToRules_OMP(SGs, rb, size.data_ptr<long>()) :
#endif #endif
SubmanifoldConvolution_SgsToRules(SGs, rb, size.data<long>()); SubmanifoldConvolution_SgsToRules(SGs, rb, size.data_ptr<long>());
} }
return rb; return rb;
} }
...@@ -476,11 +482,11 @@ RuleBook &Metadata<dimension>::getSparseToDenseRuleBook( ...@@ -476,11 +482,11 @@ RuleBook &Metadata<dimension>::getSparseToDenseRuleBook(
if (rb.empty()) if (rb.empty())
#if defined(ENABLE_OPENMP) #if defined(ENABLE_OPENMP)
openMP ? SparseToDense_InputSgsToRulesAndOutputSgs_OMP( openMP ? SparseToDense_InputSgsToRulesAndOutputSgs_OMP(
SGs, rb, spatialSize.data<long>()) SGs, rb, spatialSize.data_ptr<long>())
: :
#endif #endif
SparseToDense_InputSgsToRulesAndOutputSgs(SGs, rb, SparseToDense_InputSgsToRulesAndOutputSgs(SGs, rb,
spatialSize.data<long>()); spatialSize.data_ptr<long>());
return rb; return rb;
} }
template <Int dimension> template <Int dimension>
...@@ -500,13 +506,13 @@ RuleBook &Metadata<dimension>::getRuleBook( ...@@ -500,13 +506,13 @@ RuleBook &Metadata<dimension>::getRuleBook(
#if defined(ENABLE_OPENMP) #if defined(ENABLE_OPENMP)
openMP openMP
? Convolution_InputSgsToRulesAndOutputSgs_OMP( ? Convolution_InputSgsToRulesAndOutputSgs_OMP(
iSGs, oSGs, rb, size.data<long>(), stride.data<long>(), iSGs, oSGs, rb, size.data_ptr<long>(), stride.data_ptr<long>(),
inputSpatialSize.data<long>(), outputSpatialSize.data<long>()) inputSpatialSize.data_ptr<long>(), outputSpatialSize.data_ptr<long>())
: :
#endif #endif
Convolution_InputSgsToRulesAndOutputSgs( Convolution_InputSgsToRulesAndOutputSgs(
iSGs, oSGs, rb, size.data<long>(), stride.data<long>(), iSGs, oSGs, rb, size.data_ptr<long>(), stride.data_ptr<long>(),
inputSpatialSize.data<long>(), outputSpatialSize.data<long>()); inputSpatialSize.data_ptr<long>(), outputSpatialSize.data_ptr<long>());
} }
return rb; return rb;
} }
...@@ -526,8 +532,8 @@ RuleBook &Metadata<dimension>::getFullConvolutionRuleBook( ...@@ -526,8 +532,8 @@ RuleBook &Metadata<dimension>::getFullConvolutionRuleBook(
auto &iSGs = newM.grids[iS]; auto &iSGs = newM.grids[iS];
auto &oSGs = newM.grids[oS]; auto &oSGs = newM.grids[oS];
newM.nActive[oS] = FullConvolution_InputSgsToRulesAndOutputSgs_OMP( newM.nActive[oS] = FullConvolution_InputSgsToRulesAndOutputSgs_OMP(
iSGs, oSGs, rb, size.data<long>(), stride.data<long>(), iSGs, oSGs, rb, size.data_ptr<long>(), stride.data_ptr<long>(),
inputSpatialSize.data<long>(), outputSpatialSize.data<long>()); inputSpatialSize.data_ptr<long>(), outputSpatialSize.data_ptr<long>());
} }
return rb; return rb;
} }
...@@ -549,15 +555,15 @@ RuleBook &Metadata<dimension>::getRandomizedStrideRuleBook( ...@@ -549,15 +555,15 @@ RuleBook &Metadata<dimension>::getRandomizedStrideRuleBook(
#if defined(ENABLE_OPENMP) #if defined(ENABLE_OPENMP)
openMP openMP
? RSR_InputSgsToRulesAndOutputSgs_OMP( ? RSR_InputSgsToRulesAndOutputSgs_OMP(
iSGs, oSGs, rb, size.data<long>(), stride.data<long>(), iSGs, oSGs, rb, size.data_ptr<long>(), stride.data_ptr<long>(),
inputSpatialSize.data<long>(), outputSpatialSize.data<long>(), inputSpatialSize.data_ptr<long>(), outputSpatialSize.data_ptr<long>(),
re) re)
: :
#endif #endif
RSR_InputSgsToRulesAndOutputSgs(iSGs, oSGs, rb, size.data<long>(), RSR_InputSgsToRulesAndOutputSgs(iSGs, oSGs, rb, size.data_ptr<long>(),
stride.data<long>(), stride.data_ptr<long>(),
inputSpatialSize.data<long>(), inputSpatialSize.data_ptr<long>(),
outputSpatialSize.data<long>(), re); outputSpatialSize.data_ptr<long>(), re);
} }
return rb; return rb;
} }
...@@ -567,7 +573,7 @@ at::Tensor vvl2t(std::vector<std::vector<long>> v) { ...@@ -567,7 +573,7 @@ at::Tensor vvl2t(std::vector<std::vector<long>> v) {
for (auto &x : v) for (auto &x : v)
s += x.size(); s += x.size();
at::Tensor t = torch::empty({s}, at::CPU(at::kLong)); at::Tensor t = torch::empty({s}, at::CPU(at::kLong));
long *p = t.data<long>(); long *p = t.data_ptr<long>();
for (auto &x : v) { for (auto &x : v) {
std::memcpy(p, &x[0], x.size() * sizeof(long)); std::memcpy(p, &x[0], x.size() * sizeof(long));
p += x.size(); p += x.size();
...@@ -614,7 +620,7 @@ at::Tensor vvl2t_(std::vector<std::vector<Int>> v) { ...@@ -614,7 +620,7 @@ at::Tensor vvl2t_(std::vector<std::vector<Int>> v) {
for (auto &x : v) for (auto &x : v)
s += x.size(); s += x.size();
at::Tensor t = torch::empty({s}, at::CPU(at_kINT)); at::Tensor t = torch::empty({s}, at::CPU(at_kINT));
Int *p = t.data<Int>(); Int *p = t.data_ptr<Int>();
for (auto &x : v) { for (auto &x : v) {
std::memcpy(p, &x[0], x.size() * sizeof(Int)); std::memcpy(p, &x[0], x.size() * sizeof(Int));
p += x.size(); p += x.size();
......
...@@ -93,6 +93,7 @@ public: ...@@ -93,6 +93,7 @@ public:
/*float*/ at::Tensor &vecs, bool overwrite); /*float*/ at::Tensor &vecs, bool overwrite);
at::Tensor getSpatialLocations(/*long*/ at::Tensor &spatialSize); at::Tensor getSpatialLocations(/*long*/ at::Tensor &spatialSize);
Int getBatchSize(/*long*/ at::Tensor &spatialSize);
void createMetadataForDenseToSparse(/*long*/ at::Tensor &spatialSize, void createMetadataForDenseToSparse(/*long*/ at::Tensor &spatialSize,
/*long*/ at::Tensor &nz_, long batchSize); /*long*/ at::Tensor &nz_, long batchSize);
......
...@@ -10,13 +10,13 @@ void cpu_float_DrawCurve_2(Metadata<2> &m, ...@@ -10,13 +10,13 @@ void cpu_float_DrawCurve_2(Metadata<2> &m,
/*float*/ at::Tensor &features, /*float*/ at::Tensor &features,
/*float*/ at::Tensor &stroke) { /*float*/ at::Tensor &stroke) {
at::Tensor &location = at::zeros(at::CPU(at::kLong), {2}); at::Tensor &location = at::zeros(at::CPU(at::kLong), {2});
auto location_ = location.data<long>(); auto location_ = location.data_ptr<long>();
auto vec = at::zeros(at::CPU(at::kFloat), {3}); auto vec = at::zeros(at::CPU(at::kFloat), {3});
auto vec_ = vec.data<float>(); auto vec_ = vec.data_ptr<float>();
int n = stroke.size(0) - 1; int n = stroke.size(0) - 1;
float *s = stroke.data<float>(); // stroke is a [n+1,2] array float *s = stroke.data_ptr<float>(); // stroke is a [n+1,2] array
long idx = 0; long idx = 0;
float x1, y1, x2, y2; // n line segments (x1,y1) to (x2,y2) float x1, y1, x2, y2; // n line segments (x1,y1) to (x2,y2)
x2 = s[idx++]; x2 = s[idx++];
......
...@@ -19,6 +19,7 @@ template <Int Dimension> void dimension(py::module &m, const char *name) { ...@@ -19,6 +19,7 @@ template <Int Dimension> void dimension(py::module &m, const char *name) {
.def("setInputSpatialLocations", .def("setInputSpatialLocations",
&Metadata<Dimension>::setInputSpatialLocations) &Metadata<Dimension>::setInputSpatialLocations)
.def("getSpatialLocations", &Metadata<Dimension>::getSpatialLocations) .def("getSpatialLocations", &Metadata<Dimension>::getSpatialLocations)
.def("getBatchSize", &Metadata<Dimension>::getBatchSize)
.def("createMetadataForDenseToSparse", .def("createMetadataForDenseToSparse",
&Metadata<Dimension>::createMetadataForDenseToSparse) &Metadata<Dimension>::createMetadataForDenseToSparse)
.def("sparsifyMetadata", &Metadata<Dimension>::sparsifyMetadata) .def("sparsifyMetadata", &Metadata<Dimension>::sparsifyMetadata)
......
...@@ -15,14 +15,15 @@ double AffineReluTrivialConvolution_updateOutput(at::Tensor &input_features, ...@@ -15,14 +15,15 @@ double AffineReluTrivialConvolution_updateOutput(at::Tensor &input_features,
void AffineReluTrivialConvolution_backward( void AffineReluTrivialConvolution_backward(
at::Tensor &input_features, at::Tensor &d_input_features, at::Tensor &input_features, at::Tensor &d_input_features,
at::Tensor &d_output_features, at::Tensor &affineWeight, at::Tensor &d_output_features, at::Tensor &affineWeight,
at::Tensor &d_affineWeight, at::Tensor &affineBias, at::Tensor &d_affineBias, at::Tensor &d_affineWeight, at::Tensor &affineBias,
at::Tensor &convWeight, at::Tensor &d_convWeight, bool additiveGrad); at::Tensor &d_affineBias, at::Tensor &convWeight, at::Tensor &d_convWeight,
bool additiveGrad);
void BatchNormalization_updateOutput( void BatchNormalization_updateOutput(
at::Tensor &input_features, at::Tensor &output_features, at::Tensor &saveMean, at::Tensor &input_features, at::Tensor &output_features,
at::Tensor &saveInvStd, at::Tensor &runningMean, at::Tensor &runningVar, at::Tensor &saveMean, at::Tensor &saveInvStd, at::Tensor &runningMean,
at::Tensor &weight, at::Tensor &bias, double eps, double momentum, bool train, at::Tensor &runningVar, at::Tensor &weight, at::Tensor &bias, double eps,
double leakiness); double momentum, bool train, double leakiness);
void BatchNormalization_backward( void BatchNormalization_backward(
at::Tensor &input_features, at::Tensor &d_input_features, at::Tensor &input_features, at::Tensor &d_input_features,
...@@ -57,13 +58,15 @@ void NetworkInNetwork_updateGradInput(at::Tensor &d_input_features, ...@@ -57,13 +58,15 @@ void NetworkInNetwork_updateGradInput(at::Tensor &d_input_features,
void NetworkInNetwork_accGradParameters(at::Tensor &input_features, void NetworkInNetwork_accGradParameters(at::Tensor &input_features,
at::Tensor &d_output_features, at::Tensor &d_output_features,
at::Tensor &d_weight, at::Tensor &d_bias); at::Tensor &d_weight,
at::Tensor &d_bias);
template <Int Dimension> template <Int Dimension>
void ActivePooling_updateOutput(at::Tensor &inputSize, Metadata<Dimension> &m, void ActivePooling_updateOutput(at::Tensor &inputSize, Metadata<Dimension> &m,
at::Tensor &input_features, at::Tensor &input_features,
at::Tensor &output_features, bool average); at::Tensor &output_features, bool average);
template <Int Dimension> template <Int Dimension>
void ActivePooling_updateGradInput(at::Tensor &inputSize, Metadata<Dimension> &m, void ActivePooling_updateGradInput(at::Tensor &inputSize,
Metadata<Dimension> &m,
at::Tensor &input_features, at::Tensor &input_features,
at::Tensor &d_input_features, at::Tensor &d_input_features,
at::Tensor &d_output_features, bool average); at::Tensor &d_output_features, bool average);
...@@ -75,20 +78,18 @@ void AveragePooling_updateOutput(at::Tensor &inputSize, at::Tensor &outputSize, ...@@ -75,20 +78,18 @@ void AveragePooling_updateOutput(at::Tensor &inputSize, at::Tensor &outputSize,
at::Tensor &output_features, at::Tensor &output_features,
long nFeaturesToDrop); long nFeaturesToDrop);
template <Int Dimension> template <Int Dimension>
void AveragePooling_updateGradInput(at::Tensor &inputSize, at::Tensor &outputSize, void AveragePooling_updateGradInput(
at::Tensor &poolSize, at::Tensor &poolStride, at::Tensor &inputSize, at::Tensor &outputSize, at::Tensor &poolSize,
Metadata<Dimension> &m, at::Tensor &poolStride, Metadata<Dimension> &m, at::Tensor &input_features,
at::Tensor &input_features, at::Tensor &d_input_features, at::Tensor &d_output_features,
at::Tensor &d_input_features, long nFeaturesToDrop);
at::Tensor &d_output_features, template <Int Dimension>
long nFeaturesToDrop); double
template <Int Dimension> Convolution_updateOutput(at::Tensor &inputSize, at::Tensor &outputSize,
double Convolution_updateOutput(at::Tensor &inputSize, at::Tensor &outputSize, at::Tensor &filterSize, at::Tensor &filterStride,
at::Tensor &filterSize, at::Tensor &filterStride, Metadata<Dimension> &m, at::Tensor &input_features,
Metadata<Dimension> &m, at::Tensor &output_features, at::Tensor &weight,
at::Tensor &input_features, at::Tensor &bias);
at::Tensor &output_features, at::Tensor &weight,
at::Tensor &bias);
template <Int Dimension> template <Int Dimension>
void Convolution_backward(at::Tensor &inputSize, at::Tensor &outputSize, void Convolution_backward(at::Tensor &inputSize, at::Tensor &outputSize,
at::Tensor &filterSize, at::Tensor &filterStride, at::Tensor &filterSize, at::Tensor &filterStride,
...@@ -97,12 +98,10 @@ void Convolution_backward(at::Tensor &inputSize, at::Tensor &outputSize, ...@@ -97,12 +98,10 @@ void Convolution_backward(at::Tensor &inputSize, at::Tensor &outputSize,
at::Tensor &d_output_features, at::Tensor &weight, at::Tensor &d_output_features, at::Tensor &weight,
at::Tensor &d_weight, at::Tensor &d_bias); at::Tensor &d_weight, at::Tensor &d_bias);
template <Int Dimension> template <Int Dimension>
double SubmanifoldConvolution_updateOutput(at::Tensor &inputSize, double SubmanifoldConvolution_updateOutput(
at::Tensor &filterSize, at::Tensor &inputSize, at::Tensor &filterSize, Metadata<Dimension> &m,
Metadata<Dimension> &m, at::Tensor &input_features, at::Tensor &output_features, at::Tensor &weight,
at::Tensor &input_features, at::Tensor &bias);
at::Tensor &output_features,
at::Tensor &weight, at::Tensor &bias);
template <Int Dimension> template <Int Dimension>
void SubmanifoldConvolution_backward( void SubmanifoldConvolution_backward(
at::Tensor &inputSize, at::Tensor &filterSize, Metadata<Dimension> &m, at::Tensor &inputSize, at::Tensor &filterSize, Metadata<Dimension> &m,
...@@ -136,19 +135,23 @@ void FullConvolution_backward(at::Tensor &inputSize, at::Tensor &outputSize, ...@@ -136,19 +135,23 @@ void FullConvolution_backward(at::Tensor &inputSize, at::Tensor &outputSize,
template <Int Dimension> template <Int Dimension>
double RandomizedStrideConvolution_updateOutput( double RandomizedStrideConvolution_updateOutput(
at::Tensor &inputSize, at::Tensor &outputSize, at::Tensor &filterSize, at::Tensor &inputSize, at::Tensor &outputSize, at::Tensor &filterSize,
at::Tensor &filterStride, Metadata<Dimension> &m, at::Tensor &input_features, at::Tensor &filterStride, Metadata<Dimension> &m,
at::Tensor &output_features, at::Tensor &weight, at::Tensor &bias); at::Tensor &input_features, at::Tensor &output_features, at::Tensor &weight,
at::Tensor &bias);
template <Int Dimension> template <Int Dimension>
void RandomizedStrideConvolution_backward( void RandomizedStrideConvolution_backward(
at::Tensor &inputSize, at::Tensor &outputSize, at::Tensor &filterSize, at::Tensor &inputSize, at::Tensor &outputSize, at::Tensor &filterSize,
at::Tensor &filterStride, Metadata<Dimension> &m, at::Tensor &input_features, at::Tensor &filterStride, Metadata<Dimension> &m,
at::Tensor &d_input_features, at::Tensor &d_output_features, at::Tensor &input_features, at::Tensor &d_input_features,
at::Tensor &weight, at::Tensor &d_weight, at::Tensor &d_bias); at::Tensor &d_output_features, at::Tensor &weight, at::Tensor &d_weight,
at::Tensor &d_bias);
template <Int Dimension> template <Int Dimension>
double Deconvolution_updateOutput( double
at::Tensor &inputSize, at::Tensor &outputSize, at::Tensor &filterSize, Deconvolution_updateOutput(at::Tensor &inputSize, at::Tensor &outputSize,
at::Tensor &filterStride, Metadata<Dimension> &m, at::Tensor &input_features, at::Tensor &filterSize, at::Tensor &filterStride,
at::Tensor &output_features, at::Tensor &weight, at::Tensor &bias); Metadata<Dimension> &m, at::Tensor &input_features,
at::Tensor &output_features, at::Tensor &weight,
at::Tensor &bias);
template <Int Dimension> template <Int Dimension>
void Deconvolution_backward(at::Tensor &inputSize, at::Tensor &outputSize, void Deconvolution_backward(at::Tensor &inputSize, at::Tensor &outputSize,
at::Tensor &filterSize, at::Tensor &filterStride, at::Tensor &filterSize, at::Tensor &filterStride,
...@@ -158,7 +161,8 @@ void Deconvolution_backward(at::Tensor &inputSize, at::Tensor &outputSize, ...@@ -158,7 +161,8 @@ void Deconvolution_backward(at::Tensor &inputSize, at::Tensor &outputSize,
at::Tensor &d_weight, at::Tensor &d_bias); at::Tensor &d_weight, at::Tensor &d_bias);
template <Int Dimension> template <Int Dimension>
void InputLayer_updateOutput(Metadata<Dimension> &m, at::Tensor &spatialSize, void InputLayer_updateOutput(Metadata<Dimension> &m, at::Tensor &spatialSize,
at::Tensor &input_coords, at::Tensor &input_features, at::Tensor &input_coords,
at::Tensor &input_features,
at::Tensor &output_features, long batchSize, at::Tensor &output_features, long batchSize,
long mode); long mode);
template <Int Dimension> template <Int Dimension>
...@@ -166,7 +170,8 @@ void InputLayer_updateGradInput(Metadata<Dimension> &m, ...@@ -166,7 +170,8 @@ void InputLayer_updateGradInput(Metadata<Dimension> &m,
at::Tensor &d_input_features, at::Tensor &d_input_features,
at::Tensor &d_output_features); at::Tensor &d_output_features);
template <Int Dimension> template <Int Dimension>
void OutputLayer_updateOutput(Metadata<Dimension> &m, at::Tensor &input_features, void OutputLayer_updateOutput(Metadata<Dimension> &m,
at::Tensor &input_features,
at::Tensor &output_features); at::Tensor &output_features);
template <Int Dimension> template <Int Dimension>
void OutputLayer_updateGradInput(Metadata<Dimension> &m, void OutputLayer_updateGradInput(Metadata<Dimension> &m,
...@@ -216,7 +221,8 @@ void SparseToDense_updateOutput(at::Tensor &inputSize, Metadata<Dimension> &m, ...@@ -216,7 +221,8 @@ void SparseToDense_updateOutput(at::Tensor &inputSize, Metadata<Dimension> &m,
at::Tensor &input_features, at::Tensor &input_features,
at::Tensor &output_features, long nPlanes); at::Tensor &output_features, long nPlanes);
template <Int Dimension> template <Int Dimension>
void SparseToDense_updateGradInput(at::Tensor &inputSize, Metadata<Dimension> &m, void SparseToDense_updateGradInput(at::Tensor &inputSize,
Metadata<Dimension> &m,
at::Tensor &input_features, at::Tensor &input_features,
at::Tensor &d_input_features, at::Tensor &d_input_features,
at::Tensor &d_output_features); at::Tensor &d_output_features);
......
...@@ -22,6 +22,11 @@ class SparseConvNetTensor(object): ...@@ -22,6 +22,11 @@ class SparseConvNetTensor(object):
t = self.metadata.getSpatialLocations(spatial_size) t = self.metadata.getSpatialLocations(spatial_size)
return t return t
def batch_size(self):
"Batch size"
t = self.metadata.getBatchSize(self.spatial_size)
return t
def to(self, device): def to(self, device):
self.features=self.features.to(device) self.features=self.features.to(device)
return self return self
...@@ -40,6 +45,9 @@ class SparseConvNetTensor(object): ...@@ -40,6 +45,9 @@ class SparseConvNetTensor(object):
self.features = self.features.cpu() self.features = self.features.cpu()
return self return self
def detach():
return SparseConvNetTensor(self.features.detach(), self.metadata, self.spatial_size)
@property @property
def requires_grad(self): def requires_grad(self):
return self.features.requires_grad return self.features.requires_grad
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment