惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

P
Privacy & Cybersecurity Law Blog
人人都是产品经理
人人都是产品经理
The Cloudflare Blog
B
Blog RSS Feed
罗磊的独立博客
V
V2EX
V
Visual Studio Blog
博客园 - 叶小钗
W
WeLiveSecurity
小众软件
小众软件
K
Kaspersky official blog
美团技术团队
雷峰网
雷峰网
阮一峰的网络日志
阮一峰的网络日志
Martin Fowler
Martin Fowler
Recorded Future
Recorded Future
Project Zero
Project Zero
Hugging Face - Blog
Hugging Face - Blog
Engineering at Meta
Engineering at Meta
Security Latest
Security Latest
Microsoft Azure Blog
Microsoft Azure Blog
V
Vulnerabilities – Threatpost
月光博客
月光博客
博客园 - 三生石上(FineUI控件)
Help Net Security
Help Net Security
博客园 - Franky
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
F
Fortinet All Blogs
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Forbes - Security
Forbes - Security
M
MIT News - Artificial intelligence
H
Hacker News: Front Page
大猫的无限游戏
大猫的无限游戏
Vercel News
Vercel News
Spread Privacy
Spread Privacy
The Register - Security
The Register - Security
H
Hackread – Cybersecurity News, Data Breaches, AI and More
量子位
Google Online Security Blog
Google Online Security Blog
PCI Perspectives
PCI Perspectives
The Last Watchdog
The Last Watchdog
AI
AI
N
News | PayPal Newsroom
D
DataBreaches.Net
Cloudbric
Cloudbric
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园 - 司徒正美
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
Tailwind CSS Blog

Replicate's blog

How to make remarkable videos with Seedance 2.0 – Replicate blog How to prompt Seedream 5.0 – Replicate blog Recraft V4: image generation with design taste – Replicate blog Run Isaac 0.1 on Replicate – Replicate blog Run FLUX.2 on Replicate – Replicate blog How to prompt Nano Banana Pro – Replicate blog Retro Diffusion's pixel art models are now on Replicate – Replicate blog Replicate is joining Cloudflare – Replicate blog Extract text from documents and images with Datalab Marker and OCR – Replicate blog How to prompt Veo 3.1 – Replicate blog IBM's Granite 4.0 is now on Replicate – Replicate blog Which image editing model should I use? – Replicate blog Introducing our new search API – Replicate blog Torch compile caching for inference speed – Replicate blog Announcing Replicate's remote MCP server – Replicate blog How to prompt Veo 3 with images – Replicate blog Open source video is back – Replicate blog Generate consistent characters – Replicate blog Bria is now on Replicate – Replicate blog How we optimized FLUX.1 Kontext [dev] – Replicate blog Compare AI video models – Replicate blog The FLUX.1 Kontext hackathon – Replicate blog How to prompt Veo 3 for the best results – Replicate blog Get the most from Google Veo 3 – Replicate blog FLUX.1 Kontext from the community – Replicate blog Use FLUX.1 Kontext to edit images with words – Replicate blog Generate incredible images with Google's Imagen 4 – Replicate blog Run OpenAI’s latest models on Replicate – Replicate blog NVIDIA H100 GPUs are here – Replicate blog Run 30,000+ LoRAs on Hugging Face with Replicate – Replicate blog Ideogram 3.0 on Replicate – Replicate blog Run MiniMax Speech-02 models with an API – Replicate blog Easel AI is now on Replicate – Replicate blog Stylized video with Wan2.1 – Replicate blog Creative roundup: avatars, lightsabers, and LoRA tricks – Replicate blog Wan2.1: generate videos with an API – Replicate blog Wan2.1 parameter sweep – Replicate blog You can now fine-tune open-source video models – Replicate blog Generate short videos with the Replicate playground – Replicate blog AI video is having its Stable Diffusion moment – Replicate blog FLUX fine-tunes are now fast – Replicate blog FLUX.1 Tools – Control and steerability for FLUX – Replicate blog NVIDIA L40S GPUs are here – Replicate blog Ideogram v2 is an outstanding new inpainting model – Replicate blog Stable Diffusion 3.5 is here – Replicate blog FLUX is fast and it's open source – Replicate blog FLUX1.1 [pro] is here – Replicate blog Using synthetic training data to improve Flux finetunes – Replicate blog Fine-tune FLUX.1 with an API – Replicate blog Fine-tune FLUX.1 to create images of yourself – Replicate blog Replicate Intelligence #12 – Replicate blog Replicate Intelligence #11 – Replicate blog Fine-tune FLUX.1 with your own images – Replicate blog Replicate Intelligence #10 – Replicate blog FLUX.1: First Impressions – Replicate blog Replicate Intelligence #9 – Replicate blog Run FLUX with an API – Replicate blog Replicate Intelligence #8 – Replicate blog Run Meta Llama 3.1 405B with an API – Replicate blog Replicate Intelligence #7 – Replicate blog Replicate Intelligence #6 – Replicate blog Replicate Intelligence #5 – Replicate blog How to get the best results from Stable Diffusion 3 – Replicate blog Run Stable Diffusion 3 on your Apple Silicon Mac – Replicate blog Push a custom version of Stable Diffusion 3 – Replicate blog Replicate Intelligence #4 – Replicate blog Run Stable Diffusion 3 on your own machine with ComfyUI – Replicate blog H100s are coming to Replicate – Replicate blog Run Stable Diffusion 3 with an API – Replicate blog Replicate Intelligence #3 – Replicate blog Replicate Intelligence #2 – Replicate blog Replicate Intelligence #1 – Replicate blog Shared network vulnerability disclosure – Replicate blog Run Snowflake Arctic with an API – Replicate blog Run Meta Llama 3 with an API – Replicate blog Run Code Llama 70B with an API – Replicate blog How to create an AI narrator for your life – Replicate blog Clone your voice using open-source models – Replicate blog Businesses are building on open-source AI – Replicate blog How to run Yi chat models with an API – Replicate blog Scaffold Replicate apps with one command – Replicate blog Using open-source models for faster and cheaper text embeddings – Replicate blog Generate music from chord progressions and text prompts with MusicGen-Chord – Replicate blog Generate images in one second on your Mac using a latent consistency model – Replicate blog How to use retrieval augmented generation with ChromaDB and Mistral – Replicate blog Fine-tune MusicGen to generate music in any style – Replicate blog Jet-setting with Llama 2 + Grammars – Replicate blog How to run Mistral 7B with an API – Replicate blog Make smooth AI generated videos with AnimateDiff and an interpolator – Replicate blog Fine-tuned models now boot in less than one second – Replicate blog Painting with words: a history of text-to-image AI – Replicate blog We're cutting our prices in half – Replicate blog A guide to prompting Llama 2 – Replicate blog Streaming output for language models – Replicate blog Fine-tune SDXL with your own images – Replicate blog Run Llama 2 with an API – Replicate blog Run SDXL with an API – Replicate blog A comprehensive guide to running Llama 2 locally – Replicate blog Fine-tune Llama 2 on Replicate – Replicate blog What happened with Llama 2 in the last 24 hours? 🦙 – Replicate blog
Constraining CLIPDraw – Replicate blog
2022-05-27 · via Replicate's blog

