J'ai travaillé dans la recherche toute ma vie, donc je connais un stéréotype selon lequel les chercheurs écrivent du code laid (par exemple, voir ici , ici ou ici ). Mais je me suis dit : nous pouvons le réparer, n'est-ce pas ? J’ai donc essayé à plusieurs reprises de concevoir de jolis cadres de recherche. J'ai essayé d'introduire des interfaces et de créer de belles abstractions en utilisant des livres et des blogs de génie logiciel que j'aimais lire.
Mais à maintes reprises, tous ces efforts ont été vains. La majorité des logiciels de recherche sur lesquels j'ai travaillé n'ont jamais été mis en production (même si certains l'ont fait). Cela aurait été formidable pour ma santé mentale si quelqu'un me disait une simple vérité : la mort du code de recherche est en fait ce qui est censé arriver . Les chercheurs ne devraient pas consacrer beaucoup de temps à son ingénierie.
Les ingénieurs logiciels professionnels méprisent toujours les chercheurs qui n’utilisent pas les meilleures pratiques logicielles. Il existe plusieurs articles qui tentent de relever la barre du code de recherche (par exemple, cet excellent article et un manuel de code de recherche ). Mais cet article va dans le sens inverse : il explique comment ne pas exagérer les meilleures pratiques logicielles et plutôt investir uniquement dans une exploration rapide. Il s'adresse aux entreprises axées sur la recherche et dont l'objectif est de tester rapidement de nombreuses idées.
Un projet de recherche réussi dans une entreprise comporte deux phases : l’exploration et l’exploitation. En « exploration », vous souhaitez essayer autant de solutions diverses que possible. Lors de « l’exploitation », vous devez renforcer la meilleure solution et la transformer en un produit utile.
Les pratiques logicielles optimales sont très différentes entre les deux. C'est pourquoi les entreprises ont souvent des divisions de recherche et de produits distinctes. Tous les livres que vous pouvez généralement lire sur la conception de logiciels portent principalement sur la deuxième phase « d'exploitation ». Dans cette phase, vous construisez les bases d'un produit évolutif. C'est là qu'interviennent tous les modèles de conception : de belles API, la journalisation, la gestion des erreurs, etc.
Mais dans la première phase « d’exploration », vous ne construisez pas de fondations qui vivront éternellement. En fait, si la majorité de vos efforts survivent, alors vous (par définition) n’avez pas suffisamment exploré.
De nombreuses pratiques présentées dans cet article sont des exemples de ce qui serait normalement une « dette technologique ». C'est ce que vous obtenez en n'écrivant pas de code propre, réutilisable et bien abstrait. La dette est-elle toujours mauvaise ? Nous préférons ne jamais obtenir de prêt ou d’hypothèque, mais emprunter de l’argent est souvent une bonne stratégie dans la vie. Il n’y a rien de mal à s’endetter pour avancer rapidement et profiter plus tard.
De même, en ne contractant pas de dettes techniques, vous risquez de ralentir vos recherches. La bonne nouvelle est que la plupart du temps, vous n’avez pas à rembourser. La plupart de votre code de recherche risque de mourir de toute façon. Ainsi, en moyenne, vous ne souffrirez pas de la totalité de la dette technologique que vous avez contractée.
De nombreuses architectures logicielles et techniques de refactorisation sont spécifiquement orientées pour améliorer la réutilisabilité du code. La réutilisation du code présente des inconvénients génériques. Mais en production, ils sont contrebalancés par les avantages bien connus (par exemple, voir cet article typique ). Dans les projets de recherche, la majorité du code est vouée à sombrer dans l’oubli. S'efforcer de réutiliser le code pourrait en fait vous ralentir.
Limiter la réutilisation du code est le type de dette technique qu’il est acceptable de contracter en recherche. Il existe plusieurs modèles de réutilisation de code dont je souhaite aborder : l'ajout d'une dépendance inutile, le copier-coller de code, le maintien d'une grande partie du code de recherche partagé, les investissements de conception prématurés.
Si vous connaissez une bibliothèque versionnée bien entretenue qui va vous accélérer, allez-y ! Mais avant de vous lancer dans une nouvelle dépendance, essayez de déterminer si cela en vaut la peine. Chaque ajout supplémentaire vous rapproche de l’enfer de la dépendance. Cela vous fait investir du temps dans l’apprentissage et le dépannage. Découvrez plus de pièges liés aux dépendances dans cet article concis .
C'est probablement bien de dépendre de quelque chose si :
Mais méfiez-vous d’une dépendance si :
vous ne savez pas comment l'utiliser rapidement, il est très nouveau (ou très ancien) ou personne ne semble le savoir ; il n'y a pas de documents ni de tests
il provient de votre monorepo et est constamment modifié par d'autres équipes
il intègre de nombreuses autres dépendances et outils ; ou c'est juste difficile à installer
et enfin, vous sentez que vous (ou un LLM) pouvez écrire ce code en quelques heures.
Au lieu d'une dépendance explicite, vous pouvez suivre un joli proverbe Go : « un peu de copie vaut mieux qu'un peu de dépendance », qui est notre prochain sujet.
Certains disent que « le copier-coller devrait être illégal ». Mais à ma grande surprise, je me suis retrouvé à plaider assez souvent en sa faveur. Le copier-coller pourrait être le choix optimal pendant la phase d’exploration.
Si vous dépendez d'une fonction très utilisée provenant d'une autre partie de la base de code, vous pouvez oublier de la modifier facilement. Vous risquez de casser quelque chose pour quelqu'un et de devoir consacrer un temps précieux à la révision et aux correctifs du code. Mais si vous copiez et collez le code nécessaire dans votre dossier, vous êtes libre d’en faire ce que vous voulez. C’est un gros problème dans les projets de recherche où l’expérimentation est la norme plutôt que l’exception. Surtout si vous n’êtes pas sûr que les changements seront utiles à tout le monde.
Je trouve que les bases de code d'apprentissage profond sont les plus adaptées au copier-coller. En règle générale, la quantité de code nécessaire pour décrire un modèle et sa formation n'est pas si énorme. Mais en même temps, cela pourrait être très nuancé et difficile à généraliser. Les scripts de formation partageables ont tendance à atteindre une taille ingérable : par exemple, Hugging Face transformers
Trainer a +4 000 lignes. Chose intéressante, les transformateurs ont opté pour le copier-coller au niveau du modèle. Veuillez consulter leur article avec le raisonnement derrière leur politique de « modèle de fichier unique ». Voir plus de ressources sur la beauté du copier-coller à la fin.
Une alternative au copier-coller consiste à rester sur une branche. Mais j’ai l’impression que cela entraîne trop de frais dans le travail d’équipe. De plus, j'ai trouvé plusieurs autres articles sur la beauté du copier-coller - voir plus d'articles dans la conclusion.
La maintenance du code partagé très utilisé nécessite beaucoup de travail. Jetez un œil au nombre de lignes de fichier torch.nn.Module
tracé par rapport à la version Pytorch
. Vous pouvez constater que même les équipes de recherche les plus avancées ont du mal à maîtriser la complexité.
Ne sous-estimez pas le temps et les ressources nécessaires pour maintenir un code de recherche partagé volumineux. Plus une bibliothèque de recherche est utilisée, plus cela devient compliqué. Cela se produit plus rapidement que pour une bibliothèque classique, car chaque direction de recherche a un cas d'utilisation légèrement différent. Établissez des règles très strictes sur ce qui peut être reversé. Sinon, le code partagé devient fragile et envahi par une multitude d'options, d'optimisations boguées et de cas extrêmes. Puisque la majorité du code de recherche disparaît, toute cette complexité supplémentaire ne sera plus jamais utilisée. Supprimer une partie de votre code partagé vous libérera du temps pour effectuer de véritables recherches.
Il est en quelque sorte vrai que vous ne souhaitez pas trop pérenniser votre code, même en production. Essayez de mettre en œuvre la solution la plus simple possible qui répond aux exigences. Mais dans le code de production, il y a toujours des aspects de maintenabilité à prendre en compte. Par exemple, la gestion des erreurs, la vitesse, la journalisation et la modularisation sont ce à quoi vous devez généralement penser.
Dans le code de recherche, rien de tout cela n’a d’importance. Vous voulez simplement prouver rapidement qu’une idée est bonne ou mauvaise de la manière la plus rapide possible et passer à autre chose. Donc la sale simplicité qui permet d'y parvenir sans aucun module ni API est tout à fait acceptable !
Ne perdez pas de temps précieux sur des investissements logiciels prématurés tels que :
Le but d'un projet de recherche est de trouver une nouvelle solution. Personne ne sait (par définition) à quoi cela ressemble. Cela s’apparente à un processus d’optimisation dans un paysage de recherche complexe avec des informations limitées. Pour trouver un bon minimum, vous devez essayer de nombreux chemins, reconnaître les bons et les mauvais chemins et ne pas rester coincé dans les minima locaux. Pour faire tout cela rapidement, vous devez parfois investir dans des logiciels au lieu de contracter des dettes technologiques.
Il existe plusieurs voies de recherche différentes que vous souhaitez essayer. Existe-t-il une conception, une bibliothèque ou une optimisation qui permettrait de gagner du temps sur la majorité des chemins ? Vous devez faire attention à ne rien sur-concevoir, car vous ne connaissez pas toujours toutes les idées que vous êtes sur le point d'essayer. C'est très personnalisé pour chaque projet, mais voici quelques exemples :
Les chercheurs devraient être capables de lancer rapidement de nouvelles idées diverses. Cela semble facile au début du projet. Mais cela devient progressivement de plus en plus difficile à mesure que les gens s’enracinent dans leurs voies de recherche préférées. Pour y remédier, des changements culturels et organisationnels sont essentiels. Il devrait y avoir un processus mettant un terme aux recherches non prometteuses avant d’y investir trop d’argent et d’émotions. Des journées de démonstration régulières et des examens techniques par les pairs peuvent constituer des stratégies efficaces à cet effet. Il est également important de trouver un équilibre entre les gens qui se lancent dans une nouvelle idée brillante et ceux qui clôturent correctement les projets en cours.
Mais il s'agit d'un article sur un logiciel, voici donc quelques pratiques pour faciliter la création de nouveaux projets :
Un code bruyant et bogué rend les résultats si ambigus et peu concluants que l'ensemble du projet sera une perte de temps. Même si vous ne devriez pas trop concevoir les choses, vous pouvez facilement suivre ces règles empiriques simples pour éviter un code compliqué :
éviter le code avec des effets secondaires
par défaut les fonctions plutôt que les classes ; et avec les classes, préférez l'encapsulation à l'héritage
minimiser la longueur des fonctions/classes/modules ; minimiser le nombre d'instructions if
connaissez bien Python, mais utilisez des techniques simples. Résistez à la tentation de vous lancer dans les mauvaises herbes intellectuelles des métaclasses, des décorateurs et de la programmation fonctionnelle.
Il est difficile de travailler avec un logiciel qui produit des résultats différents au cours de différentes exécutions. Si vous avez pris une décision importante mais erronée basée sur une graine malchanceuse, vous perdrez beaucoup de temps à récupérer. Voici quelques conseils lorsque vous utilisez des logiciels non déterministes :
La punchline vient de cet article sur le code de recherche :
« Vous ne vous souciez pas d'une [bonne conception logicielle] parce que le code n'est pas la question. Le code est un outil qui vous apporte la réponse dont vous avez besoin » .
Il est extrêmement important d’avoir de bonnes bases de codage. Mais en fin de compte, ce qui compte, c’est l’exploration et le produit réellement utile. Si vous utilisez trop de logiciels de production dans la recherche, vous perdez le temps nécessaire à découvrir quelque chose de nouveau. Trouvez plutôt ce qui ralentit votre processus d’exploration. Accélérez les chemins de recherche en investissant dans un branchement rapide, des délais d'obtention des résultats et un code propre et silencieux.
Il serait fou de s’opposer complètement à la réutilisation du code. Je veux juste souligner que la réutilisation de code doit être une activité bien équilibrée. En recherche, le ratio de code jetable est plus important qu’en production. La balance penche encore davantage contre la réutilisation. Voici quelques autres articles intéressants présentant les pièges de la réutilisation du code :
Et voici quelques articles supplémentaires plaidant en faveur des pratiques de copier-coller :
Merci pour la lecture! Je pense que certains éléments sont un peu controversés, n'hésitez pas à me le faire savoir dans les commentaires !
Apparaît également ici .