void TestNDArrayView(size_t numAxes, const DeviceDescriptor& device) { srand(1); size_t maxDimSize = 15; NDShape viewShape(numAxes); for (size_t i = 0; i < numAxes; ++i) viewShape[i] = (rand() % maxDimSize) + 1; // Create a NDArrayView over a std::array std::array<ElementType, 1> arrayData = { 3 }; auto arrayDataView = MakeSharedObject<NDArrayView>(NDShape({}), arrayData); if (arrayDataView->template DataBuffer<ElementType>() != arrayData.data()) throw std::runtime_error("The DataBuffer of the NDArrayView does not match the original buffer it was created over"); std::vector<ElementType> data(viewShape.TotalSize()); ElementType scale = 19.0; ElementType offset = -4.0; for (size_t i = 0; i < viewShape.TotalSize(); ++i) data[i] = offset + ((((ElementType)rand()) / RAND_MAX) * scale); auto cpuDataView = MakeSharedObject<NDArrayView>(viewShape, data); if (cpuDataView->template DataBuffer<ElementType>() != data.data()) throw std::runtime_error("The DataBuffer of the NDArrayView does not match the original buffer it was created over"); NDArrayViewPtr dataView; if ((device.Type() == DeviceKind::CPU)) dataView = cpuDataView; else { dataView = MakeSharedObject<NDArrayView>(AsDataType<ElementType>(), viewShape, device); dataView->CopyFrom(*cpuDataView); } if (dataView->Device() != device) throw std::runtime_error("Device of NDArrayView does not match 'device' it was created on"); // Test clone auto clonedView = dataView->DeepClone(false); ElementType* first = nullptr; const ElementType* second = cpuDataView->template DataBuffer<ElementType>(); NDArrayViewPtr temp1CpuDataView, temp2CpuDataView; if ((device.Type() == DeviceKind::CPU)) { if (dataView->DataBuffer<ElementType>() != data.data()) throw std::runtime_error("The DataBuffer of the NDArrayView does not match the original buffer it was created over"); first = clonedView->WritableDataBuffer<ElementType>(); } else { temp1CpuDataView = MakeSharedObject<NDArrayView>(AsDataType<ElementType>(), viewShape, DeviceDescriptor::CPUDevice()); temp1CpuDataView->CopyFrom(*clonedView); first = temp1CpuDataView->WritableDataBuffer<ElementType>(); } for (size_t i = 0; i < viewShape.TotalSize(); ++i) { if (first[i] != second[i]) throw std::runtime_error("The contents of the clone do not match expected"); } first[0] += 1; if ((device.Type() != DeviceKind::CPU)) clonedView->CopyFrom(*temp1CpuDataView); if ((device.Type() == DeviceKind::CPU)) { first = clonedView->WritableDataBuffer<ElementType>(); second = dataView->DataBuffer<ElementType>(); } else { temp1CpuDataView = MakeSharedObject<NDArrayView>(AsDataType<ElementType>(), viewShape, DeviceDescriptor::CPUDevice()); temp1CpuDataView->CopyFrom(*clonedView); first = temp1CpuDataView->WritableDataBuffer<ElementType>(); temp2CpuDataView = MakeSharedObject<NDArrayView>(AsDataType<ElementType>(), viewShape, DeviceDescriptor::CPUDevice()); temp2CpuDataView->CopyFrom(*dataView); second = temp2CpuDataView->DataBuffer<ElementType>(); } if (first[0] != (second[0] + 1)) throw std::runtime_error("The clonedView's contents do not match expected"); // Test alias auto aliasView = clonedView->Alias(true); const ElementType* aliasViewBuffer = aliasView->DataBuffer<ElementType>(); const ElementType* clonedDataBuffer = clonedView->DataBuffer<ElementType>(); if (aliasViewBuffer != clonedDataBuffer) throw std::runtime_error("The buffers underlying the alias view and the view it is an alias of are different!"); clonedView->CopyFrom(*dataView); if (aliasViewBuffer != clonedDataBuffer) throw std::runtime_error("The buffers underlying the alias view and the view it is an alias of are different!"); // Test readonliness auto errorMsg = "Was incorrectly able to get a writable buffer pointer from a readonly view"; // Should not be able to get the WritableDataBuffer for a read-only view VerifyException([&aliasView]() { ElementType* aliasViewBuffer = aliasView->WritableDataBuffer<ElementType>(); aliasViewBuffer; }, errorMsg); // Should not be able to copy into a read-only view VerifyException([&aliasView, &dataView]() { aliasView->CopyFrom(*dataView); }, errorMsg); }
void DistributedLearnerBase::ConvertToOrdered(const std::unordered_map<Parameter, NDArrayViewPtr>& gradientValues, std::vector<std::pair<Parameter, NDArrayViewPtr>>& result, std::unordered_map<Parameter, NDArrayViewPtr>* convertedGradientValues) { result.reserve(gradientValues.size()); result.clear(); if (convertedGradientValues) convertedGradientValues->clear(); for (auto g : gradientValues) { NDArrayViewPtr p = g.second; // convert sparse gradient to dense for accumulation if (m_convertSparseToDense && p->GetStorageFormat() != StorageFormat::Dense) { NDArrayViewPtr pDense = MakeSharedObject<NDArrayView>(0, p->GetDataType(), p->Shape(), p->Device()); pDense->CopyFrom(*p); p = pDense; } auto pair = std::make_pair(g.first, p); result.push_back(pair); if (convertedGradientValues) convertedGradientValues->insert(pair); } std::sort(result.begin(), result.end(), [](const std::pair<Parameter, NDArrayViewPtr>& a, const std::pair<Parameter, NDArrayViewPtr>& b) { return a.first.Uid() < b.first.Uid(); }); }