I’m Dom, one of the engineers here at Replicate. My background is web engineering, not machine learning. I have a pretty good sense of what machine learning can do from the outside – image generation, detecting objects in images, self-driving cars – but only a faint idea of how it actually works on the inside. I studied some AI as part of my degree, many years ago, which gives me a basic (if very out of date) grounding in things like neural networks, but that’s a long way off knowing what it’s like to actually build machine learning models.

Luckily for me I work with a team of people who have PhDs in this stuff, so I’ve been working with our co-founder Andreas to learn more about how it works.

One of the models on Replicate that I’ve found most fascinating is CLIPDraw. You give it a prompt, it generates a whole bunch of random squiggles on a canvas, and then slowly morphs those squiggles into something representing your prompt. It’s nowhere near as configurable nor refined as something like pixray/text2image, but it somehow feels much more human and grokkable in the way it uses paths to create an image.

My desktop is full of outputs from this model, so it was the natural choice when choosing something to work on. 

a screenshot of CLIPDraw outputs cluttered on my desktop

Inspired by some of dribnet’s art (the author of pixray/text2image), the first change I wanted to make was to encourage clipdraw to do most of its drawing in the middle of the canvas. Sometimes the outputs it generates feel a bit scruffy and spread out, and I wanted to see what it would look like more tightly bunched.

A brief aside on the dev environment

I’m working on an M1 Macbook, which isn’t all that compatible with developing GPU-based machine learning models. (Though, hot off the press! PyTorch have announced M1 support, which I’m keen to try out.) To get around that, we used a Google Cloud Platform instance with an attached T4 GPU – the same GPU we use to run models on replicate.com.

  1. Create the instance:

    gcloud compute instances create
    my-dev-instance
    —zone=us-central1-c
    —machine-type=n1-standard-8
    —accelerator type=nvidia-tesla-t4,count=1
    —boot-disk-size=1024GB
    —image-project=deeplearning-platform-release
    —image-family=common-cu113
    —maintenance-policy TERMINATE
    —restart-on-failure
    —scopes=default,storage-rw
    —metadata=“install-nvidia-driver=True”

  2. SSH into your instance with port forwarding, for Jupyter notebook, and key forwarding, for GitHub:

    gcloud compute ssh —zone us-central1-c my-dev-instance — -L 8888:localhost:8888 -A

  3. Install Cog, clone your model repo, and then run your Cog model with a notebook:

    cog run -p 8888 jupyter notebook —allow-root —ip=0.0.0.0

    Once it’s running, open the link it prints out, and you should have access to your notebook!

Once you’ve got your instance set up you can stop and start it as needed. It’ll keep your cloned repo, and you’ll just need to rerun the cog run command each time.

Back to the story

This was my first experience working with PyTorch. Along the way I encountered a few issues, and learning opportunities: code which seemed to run, but didn’t produce any results because the gradient flow was interrupted; learning about vectorisation and how to run operations on tensors; and rethinking how to design my code, to take it from something procedural to something differentiable.

