We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Perp-Neg implementation is wrong, parallel component not ignored
https://github.com/comfyanonymous/ComfyUI/blob/18c151b3e3f6838fab4028e7a8ba526e30e610d3/comfy_extras/nodes_perpneg.py#L38-L40

The Perp-Neg node does not match the [paper](https://arxiv.org/pdf/2304.04968.pdf) (pytorch code in Appendix A.1).
When positive and negative prompt are the same, the result should be the same as an empty negative prompt because the prompts are completely parallel (i.e. there is no perpendicular component).

Positive: "forest"
Negative: ""
![ComfyUI_00194_](https://github.com/comfyanonymous/ComfyUI/assets/114889020/6c86c0d5-ec8b-478d-aa29-e41794bd3184)

Positive: "forest"
Negative: "forest"
![ComfyUI_00195_](https://github.com/comfyanonymous/ComfyUI/assets/114889020/fa4f2938-bc7a-48cb-8750-f76e6426dd4e)

I'll submit a PR in a bit.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `comfy_extras/nodes_perpneg.py`
Content:
```
1 import torch
2 import comfy.model_management
3 import comfy.sample
4 import comfy.samplers
5 import comfy.utils
6 
7 
8 class PerpNeg:
9     @classmethod
10     def INPUT_TYPES(s):
11         return {"required": {"model": ("MODEL", ),
12                              "empty_conditioning": ("CONDITIONING", ),
13                              "neg_scale": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0}),
14                             }}
15     RETURN_TYPES = ("MODEL",)
16     FUNCTION = "patch"
17 
18     CATEGORY = "_for_testing"
19 
20     def patch(self, model, empty_conditioning, neg_scale):
21         m = model.clone()
22         nocond = comfy.sample.convert_cond(empty_conditioning)
23 
24         def cfg_function(args):
25             model = args["model"]
26             noise_pred_pos = args["cond_denoised"]
27             noise_pred_neg = args["uncond_denoised"]
28             cond_scale = args["cond_scale"]
29             x = args["input"]
30             sigma = args["sigma"]
31             model_options = args["model_options"]
32             nocond_processed = comfy.samplers.encode_model_conds(model.extra_conds, nocond, x, x.device, "negative")
33 
34             (noise_pred_nocond, _) = comfy.samplers.calc_cond_uncond_batch(model, nocond_processed, None, x, sigma, model_options)
35 
36             pos = noise_pred_pos - noise_pred_nocond
37             neg = noise_pred_neg - noise_pred_nocond
38             perp = ((torch.mul(pos, neg).sum())/(torch.norm(neg)**2)) * neg
39             perp_neg = perp * neg_scale
40             cfg_result = noise_pred_nocond + cond_scale*(pos - perp_neg)
41             cfg_result = x - cfg_result
42             return cfg_result
43 
44         m.set_model_sampler_cfg_function(cfg_function)
45 
46         return (m, )
47 
48 
49 NODE_CLASS_MAPPINGS = {
50     "PerpNeg": PerpNeg,
51 }
52 
53 NODE_DISPLAY_NAME_MAPPINGS = {
54     "PerpNeg": "Perp-Neg",
55 }
56
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/comfy_extras/nodes_perpneg.py b/comfy_extras/nodes_perpneg.py
--- a/comfy_extras/nodes_perpneg.py
+++ b/comfy_extras/nodes_perpneg.py
@@ -35,7 +35,7 @@
 
             pos = noise_pred_pos - noise_pred_nocond
             neg = noise_pred_neg - noise_pred_nocond
-            perp = ((torch.mul(pos, neg).sum())/(torch.norm(neg)**2)) * neg
+            perp = neg - ((torch.mul(neg, pos).sum())/(torch.norm(pos)**2)) * pos
             perp_neg = perp * neg_scale
             cfg_result = noise_pred_nocond + cond_scale*(pos - perp_neg)
             cfg_result = x - cfg_result

{"golden_diff": "diff --git a/comfy_extras/nodes_perpneg.py b/comfy_extras/nodes_perpneg.py\n--- a/comfy_extras/nodes_perpneg.py\n+++ b/comfy_extras/nodes_perpneg.py\n@@ -35,7 +35,7 @@\n \n             pos = noise_pred_pos - noise_pred_nocond\n             neg = noise_pred_neg - noise_pred_nocond\n-            perp = ((torch.mul(pos, neg).sum())/(torch.norm(neg)**2)) * neg\n+            perp = neg - ((torch.mul(neg, pos).sum())/(torch.norm(pos)**2)) * pos\n             perp_neg = perp * neg_scale\n             cfg_result = noise_pred_nocond + cond_scale*(pos - perp_neg)\n             cfg_result = x - cfg_result\n", "issue": "Perp-Neg implementation is wrong, parallel component not ignored\nhttps://github.com/comfyanonymous/ComfyUI/blob/18c151b3e3f6838fab4028e7a8ba526e30e610d3/comfy_extras/nodes_perpneg.py#L38-L40\r\n\r\nThe Perp-Neg node does not match the [paper](https://arxiv.org/pdf/2304.04968.pdf) (pytorch code in Appendix A.1).\r\nWhen positive and negative prompt are the same, the result should be the same as an empty negative prompt because the prompts are completely parallel (i.e. there is no perpendicular component).\r\n\r\nPositive: \"forest\"\r\nNegative: \"\"\r\n![ComfyUI_00194_](https://github.com/comfyanonymous/ComfyUI/assets/114889020/6c86c0d5-ec8b-478d-aa29-e41794bd3184)\r\n\r\nPositive: \"forest\"\r\nNegative: \"forest\"\r\n![ComfyUI_00195_](https://github.com/comfyanonymous/ComfyUI/assets/114889020/fa4f2938-bc7a-48cb-8750-f76e6426dd4e)\r\n\r\nI'll submit a PR in a bit.\n", "before_files": [{"content": "import torch\nimport comfy.model_management\nimport comfy.sample\nimport comfy.samplers\nimport comfy.utils\n\n\nclass PerpNeg:\n    @classmethod\n    def INPUT_TYPES(s):\n        return {\"required\": {\"model\": (\"MODEL\", ),\n                             \"empty_conditioning\": (\"CONDITIONING\", ),\n                             \"neg_scale\": (\"FLOAT\", {\"default\": 1.0, \"min\": 0.0, \"max\": 100.0}),\n                            }}\n    RETURN_TYPES = (\"MODEL\",)\n    FUNCTION = \"patch\"\n\n    CATEGORY = \"_for_testing\"\n\n    def patch(self, model, empty_conditioning, neg_scale):\n        m = model.clone()\n        nocond = comfy.sample.convert_cond(empty_conditioning)\n\n        def cfg_function(args):\n            model = args[\"model\"]\n            noise_pred_pos = args[\"cond_denoised\"]\n            noise_pred_neg = args[\"uncond_denoised\"]\n            cond_scale = args[\"cond_scale\"]\n            x = args[\"input\"]\n            sigma = args[\"sigma\"]\n            model_options = args[\"model_options\"]\n            nocond_processed = comfy.samplers.encode_model_conds(model.extra_conds, nocond, x, x.device, \"negative\")\n\n            (noise_pred_nocond, _) = comfy.samplers.calc_cond_uncond_batch(model, nocond_processed, None, x, sigma, model_options)\n\n            pos = noise_pred_pos - noise_pred_nocond\n            neg = noise_pred_neg - noise_pred_nocond\n            perp = ((torch.mul(pos, neg).sum())/(torch.norm(neg)**2)) * neg\n            perp_neg = perp * neg_scale\n            cfg_result = noise_pred_nocond + cond_scale*(pos - perp_neg)\n            cfg_result = x - cfg_result\n            return cfg_result\n\n        m.set_model_sampler_cfg_function(cfg_function)\n\n        return (m, )\n\n\nNODE_CLASS_MAPPINGS = {\n    \"PerpNeg\": PerpNeg,\n}\n\nNODE_DISPLAY_NAME_MAPPINGS = {\n    \"PerpNeg\": \"Perp-Neg\",\n}\n", "path": "comfy_extras/nodes_perpneg.py"}], "after_files": [{"content": "import torch\nimport comfy.model_management\nimport comfy.sample\nimport comfy.samplers\nimport comfy.utils\n\n\nclass PerpNeg:\n    @classmethod\n    def INPUT_TYPES(s):\n        return {\"required\": {\"model\": (\"MODEL\", ),\n                             \"empty_conditioning\": (\"CONDITIONING\", ),\n                             \"neg_scale\": (\"FLOAT\", {\"default\": 1.0, \"min\": 0.0, \"max\": 100.0}),\n                            }}\n    RETURN_TYPES = (\"MODEL\",)\n    FUNCTION = \"patch\"\n\n    CATEGORY = \"_for_testing\"\n\n    def patch(self, model, empty_conditioning, neg_scale):\n        m = model.clone()\n        nocond = comfy.sample.convert_cond(empty_conditioning)\n\n        def cfg_function(args):\n            model = args[\"model\"]\n            noise_pred_pos = args[\"cond_denoised\"]\n            noise_pred_neg = args[\"uncond_denoised\"]\n            cond_scale = args[\"cond_scale\"]\n            x = args[\"input\"]\n            sigma = args[\"sigma\"]\n            model_options = args[\"model_options\"]\n            nocond_processed = comfy.samplers.encode_model_conds(model.extra_conds, nocond, x, x.device, \"negative\")\n\n            (noise_pred_nocond, _) = comfy.samplers.calc_cond_uncond_batch(model, nocond_processed, None, x, sigma, model_options)\n\n            pos = noise_pred_pos - noise_pred_nocond\n            neg = noise_pred_neg - noise_pred_nocond\n            perp = neg - ((torch.mul(neg, pos).sum())/(torch.norm(pos)**2)) * pos\n            perp_neg = perp * neg_scale\n            cfg_result = noise_pred_nocond + cond_scale*(pos - perp_neg)\n            cfg_result = x - cfg_result\n            return cfg_result\n\n        m.set_model_sampler_cfg_function(cfg_function)\n\n        return (m, )\n\n\nNODE_CLASS_MAPPINGS = {\n    \"PerpNeg\": PerpNeg,\n}\n\nNODE_DISPLAY_NAME_MAPPINGS = {\n    \"PerpNeg\": \"Perp-Neg\",\n}\n", "path": "comfy_extras/nodes_perpneg.py"}]}