ByteDance Seed и Tsinghua AIR представиха CUDA Agent: широкомащабна агентна RL система за генериране на CUDA ядра
ByteDance Seed и Tsinghua AIR представиха CUDA Agent — агентна система за обучение с подсилване, която обучава голям езиков модел да пише GPU ядра, превъзхождащи компилатор. Разликата, към която е насочена, е тясна, но упорита: водещите модели вече генерират коректен CUDA код, но той просто е бавен. В KernelBench базовият модел Seed1.6 преминава 74,0% от задачите, но превъзхожда torch.compile само при 27,2% от тях, с геометрично средно ускорение от 0,69×, което означава, че ядрата му средно са по-бавни от генерираните самостоятелно от компилатора. CUDA Agent преодолява тази разлика, като поставя модела в реална CUDA среда за разработка с профилиране, проверки за коректност и пясъчник с ограничени разрешения, след което го обучава с PPO в продължение на 150 стъпки при контекст от 131 072 токена. Резултатът е успеваемост от 98,8% и дял от 96,8% на задачите, при които системата е по-бърза от torch.compile, в рамките на бенчмарка от 250 задачи, с геометрично средно 2,11× спрямо компилирането — приблизително с 40 процентни пункта пред Claude Opus 4.5 и Gemini 3 Pro при най-трудното разделение Level 3.
Готова ли е за внедряване?
Отчасти, но обученият агент не е публикуван. Той е изграден върху Seed1.6 — собствен MoE модел с 23 млрд. активни и общо 230 млрд. параметри — а статията не предоставя тегла. Публично достъпни са: наборът от данни CUDA-Agent-Ops-6K, спецификацията SKILL.md и рецептите за награждаване и предварително загряване.
Кои компании: Само пясъчникът за профилиране е използвал 128 NVIDIA H20 GPU, което поставя пълното възпроизвеждане в рамките на водещи лаборатории, облачни GPU услуги и големи инфраструктурни екипи. Средните по размер екипи все пак могат да използват отделните компоненти — набора от данни, наградата за междинни цели, ограниченията срещу злоупотреби с наградата и спецификацията на уменията — върху отворен базов модел.
Индустрии и приложения: AI инфраструктура и обслужване на инференция, GPU облачни услуги, автономно шофиране, количествена търговия, медицинска образна диагностика и системи за препоръки — навсякъде, където слетите ядра са част от критичен за латентността път. Приложенията включват сливане на последователности от оператори, с които torch.compile се справя зле, намаляване на разходите за токен и повторно настройване на ядрата при различни поколения GPU.
Синтезиране на данни
Изследователският екип извлича референтни оператори от библиотеките torch и transformers. След това LLM взема до пет класа оператори от torch и ги подрежда в един слят слой. Филтърът запазва само оператори, които се изпълняват както в нетърпелив, така и в компилиран режим, са детерминистични, генерират неконстантни резултати и се изпълняват между 1 ms и 100 ms в нетърпелив режим. Премахват се образци с AST сходство над 0,9 с която и да е задача в KernelBench. Резултатът е CUDA-Agent-Ops-6K: 6000 образеца, 83,77% от които са композиции от два оператора.
Среда и награда
Цикълът на агента отразява инструментите на OpenHands — Bash, Read/Write, Edit/MultiEdit, Glob, Grep, NotebookEdit, BashOutput, KillBash — в рамките на модел ReAct. CUDA инструкциите са във формата Agent Skills. SKILL.md указва на модела да профилира PyTorch модела, да пренапише model_new.py с персонализирани ядра, да компилира в GPU пясъчник и да повтаря процеса, докато ядрото стане поне с 5% по-бързо от torch.compile при atol=1e-2, rtol=1e-2.
Злоупотребата с наградата се ограничава чрез пет противодействия: скриптове за проверка и профилиране с ограничени разрешения, контекстни мениджъри, които забраняват резервни реализации чрез torch.nn.functional, проверки с пет случайни входа, профилиране със синхронизация на устройството и предварително загряване, както и липса на инструмент за уеб търсене.
Наградата е дискретна, а не сурово съотношение на ускорението. r ∈ {−1, 1, 2, 3}: −1 при грешка в коректността, 3, ако ядрото превъзхожда както нетърпеливия режим, така и torch.compile с повече от 5%, 2, ако превъзхожда само нетърпеливия режим, и 1 във всички останали случаи.
Резултати
Таблица 1, общо: 98,8% успеваемост, 98,4% по-бързо от нетърпеливия режим, 96,8% по-бързо от torch.compile, съответно при геометрично средно ускорение от 2,60× и 2,11×. Level 2 (последователности от оператори) е най-силното разделение: 100% успеваемост, 100% дял на по-бързите задачи и 2,80× спрямо torch.compile. Level 3 достига 94,0% успеваемост, 90,0% дял на по-бързите задачи и 1,52× — приблизително с 40 процентни пункта над Claude Opus 4.5 (50,0%) и Gemini 3 Pro (52,0%) по дела на задачите, по-бързи от компилацията.
Едно несъответствие: резюмето и въведението посочват дялове на по-бързите задачи от 100% / 100% / 92% за Levels 1–3, докато Таблица 1 отчита 97,0% / 100,0% / 90,0%. Таблица 1 е основната таблица с резултати.
Аблационните изследвания са категорични. Премахването на агентния цикъл намалява дела на задачите, по-бързи от компилацията, от 96,8% на 14,1%. Сурова награда за ускорение дава 60,4%, без RFT резултатът е 49,8% плюс срив на наградата, а без предварително обучение на стойността — 50,9% плюс неконтролируемо удължаване на траекториите.
Примерите показват какво научава политиката. Диагонално матрично умножение, пренаписано като мащабиране по редове: 73,31× спрямо torch.compile. Последователност от матрично умножение, деление, сумиране и мащабиране, пренаредена и слята: 24,04×. ResNet BasicBlock с включена BatchNorm в свертката и cudnnConvolutionBiasActivationForward: 3,59×.
Стартиране на цикъла</button><button class="btn ghost" id="l-stop">Пауза</button></div>
<div class="loop">
<div class="node" id="n0"><div class="ic">
</div><div class="nm">SKILL.md</div><div class="sub">Профилиране → писане на ядро → компилиране → итерация</div></div>
<div class="node" id="n1"><div class="ic">
</div><div class="nm">CUDA Agent</div><div class="sub">Bash, Read/Write, Edit/MultiEdit, Glob, Grep</div></div>
<div class="node" id="n2"><div class="ic">
</div><div class="nm">CPU пясъчник</div><div class="sub">Docker компилация на .cu + binding.cpp</div></div>
<div class="node" id="n3"><div class="ic">
</div><div class="nm">GPU пул</div><div class="sub">Проверка на коректността + профилиране върху 128 H20</div></div>
</div>
<div class="gauge">
<div class="g"><div class="k">Ход</div><div class="v" id="g-turn">0</div></div>
<div class="g"><div class="k">Torch eager</div><div class="v warn" id="g-eager">2.30 ms</div></div>
<div class="g"><div class="k">torch.compile</div><div class="v warn" id="g-comp">1.80 ms</div></div>
<div class="g"><div class="k">Генерирано</div><div class="v good" id="g-gen">— ms</div></div>
</div>
<div class="note">Илюстративно: поетапното намаляване на времето за изпълнение на генерираното ядро е симулация на цикъла. Трите крайни стойности (2,30 ms за нетърпеливия режим, 1,80 ms за компилацията и 1,26 ms за генерираното ядро) са точните стойности, показани на Фигура 2 от статията.</div>
<div class="ref">Противодействия срещу злоупотреба с наградата: скриптовете за проверка и профилиране са с ограничени разрешения, контекстните мениджъри забраняват резервни реализации чрез <span class="mono">torch.nn.functional</span>, резултатите се проверяват с пет случайни входа, профилирането използва синхронизация на устройството, предварително загряване и повторения, а агентът няма инструмент за уеб търсене.</div>
</section>
<!-- 03 -->
<section class="mod" id="m3">
<h3>Защо наградата е дискретна, а не съотношение на ускорението</h3>
<p class="lede">Суровите награди за ускорение насочват политиката към лесни ядра и дават прекомерно големи стойности при отклонения. Вместо това CUDA Agent използва междинни цели. Преместете плъзгача, за да зададете времето за изпълнение на ядрото и да видите как се променя наградата.</p>
<div class="ctrl">
<label>Време за изпълнение на генерираното ядро <span class="mono" id="rt-lab">1.26 ms</span></label>
<input type="range" id="rt" min="20" max="320" step="1" value="126">
</div>
<div class="row"><button class="btn ghost" id="ok-tog">Проверка на коректността: <b id="ok-lab">PASS</b></button></div>
<div class="bars3" id="bars3"></div>
<div class="verdict" id="verdict">
<div class="r" id="v-r">3</div>
<div class="why" id="v-why"></div>
</div>
<div class="ref">Точното правило от Уравнение 1: r = −1, ако проверката за коректност е неуспешна; 3, ако е по-бързо от нетърпеливия режим и <span class="mono">torch.compile</span>; 2, ако е по-бързо само от нетърпеливия режим; в противен случай 1. „По-бързо“ означава b(t, t₀) = 𝟙[(t₀ − t)/t₀ > 5%]. Базовите стойности са фиксирани според тези от Фигура 2.</div>
</section>
<!-- 04 -->
<section class="mod" id="m4">
<h3>Резултати от KernelBench, Таблица 1</h3>
<p class="lede">250 задачи в три нива, претеглени съответно 100 / 100 / 50. Превключвайте между разделението и показателя — лентите ще се прерисуват с публикуваните в статията числа.</p>
<div class="selrow">
<div class="seg" id="lvl">
<button data-k="ov" class="on">Общо</button><button data-k="l1">Level 1</button><button data-k="l2">Level 2</button><button data-k="l3">Level 3</button>
</div>
<div class="seg" id="met">
<button data-k="pass">Дял на преминалите</button><button data-k="fe">По-бързо спрямо eager</button><button data-k="fc" class="on">По-бързо спрямо compile</button><button data-k="se">Ускорение спрямо eager</button><button data-k="sc">Ускорение спрямо compile</button>
</div>
</div>
<div id="chart"></div>
<div class="ref" id="chart-note"></div>
<div class="note">Резюмето и въведението посочват дялове от 100% / 100% / 92% на задачите, по-бързи от <span class="mono">torch.compile</span>, за Level 1 / 2 / 3, докато Таблица 1 отчита 97,0% / 100,0% / 90,0%. Този компонент използва Таблица 1 — основната таблица с резултати в статията.</div>
</section>
<!-- 05 -->
<section class="mod" id="m5">
<h3>Какво се поврежда при премахване на компонент</h3>
<p class="lede">Варианти с премахване на един компонент, общо разделение, дял на задачите, по-бързи от <span class="mono">torch.compile</span>. Агентният цикъл е най-важен; двата етапа на предварително загряване предотвратяват срива на обучението.</p>
<div id="abl"></div>
<div class="row" style="margin-top:14px"><button class="btn" id="st-run">
Повторно възпроизвеждане на кривата на обучение</button></div>
<svg class="spark" id="spark" viewBox="0 0 600 150" preserveAspectRatio="none"></svg>
<div class="legend"><span><i style="background:#4D9BFF"></i>PPO с RFT + предварително обучение на стойността</span><span><i style="background:#f5a623"></i>PPO без предварително загряване</span></div>
<div class="note">Схематично прерисуване на Фигура 4a, илюстративно. Посочените в статията факти са следните: първият RL опит остава стабилен в продължение на 17 стъпки, преди да се срине; с RFT на актьора и предварително обучение на стойността за критика обучението продължава 150 стъпки със стабилен ръст на наградата.</div>
<div class="ref">Посочената в статията първопричина: CUDA кодът представлява под 0,01% от данните за предварително обучение, затова извадките от малковероятни токени карат коефициента на важност в PPO да се колебае или да експлодира при несъответствие между точността на обучението и инференцията.</div>
</section>
<div class="foot">
<span>Източник: Dai, Wu, Yu и др., arXiv 2602.24286 · ByteDance Seed × Tsinghua AIR</span>
<span><b>Marktechpost</b> · интерактивно обяснение</span>
</div>
</div>
<script>
(function(){
var $=function(s){return document.querySelector(s)};
var $$=function(s){return Array.prototype.slice.call(document.querySelectorAll(s))};
/* ---- преоразмеряване ---- */
var wrap=document.getElementById('ca-wrap');
var lastH=0;
function ping(){
var h=wrap.offsetHeight+40;
if(h===lastH)return; lastH=h;
try{ parent.postMessage({type:'mtpEmbedHeight',id:'cuda-agent-explainer',height:h},'*'); }catch(e){}
}
setInterval(ping,600); window.addEventListener('load',ping); ping();
/* ---- навигация ---- */
$$('nav.ca-nav button').forEach(function(b){
b.addEventListener('click',function(){
$$('nav.ca-nav button').forEach(function(x){x.classList.remove('active')});
$$('section.mod').forEach(function(x){x.classList.remove('show')});
b.classList.add('active');
var m=b.getAttribute('data-m');
document.getElementById(m).classList.add('show');
if(m==='m5'){ setTimeout(drawSpark,30); }
ping();
});
});
/* ---- 01 конвейер ---- */
var comp=[['torch ops ×2',83.77],['torch ops ×3',7.62],['torch ops ×1',3.40],
['torch ops ×4',2.80],['torch ops ×5',1.23],['transformers',1.18]];
var compHTML='';
comp.forEach(function(c,i){
compHTML+='<div class="cb"><div class="lab">'+c[0]+'</div><div class="track"><div class="fill" data-w="'+
(c[1]/83.77*100)+'"></div></div><div class="val">'+c[1].toFixed(2)+'%</div></div>';
});
$('#comp').innerHTML=compHTML;
function tick(el,to,ms,suffix){
var t0=null;
function step(ts){ if(!t0)t0=ts; var p=Math.min((ts-t0)/ms,1);
el.textContent=Math.round(to*(1-Math.pow(1-p,3))).toLocaleString()+(suffix||'');
if(p<1)requestAnimationFrame(step); }
requestAnimationFrame(step);
}
function runPipe(){
resetPipe();
setTimeout(function(){$('#s1').classList.add('lit'); $('#c1').textContent='torch + transformers';},80);
setTimeout(function(){$('#s2').classList.add('lit'); $('#c2').textContent='\u2264 5 ops / задача';},1100);
setTimeout(function(){$('#s3').classList.add('lit'); tick($('#c3'),6000,1000,' запазени образци');},2200);
setTimeout(function(){$$('#comp .fill').forEach(function(f,i){
setTimeout(function(){f.style.width=f.getAttribute('data-w')+'%'},i*110)});},2900);
}
function resetPipe(){
['s1','s2','s3'].forEach(function(id){$('#'+id).classList.remove('lit')});
['c1','c2','c3'].forEach(function(id){$('#'+id).textContent='—'});
$$('#comp .fill').forEach(function(f){f.style.width='0%'});
}
$('#p-run').addEventListener('click',runPipe);
$('#p-reset').addEventListener('click',resetPipe);
/* ---- 02 агентен цикъл ---- */
var lt=null, li=0, turn=0, gen=2.90;
function loopStep(){
['n0','n1','n2','n3'].forEach(function(id){$('#'+id).classList.remove('act')});
$('#n'+(li%4)).classList.add('act');
if(li%4===3){
turn++; gen=Math.max(1.26, gen-(gen-1.26)*0.42);
$('#g-turn').textContent=turn;
$('#g-gen').textContent=gen.toFixed(2)+' ms';
$('#g-gen').className='v '+(gen<1.71?'good':'warn');
}
li++;
}
function loopStart(){ if(lt)return; loopStep(); lt=setInterval(loopStep,460); }
function loopStop(){ clearInterval(lt); lt=null; }
$('#l-run').addEventListener('click',function(){ if(turn>=6){turn=0;gen=2.90;} loopStart(); });
$('#l-stop').addEventListener('click',loopStop);
/* ---- 03 награда ---- */
var EAGER=2.30, COMP=1.80, ok=true;
function b(t,t0){ return (t0-t)/t0 > 0.05; }
function drawReward(){
var t=parseInt($('#rt').value,10)/100;
$('#rt-lab').textContent=t.toFixed(2)+' ms';
var max=3.4;
var rows=[['torch eager',EAGER,'#f5a623'],['torch.compile',COMP,'#4D9BFF'],['вашето ядро',t,'#5BE1F5']];
var h='';
rows.forEach(function(r){
h+='<div class="b3"><div class="lab">'+r[0]+'</div><div class="track"><div class="fill" style="width:'+
(r[1]/max*100)+'%;background:linear-gradient(90deg,'+r[2]+'55,'+r[2]+')"></div></div><div class="val">'+
r[1].toFixed(2)+' ms</div></div>';
});
$('#bars3').innerHTML=h;
var be=b(t,EAGER), bc=b(t,COMP), r, why, col;
if(!ok){ r=-1; why='Проверката за коректност е неуспешна. Времето за изпълнение е без значение — траекторията се санкционира.'; col='#f5a623'; }
else if(be&&bc){ r=3; why='С повече от 5% по-бързо от нетърпеливия режим И от torch.compile. Най-високата междинна цел.'; col='#3ddc97'; }
else if(be){ r=2; why='С повече от 5% по-бързо от нетърпеливия режим, но не и от torch.compile.'; col='#5BE1F5'; }
else { r=1; why='Коректно, но без съществено ускорение спрямо нито една от двете базови стойности.'; col='#8fa3c0'; }
$('#v-r').textContent=(r>0?'+':'')+r; $('#v-r').style.color=col;
$('#v-why').textContent=why;
$('#verdict').style.borderColor=col;
}
$('#rt').addEventListener('input',drawReward);
$('#ok-tog').addEventListener('click',function(){
ok=!ok; $('#ok-lab').textContent=ok?'PASS':'FAIL'; drawReward();
});
drawReward();
/* ---- 04 диаграма (Таблица 1) ---- */
var MODELS=['Seed1.6 (базов)','GLM 4.6','Kimi K2','Gemini 3 Pro','Claude Opus 4.5','CUDA Agent'];
var D={
ov:{pass:[74.0,75.6,66.8,91.2,95.2,98.8],fe:[43.6,44.8,40.8,87.6,90.4,98.4],
fc:[27.2,19.2,22.8,69.6,66.4,96.8],se:[0.95,0.78,0.93,1.92,1.99,2.60],
sc:[0.69,0.57,0.66,1.42,1.46,2.11]},
l1:{pass:[90.0,86.0,85.0,95.0,96.0,100.0],fe:[63.0,57.0,56.0,90.0,88.0,99.0],
fc:[51.0,32.0,39.0,72.0,72.0,97.0],se:[1.65,0.99,1.43,1.99,2.03,2.48],
sc:[1.25,0.73,1.00,1.51,1.54,1.87]},
l2:{pass:[74.0,76.0,65.0,93.0,98.0,100.0],fe:[40.0,43.0,40.0,91.0,97.0,100.0],
fc:[16.0,11.0,15.0,76.0,69.0,100.0],se:[0.68,0.60,0.93,2.03,2.24,3.27],
sc:[0.50,0.42,0.65,1.46,1.60,2.80]},
l3:{pass:[42.0,54.0,34.0,80.0,88.0,94.0],fe:[12.0,24.0,12.0,76.0,82.0,94.0],
fc:[2.0,10.0,6.0,52.0,50.0,90.0],se:[0.60,0.83,0.40,1.58,1.52,1.80],
sc:[0.40,0.62,0.29,1.17,1.10,1.52]}
};
var NOTES={ov:'Общо = претеглено според броя задачи на ниво (Level 1: 100, Level 2: 100, Level 3: 50).',
l1:'Level 1 = единични операции.', l2:'Level 2 = последователности от оператори, при които сливането е най-важно.',
l3:'Level 3 = реалистични блокове на невронни мрежи, най-трудното разделение.'};
var lvl='ov', met='fc';
function drawChart(){
var vals=D[lvl][met], pct=(met==='se'||met==='sc')?false:true;
var max=Math.max.apply(null,vals)*1.06;
var h='';
MODELS.forEach(function(m,i){
var v=vals[i];
h+='<div class="brow'+(i===5?' ours':'')+'"><div class="lab">'+m+'</div><div class="track"><div class="fill" data-w="'+
(v/max*100)+'"></div></div><div class="val">'+(pct?v.toFixed(1)+'%':v.toFixed(2)+'×')+'</div></div>';
});
$('#chart').innerHTML=h;
$('#chart-note').textContent=NOTES[lvl]+' Всички стойности са от Таблица 1 на статията.';
setTimeout(function(){$$('#chart .fill').forEach(function(f,i){
setTimeout(function(){f.style.width=f.getAttribute('data-w')+'%'},i*70)})},30);
}
$$('#lvl button').forEach(function(b2){b2.addEventListener('click',function(){
$$('#lvl button').forEach(function(x){x.classList.remove('on')});b2.classList.add('on');
lvl=b2.getAttribute('data-k');drawChart();})});
$$('#met button').forEach(function(b2){b2.addEventListener('click',function(){
$$('#met button').forEach(function(x){x.classList.remove('on')});b2.classList.add('on');
met=b2.getAttribute('data-k');drawChart();})});
drawChart();
/* ---- 05 аблация ---- */
var ABL=[['без агентен цикъл',14.1],['без устойчива награда',60.4],['без RFT',49.8],
['без предварително обучение на стойността',50.9],['CUDA Agent (пълен)',96.8]];
var ah='';
ABL.forEach(function(a,i){
ah+='<div class="brow'+(i===4?' ours':'')+'"><div class="lab">'+a[0]+
'</div><div class="track"><div class="fill" data-w="'+a[1]+'"></div></div><div class="val">'+
a[1].toFixed(1)+'%</div></div>';
});
$('#abl').innerHTML=ah;
setTimeout(function(){$$('#abl .fill').forEach(function(f,i){
setTimeout(function(){f.style.width=f.getAttribute('data-w')+'%'},i*90)})},250);
/* ---- 05 искра ---- */
var good=[0.35,0.62,0.95,1.10,1.02,1.28,1.20,1.44,1.35,1.52,1.41,1.63,1.55,1.72,1.66,1.80,1.74,1.88,1.82,1.95];
var bad =[0.32,0.58,0.88,1.05,1.18,1.30,1.22,1.05,0.86,0.62,0.40,0.22,0.12,0.06,0.03,0.02,0.02,0.01,0.01,0.01];
function pts(a){ return a.map(function(v,i){
return (30+i*(555/(a.length-1))).toFixed(1)+','+(130-v/2.1*112).toFixed(1); }).join(' '); }
function drawSpark(){
var s=$('#spark');
s.innerHTML='<line x1="30" y1="130" x2="588" y2="130" stroke="#1c2942" stroke-width="1"/>'+
'<line x1="30" y1="18" x2="30" y2="130" stroke="#1c2942" stroke-width="1"/>'+
'<line x1="200" y1="18" x2="200" y2="130" stroke="#f5a62355" stroke-width="1" stroke-dasharray="4 4"/>'+
'<text x="205" y="30" fill="#8fa3c0" font-size="10" font-family="monospace">стъпка 17: срив</text>'+
'<text x="4" y="24" fill="#8fa3c0" font-size="9" font-family="monospace">награда</text>'+
'<polyline id="pl-bad" points="'+pts(bad)+'" fill="none" stroke="#f5a623" stroke-width="2"/>'+
'<polyline id="pl-good" points="'+pts(good)+'" fill="none" stroke="#4D9BFF" stroke-width="2"/>';
['pl-bad','pl-good'].forEach(function(id){
var p=document.getElementById(id), L=0;
try{ L=p.getTotalLength(); }catch(e){ return; }
if(!L) return;
p.style.strokeDasharray=L; p.style.strokeDashoffset=L;
p.style.transition='stroke-dashoffset 1.8s ease';
setTimeout(function(){p.style.strokeDashoffset=0},60);
});
}
$('#st-run').addEventListener('click',drawSpark);
drawSpark();
})();
</script>
</body>
</html>
">
Основни изводи
- CUDA Agent постига 98,8% успеваемост и дял от 96,8% на задачите, по-бързи от
torch.compile, в KernelBench, с геометрично средно ускорение от 2,11×. - Сливането на Level 2 се отличава най-силно: 100% дял на по-бързите задачи и 2,80× спрямо
torch.compile. - Дискретната награда за междинни цели превъзхожда суровото съотношение на ускорението с 36,4 процентни пункта по дял на по-бързите задачи.
- RFT плюс предварителното обучение на стойността превръщат срив след 17 стъпки в 150 стабилни стъпки.
- Теглата са затворени; наборът от данни с 6000 образеца,
SKILL.mdи рецептата са публични.
Вижте статията, страницата на проекта и набора от данни. Също така можете да ни последвате в Twitter и не забравяйте да се присъедините към нашия ML SubReddit с над 150 хил. членове и да се абонирате за нашия бюлетин. Чакайте! В Telegram ли сте? Вече можете да се присъедините към нас и в Telegram.
Имате нужда от партньор за популяризиране на вашето GitHub хранилище ИЛИ страница в Hugging Face ИЛИ продуктова премиера ИЛИ уебинар и т.н.? Свържете се с нас
Преведено автоматично от английски. Оригиналната статия е на връзката по-долу.