Breaking the gradient flow

With my background in web engineering, my initial approach to this problem would be something like: for each point, calculate its distance from the centre, and add to the loss for anything further away than some minimum. In code, after getting to grips with how tensors work, that might look something like:

That runs, but unfortunately it makes absolutely no difference to the output. When we print out the value we’re adding to loss, it looks like it should work. And it’s a big number, so it should completely dominate the loss from CLIP for making it look like the prompt. In order to work out what’s going on, we tried to isolate this so that the loss from prompt similarity wasn’t a factor:

This fails with the error element 0 of tensors does not require grad and does not have a grad_fn. At this point Andreas patiently explained to me that the way this works is that PyTorch is keeping track of all the variables and operations involved in calculating loss, so that when it comes time to minimise it, it can work out how to change the variables to make the total loss smaller. For that to work, there needs to be a connection through every operation we perform on loss. By creating a new tensor we’re breaking that chain, and PyTorch can’t backtrack through our operations to work out how to minimise the loss.

One of the hardest parts about debugging this issue is that the failure was completely opaque. Andreas tells me it’s a common issue when working with ML models — you have to develop an intuition for what’s causing it to break, so you can step through the right part and work out the fix. Simplifying your code down to isolate the problem is a useful approach.

Vectorisation

One option to fix our broken chain is to use torch.stack() instead of creating a new tensor:

That works, but the route we actually took was to remove the list comprehension and use vectorisation, so we never have to make a new tensor in the first place. This approach is something that came pretty naturally to Andreas, who’s got a lot of experience with differentiable programming. When working with tensors, we can apply an operation to all the items in the tensor at once. In our code above, path_points is a two dimensional tensor:

We can subtract 112 from the tensor as a whole, rather than each individual element:

Operations like ** 2 or torch.sqrt work in the same way. To sum along one dimension of a tensor (rather than summing the entire thing), we can use axis:

Putting that together gives us this:

paths being sucked into a single blob in the centre of the image

That works! When we run it, the points very quickly move to the centre of the canvas and just stay there in a compact blob. So it’s doing what we want, but it’s putting way more weight behind “be in the centre” than behind “look like the prompt”. Let’s fix that:

Dividing by num_paths means the weight will be consistent whether we’re using 32 paths or 512 – it makes it a relative weight, rather than one that gets heavier and heavier as we add more paths. Multiplying by 0.001 drops the total value a few orders of magnitude to make it comparable with the loss from the similarity-to-prompt check. We didn’t apply any great science to that, we just printed out the loss from each source and tweaked it until they felt about right.

paths forming an image of a submarine as they move towards the centre

Although this is working, I think we can make it better. The model is using relatively few strokes outside of the centre to convey “this is a submarine”. That means there’s not a lot of detail. We want the points to be nearer the centre, not actually in it, so let’s subtract a threshold. And we don’t mind points being a little bit away from the centre, but we really don’t want them in the far corners, so let’s square the distance.

That works! We’re getting cute, dense, outputs now:

paths forming an image of a little submarine

Shifting from a procedural to differentiable approach

As cute as that output is, it’s a little too little, so let’s try upping the distance where the penalty starts kicking in:

Oops, we made a doughnut.

paths forming a ring shape

We’re getting a doughtnut because we’re penalising the model for putting points in the centre almost as much as if they were on the outside edges of the image. To fix that, we need to stop penalising the model for any points within our threshold.

If the distance is within the circle, we won’t apply a penalty. If it’s outside the circle, we’ll apply a penalty that increases the further away it is. Here’s some fairly procedural pseudocode for this:

It’s hard to make that code vectorisable as is, so we can’t just drop it in. One issue is that our pseudo code only operates on single points, and we’re currently operating on a tensor of multiple points. The second issue is that an if/else isn’t differentiable. To work out how we were going to implement this, Andreas encouraged me to think in terms of a mathematical function: f(x) = y. (As is often the case in programming there’s more than one way to implement this, and there’s a version using torch.maximum which will do the right thing here! But part of doing this was to help me think more in terms of differentiable programming, so we didn’t do it that way.)

We’re still using an if statement, so it isn’t differentiable yet, but it is good enough to be able to sketch out what our graph would look like. From that, we can work out how to model it with differentiable operations in PyTorch.

a graph showing the discontinuous function above

ReLU, or the Rectified Linear Unit function, is a function that’ll let us model that discontinuity at x=0. To get the quadratic curve for x>0 we can square our tensor, either before or after we apply ReLU. Armed with that, we can take a final run at this constraint:

paths forming the image of a submarine

Wrapping up

Here are a couple of outputs compared to the original clipdraw. The prompt for this one is “watercolor painting of an underwater submarine”:

comparison to original model for watercolor submarines

And the prompt for this one is “a bonfire”:

comparison to original model for bonfires

That’s it for now! We’re still a long way from anything as compelling as dribnet’s art, so there are loads more changes I want to make when I get the chance. Watch this space!

In the meantime you can check out the final code on GitHub and you can run the model for yourself on replicate.com. If you want to chat about this, or whatever models you’re working on, hop into our Discord and say hello.

👋