paint-brush
Logiciels d'exploration : parvenir à un équilibre dans la découvertepar@sinavski
331 lectures
331 lectures

Logiciels d'exploration : parvenir à un équilibre dans la découverte

par Oleg SInavski10m2024/03/21
Read on Terminal Reader

Trop long; Pour lire

Un article plaidant pour : - éviter trop de techniques de production lors de la recherche. La production et la recherche ont des objectifs différents - c'est normal de contracter une « dette technologique » dans la recherche puisque la majorité du code va mourir. Par exemple, vous ne devriez pas vous efforcer de réutiliser le code - mais en tant que chercheur, vous devriez quand même investir dans une exploration rapide, un branchement rapide et un code simple et propre
featured image - Logiciels d'exploration : parvenir à un équilibre dans la découverte
Oleg SInavski HackerNoon profile picture

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.

1. Acceptez des dettes technologiques stratégiques

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.

Au cours de l'exploration, de nombreux projets disparaissent. Vous ne devez créer une solution robuste que pendant l’exploitation.

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.

Il n’y a rien de mal à s’endetter en logiciels dans le cadre de la recherche : vous n’êtes pas obligé de tout rembourser, seulement pour la minorité qui a réussi ses recherches.

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.

Les arguments contre la réutilisation du code

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.

Réfléchissez à deux fois avant d'importer quelque chose de nouveau

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 :

  • vous l'avez déjà utilisé, il n'y a pas grand chose à apprendre, il a une grande communauté, de bons documents et tests
  • il est versionné, facile à installer
  • et enfin, vous ne pouvez pas le mettre en œuvre vous-même.

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.

Le copier-coller vous donne la liberté d'expérimentation

Le copier-coller est rapide et constitue parfois le meilleur outil lors de la recherche.

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.

Il est difficile de maintenir un code de recherche partagé

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é.

Longueur du fichier torch.nn.Module en fonction de la version de PyTorch. Cela ne devient pas plus simple.

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.

Concevoir pour l'exploration, pas pour la réutilisation du code

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 :

  • créer des interfaces de composants trop tôt dans le projet. Vous passerez trop de temps à vous adapter à des contraintes artificielles que vous avez créées vous-même.
  • optimiser l'infrastructure de formation en deep learning avant de s'engager dans une solution de deep learning
  • en utilisant des systèmes de configuration/usines/sérialisation de production ou des classes de base. Très souvent, vous n'avez pas besoin de leurs fonctionnalités lors du prototypage
  • des systèmes de peluchage et de vérification de type trop stricts. Aucune raison de ralentir le code de recherche jetable et en évolution rapide.

2. Investissez dans une exploration rapide

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.

Accélérer les chemins communs

Investissez dans l’accélération des parties communes de vos projets de recherche.

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 :


  • si vous formez des réseaux approfondis, investissez dans l’infrastructure de formation. Déterminez les hyperparamètres vous permettant de converger pendant l'entraînement de manière rapide et fiable
  • si chaque expérience nécessite que vous utilisiez un modèle différent, découvrez comment vous pouvez les échanger rapidement (par exemple en utilisant un système d'usine simple ou simplement en copiant)
  • si chaque expérience comporte trop de paramètres et est difficile à gérer, investissez dans une belle bibliothèque de configuration.

Débranchez-vous rapidement

Investissez dans la rapidité de lancement de nouvelles voies de recherche. Vous avez besoin de nombreuses directions diverses pour trouver la solution.

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 :

  • garder le code d’évaluation démêlé des algorithmes. Les évaluations sont généralement plus stables que les orientations de recherche
  • Commencez un nouveau projet à partir de zéro, mais faites ensuite attention aux composants qui sont réutilisés. Les modulariser et les nettoyer est un bon investissement
  • dans un nouveau projet de recherche, mettre en œuvre en premier le composant le plus innovant et le plus risqué. Cela permet d’identifier la majorité des goulots d’étranglement guidant la conception future de logiciels.

Augmenter le rapport signal/bruit

Les bugs et le non-déterminisme peuvent faire dérailler les projets de recherche et rendre les résultats peu concluants

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 :


  • comprendre si le bruit provient de l'algorithme ou de son évaluation. Les sources de bruit s’aggravent et vous devez vous efforcer d’obtenir une évaluation complètement déterministe.
  • n'arrêtez pas de trouver des sources de hasard jusqu'à ce que vous obteniez vraiment un script reproductible. N'oubliez pas qu'après avoir trouvé toutes les graines aléatoires, le bruit peut provenir de données ou de fonctions génériques ayant des effets secondaires.
  • Variez les graines et déterminez la variance de base de vos résultats. Ne prenez pas de décisions sur des résultats non statistiquement significatifs.

Conclusion

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 .