diff --git a/src/accelerate/utils.py b/src/accelerate/utils.py
index 4b20cc1c3..3cd8d2695 100644
--- a/src/accelerate/utils.py
+++ b/src/accelerate/utils.py
@@ -19,6 +19,7 @@
 from contextlib import contextmanager
 from dataclasses import dataclass, field
 from enum import Enum
+from functools import update_wrapper
 from typing import Any, List, Optional, Union
 
 import numpy as np
@@ -273,11 +274,13 @@ def _is_fp16_bf16_tensor(tensor):
     return recursively_apply(_convert_to_fp32, tensor, test_type=_is_fp16_bf16_tensor)
 
 
-def convert_outputs_to_fp32(model_forward):
+class ConvertOutputsToFp32:
     """
     Decorator to apply to a function outputing tensors (like a model forward pass) that ensures the outputs in FP16
     precision will be convert back to FP32.
 
+    Use a class instead of a decorator because otherwise, the prepared model can no longer be pickled (issue #273).
+
     Args:
         model_forward (:obj:`Callable`):
             The function which outputs we want to treat.
@@ -286,11 +289,15 @@ def convert_outputs_to_fp32(model_forward):
         The same function as :obj:`model_forward` but with converted outputs.
     """
 
-    def convert_outputs(*args, **kwargs):
-        outputs = model_forward(*args, **kwargs)
-        return convert_to_fp32(outputs)
+    def __init__(self, model_forward):
+        self.model_forward = model_forward
+        update_wrapper(self, model_forward)
+
+    def __call__(self, *args, **kwargs):
+        return convert_to_fp32(self.model_forward(*args, **kwargs))
+
 
-    return convert_outputs
+convert_outputs_to_fp32 = ConvertOutputsToFp32
 
 
 def extract_model_from_parallel(model):
diff --git a/tests/test_utils.py b/tests/test_utils.py
index a31c45d31..0beba353a 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -13,12 +13,14 @@
 # limitations under the License.
 
 import os
+import pickle
 import unittest
 from collections import UserDict, namedtuple
 
 import torch
 
-from accelerate.utils import patch_environment, send_to_device
+from accelerate.test_utils.training import RegressionModel
+from accelerate.utils import convert_outputs_to_fp32, patch_environment, send_to_device
 
 
 TestNamedTuple = namedtuple("TestNamedTuple", "a b c")
@@ -71,3 +73,8 @@ def test_patch_environment(self):
 
         self.assertNotIn("AA", os.environ)
         self.assertNotIn("BB", os.environ)
+
+    def test_convert_to_32_lets_model_pickle(self):
+        model = RegressionModel()
+        model.forward = convert_outputs_to_fp32(model.forward)
+        _ = pickle.dumps(model)


Review comments: body: I was thinking having this test lie in `test_utils` instead in a new `test_model_can_pickle` after it's treated. Let me know if you'd like me to take this part.
diff_hunk: @@ -268,6 +270,11 @@ def training_check():
     assert torch.allclose(old_model.a, model.a), "Did not obtain the same model on CPU or distributed training."
     assert torch.allclose(old_model.b, model.b), "Did not obtain the same model on CPU or distributed training."
 
+    try:
+        _ = pickle.dumps(model)
+    except AttributeError:
+        assert False, "Could not pickle model"
body: Makes sense. Please go ahead.
diff_hunk: @@ -268,6 +270,11 @@ def training_check():
     assert torch.allclose(old_model.a, model.a), "Did not obtain the same model on CPU or distributed training."
     assert torch.allclose(old_model.b, model.b), "Did not obtain the same model on CPU or distributed training."
 
+    try:
+        _ = pickle.dumps(model)
+    except AttributeError:
+        assert False, "Could not pickle model"
body: It looks like you did not authorize maintainers to push to your branch. I made a PR here: https://github.com/BenjaminBossan/accelerate/pull/1/files
diff_hunk: @@ -268,6 +270,11 @@ def training_check():
     assert torch.allclose(old_model.a, model.a), "Did not obtain the same model on CPU or distributed training."
     assert torch.allclose(old_model.b, model.b), "Did not obtain the same model on CPU or distributed training."
 
+    try:
+        _ = pickle.dumps(model)
+    except AttributeError:
+        assert False, "Could not pickle model"
body: ![Screenshot from 2022-03-10 21-30-41](https://user-images.githubusercontent.com/6229650/157749451-9c08cddc-4c76-4902-ba0b-103dec6b217c.png)

Strange, I explicitly chose that option. 
diff_hunk: @@ -268,6 +270,11 @@ def training_check():
     assert torch.allclose(old_model.a, model.a), "Did not obtain the same model on CPU or distributed training."
     assert torch.allclose(old_model.b, model.b), "Did not obtain the same model on CPU or distributed training."
 
+    try:
+        _ = pickle.dumps(model)
+    except AttributeError:
+        assert False, "Could not pickle model"
body: I merged your PR, thanks.
diff_hunk: @@ -268,6 +270,11 @@ def training_check():
     assert torch.allclose(old_model.a, model.a), "Did not obtain the same model on CPU or distributed training."
     assert torch.allclose(old_model.b, model.b), "Did not obtain the same model on CPU or distributed training."
 
+    try:
+        _ = pickle.dumps(model)
+    except AttributeError:
+        assert False, "Could not pickle model"
body: GitHub was giving me an error :-( Thanks for merging it!
diff_hunk: @@ -268,6 +270,11 @@ def training_check():
     assert torch.allclose(old_model.a, model.a), "Did not obtain the same model on CPU or distributed training."
     assert torch.allclose(old_model.b, model.b), "Did not obtain the same model on CPU or distributed training."
 
+    try:
+        _ = pickle.dumps(model)
+    except AttributeError:
+        assert False, "Could not pickle model"
body: ```suggestion
```
Forgot to remove this :-)
diff_hunk: @@ -14,6 +14,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import pickle
+

Discussion: body: Thanks again for your contribution!
body: Thanks for the fast response and help!