liuliu / s4nnc

Swift for NNC
https://libnnc.org
BSD 3-Clause "New" or "Revised" License
70 stars 8 forks source link

How to assign values to a tensor? #6

Closed ghost closed 1 year ago

ghost commented 1 year ago

Say ten is Tensor<Float16> . how do i assign some values to it? I tried

ten.storage[0,0,0,0] = 0.0

I get

a.swift:118:35: error: cannot convert value of type 'Int' to expected argument type 'Element.Type'
                  ten.storage[0,0,0,0] = 0.0
                                  ^
a.swift:118:42: error: cannot assign value of type 'Double' to subscript of type 'AnyTensorStorage'
                  ten.storage[0,0,0,0] = 0.0
liuliu commented 1 year ago
var ten = xxx
ten[0, 0, 0, 0] = 0

However, because it is a struct, and has "copy-on-write" property, it will only change the values on ten, not the value on xxx. That is the crux why in the reader closure, it won't work as expected (and hence why I probably should change the interface to return the tensor instead).

ghost commented 1 year ago

is there any C function I can call, to change the values of the tensor? Something like i get the mutable pointer to the location of the data, and I write the data in that location. althought the data location will be at GPU, so will need some function to write at that memory location.

ghost commented 1 year ago

Or for now, could you give me the snippet of the new read function which takes a closure ( String -> Tensor) , and I will add that locally in the s4nnc code.

liuliu commented 1 year ago

If you peek into the implementation, you will likely change the implementation like what you suggested. I won't be able to provide a snippet (it probably a bit more involved) at the moment though:

https://github.com/liuliu/s4nnc/blob/main/nnc/Store.swift#L134

Note that the C-struct tensor is mutable, there is no "copy-on-write" semantics, only when it changed and wrapped into AnyTensor, that becomes the case.

Further more, you can peek into the ccv_nnc_tensor_read implementation to get some ideas how the copying is done on C side:

https://github.com/liuliu/ccv/blob/unstable/lib/nnc/ccv_nnc_tensor_io.c#L73

ghost commented 1 year ago

Thanks a lot, I had already gone though these. I could not find any ccv function to copy data from one tensor / buffer to another tensor.

I think you should make a function called ccv_nnc_tensor_copy_data , and call that function from ccv_nnc_tensor_read. actually rename ccv_nnc_tensor_read to ccv_nnc_tensor_read_sqlite.

liuliu commented 1 year ago

Yeah, it is probably not obvious, but any data movement should be done with:

ccv_nnc_exec(CMD_DATA_TRANSFER_FORWARD(), 0, TENSOR_LIST(a), TENSOR_LIST(b), 0); // Or CMD_DATATYPE_CONVERSION, or CMD_FORMAT_TRANSFORM

It is not easier in Swift because there is no macros: https://github.com/liuliu/s4nnc/blob/main/nnc/Tensor.swift#L413

To wrap any data into a tensor, you can use ccv_nnc_tensor_new(, , , dataptr).

ghost commented 1 year ago

Actually i added this method

// use to copy data from swift CPU array to MPS GPU tensor 
// use to copy data from swift CPU array to MPS GPU tensor 
int ccv_nnc_tensor_read_from_buffer(ccv_nnc_tensor_t** const tensor_out, const void * data , size_t n)
{
    ccv_nnc_tensor_t* tensor = *tensor_out;
    if (!tensor){
        printf("this should not happen because read is being called after compile, so swift will already create a tensor before calling this \n ")
    }
    mpmemcpy(tensor->data.u8, tensor->dataof, tensor->info.type, data, 0, CCV_TENSOR_CPU_MEMORY, n );
}

how do i i call this function from my closure, where i have ten

ghost commented 1 year ago

Wow, i had to change the read function, now it works fine.