Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs(framework) Add how-to guide for designing stateful ClientApp objects #4010

Merged
merged 17 commits into from
Nov 15, 2024

Conversation

jafermarq
Copy link
Contributor

@jafermarq jafermarq commented Aug 14, 2024

Shows how to make use of the Context's state to store metrics and model parameters.

Content formatted with https://github.com/dzhu/rstfmt

@jafermarq jafermarq added the documentation Improvements or additions to documentation label Aug 14, 2024
@jafermarq jafermarq requested a review from panh99 August 14, 2024 12:52
@jafermarq jafermarq changed the title docs(framework) Add how-to guide for designing stateful ClietnApp objects docs(framework) Add how-to guide for designing stateful ClientApp objects Aug 14, 2024
@jafermarq jafermarq marked this pull request as draft September 3, 2024 15:03
@Dawitkiros
Copy link

Hi,

I am not sure if I should create a new issue or comment here. I discussed with @jafermarq on how to implement a stateful client on Slack, and he gave me great tips and a link to this repository to provide my feedback on whether everything is working as expected. I followed the steps provided to store the client parameters in the context, like the following in the fit function right after training:

# Save the parameters after training to the context for the next round
p_record = ParametersRecord()
for k, v in self.net.state_dict().items():
    # Convert to NumPy, then to Array. Add to record
    p_record[k] = ndarray_to_array(v.cpu().numpy())
# Add to context
self.client_state.parameters_records["prev_round"] = p_record

I loaded the context in set_parameters as follows:

# Here, I am hoping to get the previous state dict from the client_state
prev_state_dict = {}
# Extract record from context
p_record = self.client_state.parameters_records["prev_round"]
# Deserialize arrays
for k, v in p_record.items():
    prev_state_dict[k] = torch.from_numpy(np.copy(basic_array_deserialization(v)))
prev_state_dict_list = segment_resnet_parameters(flatten_resnet_parameters(prev_state_dict))

Everything is working as expected, but I encountered the following warning:

UserWarning: The given NumPy array is not writable, and PyTorch does not support non-writable tensors. This means writing to this tensor will result in undefined behavior. You may want to copy the array to protect its data or make it writable before converting it to a tensor. This type of warning will be suppressed for the rest of this program.

I found a way to make it work using np.copy(), though I'm not sure if it's the right solution.

Thanks.

@jafermarq
Copy link
Contributor Author

jafermarq commented Oct 10, 2024

Hi @Dawitkiros , sorry for the delay. Could you try this:

from flwr.common import  array_from_numpy
p_record = ParametersRecord()
for k, v in self.net.state_dict().items():
    # Convert to NumPy, then to Array. Add to record
    # p_record[k] = ndarray_to_array(v.cpu().numpy())
    p_record[k] = array_from_numpy(v.cpu().numpy()) # use utility method 
    
...

for k, v in p_record.items():
    # prev_state_dict[k] = torch.from_numpy(np.copy(basic_array_deserialization(v)))
    prev_state_dict[k] = torch.from_numpy(v.numpy()) # instead of the line above

This shows how to do it with the built-int serialization from numpy to Array. Then, we can revert such process with the .numpy() method Array objects have.

def numpy(self) -> NDArray:

@Dawitkiros
Copy link

Hi @jafermarq,

Your suggestion works!

@jafermarq
Copy link
Contributor Author

Hi @jafermarq,

Your suggestion works!

amazing! thanks for confirming. If you have some suggestions on how to improve this doc page. We are very happy to incorporate your feedback. We might be merging this PR soon.

@jafermarq jafermarq marked this pull request as ready for review October 25, 2024 07:12
Co-authored-by: Chong Shen Ng <chong.shen@flower.ai>
doc/source/how-to-design-stateful-clients.rst Outdated Show resolved Hide resolved
doc/source/how-to-design-stateful-clients.rst Outdated Show resolved Hide resolved
doc/source/how-to-design-stateful-clients.rst Outdated Show resolved Hide resolved
doc/source/how-to-design-stateful-clients.rst Outdated Show resolved Hide resolved
doc/source/how-to-design-stateful-clients.rst Outdated Show resolved Hide resolved
doc/source/how-to-design-stateful-clients.rst Outdated Show resolved Hide resolved
doc/source/how-to-design-stateful-clients.rst Outdated Show resolved Hide resolved
doc/source/how-to-design-stateful-clients.rst Outdated Show resolved Hide resolved
doc/source/how-to-design-stateful-clients.rst Outdated Show resolved Hide resolved
doc/source/how-to-design-stateful-clients.rst Outdated Show resolved Hide resolved
@danieljanes danieljanes enabled auto-merge (squash) November 15, 2024 16:09
@danieljanes danieljanes merged commit eb4293d into main Nov 15, 2024
55 checks passed
@danieljanes danieljanes deleted the docs-how-to-make-clients-stateful branch November 15, 2024 16:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants