Fazendo o DeepSeek-OCR funcionar em um NVIDIA Spark via força bruta usando Claude Code

Fazendo o DeepSeek-OCR funcionar em um NVIDIA Spark via força bruta usando Claude Code


Fazendo o DeepSeek-OCR funcionar em um NVIDIA Spark via força bruta usando Claude Code

20 de outubro de 2025

DeepSeek lançou ontem um novo modelo: DeepSeek-OCR, um modelo de 6,6 GB ajustado especificamente para OCR. Eles o lançaram como pesos de modelo executados usando PyTorch e CUDA. Eu consegui executá-lo no NVIDIA Spark fazendo com que Claude Code efetivamente usasse força bruta no desafio de fazê-lo funcionar naquele hardware específico.

Este pequeno projeto (40 minutos esta manhã, a maior parte dos quais foi Claude Code trabalhando enquanto eu tomava café da manhã e fazia outras coisas) une vários conceitos diferentes que venho explorando recentemente. Projetei um loop de agente para o problema, dei permissões completas a Claude dentro de uma sandbox do Docker, adotei o estilo de vida dos agentes paralelos e reutilizei minhas anotações no NVIDIA Spark da semana passada.

Eu sabia que executar um modelo PyTorch CUDA no Spark seria um pouco frustrante, então decidi terceirizar todo o processo para Claude Code para ver o que aconteceria.

TLDR: Funcionou. Foram necessárias quatro solicitações (uma longa, três muito curtas) para que Claude Code descobrisse tudo o que era necessário para executar o novo modelo DeepSeek no NVIDIA Spark, OCR um documento para mim e produzisse abundante notas sobre o processo.

A configuração

Conectei-me ao Spark do meu Mac via SSH e iniciei um novo contêiner Docker lá:

docker run -it --gpus=all \
  -v /usr/local/cuda:/usr/local/cuda:ro \
  nvcr.io/nvidia/cuda:13.0.1-devel-ubuntu24.04 \
  bash

Então instalei o npm e usei-o para instalar o Claude Code:

apt-get update
DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt-get install -y npm
npm install -g @anthropic-ai/claude-code

Em seguida, iniciei o Claude Code, dizendo que estava tudo bem se ele estivesse funcionando como root porque está em uma sandbox:

IS_SANDBOX=1 claude --dangerously-skip-permissions

Ele me forneceu um URL para clicar para autenticar minha conta Antrópica.

Os prompts iniciais

Eu comecei com este prompt:

Crie uma pasta deepseek-ocr e faça todo o resto nessa pasta

Em seguida, executei o seguinte, fornecendo links para o repositório GitHub e o modelo Hugging Face, fornecendo uma pista sobre o NVIDIA ARM e fornecendo uma imagem (esta, veja a postagem anterior) na qual eu queria que o OCR fosse executado.

Sua tarefa é fazer isso funcionar: https://github.com/deepseek-ai/DeepSeek-OCR — ele usa Hugging Face Transformers e modelos de https://huggingface.co/deepseek-ai/DeepSeek-OCR — você está executando em um contêiner Docker em um dispositivo NVIDIA ARM, primeiro pesquise seu ambiente para verificar se será possível fazer isso. Git clone ambos – talvez seja necessário habilitar o LFS primeiro. Faça anotações extensas à medida que avança em um arquivo notes.md ao qual você só deve anexar novas notas. No final disso, você deve ter scripts na pasta que podem ser executados para configurar e, em seguida, executar o modelo em um exemplo – use https://static.simonwillison.net/static/2025/ft.jpeg como a imagem de exemplo que você faz o OCR. Como etapa final, crie um arquivo README.md detalhado explicando o projeto, o que você aprendeu e como executar seu código.

Observe como eu também disse para “fazer anotações extensas à medida que avança em um arquivo notes.md ao qual você só deve anexar novas notas” para que eu tivesse algumas notas úteis no final.

Os acompanhamentos

Ele agitou-se por 13 minutos e fez uma sequência de descobertas sobre a plataforma e o modelo e as dificuldades de executar o PyTorch nele.

E então… desistiu:

A GPU NVIDIA GB10 possui capacidade de computação sm_121, que é muito nova para PyTorch 2.5.1

  • PyTorch 2.5.1 suporta: sm_50, sm_80, sm_86, sm_89, sm_90, sm_90a
  • GB10 requer: sm_121
  • Erro: CUDA error: no kernel image is available for execution on the device

Além disso, o modelo foi codificado .cuda() chamadas, evitando fallback de CPU sem modificações de código.

Então eu dei um incentivo:

Alguma outra opção que possa ajudar a fazer o CUDA funcionar, como usar versões diferentes do PyTorch que tenham rodas CUDA disponíveis para esta plataforma? Você verificou quais versões do PyTorch já possuem essas rodas ARM CUDA que funcionariam aqui?

Ele executou este comando para grep para todas as rodas PyTorch disponíveis em download.pytorch.org que correspondem à arquitetura ARM:

curl -s https://download.pytorch.org/whl/torch/ | grep -o 'torch-(0-9.)*.*aarch64.whl' | sort -V | tail -20

… e isso o desbloqueou.

Excelente! Posso ver que PyTorch 2.9.0 tem rodas ARM64 para CUDA 12.8, 12.9 e CUDA 13.0 (cu130)! É exatamente disso que precisamos!

Instalou as rodas que encontrou e relatou:

Boas notícias! PyTorch 2.9.0 pode detectar a GPU GB10 com capacidade CUDA 12.1 (sm_121), mas diz que o máximo suportado é 12.0. No entanto, agora é apenas um aviso em vez de um erro grave! Vamos tentar executar a inferência: (…)

Então continuei mexendo um pouco, ignorando os avisos, e consegui rodar o modelo! Ele carregou a imagem e executou este prompt:

<|grounding|>OCR this image.

E recuperei a saída que começou assim:

<|ref|>The perils of vibe coding<|/ref|><|det|>((352, 30, 624, 111))<|/det|>
<|ref|>opt<|/ref|><|det|>((970, 0, 994, 30))<|/det|>
<|ref|>such<|/ref|><|det|>((970, 24, 996, 58))<|/det|>
<|ref|>days<|/ref|><|det|>((970, 52, 996, 87))<|/det|>
<|ref|>pavi<|/ref|><|det|>((970, 85, 996, 118))<|/det|>
<|ref|>TECHNOLOGY<|/ref|><|det|>((33, 199, 127, 230))<|/det|>
<|ref|>holds the promise of replacing program-<|/ref|><|det|>((220, 170, 390, 210))<|/det|>
<|ref|>mers - a profession of very well paid<|/ref|><|det|>((220, 199, 390, 238))<|/det|>
<|ref|>people.For another, the work can be<|/ref|><|det|>((220, 228, 390, 267))<|/det|>

Claude declarou vitória e me indicou o arquivo output/result.mmd, que continha apenas espaços em branco. Portanto, o OCR funcionou, mas o resultado não foi gravado corretamente no disco.

Eu disse:

Esse arquivo result.mmd parece ser exclusivamente um espaço em branco para mim, tente obter um resultado melhor lá – a imagem da caixa delimitadora era boa

O que fez com que Claude reconsiderasse a sugestão usada:

Talvez precisemos usar um prompt diferente. Olhando para o README do DeepSeek-OCR, existem diferentes prompts:

  • "\n<|grounding|>Convert the document to markdown."—para documentos
  • "\n<|grounding|>OCR this image."—OCR geral
  • "\nFree OCR."—sem layouts

O modo “aterramento” parece estar focado em caixas delimitadoras, e é por isso que obtivemos bons resultados de caixas delimitadoras, mas a saída de texto pode estar em um formato diferente.

Deixe-me tentar executá-lo novamente com um prompt diferente, mais focado na extração de texto do que no aterramento.

Ele tentou todas as variantes de prompt, anotou-as e criou um arquivo chamado PROMPTS_GUIDE.md com mais detalhes, incluindo esta tabela de comparação:

Incitar Velocidade Qualidade do texto Estrutura Coordenadas Melhor caso de uso
OCR grátis ⚡⚡⚡ Rápido ⭐⭐⭐ Excelente ⭐ Básico ❌ Não OCR geral
Remarcação ⚡⚡ Médio ⭐⭐⭐ Excelente ⭐⭐⭐ Completo ⭐⭐ Parcial Documentos
Aterramento ⚡ Lento ⭐⭐Bom ⭐ Básico ⭐⭐⭐ Completo Anotações
Detalhado ⚡⚡⚡ Mais rápido ⭐ N/A ❌ N/A ❌ Não Análise de imagem

E esta tabela sob o título “Benchmarks de desempenho”:

Imagem de teste: 3503×1668 pixels (artigo do Financial Times)

Incitar Tempo Tamanho de saída Fichas
OCR grátis 24s Texto limpo 2257
Remarcação 39 anos MD formatado 2257 + estrutura
Aterramento 58 anos Texto + coordenadas 2257 + caixas
Detalhado 9s Descrição ~300

Minha solicitação final foi esta: reunir tudo em um arquivo zip que eu pudesse extrair do contêiner do Docker:

Crie um arquivo zip com a saída e output_text e todos os scripts e notas – mas deixe de fora o repositório github e os diretórios do repositório huggingface

Adicionei o conteúdo desse arquivo zip ao meu novo repositório GitHub simonw/research na pasta deepseek-ocr-nvidia-spark.

Claude gosta muito de fazer anotações! Aqui está a lista de diretórios dessa pasta finalizada:

  |-- download_test_image.sh
  |-- FINAL_SUMMARY.md
  |-- notes.md
  |-- output
  |   |-- images
  |   |-- result_with_boxes.jpg
  |   `-- result.mmd
  |-- output_text
  |   |-- detailed
  |   |   |-- images
  |   |   |-- result_with_boxes.jpg
  |   |   `-- result.mmd
  |   |-- free_ocr
  |   |   |-- images
  |   |   |-- result_with_boxes.jpg
  |   |   `-- result.mmd
  |   `-- markdown
  |       |-- images
  |       |   `-- 0.jpg
  |       |-- result_with_boxes.jpg
  |       `-- result.mmd
  |-- PROMPTS_GUIDE.md
  |-- README_SUCCESS.md
  |-- README.md
  |-- run_ocr_best.py
  |-- run_ocr_cpu_nocuda.py
  |-- run_ocr_cpu.py
  |-- run_ocr_text_focused.py
  |-- run_ocr.py
  |-- run_ocr.sh
  |-- setup.sh
  |-- SOLUTION.md
  |-- test_image.jpeg
  |-- TEXT_OUTPUT_SUMMARY.md
  `-- UPDATE_PYTORCH.md

Conclusões

Minha primeira solicitação foi às 15:31:07 (UTC). A mensagem final de Claude Code chegou às 16h10min03s. Isso significa que demorou menos de 40 minutos do início ao fim e só estive ativamente envolvido por cerca de 5 a 10 minutos desse tempo. O resto do tempo eu tomava café da manhã e fazia outras coisas.

Tendo tentado e falhado em fazer o PyTorch funcionar no passado, considero isso um enorme ganhar. Usarei esse processo muito mais no futuro.

Quão bons foram os resultados reais? Honestamente, há tanto material nas notas resultantes criadas por Claude que não revi tudo. Pode muito bem haver todo tipo de erros aí, mas é indiscutível que ele conseguiu rodar o modelo e fez anotações sobre como ele fez isso, de modo que poderei fazer a mesma coisa no futuro.

Acho que os fatores-chave para a execução deste projeto com sucesso foram os seguintes:

  1. Dei exatamente o que ele precisava: um ambiente Docker no hardware de destino, instruções sobre onde conseguir o que precisava (o código e o modelo) e um objetivo claro a ser perseguido. Este é um ótimo exemplo do padrão que descrevi ao projetar loops de agente.
  2. Executá-lo em uma sandbox Docker significava que eu poderia usar claude --dangerously-skip-permissions e deixe-o funcionando sozinho. Se eu tivesse que aprovar todos os comandos que ele queria executar, teria ficado frustrado e encerrado o projeto depois de apenas alguns minutos.
  3. Apliquei meu próprio conhecimento e experiência quando tudo travou. Eu estava confiante (com base em experimentos anteriores com o Spark) de que existia uma roda CUDA para ARM64 que provavelmente funcionaria, então, quando ela desisti, solicitei que tentasse novamente, levando ao sucesso.

Ah, e parece que o DeepSeek OCR é um modelo muito bom se você gastar tempo experimentando diferentes maneiras de executá-lo.

Bônus: usando o VS Code para monitorar o contêiner

Um pequeno TIL de hoje: eu iniciei o trabalho em execução no contêiner Docker via SSH para o Spark quando percebi que seria legal se eu pudesse monitorar facilmente os arquivos que ele estava criando enquanto estava em execução.

Perguntei a Claude.ai:

Estou executando um contêiner Docker em uma máquina remota, que iniciei por SSH

Como posso fazer com que meu código VS local no MacOS me mostre o sistema de arquivos naquele contêiner docker dentro daquela máquina remota, sem reiniciar nada?

Isso me deu um conjunto de etapas que resolveram exatamente esse problema:

  1. Instale as extensões VS Code “Remote SSH” e “Dev Containers”
  2. Use “Remote-SSH: Connect to Host” para conectar-se à máquina remota (na minha rede Tailscale que é spark@100.113.1.114)
  3. Na janela dessa sessão SSH remota, execute “Dev Containers: Attach to Running Container” – isso mostra uma lista de contêineres e você pode selecionar aquele ao qual deseja anexar
  4. … e é isso! O VS Code abre uma nova janela que fornece acesso total a todos os arquivos desse contêiner. eu abri notes.md e assisti como Claude Code anexou em tempo real.

No final, quando eu disse a Claude para criar um arquivo zip dos resultados, eu poderia selecioná-lo no explorador de arquivos do VS Code e usar o item de menu “Download” para baixá-lo para o meu Mac.



Source link

Postagens Similares

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *