<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	 xmlns:media="http://search.yahoo.com/mrss/" >

<channel>
	<title>PyCharm : The only Python IDE you need. | The JetBrains Blog</title>
	<atom:link href="https://blog.jetbrains.com/pycharm/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.jetbrains.com</link>
	<description>Developer Tools for Professionals and Teams</description>
	<lastBuildDate>Thu, 21 May 2026 08:53:25 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://blog.jetbrains.com/wp-content/uploads/2024/01/cropped-mstile-310x310-1-32x32.png</url>
	<title>PyCharm : The only Python IDE you need. | The JetBrains Blog</title>
	<link>https://blog.jetbrains.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Improving Accessibility in JetBrains IDEs: What’s New and What’s Next in 2026</title>
		<link>https://blog.jetbrains.com/platform/2026/05/improving-accessibility-in-jetbrains-ides-what-s-new-and-what-s-next-in-2026/</link>
		
		<dc:creator><![CDATA[Ekaterina Valeeva]]></dc:creator>
		<pubDate>Thu, 21 May 2026 06:45:13 +0000</pubDate>
		<featuredImage>https://blog.jetbrains.com/wp-content/uploads/2026/05/Blog-Featured-1280x720-1-1.png</featuredImage>		<product ><![CDATA[clion]]></product>
		<product ><![CDATA[go]]></product>
		<product ><![CDATA[idea]]></product>
		<product ><![CDATA[phpstorm]]></product>
		<product ><![CDATA[pycharm]]></product>
		<product ><![CDATA[ruby]]></product>
		<product ><![CDATA[rust]]></product>
		<product ><![CDATA[webstorm]]></product>
		<category><![CDATA[news]]></category>
		<category><![CDATA[accessibility]]></category>
		<guid isPermaLink="false">https://blog.jetbrains.com/?post_type=platform&#038;p=707397</guid>

					<description><![CDATA[Making software accessible often comes down to removing small but repeated points of friction in everyday workflows. Today, on Global Accessibility Awareness Day, we’re sharing recent improvements in JetBrains IDEs across several areas: compatibility with assistive technologies on various platforms, keyboard navigation, and non-visual feedback. Some of these improvements are already available, and some are [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>Making software accessible often comes down to removing small but repeated points of friction in everyday workflows. Today, on <a href="https://accessibility.day/" target="_blank" rel="noopener">Global Accessibility Awareness Day</a>, we’re sharing recent improvements in JetBrains IDEs across several areas: compatibility with assistive technologies on various platforms, keyboard navigation, and non-visual feedback. Some of these improvements are already available, and some are coming later this year.</p>



<p><em>You can use the audio player below to listen to this blog post.</em></p>


                                    <audio class="article-audio" preload="metadata" style="width: 100%;" controls>
                <source type="audio/mp4" src="https://blog.jetbrains.com/wp-content/uploads/2026/05/Accessibility-Blog-Post-Audio.mp4">
                <a href="https://blog.jetbrains.com/wp-content/uploads/2026/05/Accessibility-Blog-Post-Audio.mp4">
                    Accessibility Blog Post Audio                </a>
            </audio>
            


<h2 class="wp-block-heading">Better compatibility with assistive technologies</h2>



<p>One of the key areas we’ve been working on is improving how JetBrains IDEs interact with OS-level accessibility tools.</p>



<h3 class="wp-block-heading">Improved Magnifier support on Windows</h3>



<p>Screen magnifiers are among the most commonly used assistive technologies in JetBrains IDEs. Until recently, the built-in Windows Magnifier didn’t reliably follow the text cursor in the editor, making navigation and editing more difficult for low-vision users. We’ve implemented support for cursor tracking so Magnifier follows text as you type, just as it does in other applications.</p>



<figure class="wp-block-video" alt="Video demonstrating how Windows Magnifier follows the text caret while typing in a code editor"><video controls src="https://blog.jetbrains.com/wp-content/uploads/2026/05/MAgnifier_output.mp4"></video></figure>



<p>This builds on earlier work on macOS, where we addressed text cursor tracking with macOS Zoom. Now, the same support is being extended to Windows.</p>



<h3 class="wp-block-heading">Orca and GNOME Magnifier support on Linux</h3>



<p>With version 2026.2, coming this summer, JetBrains IDEs will allow you to use the Orca screen reader and GNOME Magnifier in <a href="https://www.jetbrains.com/help/idea/2026.1/installation-guide.html#operating-systems" target="_blank" rel="noopener">supported Linux environments</a>.&nbsp;</p>



<p>This is an active area of work, with multiple related tasks already underway. Accessibility shouldn’t depend on your operating system, and we’re continuing to improve support across platforms.</p>



<h2 class="wp-block-heading">More predictable keyboard navigation</h2>



<p>We’ve also been making it easier to move through the IDE without relying on a mouse.</p>



<h3 class="wp-block-heading">Main menu access with <em>Alt </em>on Windows</h3>



<p>In native Windows applications, pressing <em>Alt</em> moves the focus to the main menu, allowing you to navigate it with the keyboard. This behavior was previously missing from JetBrains IDEs, and screen readers, such as NVDA, would sometimes announce the system menu instead.</p>



<p>Now, the main menu behaves in a way that feels familiar and predictable for keyboard-only and screen-reader users, and the bright focus indicator helps low-vision users identify the selected item.&nbsp;&nbsp;</p>



<figure class="wp-block-video" alt="Video demonstrating how the IDE main menu receives focus and is highlighted with a blue frame when pressing the Alt key"><video controls src="https://blog.jetbrains.com/wp-content/uploads/2026/05/AltF_output.mp4"></video></figure>



<h3 class="wp-block-heading">Navigating between major parts of the IDE</h3>



<p>Another focus area is the experience of moving between different parts of the IDE interface, such as toolbars, panels, and the editor. We’re working on a more structured model for navigating through the big component groups:</p>



<ul>
<li><em>Tab</em> and <em>Shift+Tab</em> move the focus within the current area.</li>



<li>A dedicated shortcut lets you jump between larger sections of the IDE.</li>
</ul>



<p>This reduces the effort required to reach essential controls and makes the overall layout easier to navigate. For the current iteration, we made it possible to bring the main toolbar and status bar into focus, and we fixed the <em>Project</em><strong> </strong>and <em>Git</em> toolbar widgets, which were not selectable by screen readers, even though other elements already were.&nbsp;</p>



<figure class="wp-block-video" alt="Video demonstrating how the IDE main toolbar receives focus and is highlighted with a blue frame when the Alt+PgUp shortcut is pressed"><video controls src="https://blog.jetbrains.com/wp-content/uploads/2026/05/AltPgUp_output.mp4"></video></figure>



<p>As the next step, we’ll polish specific controls and include tool window bars on both sides of the IDE frame in the navigation flow.</p>



<h2 class="wp-block-heading">Exploring richer non-visual feedback with audio cues</h2>



<p>Accessibility is not only about reaching controls, but also about understanding what’s happening while you work. We’re exploring ways to provide richer audio feedback in the IDE. Two directions we’re currently investigating:</p>



<ul>
<li>Contextual signals when the caret lands on lines with errors, warnings, breakpoints, or version control changes. We want the IDE to provide immediate, non-visual feedback in context.</li>



<li>More general audio notifications for IDE actions and state changes.</li>
</ul>



<p>The goal is to reduce the need to rely on visual indicators or switch contexts just to understand what changed. Instead, we want the IDE to provide that information more directly.</p>



<h2 class="wp-block-heading">Accessibility as an ongoing effort</h2>



<p>We’re improving accessibility in JetBrains IDEs across multiple areas at once, including by providing compatibility with assistive technologies like screen readers and magnifiers, as well as by offering more consistent keyboard navigation and clearer feedback for events that are otherwise mostly visual.</p>



<p>These improvements build on earlier updates, such as support for VoiceOver and NVDA, a high-contrast UI theme, and color schemes for red-green vision deficiency. There’s still more to do, and we’ll continue working in this direction.</p>



<h2 class="wp-block-heading">We’d love to hear from you</h2>



<p>We’re eager to hear from developers who rely on accessibility features, as well as from anyone interested in improving the experience of using them.</p>



<p>If you have ideas or feedback about accessibility in JetBrains IDEs, you can reach us directly at <strong>accessibility@jetbrains.com</strong>. You can also report issues through <a href="https://youtrack.jetbrains.com/newIssue?project=IJPL" target="_blank" rel="noopener">YouTrack</a> or the <a href="https://www.jetbrains.com/support/" target="_blank" rel="noopener">support request form</a>.</p>



<p>If you’d like to stay informed about accessibility improvements, you can subscribe to updates <a href="https://lp.jetbrains.com/ij-accessibility/" target="_blank" rel="noopener">here</a>.</p>
]]></content:encoded>
					
		
		
		                    <language>
                        <code><![CDATA[zh-hans]]></code>
                        <url>https://blog.jetbrains.com/zh-hans/platform/2026/05/improving-accessibility-in-jetbrains-ides-what-s-new-and-what-s-next-in-2026/</url>
                    </language>
                                    <language>
                        <code><![CDATA[ko]]></code>
                        <url>https://blog.jetbrains.com/ko/platform/2026/05/improving-accessibility-in-jetbrains-ides-what-s-new-and-what-s-next-in-2026/</url>
                    </language>
                                    <language>
                        <code><![CDATA[ja]]></code>
                        <url>https://blog.jetbrains.com/ja/platform/2026/05/improving-accessibility-in-jetbrains-ides-what-s-new-and-what-s-next-in-2026/</url>
                    </language>
                                    <language>
                        <code><![CDATA[fr]]></code>
                        <url>https://blog.jetbrains.com/fr/platform/2026/05/improving-accessibility-in-jetbrains-ides-what-s-new-and-what-s-next-in-2026/</url>
                    </language>
                                    <language>
                        <code><![CDATA[de]]></code>
                        <url>https://blog.jetbrains.com/de/platform/2026/05/improving-accessibility-in-jetbrains-ides-what-s-new-and-what-s-next-in-2026/</url>
                    </language>
                	</item>
		<item>
		<title>LLM Evaluation and AI Observability for Agent Monitoring</title>
		<link>https://blog.jetbrains.com/pycharm/2026/05/llm-evaluation-and-ai-observability-for-agent-monitoring/</link>
		
		<dc:creator><![CDATA[Evgenia Verbina]]></dc:creator>
		<pubDate>Tue, 19 May 2026 09:46:54 +0000</pubDate>
		<featuredImage>https://blog.jetbrains.com/wp-content/uploads/2026/05/PC-social-BlogFeatured-1280x720-1-4.png</featuredImage>		<category><![CDATA[tutorials]]></category>
		<category><![CDATA[ai]]></category>
		<category><![CDATA[ai-agents]]></category>
		<category><![CDATA[llm]]></category>
		<guid isPermaLink="false">https://blog.jetbrains.com/?post_type=pycharm&#038;p=707771</guid>

					<description><![CDATA[This is a guest post from Naa Ashiorkor, a data scientist and tech community builder. Artificial intelligence keeps evolving at a rapid pace. The latest major application of AI, specifically of LLMs, is AI agents. These are systems that use their perception of their environment, processes, and input to take action to achieve specific goals, [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p><em>This is a guest post from </em><strong><em><a href="https://blog.jetbrains.com/pycharm/2026/05/llm-evaluation-and-ai-observability-for-agent-monitoring/#author" data-type="link" data-id="https://blog.jetbrains.com/pycharm/2026/05/llm-evaluation-and-ai-observability-for-agent-monitoring/#author">Naa Ashiorkor</a></em></strong><em>, a data scientist and tech community builder.</em></p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" fetchpriority="high" src="https://blog.jetbrains.com/wp-content/uploads/2026/05/PC-social-BlogFeatured-1280x720-1-4.png" alt="" class="wp-image-708070"/></figure>



<p>Artificial intelligence keeps evolving at a rapid pace. The latest major application of AI, specifically of LLMs, is AI agents. These are systems that use their perception of their environment, processes, and input to take action to achieve specific goals, and they are built on LLMs.&nbsp;</p>



<p>Increasingly, complex AI agents are being used in real-world applications. While simpler agentic applications that use only one agent to achieve a goal still exist, organizations are now shifting towards multi-agent systems that use multiple subagents coordinated by a main agent. These are more adaptable and can mimic human teams when it comes to performing specialized tasks such as data analysis, compliance, customer support, and more. The reasoning and autonomy of AI agents have improved; consequently, they can gather data, conduct cross-references, and generate analysis.</p>



<p>As we move towards these complex, real-world applications of agents, an ever-stronger spotlight is being shone both on how we observe AI agents and how we evaluate the LLMs they’re built upon. The complexity, interactions, and autonomous processes under the surface of AI agents make rigorous monitoring and assessment an essential part of building and maintaining these applications. LLM evaluation determines if the AI agent <em>can</em> <em>work</em>, while AI agent observability determines if it <em>is working</em>. LLM evaluation tests an agent’s basic capabilities before and during deployment, while agent observability provides deep, real-time visibility into an agent’s internal reasoning and operational health once it is live. It is pretty obvious that having just one of these is a loss and a formula for failure.&nbsp;</p>



<p>In this blog post, we’ll explore how to evaluate agents using advanced metrics and observability tools. It’s designed as a practical, end-to-end reference for teams that want to move beyond demos and actually run AI agents in live, real-world environments, avoiding the common pitfalls that cause failure in production.</p>



<h2 class="wp-block-heading">Core LLM evaluation metrics for modern AI systems</h2>



<p>As LLMs are now applied to a wide range of use cases, it is important that their evaluation covers both the tasks they may perform and their potential risks. Evaluation metrics give a better understanding of the strengths and weaknesses of LLMs, influence the guidance of human-LLM interactions, and highlight the importance of ensuring LLM safety and reliability. Hence, LLM evaluation metrics for assessing the performance of an LLM are indispensable in modern AI systems. Without well-defined evaluation metrics, assessing model quality becomes subjective.&nbsp;</p>



<p>There are several key evaluation metrics, each with a different purpose, and the table below provides a summary of some of them.</p>



<figure class="wp-block-table"><table><tbody><tr><td><strong>Evaluation Metric</strong></td><td><strong>What the metric evaluates</strong></td></tr><tr><td>Hallucination rate</td><td>Factual accuracy and truthfulness of generated content</td></tr><tr><td>Toxicity scores</td><td>Harmful, offensive, or inappropriate content</td></tr><tr><td>RAGAS (Retrieval Augmented Generation Assessment)</td><td>Measures whether the RAG system retrieves the right documents and generates answers that are faithful to those sources</td></tr><tr><td>DeepEval</td><td>Tests everything from basic accuracy and safety to complex agent behaviors and security vulnerabilities across the entire LLM application</td></tr></tbody></table></figure>



<h3 class="wp-block-heading">Hallucination rate</h3>



<p>Hallucinations in LLMs produce outputs that seem convincing yet are factually unsupported and can be categorized as either intrinsic, where the output contradicts the source content, or extrinsic, where it simply cannot be verified. They can stem from a range of factors across data, training, and inference, from quality issues in the large datasets used for initial training and the data used to fine-tune model behavior to post-training techniques that make models overly eager to provide responses to imperfect decoding strategies at inference. Because hallucination is an unsolved challenge cutting across every stage of model development, measuring and assessing it remains a vital part of LLM evaluation.</p>



<p>There is a wide variety of techniques for detecting hallucinations. These include:&nbsp;</p>



<ul>
<li><strong>Fact-checking: </strong>Extracting independent factual statements from the model&#8217;s outputs (fact extraction) and then verifying these against trusted knowledge sources (fact verification).</li>



<li><strong>Uncertainty estimation:</strong> Using the certainty provided in the model&#8217;s internal state to estimate how likely a piece of factual content is to be a hallucination.</li>



<li><strong>Faithfulness hallucination detection:</strong> Ensures the faithfulness of LLMs to provide context or user instructions.&nbsp;</li>
</ul>



<p>There are several metrics for hallucination detection. Some of the most commonly used metrics include:</p>



<ul>
<li><strong>Fact-based metrics:</strong> Assessing faithfulness by measuring the overlap of facts between the generated content and the source content.&nbsp;</li>



<li><strong>Classifier-based metrics:</strong> Utilizing trained classifiers to distinguish between the level of entailment between the generated content and the source content.&nbsp;</li>



<li><strong>QA-based metrics:</strong> Using question-answering systems to validate the consistency of information between the source content and the generated content.&nbsp;</li>



<li><strong>Uncertainty-based metrics:</strong> Assessing faithfulness by measuring the model’s confidence in its generated outputs.&nbsp;</li>



<li><strong>LLM-based metrics:</strong> Using LLMs as evaluators to assess the faithfulness of generated content through specific prompting strategies.&nbsp;</li>
</ul>



<p>PyCharm&#8217;s <a href="http://jetbrains.com/help/pycharm/hugging-face.html" target="_blank" rel="noopener">Hugging Face integration</a> lets you discover evaluation models and datasets without leaving the IDE. Use the <em>Insert HF Model</em> feature to search for hallucination or toxicity classifiers, and hover over any model or dataset name in your code to instantly preview its model card, including training data, intended use, and limitations. This means you can import a dataset, evaluate your LLM, and verify the tools you&#8217;re using, all from one place.</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" src="https://blog.jetbrains.com/wp-content/uploads/2026/05/image1-2.png" alt="PyCharm's Hugging Face integration" class="wp-image-707885"/><figcaption class="wp-element-caption"><em>Opening the Hugging Face model browser in PyCharm from the </em><strong><em>Code</em></strong><em> menu, then selecting </em><strong><em>Insert HF Model</em></strong><em>.</em></figcaption></figure>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" src="https://blog.jetbrains.com/wp-content/uploads/2026/05/image3.png" alt="PyCharm's &quot;Insert HF Model&quot; feature" class="wp-image-707898"/><figcaption class="wp-element-caption"><em>Searching for a specific hallucination model and selecting one. </em><strong><em>Use Model</em></strong><em> inserts a ready-to-use code snippet into the editor.</em></figcaption></figure>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/05/image2.png" alt="PyCharm's &quot;Use Model&quot; feature" class="wp-image-707911"/><figcaption class="wp-element-caption"><em>A ready-to-use code snippet of the </em><strong><em>Vectara hallucination evaluation model </em></strong><em>is inserted into the editor.</em></figcaption></figure>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" src="https://blog.jetbrains.com/wp-content/uploads/2026/05/image-19.png" alt="Vectara hallucination evaluation model" class="wp-image-707808"/><figcaption class="wp-element-caption"><em>Hovering over the </em><strong><em>Vectara hallucination evaluation model</em></strong><em> in the code to preview its model card within PyCharm.</em></figcaption></figure>



<p>Trust is imperative in the acceptance and adoption of technology. Trust in AI is especially important in areas such as healthcare, finance, personal assistance, autonomous vehicles, and others. Hallucinations have a huge impact on users&#8217; trust in LLMs.</p>



<p>In 2023, <a href="https://hai.stanford.edu/news/hallucinating-law-legal-mistakes-large-language-models-are-pervasive" target="_blank" rel="noopener">a story went viral</a> about a Manhattan lawyer who submitted a legal brief largely generated by ChatGPT. The judge quickly noticed how different it was from a human-written submission, revealing clear signs of hallucination. Incidents like this highlight the real-world risks of LLM errors and their impact on user trust. As people encounter more examples of hallucination, skepticism around LLM reliability continues to grow.</p>



<h3 class="wp-block-heading">Toxicity scores</h3>



<p>LLMs that have been pretrained on large datasets from the web have the tendency to generate harmful, offensive, and disrespectful content as well as toxic language, such as hate speech, harassment, threats, and biased language, which have a negative impact on their safe deployment. Toxicity detection is the process of identifying and flagging toxic content by integrating open-source tools or APIs into the LLM workflow to analyze both the user input and the LLM output. Some of the available toxicity tools include the <a href="https://developers.openai.com/api/docs/guides/moderation" target="_blank" rel="noopener">OpenAI Moderation API</a>, which is free, works with any text, and has a quick implementation. <a href="https://perspectiveapi.com/" target="_blank" rel="noopener">Perspective API</a> by Google is also widely used with a transparent methodology, but will no longer be in service after 2026. <a href="https://github.com/unitaryai/detoxify" target="_blank" rel="noopener">Detoxify</a>, which is open source, has no API costs, and is Python-friendly, and <a href="https://azure.microsoft.com/en-us/products/ai-services/ai-content-safety" target="_blank" rel="noopener">Azure AI Content Safety</a> by Microsoft, which is customizable and best for enterprise deployments and existing Azure users. <a href="https://huggingface.co/models?other=toxicity" target="_blank" rel="noopener">Hugging Face Toxicity Models</a> have many model options and easy integration with Transformers.</p>



<p>Toxicity detection has become a guardrail; hence, it is important in public-facing applications. They prevent toxic content from reaching users, which protects both individuals and organizations. In public-facing applications, toxicity detection operates by input filtering, output monitoring, and real-time scoring. This prevents attacks where users intentionally train AI to produce toxic content through coordinated toxic inputs; toxic content will never reach the user, even if produced by the underlying AI, so systems can adjust their behavior dynamically based on conversation content and escalating risks. Unguarded AI can be exploited, which leads to reputational damage.&nbsp;</p>



<p>For toxicity evaluation, PyCharm&#8217;s <a href="http://jetbrains.com/help/pycharm/hugging-face.html" target="_blank" rel="noopener">Hugging Face</a> <em>Insert HF Model feature </em>helps you discover classifiers like s-nlp/roberta_toxicity_classifier directly in the IDE. Hovering over the model name reveals its model card, where you can see it was trained on the Jigsaw toxic comment datasets, helping you understand what the model can and can&#8217;t detect before you write a single line of evaluation code.&nbsp;</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/05/image4.png" alt="PyCharm's Hugging Face Insert HF Model feature" class="wp-image-707947"/><figcaption class="wp-element-caption"><em>Opening the Hugging Face model browser in PyCharm from the </em><strong><em>Code</em></strong><em> menu, then selecting the </em><strong><em>Insert HF Model</em></strong><em>.</em></figcaption></figure>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/05/image7-1.png" alt="PyCharm's &quot;Use Hugging Face Model&quot;" class="wp-image-707970"/><figcaption class="wp-element-caption"><em>Searching for a specific toxicity model and selecting one. </em><strong><em>Use Model</em></strong><em> inserts a ready-to-use code snippet into the editor.</em></figcaption></figure>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/05/image6-2.png" alt="" class="wp-image-707983"/><figcaption class="wp-element-caption"><em>A ready-to-use code snippet of the </em><strong><em>roberta_toxicity_classifier </em></strong><em>is inserted into the editor.</em></figcaption></figure>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/05/image9-2.png" alt="" class="wp-image-707996"/><figcaption class="wp-element-caption"><em>Hovering over the </em><strong><em>roberta_toxicity_classifier</em></strong><em> in the code to preview its model card within PyCharm.</em></figcaption></figure>



<h3 class="wp-block-heading">Frameworks for LLM evaluation</h3>



<p>Frameworks for LLM evaluation have changed the game; teams don’t have to rely on manual reviews, gut instinct, and subjective judgment to assess model quality. These frameworks automate the measurement of model quality using standardized, quantifiable metrics. They assign numerical scores to outputs that measure faithfulness, relevancy, toxicity, and other important dimensions. This automation results in reproducibility, speed, and objectivity.&nbsp;</p>



<p>Consequently, the same input always produces the same score; evaluation runs 10–100 times faster, so in minutes instead of days; and there are no more debates on the quality of the output. Some of these frameworks include <a href="https://deepeval.com/" target="_blank" rel="noopener">DeepEva</a>l and <a href="https://docs.ragas.io/en/stable/" target="_blank" rel="noopener">Retrieval Augmented Generation Assessment (Ragas)</a>. DeepEval is an open-source evaluation framework built with seven principles in mind, such as the ability to easily &#8220;unit test&#8221; LLM outputs in a similar way to Pytest and plug in and use over 50 LLM-evaluated metrics, most of which are backed by research and all of which are multimodal.&nbsp;</p>



<p>It is extremely easy to build and iterate on LLM applications with two modes of evaluation, namely, end-to-end LLM evals and component-level LLM evals. It is used for comprehensive testing across RAG, agents, and chatbots. Ragas is a framework for reference-free evaluation of RAG pipelines. There are several dimensions to consider, such as the ability of the retrieval system to identify relevant and focused context passages, as well as the capability of the LLM to exploit such passages in a faithful way; hence, it is challenging to evaluate RAG systems. Ragas provides a suite of metrics for evaluating these dimensions without relying on ground-truth human annotations.&nbsp;</p>



<h3 class="wp-block-heading">The limits of static prompt evaluation</h3>



<p>Traditional LLM evaluation methods are useful for single prompt-response pairs, measuring output quality, RAG systems with straightforward retrieval, and static evaluation with fixed inputs. But they are limited for multi-step agents because LLM evaluation focuses on the final output quality, not the decision-making process that produced it. Multi-step agents exhibit a different kind of complexity, as they chain multiple decisions.</p>



<h2 class="wp-block-heading">Why traditional LLM evaluation isn’t enough for agents&nbsp;</h2>



<p>Agents operate independently within complex workflows, and this independence can introduce challenges such as deviation from expected behavior, errors in production, and more failure points than in traditional software applications. Hence, an agent can perform well in testing but fail in production. Traditional LLM evaluations don’t have the capacity to test such use cases. Testing is usually done in a controlled environment with limited scenarios, but production involves real users, edge cases, unpredictable inputs, and scale. This means that agents can make decisions that are not seen in testing, and in production, tasks could be completed, though incorrectly, without generating an error signal. This is where advanced evaluation and monitoring practices come to the rescue! They provide the visibility and systematic measurement needed to deploy agents confidently, rather than relying on trial and error.</p>



<h3 class="wp-block-heading">The complexity of agent behavior</h3>



<p>Traditional LLM evaluation measures single prompt-response pairs: provide an input prompt, receive an output response, and measure quality through metrics such as accuracy, relevance, and faithfulness. Due to the complexity and non-deterministic, multi-step reasoning of AI agents, they cannot be reliably evaluated using traditional evaluation metrics.</p>



<p>Agent behavior is complex, and this complexity introduces challenges. Agents operate in dynamic environments where APIs might be down, databases change between queries, and the “right” answer depends on current conditions. They can use external tools and APIs to complete tasks, and may either use the wrong tool or use the right tool with the wrong parameters or input type. Their internal reasoning traces remain hidden unless they are logged explicitly, so it might be challenging to determine whether an agent was successful through logic or chance. An agent&#8217;s output could be perfectly correct despite poor internal decisions, or the entire task could fail despite correct step execution.</p>



<p>This is where observability tooling becomes essential. PyCharm&#8217;s <a href="http://blog.jetbrains.com/pycharm/2025/08/pycharm-2025-2/#ai-agents-debugger">AI Agents Debugger</a> breaks open the black box of agentic systems, letting you trace LangGraph workflows and inspect each agent node&#8217;s inputs, outputs, and reasoning directly in the IDE, with zero extra code. Just install the plugin, run your agent, and the debugger automatically captures execution traces. Click the <em>Graph</em> button to visualize the full workflow, making it easy to spot where an agent chose the wrong tool, passed bad parameters, or succeeded by luck rather than logic.</p>



<p>To see this in action, I built a simple travel-planning agent using LangGraph in two steps: a research node that suggests summer destinations based on my preferences, and a plan node that picks the best option and builds a three-day itinerary. With the AI Agents Debugger, you can trace exactly what information flowed between these two steps – what the research node suggested and how the planner used those suggestions to build the final itinerary.</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/05/image8-1.png" alt="" class="wp-image-708007"/><figcaption class="wp-element-caption"><em>The </em><strong><em>AI Agents Debugger</em></strong><em> shows how the agent moves from initialization to the research stage, displaying the data passed in and out, and the LLM call used to generate the research results.</em></figcaption></figure>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/05/image12.png" alt="" class="wp-image-708018"/><figcaption class="wp-element-caption"><em>The </em><strong><em>AI Agents Debugger</em></strong><em> shows how the planning step processes inputs and produces outputs, using an LLM call to construct the final travel itinerary.</em></figcaption></figure>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/05/image10-1.png" alt="" class="wp-image-708029"/><figcaption class="wp-element-caption"><em>The </em><strong><em>Graph </em></strong><em>viewprovides a high-level overview of the agent’s workflow, mapping how it progresses from the initial step through research and planning to the final result.</em></figcaption></figure>



<h2 class="wp-block-heading">Advanced agent evaluation metrics</h2>



<p>The complexity of AI agents demands evaluation that goes beyond considering the final output quality, that is, measuring whether it is accurate, relevant, and grounded. Specialized agent evaluation assesses the complete decision-making process, including the planning logic, tool selection, parameter construction, reasoning coherence, and resource efficiency that led to the final output. Hence, the advanced agent evaluation metrics are designed to make such a process visible and measurable. Some of them are task completion rate, tool usage, reasoning quality, efficiency, and error handling.</p>



<h3 class="wp-block-heading">Task completion rate</h3>



<p>Task completion rate measures the percentage of tasks where an agent successfully achieves the end goal. This is calculated as the number of completed tasks divided by the total number of tasks attempted. The context of “completed” differs by use case. There are real-world use cases for task completion rate. Let’s start with a basic use case. Consider a customer service agent handling a specific food delivery order: &#8220;Where is my order #0001? It has not been delivered to me.” Completion rate means successfully looking up the order ID, retrieving the tracking information, and providing an accurate delivery estimate, so all three steps must succeed. If the agent retrieves the wrong order or fails to assess the tracking system, that is a failed task, even if it produces the same output.&nbsp;</p>



<p>Next, let us look at a medium-complexity use case, sequential API calls. Consider an agent tasked with creating a Jira support ticket and notifying the relevant team in Slack. The agent calls the Jira API to create a ticket, parses the response to get the ticket ID, calls the Slack API with the ticket link, and finally verifies the success of both. If the agent successfully creates the Jira ticket, but the Slack notification fails, that is considered a failed task even if the ticket exists in Jira, since the team wasn’t notified.&nbsp;</p>



<p>Finally, let’s examine a high-complexity use case: An agent is given the task of completing an online purchase, which means it must handle everything from checkout to order confirmation. Six steps are involved: Verify the item is still in stock, process the payment with a credit or debit card, reserve or decrement inventory, create an order record, generate an order confirmation number, and send a confirmation email to the customer. If the agent successfully charges the customer’s card but the confirmation email fails to send, that’s a failed task, even if the payment was processed and the order was created. In such a situation, the customer has no proof of purchase, so they will likely contact support or attempt to purchase again.</p>



<h3 class="wp-block-heading">Tool usage correctness</h3>



<p>Tool usage correctness assesses whether an agent correctly identifies and invokes the relevant tools and APIs. It is a deterministic measure that is assessed using techniques such as LLM as a judge, like most LLM evaluation metrics. It has three dimensions:&nbsp;</p>



<ul>
<li>Did the agent choose the right tool for the task (tool selection)?&nbsp;</li>



<li>Were the parameters constructed correctly (input parameters)?&nbsp;</li>



<li>Did the agent properly use the tool results (output handling)?&nbsp;</li>
</ul>



<p>Hence, it is important for reliability and functional correctness.&nbsp;</p>



<h3 class="wp-block-heading">Step-by-step reasoning accuracy</h3>



<p>In real-world use cases, an LLM agent’s reasoning is shaped by much more than just the model itself. Modern frameworks such as <a href="https://docs.langchain.com/oss/python/langchain/overview" target="_blank" rel="noopener">LangChain</a> expose the agent’s internal &#8220;thoughts&#8221; through structured logging of intermediate reasoning steps. This is done using the ReAct (Reasoning and Acting) pattern, which involves the agent thinking about what to do, using a tool, observing the tool result, and then repeating until the task is complete. Each “thought” is logged as text, which creates a complete trace of the reasoning process from initial query to final answer. These traces can be extracted programmatically and evaluated to assess whether the agent’s logic is sound even when the final output appears correct. Evaluating planning steps involves assessing aspects such as the overall approach&#8217;s logic, the ordering of steps, and whether any steps are unnecessary or redundant. Evaluating execution assesses whether the implementation worked, such as whether tools were called with correct parameters, whether each step was completed successfully, whether errors were handled appropriately, and whether the output was interpreted correctly. This can be done seamlessly in PyCharm using the <a href="https://plugins.jetbrains.com/plugin/26921-ai-agents-debugger/edit" target="_blank" rel="noopener">AI Agents Debugger</a>.</p>



<h3 class="wp-block-heading">Groundedness (faithfulness)</h3>



<p>Groundedness, also known as faithfulness, is the most critical metric for retrieval-augmented generation (RAG), which is a common component of agentic applications. It assesses whether the agent’s response is actually supported by the retrieved source documents or whether, instead, the model hallucinated information. Different evaluation techniques include:</p>



<ul>
<li><strong>Atomic claim verification:</strong> Breaks up the response into atomic claims and checks each claim against the retrieved context. It is slow but best for production RAG and thorough evaluation.&nbsp;</li>



<li><strong>Semantic similarity:</strong> Compares the embeddings of the response and source documents. It is fast, so it is best for quick checks and first-pass filtering.&nbsp;</li>



<li><strong>LLM-as-Judge:</strong> works by prompting the LLM to score groundedness by extracting factual statements from the response and then checking each statement against the retrieved context. It offers medium speed and is best for flexible, custom criteria.&nbsp;</li>
</ul>



<h2 class="wp-block-heading">AI observability and why it matters</h2>



<p>AI observability is about visibility into what the agent is doing. This covers recording everything that happens when a task is executed, including the agent’s reasoning at each step, which tools were called with what parameters, what data was retrieved, and how decisions were made from start to finish. With such a transparent system where every decision can be logged and traced, teams are able to understand why an agent fails, behaves unexpectedly, or becomes expensive to run because issues can be debugged and behavior can be audited. Consequently, system design improves, and guesswork is eliminated.</p>



<h3 class="wp-block-heading">Definition of AI observability</h3>



<p>AI observability is the real-time monitoring of agent actions, thoughts, and environmental interactions: what went in, what came out, how the agent thought through the problem, and which tools, APIs, and data were used. AI observability builds on the three pillars of DevOps observability – that is, metrics, logs, and traces – but extends each one for AI’s unique needs. DevOps metrics track CPU and latency, while AI metrics track token usage and cost per interaction. DevOps logs capture system errors, while AI logs capture reasoning traces and decision points. DevOps traces follow requests through services, while AI traces follow reasoning through agent steps, tool calls, and observations.</p>



<h3 class="wp-block-heading">Benefits for agent monitoring</h3>



<p>Agent monitoring has immense benefits – here are some of the most important:</p>



<ul>
<li><strong>It debugs reasoning errors:</strong> When an agent fails or gives an unexpected output, monitoring provides a complete trace of its decision-making process, which shows exactly where the logic broke down. Hence, there is no need to spend hours guessing the causes.</li>



<li><strong>It measures performance and latency over time:</strong> Since metrics such as average latency, token usage, cost per interaction, and completion rates across all queries are tracked, degradation patterns can be identified before they affect users. As a result, performance issues can be identified and resolved before users file any complaints.&nbsp;</li>



<li><strong>It identifies regressions after model or prompt updates:</strong> Baseline metrics such as completion rate, faithfulness scores, latency, and cost are established and then monitored for deviations after deployments. If a new prompt drops the compilation rate or a model update increases the hallucination rate, automated alerts catch it immediately. Hence, issues are caught before users are affected.</li>
</ul>



<h3 class="wp-block-heading">Popular tools for agent monitoring</h3>



<p>Several frameworks and platforms have emerged to provide built-in observability for AI agents, with each having different strengths and integration approaches and matching different features and requirements. The choice of the right tool depends on the framework, deployment preferences, and primary needs. The table below shows some popular tools and whether they match different features and requirements.</p>



<figure class="wp-block-table"><table><tbody><tr><td><strong>Tool</strong></td><td><strong>Traces agent steps?</strong></td><td><strong>Tracks costs?</strong></td><td><strong>Detects regressions?&nbsp;</strong></td><td><strong>Self-</strong><strong>hostable?</strong></td><td><strong>Open source?</strong></td><td><strong>Easy integration?</strong></td></tr><tr><td><a href="https://www.helicone.ai/" target="_blank" rel="noopener">Helicone</a></td><td>Yes</td><td>Yes</td><td>Yes</td><td>Yes</td><td>Yes</td><td>Yes</td></tr><tr><td><a href="https://www.langchain.com/langsmith/observability" target="_blank" rel="noopener">LangSmith</a></td><td>Yes</td><td>Yes</td><td>Yes</td><td>Limited</td><td>No</td><td>Yes</td></tr><tr><td><a href="https://langfuse.com/" target="_blank" rel="noopener">LangFuse</a></td><td>Yes</td><td>Yes</td><td>Yes</td><td>Yes</td><td>Yes</td><td>Moderate</td></tr><tr><td><a href="https://github.com/traceloop/openllmetry" target="_blank" rel="noopener">OpenLLMetry</a></td><td>Yes</td><td>Limited</td><td>Limited</td><td>Yes</td><td>Yes</td><td>Moderate</td></tr><tr><td><a href="https://arize.com/docs/phoenix" target="_blank" rel="noopener">Phoenix</a></td><td>Yes</td><td>Limited</td><td>Yes</td><td>Yes</td><td>Yes</td><td>Moderate</td></tr><tr><td><a href="https://www.trulens.org/" target="_blank" rel="noopener">TruLens</a></td><td>Yes</td><td>Limited</td><td>Yes</td><td>Yes</td><td>Yes</td><td>Moderate</td></tr><tr><td><a href="https://www.datadoghq.com/" target="_blank" rel="noopener">DataDog</a></td><td>Limited</td><td>Yes</td><td>Yes</td><td>No</td><td>No</td><td>Moderate</td></tr></tbody></table></figure>



<h2 class="wp-block-heading">Best practices for evaluating agents in production</h2>



<p>Evaluation does not end after deployment; rather, it is intensified. This continuous evaluation tracks how much the system costs to run, how quickly it responds under various loads, and how it handles errors or unusual inputs. Without such evaluation, problems can only be identified after the users are affected. An agent can pass all the quality checks with excellent faithfulness scores, high completion rates, and strong reasoning but fail in production if costs spiral, latency increases, or edge cases cause instability. Hence, there is a critical need for ongoing evaluation and monitoring, which will lead to systems that are reliable, scalable, and financially sustainable.</p>



<h3 class="wp-block-heading">Monitor cost and latency</h3>



<p>Monitoring cost and latency is critical for production sustainability. Token usage and response time must be tracked continuously because small inefficiencies compound dramatically over time, and the cost per token of the powerful reasoning models used for agents can be high. Production workloads require cost and latency monitoring to identify problems before user experience and budget are impacted. Cost monitoring tracks token usage at different levels, such as per request, per query type, and over time. Without visibility into patterns generated by these, teams end up discovering cost problems through surprise bills. With monitoring, they can proactively cache common queries and optimize prompts to reduce token use. Latency monitoring reveals track response time and component breakdowns to identify bottlenecks.</p>



<p>Cost control in production workloads is important because production costs can spiral quickly, unmonitored systems can exceed budgets, and latency impacts user experience and retention.</p>



<h3 class="wp-block-heading">Combine offline and online evaluation</h3>



<p>Effective agent evaluation requires combining offline and online evaluation, where each addresses gaps the other leaves. Offline evaluation uses fixed test databases for reproducible benchmarking, which enables fast iteration on prompts and models in controlled environments without production risk. Online evaluation monitors real user interactions in production, which reveals edge cases in testing that were never expected, so it is useful for real-time feedback, user data, and observability tools. A combination of both results in an optimal strategy where offline evaluation validates changes before deployment, then online evaluation monitors production reality.&nbsp;</p>



<h3 class="wp-block-heading">Use human-in-the-loop when necessary</h3>



<p>LLM agents are appreciated for how they have played a positive role in the different ecosystems, but not every agent should run autonomously since they can misinterpret prompts, cross boundaries, or make dreadful errors that can’t be caught by automation alone. Hence, the need for human-in-the-loop failsafes. Human-in-the-loop is also essential during initial setup: Unless teams already have domain-specific evaluation datasets for monitoring the agent, these will need to be created manually by assessing the agent&#8217;s performance. A hybrid approach is required when critical decisions require human validation, such as approving transactions, modifying sensitive data, or triggering irreversible workflows. In this approach, it is important that decisions are routed through a human checkpoint before proceeding. The intention is not to slow automation but rather to ensure that the right decisions involve the right oversight. A well-designed human-in-the-loop system delivers compound returns over time. Every human correction becomes feedback, which improves the agent&#8217;s accuracy and gradually reduces the need for manual review. Human oversight isn’t treated as a failure but rather as a safety net that makes the system better with use.</p>



<h2 class="wp-block-heading">Final thoughts</h2>



<p>Fundamentally, AI agents are different from single-prompt LLMs. They navigate multi-step workflows, make autonomous decisions, and use external tools, which introduces complexities that demand continuous evaluation, not just static testing. Evaluation must evolve from pre-deployment checkpoints to ongoing monitoring. Production-ready agents aren&#8217;t just well-tested; they&#8217;re continuously observed and improved based on real behavior. LLM evaluation and AI observability enable faster, safer iteration by catching issues early and feeding production insights back into development.</p>



<p><a href="https://www.jetbrains.com/pycharm/whatsnew/" target="_blank" rel="noopener">PyCharm</a> streamlines agent development with integrated debugging, profiling, and testing. Step through reasoning with breakpoints, find cost bottlenecks, and iterate on evaluation tests rapidly. These workflows transform hours of debugging into minutes of systematic investigation. Explore PyCharm for AI development to see how integrated tools can help you build, evaluate, and deploy reliable AI agents.</p>



<h2 class="wp-block-heading" id="author">About the author</h2>


    <div class="about-author ">
        <div class="about-author__box">
            <div class="row">
                                                            <div class="about-author__box-img">
                            <img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" src="https://blog.jetbrains.com/wp-content/uploads/2026/05/image-1.jpeg" alt="" loading="lazy">
                        </div>
                                        <div class="about-author__box-text">
                                                    <h4>Naa Ashiorkor</h4>
                                                <p><span style="font-weight: 400;">Naa Ashiorkor is a data scientist and tech community builder. She is deeply involved in the Python community and serves as an organizer for various conferences, including EuroPython. She is currently building PyLadies Tampere.</span></p>
                    </div>
                            </div>
        </div>
    </div>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Pyrefly LSP Integration with Type Engine in PyCharm 2026.1.2</title>
		<link>https://blog.jetbrains.com/pycharm/2026/05/pyrefly-lsp-integration-in-pycharm-2026-1-2/</link>
		
		<dc:creator><![CDATA[Cheuk Ting Ho]]></dc:creator>
		<pubDate>Fri, 15 May 2026 15:31:27 +0000</pubDate>
		<featuredImage>https://blog.jetbrains.com/wp-content/uploads/2026/05/PC-social-BlogFeatured-1280x720-1-3.png</featuredImage>		<category><![CDATA[releases]]></category>
		<category><![CDATA[lsp]]></category>
		<category><![CDATA[type-inference]]></category>
		<guid isPermaLink="false">https://blog.jetbrains.com/?post_type=pycharm&#038;p=706872</guid>

					<description><![CDATA[In PyCharm 2026.1.2, you can enable Pyrefly as an external type provider, dramatically increasing the speed of the IDE’s code insight features. What is the Pyrefly LSP? “LSP” stands for the Language Server Protocol – a standardized protocol that allows code editors and IDEs to communicate with language servers. The LSP enables language servers to [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>In PyCharm 2026.1.2, you can enable <a href="https://pyrefly.org/" target="_blank" rel="noopener">Pyrefly</a> as an external type provider, dramatically increasing the speed of the IDE’s code insight features.</p>



<h2 class="wp-block-heading">What is the Pyrefly LSP?</h2>



<p>“LSP” stands for the <strong>Language Server Protocol</strong> – a standardized protocol that allows code editors and IDEs to communicate with <strong>language servers</strong>. The LSP enables language servers to provide code intelligence features, such as:</p>



<ul>
<li>Code completion</li>



<li>Information on hover (for example, quick documentation)</li>



<li><em>Go to definition </em>and other actions</li>



<li>Error checking and type-related diagnostics</li>
</ul>



<p></p>



<p>The key benefit of the LSP is that it allows a single language server to be used across multiple tools. This means that language-specific intelligence does not have to be implemented separately in every editor, IDE, or CI pipeline.</p>



<p>Pyrefly is Meta’s next-generation Python type checker, engineered from the ground up in Rust to replace its predecessor, Pyre (written in OCaml). With the move to Rust, Pyrefly achieves significantly faster performance and improved cross-platform portability. More than just a rewrite, it is designed to be more capable and robust, offering an efficient toolset for maintaining large-scale Python codebases with high precision and minimal overhead.</p>



<p>Pyrefly provides the following benefits:</p>



<ul>
<li><strong>Higher performance and efficiency</strong> – Thanks to its Rust-based architecture, Pyrefly achieves significantly faster speeds and improves cross-platform portability.&nbsp;</li>



<li><strong>Enhanced code intelligence</strong> – As an external type provider, Pyrefly powers essential code insight features in the IDE, including type inference, type-related diagnostics, quick documentation, and inlay hints.</li>



<li><strong>Scalability</strong> – Pyrefly is designed to handle <strong>large-scale Python codebases</strong> with high precision and minimal overhead.</li>
</ul>



<p>Pyrefly is highly beneficial for projects and developers dealing with <strong>large, complex Python codebases</strong> that prioritize performance and robust typing. Integrating Pyrefly via the LSP is part of our ongoing work to enhance code insight performance in PyCharm.</p>



<h2 class="wp-block-heading">Using Pyrefly in PyCharm</h2>



<p>Once enabled, Pyrefly powers all code insight functionality in PyCharm, including type inference and type-related diagnostics, quick documentation, and inlay hints. Delegating analysis to this faster engine delivers significantly improved performance.</p>



<p>To start using Pyrefly in your PyCharm project, go to the <em>Type</em> widget at the bottom of the window. By default, the IDE uses the built-in type engine. Click on the widget and select the option to use Pyrefly. If you do not have Pyrefly installed yet, PyCharm will install it automatically.&nbsp;</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/05/install-pyrefly.gif" alt="" class="wp-image-706921"/></figure>



<p>Once you’ve switched to the Pyrefly type engine, you will see a Pyrefly icon at the bottom, which you can hover over to check the version being used.</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/05/image-15.png" alt="" class="wp-image-706874"/></figure>



<p>Please note that the integration currently works for local interpreter configurations. Support for Docker, Docker Compose, WSL, SSH, and multi-module projects is planned for future releases.</p>



<h2 class="wp-block-heading">Pyrefly vs. the built-in type engine</h2>



<p>Now let’s look at how Pyrefly and the built-in type engine behave in a complex Python project. In this FastAPI example, multiple files are typed, but in this file, the variable <em>ref </em>is incorrectly typed, causing four errors. When using the built-in type engine, the IDE identifies that something is wrong, but it suggests running further analysis to fix the problem, which requires an extra step.</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/05/image.jpeg" alt="" class="wp-image-706886"/></figure>



<p>Using Pyrefly as the type engine, the IDE reports errors immediately and highlights where they originate. However, it is worth noting that, in our example, there are four errors, but Pyrefly picks up only three of them. It misses the one in <code>self._storage[ref]</code>.</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/05/pyrefly-checking.gif" alt="" class="wp-image-706934"/></figure>



<h2 class="wp-block-heading">Download the latest version of PyCharm and try it out</h2>



<p>Ready to experience a dramatic leap in Python development performance? The Pyrefly type engine in PyCharm 2026.1.2 delivers the next generation of type checking. Engineered in Rust for unparalleled speed, it resolves files in as little as 0.5–1 seconds, significantly faster than the built-in engine. If you maintain large, complex Python codebases and prioritize robust typing, this feature is essential, as it allows you to delegate analysis to a faster engine and receive immediate type-related diagnostics. Download the latest version of PyCharm (2026.1.2) to unlock superior efficiency, scalability, and code insight.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Support for uv, Poetry, and Hatch Workspaces (Beta)</title>
		<link>https://blog.jetbrains.com/pycharm/2026/05/support-for-uv-poetry-and-hatch-workspaces-beta/</link>
		
		<dc:creator><![CDATA[Antonina Belianskaya]]></dc:creator>
		<pubDate>Wed, 13 May 2026 12:28:25 +0000</pubDate>
		<featuredImage>https://blog.jetbrains.com/wp-content/uploads/2026/05/PC-social-BlogFeatured-1280x720-1-1.png</featuredImage>		<category><![CDATA[uv]]></category>
		<category><![CDATA[workspaces]]></category>
		<guid isPermaLink="false">https://blog.jetbrains.com/?post_type=pycharm&#038;p=706614</guid>

					<description><![CDATA[Workspaces are increasingly the go-to choice for companies and open-source teams aiming to manage shared code, enforce consistency, and simplify dependency management across multiple services. Working within massive codebases often means juggling many interdependent Python projects simultaneously. To streamline this experience, PyCharm 2026.1.1 introduced&#160;built-in support for uv workspaces, as well as those managed by Poetry [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>Workspaces are increasingly the go-to choice for companies and open-source teams aiming to manage shared code, enforce consistency, and simplify dependency management across multiple services. Working within massive codebases often means juggling many interdependent Python projects simultaneously.</p>



<p>To streamline this experience, PyCharm 2026.1.1 introduced&nbsp;built-in support for uv workspaces, as well as those managed by Poetry and Hatch. This new functionality – currently in Beta – allows the IDE to automatically manage dependencies and environments across your entire workspace.</p>



<h2 class="wp-block-heading">Intelligent workspace detection</h2>



<p>When you open a workspace, PyCharm can now derive its entire structure and all its dependencies directly from your pyproject.toml files. This allows the IDE to understand relationships between projects deeply, significantly reducing the amount of configuration you have to do manually.</p>



<p>Because this is a fundamental change to how PyCharm handles your workspace, we’ve implemented it as an opt-in feature. Here is what you need to know about the transition:</p>



<ul>
<li><strong>Opt-in dialog:</strong> When you open a project, PyCharm may suggest enabling automatic detection for uv workspaces and Poetry/Hatch setups.&nbsp;</li>
</ul>



<figure class="wp-block-gallery has-nested-images columns-2 is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" data-id="706672" src="https://blog.jetbrains.com/wp-content/uploads/2026/05/opt-in-dialog.png" alt="" class="wp-image-706672"/></figure>



<figure class="wp-block-image size-large"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" data-id="706676" src="https://blog.jetbrains.com/wp-content/uploads/2026/05/opt-in-dialog-example.png" alt="" class="wp-image-706676"/></figure>
</figure>



<ul>
<li><strong>Manual configuration:</strong> You can toggle workspace detection in <em>Settings | Project Structure</em>.</li>
</ul>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/05/manual-configuration.png" alt="" class="wp-image-706697"/></figure>



<ul>
<li><strong>Configuration note:</strong> If you previously manually edited settings in .idea files, those settings may be reset when you agree to the new model.</li>
</ul>



<h2 class="wp-block-heading">Managing workspaces and their projects</h2>



<p>PyCharm now provides an integrated experience that handles the complexities of multi-package setups in uv workspaces automatically. When you open a uv workspace, the IDE identifies the individual projects and their interdependencies, ensuring the project structure is ready for you to work with.</p>



<h3 class="wp-block-heading">Visualizing workspace dependencies</h3>



<p>Once the workspace is loaded, you can verify how your projects relate to one another. PyCharm presents these dependencies in <em>Settings | Project Dependencies</em>.</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/05/visualizing-workspace-dependencies.png" alt="" class="wp-image-706708"/></figure>



<p>These relationships are derived directly from your configuration and are shown as read-only in the UI. To make changes to the dependency graph, you can edit the pyproject.toml file manually – PyCharm will then update its internal model.</p>



<h3 class="wp-block-heading">Automatic environment configuration</h3>



<p>PyCharm prioritizes a zero-config approach to your Python SDK. When you open a .py or pyproject.toml file within a project, the IDE performs an immediate check.</p>



<p>If a compatible environment already exists on your system, PyCharm automatically configures it as the SDK for that project. If no environment is detected, a file-level notification will appear suggesting that you create a new uv environment and install the necessary dependencies for that project.</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/05/automatic-environment-configuration.png" alt="" class="wp-image-706719"/></figure>



<h3 class="wp-block-heading">Maintaining environment consistency</h3>



<p>Beyond the initial setup, PyCharm continuously monitors the health of your environment to ensure it stays in sync with your defined requirements.&nbsp;</p>



<p>If a dependency is not defined in your pyproject.toml file but is imported in your code, PyCharm will trigger a warning with a <em>Sync project</em> quick-fix to resolve these discrepancies.</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/05/maintaining-environment-consistency.png" alt="" class="wp-image-706730"/></figure>



<h3 class="wp-block-heading">Import management</h3>



<p>PyCharm also assists when you are actively writing code by identifying gaps in your project configuration.</p>



<p>If you import a package that isn’t present in the environment and is not yet listed in the project’s pyproject.toml, the IDE will detect the omission. A quick-fix will suggest adding the package to the environment and updating the corresponding .toml file simultaneously.</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/05/import-management.png" alt="" class="wp-image-706741"/></figure>



<h3 class="wp-block-heading">Transparency via the <em>Python Process Output</em> tool window</h3>



<p>While PyCharm automates the backend execution of commands – such as uv sync &#8211;all-packages – it still remains fully transparent.</p>



<p>You can track all executed commands and their live output in the <em>Python Process Output</em> tool window. If synchronization fails for an environment, you can analyze the specific error logs to quickly identify the root cause.</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/05/image-14.png" alt="" class="wp-image-706630"/></figure>



<h3 class="wp-block-heading">Poetry and Hatch workspaces</h3>



<p>The logic for Poetry and Hatch workspaces follows this exact same workflow. PyCharm detects projects via their pyproject.toml files and manages the environments with the same automated precision.</p>



<p>The only minor difference is in tool selection – the suggested environment tool is determined by what you have specified in your pyproject.toml. If no tool is specified, PyCharm will prioritize uv (if installed) or a standard virtual environment to get you up and running quickly.</p>



<h2 class="wp-block-heading">Looking ahead</h2>



<p>This Beta version of the functionality is just the beginning of our focus on supporting complex workspace structures. We are already working on expanding the UI to allow creating new projects, linking dependencies, and activating the terminal for specific projects.</p>



<p>As we refine these features, your feedback is our best guide – please share your thoughts or report any issues on our <a href="https://youtrack.jetbrains.com/issues/PY?u=1" target="_blank" rel="noopener">YouTrack issue tracker</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Python Unplugged on PyTV: Key Takeaways From Our Community Conference</title>
		<link>https://blog.jetbrains.com/pycharm/2026/05/python-unplugged-on-pytv-key-takeaways-from-our-community-conference/</link>
		
		<dc:creator><![CDATA[Evgenia Verbina]]></dc:creator>
		<pubDate>Thu, 07 May 2026 11:27:22 +0000</pubDate>
		<featuredImage>https://blog.jetbrains.com/wp-content/uploads/2026/05/PyTV-Recap-YouTube-Thumbnail-Stream-1920x1080-1.png</featuredImage>		<category><![CDATA[news]]></category>
		<category><![CDATA[conference]]></category>
		<category><![CDATA[python]]></category>
		<guid isPermaLink="false">https://blog.jetbrains.com/?post_type=pycharm&#038;p=704908</guid>

					<description><![CDATA[AI is changing how Python developers learn, build, and contribute to open source. At the same time, long-standing questions around community, sustainability, data workflows, and web development are becoming even more important. Python Unplugged on PyTV, a free online conference hosted by JetBrains PyCharm, brought these conversations together in over seven hours of talks and [&#8230;]]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/05/PyTV-Recap-YouTube-Thumbnail-Stream-1920x1080-1.png" alt="Python Unplugged on PyTV: Key Takeaways From Our Community Conference" class="wp-image-704918"/></figure>



<p>AI is changing how Python developers learn, build, and contribute to open source. At the same time, long-standing questions around community, sustainability, data workflows, and web development are becoming even more important.</p>



<p><a href="https://lp.jetbrains.com/python-unplugged/" target="_blank" rel="noopener"><em>Python Unplugged on PyTV</em></a>, a free online conference hosted by JetBrains <a href="https://www.jetbrains.com/pycharm/" data-type="link" data-id="https://www.jetbrains.com/pycharm/" target="_blank" rel="noopener">PyCharm</a>, brought these conversations together in over seven hours of talks and discussions with developers, maintainers, educators, and tool builders from across the Python ecosystem.</p>



<p>Don’t have time to watch the full event? This blog post gives you a quick overview of what’s happening in Python today, based on talks from 13 Python experts – from AI-assisted development and open-source sustainability to modern data processing, Django, and community building.</p>



<h2 class="wp-block-heading">Watch the recap video</h2>



<p>Want to see the highlights from <em>Python Unplugged on PyTV</em>? Watch the full recap video below.</p>



<p>JetBrains’ Dr. Jodie Burchell, Data Scientist and Python Advocacy Team Lead; Cheuk Ting Ho, Data Scientist and Developer Advocate; and Will Vincent, Python Developer Advocate, discuss the key talking points from the day.</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="Python Unplugged on PyTV Recap | Key Takeaways From Our Community Conference" src="https://www.youtube.com/embed/eBc1dA9NB7A?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<h2 class="wp-block-heading">Need a quick overview? Here are the highlights</h2>



<p>If you’d rather get the key takeaways in a written format, we’ve broken down the biggest insights from the day below. From the evolving role of AI to the importance of the Python community, these are the moments that stood out most from <em>Python Unplugged on PyTV</em>.</p>



<h2 class="wp-block-heading">Highlight 1: Python goes beyond scripts and prototypes</h2>



<p>Many developers first come to Python through a specific use case: automating tasks, building prototypes, learning data science, or experimenting with AI and machine learning. That accessibility is one of Python’s strengths, but it’s only the entry point.</p>



<p>In her session, <a href="https://www.youtube.com/watch?v=DkN7P4Cmto8&amp;list=PLCTHcU1KoD99wZ0UjDhMtxweI1JL82kcb&amp;index=1" data-type="link" data-id="https://www.youtube.com/watch?v=DkN7P4Cmto8&amp;list=PLCTHcU1KoD99wZ0UjDhMtxweI1JL82kcb&amp;index=1" target="_blank" rel="noopener"><em>AI Practitioners Are Only Getting Half the Goodness of Python</em></a>, Deb Nicholson, Executive Director at the PSF, discussed how many AI and ML practitioners use Python mainly as a scripting or prototyping language. But Python is also used to build and maintain real-world software, supported by frameworks, data tools, testing workflows, packaging standards, and an active open-source community.</p>



<p>This broader context matters for learning, too. In his <a href="https://www.youtube.com/watch?v=i6SdsSj96ys" target="_blank" rel="noopener"><em>How to Learn Python</em></a> session, Mark Smith, Head of Python Ecosystem at JetBrains, focused on what comes after the fundamentals: building real projects, reading other people’s code, and developing the habits needed to move past &#8220;tutorial hell.&#8221;</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="How to Learn Python the Right Way" src="https://www.youtube.com/embed/i6SdsSj96ys?list=PLCTHcU1KoD99wZ0UjDhMtxweI1JL82kcb" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<p>AI can help, but it shouldn’t replace hands-on practice. As Cheuk noted in the recap video, one useful tip from Mark’s talk was to turn off AI features while learning, so beginners still build the judgment needed to understand and improve the code they work with.</p>



<h2 class="wp-block-heading">Highlight 2: The continuing role of community in Python</h2>



<p>Python’s success has always been rooted in its community, and that remains as true as ever. Georgi Ker, Director and Fellow at the PSF; Una Galyeva, Head of AI at Geobear Global; and Jessica Greene, Senior ML Engineer at Ecosia, showcased this in their <a href="https://youtu.be/qKkyBhXIJJU?t=8630" target="_blank" rel="noopener"><em>How PyLadies Is Shaping the Future of Python</em></a> discussion.</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="How PyLadies Is Shaping the Future of Python" src="https://www.youtube.com/embed/gkdAcuRIs-o?list=PLCTHcU1KoD99wZ0UjDhMtxweI1JL82kcb" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<p><a href="https://pyladies.com/" target="_blank" rel="noopener">PyLadies</a> is an international mentorship group focused on helping more women become active participants and leaders in the Python community. The success of initiatives like PyLadies highlights how inclusive spaces can broaden participation and shape the future of the language.</p>



<p>As Will noted in our recap video, “Being part of the community is not just the code. It’s the conferences, it’s the people, it’s the live events – that’s what makes Python special.”</p>



<p>Python depends on a culture of shared responsibility, and contributors play a vital role. As AI brings more people into the ecosystem, preserving these values becomes even more important. Travis Oliphant, creator of <a href="https://numpy.org/" target="_blank" rel="noopener">NumPy</a>, touched on this in his insightful session, <a href="https://www.youtube.com/watch?v=opzIYSWWZ3E&amp;list=PLCTHcU1KoD99wZ0UjDhMtxweI1JL82kcb&amp;index=9" data-type="link" data-id="https://www.youtube.com/watch?v=opzIYSWWZ3E&amp;list=PLCTHcU1KoD99wZ0UjDhMtxweI1JL82kcb&amp;index=9" target="_blank" rel="noopener"><em>Community is More Than Code: People Are What Make Python Thrive, and Why That Will Continue in an AI-Enabled Era</em></a>.</p>



<p>There’s also a strong link between community and innovation, as Carol Willing, Core Developer at JupyterLab, explained in her session, <a href="https://www.youtube.com/watch?v=Wg99AGQcohY&amp;list=PLCTHcU1KoD99wZ0UjDhMtxweI1JL82kcb&amp;index=13" data-type="link" data-id="https://www.youtube.com/watch?v=Wg99AGQcohY&amp;list=PLCTHcU1KoD99wZ0UjDhMtxweI1JL82kcb&amp;index=13" target="_blank" rel="noopener"><em>Conversation, Computation, and Community: Key Principles for Solving Scientific Problems With Jupyter Notebooks and AI Tools</em></a>. Tools like <a href="https://www.jetbrains.com/help/pycharm/jupyter-notebook-support.html" target="_blank" rel="noopener">Jupyter</a> have thrived in part because they enable conversation, collaboration, and knowledge sharing among people.</p>



<h2 class="wp-block-heading">Highlight 3: AI poses both a threat and an opportunity for Python open source</h2>



<p>AI is fundamentally changing how developers interact with open source.</p>



<p>On the positive side, AI coding tools lower the barrier to entry and allow more people to contribute. However, this increased accessibility comes with trade-offs. Maintainers are now dealing with a higher volume of contributions, many of which require significant review or refinement. Deb Nicholson, Executive Director at the PSF, discussed this trade-off in more detail in her session, <a href="https://www.youtube.com/watch?v=DkN7P4Cmto8&amp;list=PLCTHcU1KoD99wZ0UjDhMtxweI1JL82kcb&amp;index=1" data-type="link" data-id="https://www.youtube.com/watch?v=DkN7P4Cmto8&amp;list=PLCTHcU1KoD99wZ0UjDhMtxweI1JL82kcb&amp;index=1" target="_blank" rel="noopener"><em>AI Practitioners Are Only Getting Half the Goodness of Python</em></a>.</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="What AI Developers Miss About Python" src="https://www.youtube.com/embed/DkN7P4Cmto8?list=PLCTHcU1KoD99wZ0UjDhMtxweI1JL82kcb" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<p>This shift places additional pressure on those responsible for maintaining open-source projects. While AI can accelerate development, it also risks introducing poorly structured or low-quality code at scale.</p>



<p>Paul Everitt, Developer Advocate at JetBrains; Georgi Ker, Director and Fellow at the PSF; and Carol Willing, Core Developer at JupyterLab, pondered this in their <a href="https://www.youtube.com/watch?v=-P15to8sj60&amp;list=PLCTHcU1KoD99wZ0UjDhMtxweI1JL82kcb&amp;index=3" target="_blank" rel="noopener"><em>Open Source in the Age of Coding Agents</em></a> discussion. Ultimately, AI can’t replace the human systems that sustain open source. Trust, collaboration, and shared ownership remain essential, and arguably become even more important as contribution volumes increase. The real challenge lies in ensuring communities remain healthy and resilient as they scale.</p>



<h2 class="wp-block-heading">Highlight 4: AI has also revolutionized how Python practitioners work</h2>



<p>Beyond its impact on open source, AI is transforming day-to-day development workflows.</p>



<p>As Marlene Mhangami, Senior Developer Advocate at Microsoft Agentic, explained in her <a href="https://www.youtube.com/watch?v=QrfsX-sW6QI&amp;list=PLCTHcU1KoD99wZ0UjDhMtxweI1JL82kcb&amp;index=10" data-type="link" data-id="https://www.youtube.com/watch?v=QrfsX-sW6QI&amp;list=PLCTHcU1KoD99wZ0UjDhMtxweI1JL82kcb&amp;index=10" target="_blank" rel="noopener"><em>A Practical Guide to Agentic Coding</em></a> session, coding is emerging as a new paradigm in which developers delegate tasks to AI systems capable of planning, executing, and refining code. This means the developer’s role is moving toward orchestration and validation, requiring new skills in guiding and evaluating AI outputs.</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="A Practical Guide to Agentic Coding" src="https://www.youtube.com/embed/QrfsX-sW6QI?list=PLCTHcU1KoD99wZ0UjDhMtxweI1JL82kcb" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<p>At the same time, development is becoming more conversational and exploratory. In environments like Jupyter, AI tools help users iterate faster, test ideas more easily, and move more fluidly between thinking and coding.</p>



<p>AI is also having a tangible impact on frameworks like Django, as discussed by Sheena O’Connell, Board Member at the PSF, in her talk, <a href="https://www.youtube.com/watch?v=MJMex1FNjXI&amp;list=PLCTHcU1KoD99wZ0UjDhMtxweI1JL82kcb&amp;index=8" target="_blank" rel="noopener"><em>Powering Up Django Development With Claude Code</em></a>. AI tools can speed up development in <a href="https://www.jetbrains.com/pycharm/web-development/django/" target="_blank" rel="noopener">Django</a> by handling repetitive tasks such as boilerplate generation and debugging. However, this comes with a caveat – developers must remain critical and treat AI as a collaborator, not a source of truth.</p>



<p>For beginners, AI can be a powerful learning aid, but over-reliance can limit deeper understanding. Building projects, reading code, and actively solving problems remain essential for developing real expertise.</p>



<h2 class="wp-block-heading">Highlight 5: The importance of open-source AI</h2>



<p>The open-source AI ecosystem is expanding rapidly, bringing with it a growing landscape of models, datasets, and tools.</p>



<p>This openness drives collaboration, transparency, and innovation, making it easier for developers to experiment and build on existing work. At the same time, it introduces challenges around fragmentation and long-term sustainability.</p>



<p>As Merve Noyan, ML Engineer at Hugging Face, explained in her <a href="https://www.youtube.com/watch?v=Rz9uNpcfXFM&amp;list=PLCTHcU1KoD99wZ0UjDhMtxweI1JL82kcb&amp;index=11" target="_blank" rel="noopener"><em>Open-Source AI Ecosystem</em></a> session, platforms like <a href="https://www.jetbrains.com/help/pycharm/hugging-face.html" target="_blank" rel="noopener">Hugging Face</a> play a key role in organizing this ecosystem and making it more accessible, while Python continues to connect tools, communities, and technologies.</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="Open-Source AI Ecosystem" src="https://www.youtube.com/embed/Rz9uNpcfXFM?list=PLCTHcU1KoD99wZ0UjDhMtxweI1JL82kcb" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<h2 class="wp-block-heading">Highlight 6: Context is key for effective AI agents</h2>



<p>As AI systems become more advanced, the way they interact with their input data is becoming increasingly important. Tuana Çelik, Developer Relations Engineer at LlamaIndex, covered this in detail in her insightful <a href="https://www.youtube.com/watch?v=4QYA2X6Zlqg&amp;list=PLCTHcU1KoD99wZ0UjDhMtxweI1JL82kcb&amp;index=12" target="_blank" rel="noopener"><em>Orchestrating Document-Centric Agents With LlamaIndex</em></a> talk.</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="Orchestrating Document-Centric Agents With LlamaIndex" src="https://www.youtube.com/embed/4QYA2X6Zlqg?list=PLCTHcU1KoD99wZ0UjDhMtxweI1JL82kcb" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<p><a href="https://www.llamaindex.ai/" target="_blank" rel="noopener">LlamaIndex</a> enables developers to build document-centric AI agents that retrieve, index, and reason over large collections of information. By structuring how documents are ingested and queried, it provides the LLM with much more context for the text it is processing, helping produce more accurate, context-aware responses.</p>



<p>This is particularly valuable in knowledge bases and enterprise assistants, where understanding relationships between pieces of information is as important as accessing the data itself.</p>



<h2 class="wp-block-heading">Highlight 7: How Polars is refining high-performance data processing</h2>



<p><a href="https://pola.rs/" target="_blank" rel="noopener">Polars</a> is pushing Python data processing toward a more scalable, production-ready future, as Polars creator Ritchie Vink explained in his <a href="https://www.youtube.com/watch?v=jGUQtWgUiVc&amp;list=PLCTHcU1KoD99wZ0UjDhMtxweI1JL82kcb&amp;index=4" target="_blank" rel="noopener"><em>Towards Query Profiling in Polars</em></a> session.</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="Query Profiling in Polars" src="https://www.youtube.com/embed/jGUQtWgUiVc?list=PLCTHcU1KoD99wZ0UjDhMtxweI1JL82kcb" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<p>Its high-performance, lazy execution model allows queries to be optimized automatically behind the scenes. However, this level of abstraction can make it harder for developers to fully understand performance.</p>



<p>To address this, there’s a growing need for better tooling, particularly around query profiling. By exposing execution plans, memory usage, and bottlenecks, developers can make informed decisions and build more efficient data workflows.</p>



<p>With features like streaming execution, Polars is helping bridge the gap between local data processing and large-scale systems.</p>



<p>As Jodie highlighted in the recap discussion, this shift is bringing more advanced data concepts into everyday Python workflows. She commented, “It’s really interesting to see more big data ideas coming to local Python data processing.”</p>



<h2 class="wp-block-heading">Highlight 8: The power of typing in modern Python</h2>



<p>Typing in Python continues to evolve, with a growing focus on flexibility rather than rigid enforcement. Open-source Django projects creator Carlton Gibson shed more light on this during his talk, <a href="https://www.youtube.com/watch?v=j0cLwyChYOQ&amp;list=PLCTHcU1KoD99wZ0UjDhMtxweI1JL82kcb&amp;index=6" target="_blank" rel="noopener"><em>Static Islands, Dynamic Sea: Some Thoughts on Incremental Typing</em></a>.</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="Incremental Typing in Django" src="https://www.youtube.com/embed/j0cLwyChYOQ?list=PLCTHcU1KoD99wZ0UjDhMtxweI1JL82kcb" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<p>The talk highlighted how developers are increasingly adopting an incremental approach. By creating “static islands” within a dynamic codebase, they can improve reliability, maintainability, and tooling without sacrificing Python’s core strengths.</p>



<p>In our recap video, Will agreed with this sentiment, adding, “It doesn’t have to be all-or-nothing. We don’t have to turn Python into something that it’s not.”</p>



<p>This approach is particularly useful in large frameworks like Django, where typing can help define clearer boundaries while still preserving developer ergonomics.</p>



<h2 class="wp-block-heading">Highlight 9: The Django renaissance: Debunking aging myths</h2>



<p>Django remains a modern, actively developed framework, as Django Fellow Sarah Boyce revealed in her session, <a href="https://www.youtube.com/watch?v=yyX0QoUzoE4&amp;list=PLCTHcU1KoD99wZ0UjDhMtxweI1JL82kcb&amp;index=7" target="_blank" rel="noopener"><em>Django Has a Marketing Problem: Debunking the Myths That Won&#8217;t Die</em></a>.</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="Debunking Django Myths" src="https://www.youtube.com/embed/yyX0QoUzoE4?list=PLCTHcU1KoD99wZ0UjDhMtxweI1JL82kcb" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<p>Many of the criticisms that it’s outdated or unscalable don’t reflect the current reality. In practice, Django continues to evolve and power a wide range of applications.</p>



<p>The challenge is less about Django’s capabilities and more about perception, as the Django community was called to champion its strengths, ongoing evolution, and real-world impact.</p>



<p>Shifting this narrative will be key to ensuring its continued relevance and adoption in the years ahead.</p>



<h2 class="wp-block-heading">What’s next for <em>Python Unplugged on PyTV</em>?</h2>



<p><em>Python Unplugged on PyTV</em> was our first step in reimagining what a fully online community conference can look like, and the response was incredible.</p>



<p>Looking at the numbers, more than 5,500 people joined us during the livestream. Since then, we’ve had a further 110,000 watch the event recording, showing just how global and engaged the Python community really is.</p>



<p>We’d love to bring <em>Python Unplugged on PyTV</em> back next year. What would you like to see more of? Who should we invite as speakers? Are there topics we didn’t cover that you’d love to explore?</p>



<p>Drop your suggestions in the comments and help shape the future of <em>Python Unplugged on PyTV</em>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>PyTorch vs. TensorFlow: Choosing the Right Framework in 2026</title>
		<link>https://blog.jetbrains.com/pycharm/2026/05/pytorch-vs-tensorflow-choosing-framework-2026/</link>
		
		<dc:creator><![CDATA[Evgenia Verbina]]></dc:creator>
		<pubDate>Mon, 04 May 2026 10:07:20 +0000</pubDate>
		<featuredImage>https://blog.jetbrains.com/wp-content/uploads/2026/05/PC-social-BlogFeatured-1280x720-1.png</featuredImage>		<category><![CDATA[data-science]]></category>
		<category><![CDATA[pytorch]]></category>
		<category><![CDATA[tensorflow]]></category>
		<guid isPermaLink="false">https://blog.jetbrains.com/?post_type=pycharm&#038;p=704743</guid>

					<description><![CDATA[Choosing between PyTorch and TensorFlow isn’t about finding the &#8220;better&#8221; framework – it’s about finding the right fit for your project. Both power cutting-edge AI systems, but they excel in different domains. PyTorch dominates research and experimentation, while TensorFlow leads in production deployment at scale. The frameworks have evolved significantly since their early days, each [&#8230;]]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/05/PC-social-BlogFeatured-1280x720-1.png" alt="PyTorch vs. TensorFlow" class="wp-image-704800"/></figure>



<p>Choosing between <a href="https://pytorch.org/" target="_blank" rel="noopener">PyTorch</a> and <a href="https://www.tensorflow.org/" target="_blank" rel="noopener">TensorFlow</a> isn’t about finding the &#8220;better&#8221; framework – it’s about finding the right fit for your project. Both power cutting-edge AI systems, but they excel in different domains. PyTorch dominates research and experimentation, while TensorFlow leads in production deployment at scale.</p>



<p>The frameworks have evolved significantly since their early days, each building tools and capabilities to support research and production. Despite these improvements, fundamental differences remain in their philosophies, ecosystems, and ideal use cases, which will naturally influence which framework will best fit your project.</p>



<p>This guide examines where each framework shines, compares them across key dimensions, and helps you choose the right tool for your natural language processing, computer vision, and reinforcement learning projects.</p>



<h2 class="wp-block-heading"><strong>What sets PyTorch and TensorFlow apart?</strong></h2>



<p>PyTorch and TensorFlow took different approaches from day one. Google launched TensorFlow in 2015, focusing on production deployment and enterprise scalability. Meta released PyTorch in 2016, prioritizing research flexibility and Pythonic development. These roots still shape each framework today.</p>



<p>The key difference between the two lies in computational graphs. PyTorch uses dynamic graphs that execute operations immediately, making debugging natural – you use standard Python tools and inspect tensors at any point. TensorFlow originally required static graphs defined before execution, though version 2.x now defaults to eager execution while retaining optional graph compilation for performance.</p>



<p><a href="https://6sense.com/tech/data-science-machine-learning/" target="_blank" rel="noopener">Market data shows</a> TensorFlow holds a 37% market share, while PyTorch commands 25%. But the research tells a different story: <a href="https://leapcell.io/blog/tensorflow-vs-pytorch-a-comparative-analysis-for-2025" target="_blank" rel="noopener">PyTorch powers 85% of deep learning papers</a> presented at top AI conferences.</p>



<h3 class="wp-block-heading"><strong>PyTorch: Strengths and weaknesses</strong></h3>



<p>PyTorch’s Pythonic API treats models like regular Python code, making development feel intuitive from the start. The framework’s dynamic computational graphs execute operations immediately rather than requiring upfront model definition, fundamentally changing how you approach debugging and experimentation.</p>



<p>This design philosophy has made PyTorch the dominant choice in research, where flexibility matters more than deployment infrastructure. However, this research-first design means production deployment tools remain less mature than TensorFlow’s enterprise infrastructure.</p>



<h4 class="wp-block-heading">PyTorch strengths</h4>



<ul>
<li><strong>Intuitive, Pythonic API:</strong> Models use standard Python syntax with minimal framework-specific concepts, reducing the learning curve dramatically compared to other frameworks.</li>



<li><strong>Dynamic graphs enable natural debugging:</strong> Set breakpoints in training loops, inspect tensor values mid-execution, and modify architectures on the fly using tools you already know.</li>



<li><strong>Priority access to the latest techniques:</strong> Because of its research dominance, when cutting-edge architectures or methods emerge, they’re implemented in PyTorch before anywhere else.</li>



<li><strong>Strong ecosystem:</strong> Libraries like PyTorch Lightning handle training loops and best practices automatically, letting you focus on model architecture.</li>
</ul>



<h4 class="wp-block-heading">PyTorch weaknesses</h4>



<ul>
<li><strong>Production deployment tools are less mature:</strong> Deployment options lag behind TensorFlow’s battle-tested infrastructure, so you need to do more setup work for production systems.</li>



<li><strong>Mobile and edge deployment is limited:</strong> PyTorch Mobile is functional but less polished than TensorFlow Lite for smartphones and IoT devices.</li>



<li><strong>Dynamic nature complicates optimization:</strong> The flexibility that aids development can make optimization for production performance harder without additional tools like TorchScript.</li>



<li><strong>Smaller enterprise adoption:</strong> Fewer production patterns and case studies compared to TensorFlow’s extensive enterprise documentation.</li>
</ul>



<h3 class="wp-block-heading"><strong>TensorFlow: Strengths and weaknesses</strong></h3>



<p>TensorFlow’s production ecosystem provides you with a comprehensive infrastructure for deploying models at scale. Google built the framework specifically for enterprise environments where reliability, performance, and deployment flexibility matter most.</p>



<p>This production-first approach created mature tooling for serving, mobile optimization, and MLOps that PyTorch is still catching up to. The trade-off comes in development experience – TensorFlow’s API can feel more complex and less intuitive than PyTorch’s streamlined approach.</p>



<h4 class="wp-block-heading">TensorFlow strengths</h4>



<ul>
<li><strong>Mature production deployment tools:</strong> Battle-tested infrastructure with <a href="https://www.tensorflow.org/tfx/guide/serving" target="_blank" rel="noopener">TensorFlow Serving</a> for high-throughput serving, <a href="https://www.tensorflow.org/lite" target="_blank" rel="noopener">TensorFlow Lite</a> for mobile, and TensorFlow.js for browsers.</li>



<li><strong>Superior mobile and edge optimization:</strong> TensorFlow Lite delivers industry-standard performance and comprehensive device support for smartphones and edge devices.</li>



<li><strong>Strong enterprise adoption:</strong> Proven production patterns used by thousands of companies, with extensive documentation for scaling systems serving millions of predictions.</li>



<li><strong>Comprehensive MLOps tooling:</strong> TensorFlow Extended (TFX) gives you end-to-end pipelines for production ML workflows, from data validation through model monitoring.</li>



<li><strong>TPU support for large-scale training:</strong> Access to Google’s specialized Tensor Processing Units for training at massive scale with performance advantages over GPU infrastructure.</li>
</ul>



<h4 class="wp-block-heading">TensorFlow weaknesses</h4>



<ul>
<li><strong>Steeper learning curve:</strong> More complexity when implementing custom models or debugging issues, even with Keras integration simplifying high-level operations.</li>



<li><strong>More verbose code for custom work:</strong> Novel architectures or training procedures require significantly more code compared to PyTorch’s streamlined approach.</li>



<li><strong>Larger, less cohesive API:</strong> Broader API surface with multiple ways to accomplish the same task creates confusion and longer learning curves.</li>



<li><strong>Debugging can be challenging:</strong> Graph-related issues may require you to understand TensorFlow’s internal execution model despite eager execution improvements.</li>



<li><strong>Slower adoption of research techniques:</strong> New methods from research papers typically take longer to appear in TensorFlow compared to PyTorch.</li>
</ul>



<p>If you’re new to TensorFlow and want a hands-on starting point, check out <a href="https://blog.jetbrains.com/pycharm/2026/04/how-to-train-your-first-tensorflow-model/">How to Train Your First TensorFlow Model in PyCharm</a>, where you’ll build and train a simple model step by step using Keras and visualize the results.</p>



<h2 class="wp-block-heading"><strong>PyTorch vs. TensorFlow: Head-to-head comparison</strong></h2>



<p>Choosing between PyTorch and TensorFlow isn’t always straightforward, and there are many factors to consider.&nbsp;</p>



<p>The table below provides a high-level head-to-head comparison of PyTorch and TensorFlow so you can quickly assess which framework generally fits your needs. We’ll later consider project-specific scenarios and provide a detailed decision matrix to guide your choice.</p>



<figure class="wp-block-table"><table><tbody><tr><td><strong>Dimension</strong></td><td><strong>PyTorch</strong></td><td><strong>TensorFlow</strong></td></tr><tr><td><strong>Learning curve</strong></td><td>Easier: Pythonic and intuitive</td><td>Steeper: more complex API despite Keras</td></tr><tr><td><strong>Debugging</strong></td><td>Excellent: standard Python tools work naturally</td><td>Good: improved with eager execution</td></tr><tr><td><strong>Production deployment</strong></td><td>Improving: TorchServe and TorchScript available</td><td>Excellent: mature ecosystem (Serving, Lite, JS)</td></tr><tr><td><strong>Research/experimentation</strong></td><td>Dominant: 85% of deep‑learning research papers</td><td>Present: but trailing PyTorch in adoption</td></tr><tr><td><strong>Community ecosystem</strong></td><td>Research-focused: Hugging Face, PyTorch Lightning</td><td>Enterprise-focused: TFX, strong cloud integration</td></tr><tr><td><strong>Performance at scale</strong></td><td>Strong: DDP for distributed training</td><td>Strong: graph optimization, TPU support</td></tr><tr><td><strong>Industry adoption</strong></td><td>Growing: used by 15,800+ companies</td><td>Established: used by more than 23,000 companies</td></tr></tbody></table></figure>



<h2 class="wp-block-heading"><strong>PyTorch vs. TensorFlow for different use cases and applications&nbsp;</strong></h2>



<p>Your framework choice depends heavily on what you’re building. Here’s how PyTorch and TensorFlow stack up for major <a href="https://blog.jetbrains.com/pycharm/2022/06/start-studying-machine-learning-with-pycharm/">machine learning</a> domains.</p>



<h3 class="wp-block-heading"><strong>Natural language processing</strong></h3>



<p>PyTorch dominates NLP with no signs of slowing. The <a href="https://huggingface.co/docs/transformers" target="_blank" rel="noopener">Hugging Face Transformers</a> library – the de facto standard for working with language models – started as a PyTorch-only framework and later added TensorFlow support as a secondary option. When you’re fine-tuning transformers, implementing custom attention mechanisms, or experimenting with novel architectures, PyTorch’s flexibility accelerates your iteration.</p>



<p><strong>Verdict:</strong> PyTorch leads NLP decisively. Choose TensorFlow only if you have specific mobile deployment requirements that override all other considerations.</p>



<h3 class="wp-block-heading"><strong>Computer vision</strong></h3>



<p>Computer vision presents a more balanced landscape for your projects. PyTorch benefits from research momentum – when you’re developing novel detection algorithms or experimenting with architectures, you’ll find state-of-the-art implementations appear in PyTorch first. TensorFlow excels for building production CV systems, especially for mobile object detection or on-device image classification, where TensorFlow Lite’s optimization matters most.</p>



<p>For a hands-on example, watch this video on how to build a TensorFlow object detection app to see how to take a pre-trained model and turn it into a real-time object detection app running on a robot in PyCharm:</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="Build a TensorFlow Object Detection App | Run It on Reachy Mini" src="https://www.youtube.com/embed/F8uUIerl-XY?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<p><strong>Verdict:</strong> Use case dependent. Choose PyTorch for research and novel architectures, TensorFlow when your deployment priorities favor mobile and edge devices.</p>



<h3 class="wp-block-heading"><strong>Reinforcement learning</strong></h3>



<p>PyTorch holds a slight edge in reinforcement learning, driven by the research community’s preference for it. When you’re implementing custom RL algorithms, modifying reward functions dynamically, or debugging agent behavior, PyTorch’s flexibility serves you better. TensorFlow offers solid capabilities through TF-Agents for production RL systems at scale.</p>



<p><strong>Verdict:</strong> Choose PyTorch for RL research and experimentation or TensorFlow for building large-scale production-grade RL systems like recommendation engines.</p>



<h2 class="wp-block-heading"><strong>Tooling and developer experience in PyCharm</strong></h2>



<p>PyCharm provides comprehensive support for both frameworks, streamlining your development workflow regardless of which you choose.</p>



<ul>
<li><a href="https://www.jetbrains.com/help/pycharm/debugging-code.html" target="_blank" rel="noopener"><strong>Debugging</strong></a><strong>:</strong> Set breakpoints in training loops, inspect tensor values, and step through model forward passes using the integrated debugger that works naturally with PyTorch’s dynamic graphs and TensorFlow’s eager execution.</li>



<li><a href="https://www.jetbrains.com/help/pycharm/jupyter-notebook-support.html" target="_blank" rel="noopener"><strong>Jupyter notebook support</strong></a><strong>:</strong> Prototype in notebooks, inspect data transformations visually, then move to scripts for production training with seamless integration.</li>



<li><a href="https://www.jetbrains.com/help/pycharm/installing-uninstalling-and-upgrading-packages.html" target="_blank" rel="noopener"><strong>Package management</strong></a><strong>:</strong> Handle complex dependency trees and CUDA requirements using virtual environment management to prevent conflicts between frameworks.</li>



<li><a href="https://www.jetbrains.com/help/pycharm/configuring-remote-interpreters-via-docker.html" target="_blank" rel="noopener"><strong>Remote interpreters</strong></a><strong>:</strong> Connect to remote GPU servers, develop locally while training remotely, and sync code automatically to take advantage of powerful hardware without leaving your IDE.</li>



<li><a href="https://www.jetbrains.com/help/pycharm/tensorboard-support.html" target="_blank" rel="noopener"><strong>TensorBoard integration</strong></a><strong>:</strong> Track training metrics, visualize model graphs, and compare experiments within PyCharm using native TensorFlow support or torch.utils.tensorboard for PyTorch.</li>



<li><a href="https://www.jetbrains.com/help/pycharm/auto-completing-code.html" target="_blank" rel="noopener"><strong>Code completion</strong></a><strong>:</strong> Get framework-specific suggestions for layer definitions, optimizer configurations, and data pipeline operations that reduce errors and accelerate development.</li>
</ul>



<h2 class="wp-block-heading"><strong>Performance, scalability, and deployment</strong></h2>



<p>Training performance barely differs between frameworks for most workloads – both handle GPU training efficiently with comparable speeds. TensorFlow gains an edge when you need TPU support for large-scale training, offering more mature integration with Google’s specialized hardware. For multi-GPU scaling, both deliver strong performance with PyTorch’s DDP and TensorFlow’s <a href="https://www.tensorflow.org/api_docs/python/tf/distribute/MirroredStrategy" target="_blank" rel="noopener">MirroredStrategy</a>.</p>



<p>Deployment scenarios differentiate the frameworks more clearly. TensorFlow Serving handles production model serving at scale with built-in versioning and A/B testing that PyTorch’s <a href="https://docs.pytorch.org/serve/" target="_blank" rel="noopener">TorchServe</a> can’t yet match in maturity. When deploying to mobile devices or edge hardware, TensorFlow Lite provides industry-standard optimization through quantization and pruning. For browser deployment, TensorFlow.js offers more integrated, optimized inference compared to serving PyTorch models via ONNX Runtime.</p>



<p>Memory management affects development experience – PyTorch’s caching allocator handles GPU memory efficiently with dynamic batch sizes, causing fewer surprises when experimenting with different model configurations.</p>



<h2 class="wp-block-heading"><strong>Community, ecosystem, and library support</strong></h2>



<p>PyTorch’s research dominance created a vibrant, innovation-focused community that accelerates development. The <a href="https://pytorch.org/blog/2024-year-in-review/" target="_blank" rel="noopener">PyTorch Conference 2024 saw triple the registrations</a> versus 2023, and when cutting-edge techniques emerge, they appear in PyTorch first. The <a href="https://huggingface.co/" target="_blank" rel="noopener">Hugging Face</a> ecosystem amplifies this advantage – more than 220,000 PyTorch-compatible models versus around 15,000 for TensorFlow makes a tangible difference in development speed.</p>



<p>TensorFlow’s community skews toward production engineering, providing comprehensive enterprise-grade documentation and proven deployment patterns. Google’s backing ensures strong cloud platform integrations, particularly with Google Cloud, offering managed services that reduce operational complexity. The <a href="https://www.tensorflow.org/guide/model_garden" target="_blank" rel="noopener">Model Garden</a> provides production-ready implementations optimized for deployment rather than research experimentation.</p>



<p>Learning resources reflect these different audiences – PyTorch tutorials emphasize research workflows and novel implementations, while TensorFlow documentation prioritizes production deployment patterns and enterprise-scale systems.</p>



<h2 class="wp-block-heading"><strong>Choosing the right framework for your project</strong></h2>



<p>Many successful teams use both frameworks strategically – researching and experimenting in PyTorch, then deploying in TensorFlow. The frameworks aren’t mutually exclusive. You can use <a href="https://onnx.ai/" target="_blank" rel="noopener">ONNX</a> to enable model conversion between them when needed.</p>



<p>When making a choice, it helps to prioritize factors most relevant to your project: Mobile deployment requirements may override other considerations, research-heavy work might make PyTorch essential, and enterprise support with MLOps integration could tip the scales toward TensorFlow.&nbsp;</p>



<p>Use the table below to match your project requirements with the framework strengths.&nbsp;</p>



<figure class="wp-block-table"><table><tbody><tr><td><strong>Decision Factor</strong></td><td><strong>PyTorch</strong></td><td><strong>TensorFlow</strong></td></tr><tr><td><strong>By use case</strong></td><td></td><td></td></tr><tr><td>Natural language processing</td><td>✅ NLP standard choice</td><td>Only if mobile deployment is critical</td></tr><tr><td>Computer vision</td><td>✅ Research/novel architectures</td><td>✅ Production mobile/edge apps</td></tr><tr><td>Reinforcement learning</td><td>✅ Research and experimentation</td><td>✅ Large-scale production RL</td></tr><tr><td><strong>By experience level</strong></td><td></td><td></td></tr><tr><td>Beginner</td><td>✅ More intuitive API</td><td>Keras simplifies learning</td></tr><tr><td>Intermediate/Advanced</td><td>✅ Research and prototyping</td><td>✅ Production systems at scale</td></tr><tr><td><strong>By project phase</strong></td><td></td><td></td></tr><tr><td>Research/Experimentation</td><td>✅ Dynamic graphs aid iteration</td><td>Graph compilation for optimization</td></tr><tr><td>Rapid prototyping</td><td>✅ Fast experimentation</td><td>Keras for simple models</td></tr><tr><td>Production deployment</td><td>TorchServe improving</td><td>✅ Mature deployment tools</td></tr><tr><td><strong>By deployment target</strong></td><td></td><td></td></tr><tr><td>Cloud/Server</td><td>Strong performance</td><td>✅ Strong performance, slight GCP advantage</td></tr><tr><td>Mobile/Edge devices</td><td>Basic support via PyTorch Mobile</td><td>✅ TensorFlow Lite industry standard</td></tr><tr><td>Web Applications</td><td>Via ONNX Runtime</td><td>✅ TensorFlow.js optimized</td></tr><tr><td><strong>By team context</strong></td><td></td><td></td></tr><tr><td>Research-focused team</td><td>✅ Natural fit for researchers</td><td>If already using TensorFlow</td></tr><tr><td>Production-focused team</td><td>If comfortable with tooling</td><td>✅ Proven enterprise patterns</td></tr></tbody></table></figure>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Using Bag-of-Words With PyCharm</title>
		<link>https://blog.jetbrains.com/pycharm/2026/04/using-bag-of-words-with-pycharm/</link>
		
		<dc:creator><![CDATA[Jodie Burchell]]></dc:creator>
		<pubDate>Wed, 29 Apr 2026 17:42:41 +0000</pubDate>
		<featuredImage>https://blog.jetbrains.com/wp-content/uploads/2026/04/PC-social-BlogFeatured-1280x720-1-6.png</featuredImage>		<guid isPermaLink="false">https://blog.jetbrains.com/?post_type=pycharm&#038;p=703589</guid>

					<description><![CDATA[Have you ever wondered how machine learning models actually work with text? After all, these models require numerical input, but text is, well, text. Natural language processing (NLP) offers many ways to bridge this gap, from the large language models (LLMs) that are dominating headlines today all the way back to the foundational techniques of [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>Have you ever wondered how <a href="https://www.jetbrains.com/pycharm/data-science/" target="_blank" rel="noopener">machine learning</a> models actually work with text? After all, these models require numerical input, but text is, well, text.</p>



<p>Natural language processing (NLP) offers many ways to bridge this gap, from the large language models (LLMs) that are dominating headlines today all the way back to the foundational techniques of the 1950s. Those early methods fall under what we now call the <strong>bag-of-words (BoW) model</strong>, and despite their age, they remain remarkably effective for a wide range of language problems.</p>



<p>In this post, we&#8217;ll unpack how the bag-of-words model works, explore the techniques it uses to convert text into numerical representations, and look at where it fits relative to more modern NLP approaches. We&#8217;ll also build a text classification project using BoW techniques, and see how PyCharm&#8217;s specific features make the whole process faster and easier.</p>



<h2 class="wp-block-heading">What is the bag-of-words model?</h2>



<p>The bag-of-words model is a text representation technique that converts unstructured text into numerical vectors by tracking which words appear across a corpus (a collection of texts). Rather than preserving grammar or word order, it simply represents each document as a &#8220;bag&#8221; of its words, recording how often each one appears. The result is a vector of counts that captures what a text is about, even if it discards how that content is expressed.</p>



<p>This apparent limitation turns out to matter less than you might expect. For many tasks, such as text classification and sentiment analysis, the presence of certain words is often a stronger signal than their arrangement, and BoW captures that signal efficiently.</p>



<h2 class="wp-block-heading">How does bag-of-words work?</h2>



<p>To use the bag-of-words model, we need to convert each text in a corpus into a numerical vector. Let&#8217;s walk through how that works, starting with what that vector actually looks like.</p>



<p>Take the following sentence:</p>



<blockquote class="wp-block-quote">
<p>When diving into natural language processing, it is natural for beginners to feel overwhelmed by the complexity of sentiment analysis, which involves distinguishing negative from positive text. However, as you practice with libraries like NLTK or spaCy, the concepts naturally start to click.</p>
</blockquote>



<p>A vector representation of this text using the BoW model might look something like this.</p>



<figure class="wp-block-table"><table><tbody><tr><td>&#8230;</td><td>natural</td><td>naturally</td><td>nausea</td><td>near</td><td>neared</td><td>nearing</td><td>necessary</td><td>negative</td><td>&#8230;</td></tr><tr><td></td><td>2</td><td>1</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>1</td><td></td></tr></tbody></table></figure>



<p>If we think of this vector as a table, you may have noticed that each column represents a word in the corpus, and the row contains a number from 0 to 2. This number is a count of how many times the word occurs in the text, as we can see below:</p>



<blockquote class="wp-block-quote">
<p>When diving into <strong>natural</strong> language processing, it is <strong>natural</strong> for beginners to feel overwhelmed by the complexity of sentiment analysis, which involves distinguishing <strong>negative</strong> from positive text. However, as you practice with libraries like NLTK or spaCy, the concepts <strong>naturally</strong> start to click.</p>
</blockquote>



<p>Each column represents a word in the vocabulary; each value records how many times that word appears. Here, “natural” appears twice, while “naturally” and “negative” each appear once.</p>



<h3 class="wp-block-heading">Tokenization</h3>



<p>Before we can build this vector, we need to split our text into tokens. In BoW modeling, this is typically straightforward: We split on whitespace, so &#8220;When diving into natural language processing,&#8221; becomes seven tokens: <code>["When", "diving", "into", "natural", "language", "processing", ","]</code>. This is considerably simpler than the tokenization used in LLMs.</p>



<h3 class="wp-block-heading">Vocabulary creation</h3>



<p>Applying tokenization across every text in the corpus produces a long list of words. Deduplicating this list gives us our vocabulary, which we can see in the set of columns in the vector above. This process does introduce some noise: &#8220;Natural&#8221; and &#8220;natural&#8221;, for instance, would be treated as two separate tokens. We&#8217;ll look at preprocessing steps to address this shortly.</p>



<h3 class="wp-block-heading">Encoding</h3>



<p>With a vocabulary in hand, we create a vector for each text with one element per vocabulary word. Encoding is then the process of filling in those elements by checking each vocabulary word against the text.</p>



<p>The simplest approach is <strong>binary vectorization</strong>: 0 if a word is absent, 1 if present. More common, however, is <strong>count vectorization</strong>, which records the actual number of occurrences, as we saw in the example above. Count vectorization carries more information, since it helps distinguish texts that merely mention a topic from those that focus on it heavily.</p>



<p>One practical consequence of this approach is sparsity. If a corpus contains thousands of unique words, each vector will have thousands of elements, but any individual text will only use a small fraction of them, leaving most values at zero. This signal-to-noise issue is something we&#8217;ll return to.</p>



<h2 class="wp-block-heading">Advantages of the bag-of-words model</h2>



<p>The bag-of-words model has remained a staple in NLP for good reason. Its greatest strength is its simplicity: Because text is represented as a collection of word counts, the approach is easy to understand and straightforward to implement, making it a natural baseline before reaching for more complex architectures.</p>



<p>Beyond simplicity, BoW is computationally efficient. As you saw above, the underlying math is lightweight, which means it scales well to large text collections without demanding significant computing resources. For tasks where the presence of specific words is sufficient to capture meaning, with sentiment analysis and topic categorization being the clearest examples, it remains a highly effective tool.</p>



<h2 class="wp-block-heading">Applications of bag-of-words</h2>



<p>Like many NLP approaches, the bag-of-words model can be applied to many natural language problems. These potential applications include:</p>



<ul>
<li><strong>Document classification</strong>, where encoded documents are sorted into predefined categories. A classic example of this is automatically sorting incoming news articles into distinct categories such as sports, politics, or technology, as we’ll see in the project we do in this post.</li>



<li><strong>Sentiment analysis</strong>, where the presence of certain words strongly indicates the overall tone of a text, allows models to easily determine whether a piece of writing expresses a positive, negative, or neutral sentiment. If you’re interested in learning more about BoW and other approaches to sentiment analysis, you can see a <a href="https://blog.jetbrains.com/pycharm/2024/12/introduction-to-sentiment-analysis-in-python/">prior blog post</a> I wrote on this topic.</li>



<li><strong>Spam detection</strong>, which relies heavily on BoW to identify and filter out unwanted emails or messages by learning to recognize the distinct, high-frequency word patterns characteristic of spam.&nbsp;</li>



<li><strong>Retrieval systems</strong>, where it helps to efficiently find the most relevant documents from an immense corpus based on a user’s search query.&nbsp;</li>



<li><strong>Topic modeling</strong>, which aims to group similar text vectors in order to discover and extract the hidden, latent topics present within a large collection of documents.</li>
</ul>



<p>As you can see, the number of potential applications is broad, making bag-of-words modeling a popular first approach to natural language problems.</p>



<h2 class="wp-block-heading">Why use PyCharm for NLP?</h2>



<p><a href="https://www.jetbrains.com/pycharm/" target="_blank" rel="noopener">PyCharm</a> is particularly well-suited to bag-of-words modeling because it supports the iterative, detail-oriented workflow that text processing requires. As you’ll soon see, building a reliable BoW pipeline involves multiple steps, such as cleaning text, tokenizing, vectorizing, and validating outputs, and PyCharm&#8217;s code intelligence makes each of these smoother. Autocompletion, parameter hints, and quick navigation through specialized NLP libraries reduce friction when experimenting with different vectorizer settings, and help you understand how each component behaves.</p>



<p><a href="https://www.jetbrains.com/pycharm/features/debugger.html" target="_blank" rel="noopener">Debugging</a> and data inspection are equally important here, since small preprocessing mistakes can have an outsized effect on results. PyCharm lets you step through your code and examine intermediate states of things such as token lists and vocabulary at runtime, making it straightforward to verify that your feature extraction is working as intended. This visibility is especially useful when diagnosing issues like unexpected vocabulary sizes or missing terms.</p>



<p>PyCharm also supports exploratory work through its excellent <a href="https://www.jetbrains.com/help/pycharm/jupyter-notebook-support.html" target="_blank" rel="noopener">Jupyter Notebook integration</a> and scientific tooling. BoW modeling often involves trying different preprocessing strategies and observing their effects immediately, so the ability to run code interactively and inspect outputs inline is a genuine advantage. Combined with built-in virtual environment and package management support, this keeps experiments reproducible and well-organized.</p>



<p>As projects grow, PyCharm&#8217;s refactoring tools, project navigation, and version control integration help manage the added complexity. BoW models rarely exist in isolation, and they&#8217;re often embedded in larger ML pipelines. In such contexts, PyCharm’s features for working with larger applications mean you spend less time managing code and more time improving your models.</p>



<h3 class="wp-block-heading">Setting up the project</h3>



<p>To see these components in action, let&#8217;s build an actual bag-of-words project. We&#8217;ll use a classic text classification dataset and the AG News dataset, and then use the model to classify news articles into one of four categories: World, Sports, Business, or Science/Technology.</p>



<p>To get started in PyCharm, open the <em>Projects and Files</em> tool window and select <em>New… &gt; New Project…</em>. Since this is a data science project, we can use PyCharm&#8217;s built-in Jupyter project type, which sets up a sensible default structure for us.</p>



<p>During project configuration, you&#8217;ll be asked to choose a Python interpreter. By default, PyCharm uses uv and lets you select from a range of Python versions, though all major dependency management systems are supported: pip, Anaconda, Pipenv, Poetry, and Hatch. Every project is automatically created with an attached virtual environment, so your setup will be ready to go each time you reopen the project.</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/04/screenshot-1-selecting-uv-project.png" alt="" class="wp-image-703594"/></figure>



<p>With the project configured, we can install our dependencies via the <em>Python Packages</em> tool window. Simply search for a package by name, select it from the list, and install your desired version directly into the virtual environment. You can also see the same information about the package you&#8217;d find on PyPI directly within the IDE. For this project, we&#8217;ll need pandas and Numpy, along with datasets from Hugging Face, scikit-learn, Pytorch, and spaCy.</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/04/screenshot-2-installing-package.png" alt="" class="wp-image-703605"/></figure>



<h2 class="wp-block-heading">Implementing bag-of-words with PyCharm</h2>



<p>There are many versions of this dataset online. We’ll be using <a href="https://huggingface.co/datasets/sh0416/ag_news" target="_blank" rel="noopener">one of the versions</a> hosted on Hugging Face Hub.</p>



<h3 class="wp-block-heading">Loading and preparing the data</h3>



<p>We’ll use Hugging Face’s <code>datasets</code> package to download this dataset.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">from datasets import load_dataset
ag_news_all = load_dataset("sh0416/ag_news")</pre>



<p>This gives us a Hugging Face <code>DatasetDict</code> object. If we look at it, we can see it contains a training dataset with 120,000 news articles, and a test dataset containing 7,600 articles.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">ag_news_all</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">DatasetDict({
    train: Dataset({
        features: ['label', 'title', 'description'],
        num_rows: 120000
    })
    test: Dataset({
        features: ['label', 'title', 'description'],
        num_rows: 7600
    })
})</pre>



<p>As we’ll be training a model, we also need a validation set. We’ll convert the training and test sets to pandas DataFrames, and use the <code>train_test_split</code> method from scikit-learn to create the validation set from the training data.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import pandas as pd
from sklearn.model_selection import train_test_split

ag_news_train = ag_news_all["train"].to_pandas()
ag_news_test = ag_news_all["test"].to_pandas()

ag_news_train, ag_news_val = train_test_split(
   ag_news_train,
   test_size=0.1,     
   random_state=456,   
   stratify=ag_news_train['label'] 
)

print(f"Training set: {len(ag_news_train)} samples")
print(f"Validation set: {len(ag_news_val)} samples")</pre>



<p>We now have a validation set with 12,000 articles, and a training set with 108,000 articles.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Training set: 108000 samples
Validation set: 12000 samples</pre>



<p>For those of you new to machine learning, you might be wondering why we need all of these different datasets. The reason for this is to make sure we have a good idea that our model will generalize well and perform as expected on unseen data. The training set is the only data the model ever learns from directly. The validation set is used to monitor how the model is performing on unseen data as we make modeling decisions, such as choosing how many epochs to train for, how large to make the hidden layer, or which preprocessing steps to apply (we’ll see all of this later). This means that we look at validation performance repeatedly while building the model, and this increases the risk that our choices gradually become tuned to the quirks of that particular split. This is why we need a third set (the test set), which we keep completely locked away until we&#8217;ve finished all modeling decisions and want a single, unbiased estimate of how well our model will perform on new data. Using the test set for anything other than this final evaluation would give us an overly optimistic picture of our model&#8217;s real-world performance.</p>



<p>Let’s now inspect our datasets. PyCharm Pro has a lot of built-in features that make working with DataFrames easier, a few of which we’ll see soon. In this DataFrame, we have three columns: The article title and description, the article text, and the label indicating which of the four news categories the article belongs to. You can open any of the DataFrame cells in the <em>Value Editor</em> to see its full text, or widen the column to prevent truncation, both of which are useful for a quick visual inspection.</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/04/screenshot-3-viewing-full-text.png" alt="" class="wp-image-703617" style="aspect-ratio:2.695219123505976;width:840px;height:auto; width:100% !important; height:auto !important; max-width:100% !important;"/></figure>



<p>At the top of each column, PyCharm displays column statistics, giving you an at-a-glance summary of the data. Switching from <em>Compact</em> to <em>Detailed</em> mode via <em>Show Column Statistics</em> gives you rich summary statistics about each column, and saves you from writing a lot of pandas boilerplate to get it! From these statistics, we can see that our training set is evenly split across the news categories (which is very handy when training a model). We can also see that some headlines and descriptions are not unique, which may introduce noise when classifying these duplicates.</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/04/screenshot-4-column-statistics.png" alt="" class="wp-image-703628"/></figure>



<p>The first step in preparing the data is basic string cleaning, which normalizes the text and reduces meaningless token variation. For instance, without cleaning, &#8220;Natural&#8221; and &#8220;natural&#8221; would be treated as two separate vocabulary entries, as we noted earlier.&nbsp;</p>



<p>We&#8217;ll apply four cleaning steps: lowercasing, punctuation removal, number removal, and whitespace normalization. There are different string cleaning steps you can apply depending on the language and use case, but for English-language texts, these tend to be very standard. Let’s go ahead and write a function to do this.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">def apply_string_cleaning(dataset: pd.Series) -> pd.Series:
   patterns_to_remove = [
       r"[^a-zA-Z\s]",
   ]

   cleaned = dataset.str.lower()

   for pattern in patterns_to_remove:
       cleaned = cleaned.str.replace(pattern, " ", regex=True)

   cleaned = cleaned.str.replace(r"\s+", " ", regex=True).str.strip()

   return cleaned

ag_news_train["title_clean"] = apply_string_cleaning(ag_news_train["title"])
ag_news_train["description_clean"] = apply_string_cleaning(ag_news_train["description"])</pre>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/04/screenshot-5-raw-and-cleaned-text.png" alt="" class="wp-image-703639"/></figure>



<p>This mostly works, but there&#8217;s one issue: The regex strips apostrophes entirely, turning contractions like &#8220;you&#8217;re&#8221; into &#8220;you re&#8221; and possessives like &#8220;Canada’s&#8221; into &#8220;Canada s&#8221;. The cleanest fix is a regex that preserves apostrophes in contractions while removing possessive endings, but this is not the most enjoyable thing to write by hand.</p>



<p>This is where PyCharm&#8217;s built-in <a href="https://www.jetbrains.com/pycharm/features/ai/" target="_blank" rel="noopener">AI Assistant</a> comes in. Open the chat window via the <em>AI Chat</em> icon on the right-hand side of the IDE and enter the following prompt:</p>



<blockquote class="wp-block-quote">
<p>Can you please alter the <code>@apply_string_cleaning</code> function so that it retains apostrophes inside words when they&#8217;re used for contractions (e.g., &#8220;you&#8217;re&#8221;), but removes them when they&#8217;re used for possessives (e.g., &#8220;Canada’s&#8221; into &#8220;Canada&#8221;).</p>
</blockquote>



<p>The <code>@</code> notation lets you reference specific files or objects in your IDE without copying and pasting code into the prompt, including Jupyter variables like datasets and functions.</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/04/screenshot-6-ai-chat.png" alt="" class="wp-image-703650"/></figure>



<p>I ran this against Claude Sonnet 4.5, though JetBrains AI supports a wide range of models from OpenAI, Anthropic, Google, and xAI, as well as open models via Ollama, LM Studio, and OpenAI-compatible APIs. Below is the updated function it returned:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">def apply_string_cleaning(dataset: pd.Series) -> pd.Series:
    cleaned = dataset.str.lower()
    
    # Remove possessive apostrophes (word's -> word)
    # This pattern matches: letter(s) + 's + word boundary
    cleaned = cleaned.str.replace(r"(\w+)'s\b", r"\1", regex=True)
    
    # Remove all non-letter characters except apostrophes within words
    cleaned = cleaned.str.replace(r"[^a-zA-Z'\s]", " ", regex=True)
    
    # Clean up any apostrophes at the start or end of words
    cleaned = cleaned.str.replace(r"\s'|'\s", " ", regex=True)
    
    # Remove multiple spaces and trim
    cleaned = cleaned.str.replace(r"\s+", " ", regex=True).str.strip()
    
    return cleaned

ag_news_train["title_clean"] = apply_string_cleaning(ag_news_train["title"])
ag_news_train["description_clean"] = apply_string_cleaning(ag_news_train["description"])
</pre>



<p>We can insert this into our Jupyter notebook directly by clicking on <em>Insert Snippet as Jupyter Cell</em> in the AI chat.</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/04/screenshot-7-insert-code-as-cell.png" alt="" class="wp-image-703664"/></figure>



<p>Once we run this updated function on our raw text, we get the correct result:</p>



<figure class="wp-block-table"><table><tbody><tr><td><strong>text</strong></td><td><strong>text_clean</strong></td></tr><tr><td>Don’t stand for racism &#8211; football chief</td><td>don&#8217;t stand for racism football chief</td></tr><tr><td>Canada&#8217;s Barrick Gold acquires nine per cent stake in Celtic Resources (Canadian Press)</td><td>canada barrick gold acquires nine per cent stake in celtic resources canadian press</td></tr></tbody></table></figure>



<p>We can see the contraction “don’t” is correctly preserved in the first example, but the possessive “Canada’s” has been removed. We apply this to both the training and validation datasets using the same function, so that the cleaning is consistent across both splits:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">ag_news_val["title_clean"] = apply_string_cleaning(ag_news_val["title"])
ag_news_val["description_clean"] = apply_string_cleaning(ag_news_val["description"])</pre>



<h3 class="wp-block-heading">Creating the bag-of-words model</h3>



<p>Now that we have clean text, we need to build our vocabulary and encode it. We&#8217;ll use scikit-learn&#8217;s <code>CountVectorizer</code> for this:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">from sklearn.feature_extraction.text import CountVectorizer

countVectorizerNews = CountVectorizer()
countVectorizerNews.fit(ag_news_train["text_clean"])
ag_news_train_cv = countVectorizerNews.transform(ag_news_train["text_clean"]).toarray()</pre>



<p>The process has two distinct steps. First, <code>.fit()</code> scans the training data and builds a vocabulary by identifying every unique word and assigning it a fixed index position (for example, &#8220;government&#8221; = column 8,901). The result is a mapping of 59,544 unique words, which you can think of as the column headers for our eventual matrix.</p>



<p>Second, <code>.transform()</code> uses that vocabulary to convert each headline into a numerical vector, counting how many times each vocabulary word appears and placing that count at the corresponding index position.</p>



<p>The reason these are two separate steps is important: When we later process our validation and test data, we&#8217;ll call <code>.transform()</code> using the vocabulary learned from the training set. This ensures that all three splits share a consistent feature space. If we re-ran .fit() on the test data, we&#8217;d get a different vocabulary, and the model&#8217;s predictions would be meaningless.</p>



<p>With the vectorizer fitted and our training data transformed, we can start exploring what we&#8217;ve actually built. Let&#8217;s first take a look at the vocabulary. <code>CountVectorizer</code> stores it as a dictionary mapping each word to its index position, accessible via <code>vocabulary_</code>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">countVectorizerNews.vocabulary_</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{'fed': 18461,
 'up': 55833,
 'with': 58324,
 'pension': 38929,
 'defaults': 13156,
 'citing': 9475,
 'failure': 18077,
 'of': 36704,
 'two': 54804,
 'big': 5269,
 'airlines': 1139,
 'to': 53531,
 'make': 31397,
 'payments': 38686,
 'their': 52947,
...}</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">len(countVectorizerNews.vocabulary_)</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">59544</pre>



<p>This confirms that our vocabulary contains 59,544 unique words. Browsing through it, you can start to guess what kinds of terms appear frequently in the different types of news. Country names feature heavily in the “world” news category, terms like “football” and “cricket” in the “sports” news category, terms like “profit” and “losses” in the “business” news category, and company names like “Google” and “Microsoft” in the “science/technology” category.</p>



<p>Next, let&#8217;s inspect the feature matrix itself. ag_news_train_cv is a NumPy array with one row per headline and one column per vocabulary word, giving us a matrix of shape (108,000 × 59,544). We can wrap it in a DataFrame to make it easier to inspect in PyCharm&#8217;s DataFrame viewer:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">pd.DataFrame(ag_news_train_cv, columns=countVectorizerNews.get_feature_names_out())</pre>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/04/screenshot-8-sparse-matrix.png" alt="" class="wp-image-703675"/></figure>



<p>As expected, the matrix is very sparse. Most values are zero, since any individual headline only contains a small fraction of the full vocabulary. In fact, you might have noticed that the number of columns is two-thirds of the number of rows, which is never good for a feature matrix. We’ll explore how to reduce the dimensionality of the feature space in a later section.</p>



<p>Note that we also need to apply this vectorization to the validation dataset before moving on to modeling. Importantly, we are only applying the <code>.transform</code> method to the validation set, as we already trained it on the training dataset.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">ag_news_val_cv = countVectorizerNews.transform(ag_news_val["text_clean"]).toarray()</pre>



<h2 class="wp-block-heading">Visualizing the results</h2>



<p>Before we move onto reducing down the dimensionality of our feature space, let&#8217;s explore the distribution of the words in our corpus. This can help us to understand the most common and rare words, and how we might use this to further process our data to amplify the signal-to-noise ratio.</p>



<h3 class="wp-block-heading">Word frequency plots</h3>



<p>We’ll start by creating a DataFrame that aggregates word counts across all headlines and ranks them by frequency:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import numpy as np

vocab = countVectorizerNews.get_feature_names_out()
counts = np.asarray(ag_news_train_cv.sum(axis=0)).flatten()

pd.DataFrame({
  'vocab': vocab,
  'count': counts,
}).sort_values('count', ascending=False).reset_index(drop=True)</pre>



<p>First, we retrieve the vocabulary in index order using <code>get_feature_names_out()</code>, so each word lines up with its corresponding column in the feature matrix. We then sum the matrix column-wise (that is, across all documents) to get the total number of times each word appears in the training set. Finally, we wrap these two arrays into a DataFrame and sort by count, giving us a ranked list of the most frequent terms.</p>



<p>Once this DataFrame is displayed in PyCharm, we can easily turn it into a visualization without writing a single line of code. By clicking on the <em>Chart View</em> button in the top left-hand corner of the DataFrame, we can explore a range of ways of visualizing our data. Go to <em>Show Series Settings</em> in the top right-hand corner, and adjust the parameters to get the count frequencies of the words: we set the <em>X axis</em> value to “vocab” (and change <em>group and sort</em> to <em>none</em>), the <em>Y axis</em> value to “count”, and the chart type to “Bar”.</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/04/screenshot-9-chart-view.png" alt="" class="wp-image-703686"/></figure>



<p>Hovering over this chart, we can see that it has a very long-tailed distribution, which is very typical of vocabulary frequencies (this is actually so typical that it is described in something called Zipf’s law). This means that the majority of our words very rarely occur in the text, and in fact, if we hover over the right-hand side of the chart, it looks like around a third of our vocabulary terms are only used once!&nbsp;</p>



<p>On the other hand, when we hover over the left-hand side of the chart, we can see that this is dominated by very common words, prepositions, and articles, such as “to”, “in”, “the”, and “you”. These words don’t really carry any meaning and pretty much occur in every text, so they’re unlikely to be useful for our classification task.&nbsp;</p>



<p>Let’s have a look at some things we can do to clean up our feature space and help our semantically meaningful words stand out a bit more.</p>



<h2 class="wp-block-heading">Advanced bag-of-words techniques</h2>



<p>The basic BoW pipeline we&#8217;ve built so far is a solid foundation, but there are several techniques that can meaningfully improve its quality. This section walks through the most important ones. We’ll only be using a selection of them in our project, but you can investigate which of these seem appropriate when building your own project.</p>



<h3 class="wp-block-heading">Stop word removal</h3>



<p>Stop words are extremely common words that appear frequently across all kinds of text but carry little meaningful information. This includes words like &#8220;the&#8221;, &#8220;is&#8221;, &#8220;and&#8221;, &#8220;of&#8221;, as we saw in the histogram in the previous section. They inflate vocabulary size without adding signal, so removing them is one of the most straightforward ways to improve your BoW representation. NLTK provides a built-in stop word list for English and many other languages.</p>



<h3 class="wp-block-heading">Stemming and lemmatization</h3>



<p>Another issue you might have noticed in our vocabulary is that words that are semantically equivalent have different syntactic forms, meaning that while they should be treated as the same token, they occupy additional token slots. We can resolve this through two techniques: stemming and lemmatization. Stemming reduces words to their root form using simple rule-based truncation (e.g. &#8220;running&#8221; → &#8220;run&#8221;), while lemmatization takes a linguistic approach, mapping words to their dictionary base form. Lemmatization is slower but generally produces cleaner results, particularly for irregular word forms.</p>



<h3 class="wp-block-heading">TF-IDF</h3>



<p>Term frequency-inverse document frequency (TF-IDF) is an extension of basic count vectorization that weights each word by how informative it actually is. A word that appears frequently in one document but rarely across the corpus receives a high weight; a word that appears everywhere receives a low one. This neatly addresses one of the core weaknesses of raw count vectors: common but uninformative words can dominate the feature space even after stop-word removal.</p>



<h3 class="wp-block-heading">N-grams</h3>



<p>Standard BoW treats each word independently, which means it misses phrases whose meaning depends on word combinations. A classic example of this is &#8220;machine learning”, which has a distinct meaning to “machine” + “learning”. N-grams address this by treating sequences of adjacent words as single tokens, so a bigram model would capture &#8220;machine learning&#8221; as a feature in its own right. The trade-off is a much larger vocabulary, so in practice, bigrams are most commonly used, with trigrams reserved for cases where capturing longer phrases is important.</p>



<h3 class="wp-block-heading">Handling out-of-vocabulary words</h3>



<p>When you apply your fitted vectorizer to new data, any words not present in the training vocabulary are silently ignored by default. For many tasks, this is acceptable, but if your production data is likely to continue introducing new terms that carry meaningful signal, it&#8217;s worth considering alternatives. One common approach is to reserve a special &lt;UNK&gt; token to represent unseen words, which at least preserves the information that something unfamiliar appeared, even if its identity is unknown and multiple (perhaps unrelated) words are collapsed onto the same token.&nbsp;</p>



<p>However, LLMs, with their more flexible approach to tokenization, tend to be a better choice if out-of-vocabulary words will be a major issue for your model once it is in production.</p>



<h3 class="wp-block-heading">Dimensionality reduction</h3>



<p>Even after stop word removal and other cleaning steps, BoW feature matrices are typically very high-dimensional and sparse. Two widely used techniques can help. Reducing to the top-N most frequent terms is the simplest approach, discarding low-frequency words that are unlikely to generalize well. For a more principled reduction, techniques like principal component analysis (PCA) or latent semantic analysis (LSA) project the feature matrix into a lower-dimensional space, compressing the representation while preserving as much of the meaningful variance as possible.</p>



<h3 class="wp-block-heading">Feature selection techniques</h3>



<p>Rather than reducing dimensionality arbitrarily, feature selection methods identify and retain only the features most relevant to your specific task. Chi-squared testing measures the statistical dependence between each term and the target label, making it well-suited to classification tasks. Mutual information takes a similar approach, scoring each feature by how much it reduces uncertainty about the class. Both methods can substantially reduce vocabulary size while preserving model performance.</p>



<h2 class="wp-block-heading">Applying bag-of-words to a real-world problem</h2>



<p>Let&#8217;s now continue the example we started earlier. We&#8217;re going to take the work we&#8217;ve done on our AG News text classification task and take it to its completion by building a model.</p>



<p>A common way to build a model using encoded text is neural networks, where each of the words in the vocabulary is treated as a feature, and the categories we want to predict (in our case, the news category) are the output. We&#8217;ll start by building a baseline model that applies only string cleaning and encoding to the text.</p>



<p>I had originally written this model in Keras, as part of a previous BoW project from a couple of years ago. However, that code was now out of date. In order to update it and adapt it to Pytorch, I asked JetBrains AI to do the following:</p>



<blockquote class="wp-block-quote">
<p>Please update this neural network from Keras to Pytorch, making improvements to make the code as reusable as possible.</p>
</blockquote>



<p>This gave us the following successful port of the code:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import TensorDataset, DataLoader

class MulticlassClassificationModel(nn.Module):
   def __init__(self, input_size: int, hidden_layer_size: int, num_classes: int = 4):
       super(MulticlassClassificationModel, self).__init__()
       self.fc1 = nn.Linear(input_size, hidden_layer_size)
       self.relu = nn.ReLU()
       self.fc2 = nn.Linear(hidden_layer_size, num_classes)

   def forward(self, x):
       x = self.fc1(x)
       x = self.relu(x)
       x = self.fc2(x)
       return x

def train_text_classification_model(
       train_features: np.ndarray,
       train_labels: np.ndarray,
       validation_features: np.ndarray,
       validation_labels: np.ndarray,
       input_size: int,
       num_epochs: int,
       hidden_layer_size: int,
       num_classes: int = 4,
       batch_size: int = 1920,
       learning_rate: float = 0.001) -> MulticlassClassificationModel:

   # Convert labels to 0-indexed (AG News has labels 1,2,3,4 -> need 0,1,2,3)
   train_labels_indexed = train_labels - 1
   validation_labels_indexed = validation_labels - 1

   # Convert numpy arrays to PyTorch tensors
   X_train = torch.FloatTensor(train_features.copy())
   y_train = torch.LongTensor(train_labels_indexed.copy())
   X_val = torch.FloatTensor(validation_features.copy())
   y_val = torch.LongTensor(validation_labels_indexed.copy())

   # Create datasets and dataloaders
   train_dataset = TensorDataset(X_train, y_train)
   train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)

   # Initialize model, loss function, and optimizer
   model = MulticlassClassificationModel(input_size, hidden_layer_size, num_classes)
   criterion = nn.CrossEntropyLoss()
   optimizer = optim.RMSprop(model.parameters(), lr=learning_rate)

   # Training loop
   for epoch in range(num_epochs):
       model.train()
       train_loss = 0.0
       correct_train = 0
       total_train = 0

       for batch_features, batch_labels in train_loader:
           # Forward pass
           outputs = model(batch_features)
           loss = criterion(outputs, batch_labels)

           # Backward pass and optimization
           optimizer.zero_grad()
           loss.backward()
           optimizer.step()

           # Calculate training metrics
           train_loss += loss.item()
           _, predicted = torch.max(outputs, 1)
           correct_train += (predicted == batch_labels).sum().item()
           total_train += batch_labels.size(0)

       # Validation
       model.eval()
       with torch.no_grad():
           val_outputs = model(X_val)
           val_loss = criterion(val_outputs, y_val)
           _, val_predicted = torch.max(val_outputs, 1)
           correct_val = (val_predicted == y_val).sum().item()
           total_val = y_val.size(0)

       # Print epoch metrics
       train_acc = correct_train / total_train
       val_acc = correct_val / total_val
       print(f'Epoch [{epoch+1}/{num_epochs}], '
             f'Train Loss: {train_loss/len(train_loader):.4f}, '
             f'Train Acc: {train_acc:.4f}, '
             f'Val Loss: {val_loss:.4f}, '
             f'Val Acc: {val_acc:.4f}')

   return model

def generate_predictions(model: MulticlassClassificationModel,
                       validation_features: np.ndarray,
                       validation_labels: np.ndarray) -> list:
   model.eval()

   # Convert to tensors
   X_val = torch.FloatTensor(validation_features.copy())

   with torch.no_grad():
       outputs = model(X_val)
       _, predicted = torch.max(outputs, 1)

   # Convert back to 1-indexed labels to match original dataset
   predicted_labels = (predicted.numpy() + 1)

   print("Confusion Matrix:")
   print(pd.crosstab(validation_labels, predicted_labels,
                     rownames=['Actual'], colnames=['Predicted']))
   return predicted_labels.tolist()</pre>



<p>Let’s walk through this code step-by-step to understand how we’re going to train our text classifier.</p>



<h3 class="wp-block-heading">The model architecture</h3>



<p><code>MulticlassClassificationModel</code> is a simple two-layer feedforward neural network. It takes a BoW vector as input, with each feature being a vocabulary word, and passes it through two sequential transformations to produce a prediction. The first layer (<code>fc1</code>) compresses this high-dimensional input down to a smaller intermediate representation, whose size we control via <code>hidden_layer_size</code>. A ReLU activation is then applied, which introduces a small amount of mathematical complexity that allows the model to learn patterns that a simple weighted sum couldn&#8217;t capture. The second layer (<code>fc2</code>) takes this intermediate representation and maps it down to four output values, one per news category, where the category with the highest value becomes the model&#8217;s prediction.</p>



<h3 class="wp-block-heading">Training and validation</h3>



<p><code>train_text_classification_model</code> handles the full training loop. It starts with a small amount of housekeeping: The AG News labels run from 1 to 4, but PyTorch expects 0-indexed classes, so these are shifted down by 1. The features and labels are then converted to PyTorch tensors, and a <code>DataLoader</code> is created to feed the training data to the model in batches.</p>



<p>Each epoch, the model processes the training data batch by batch. For each batch, it runs a forward pass to generate predictions, computes the cross-entropy loss against the true labels, and then runs a backward pass to update the model weights via the RMSprop optimizer. At the end of every epoch, the model switches into evaluation mode and runs inference over the full validation set, printing the training and validation loss and accuracy so we can monitor how training is progressing.</p>



<h3 class="wp-block-heading">Generating predictions</h3>



<p>Once training is complete, <code>generate_predictions</code> runs the trained model on a held-out dataset and returns the predicted class for each article. It also prints a confusion matrix, which gives us a breakdown of which categories the model is getting right and where it&#8217;s getting confused, which is a much more informative picture than accuracy alone.</p>



<h3 class="wp-block-heading">Running the baseline</h3>



<p>We can now train the baseline model. We pass in the raw count-vectorized training and validation features, specify an input size equal to the vocabulary size (59,544 columns), train for two epochs, and use a hidden layer of 5,000 nodes.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">baseline_model = train_text_classification_model(
    ag_news_train_cv,
    ag_news_train["label"].to_numpy(),
    ag_news_val_cv,
    ag_news_val["label"].to_numpy(),
    ag_news_train_cv.shape[1],
    5,
    5000
)

predictions = generate_predictions(
    baseline_model,
    ag_news_val_cv,
    ag_news_val["label"].to_numpy()
)</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Epoch [1/2], Train Loss: 0.3553, Train Acc: 0.8813, Val Loss: 0.2307, Val Acc: 0.9243
Epoch [2/2], Train Loss: 0.1217, Train Acc: 0.9587, Val Loss: 0.2352, Val Acc: 0.9240

Confusion Matrix:
Predicted     1     2     3     4
Actual                           
1          2774    65    89    72
2            37  2944     9    10
3           112    20  2694   174
4            97    20   207  2676</pre>



<p>Even with the very basic data preparation we did, we can see we’ve performed very well on this prediction task, with around 92% accuracy. The confusion matrix shows that the model seems to have the easiest time distinguishing between category two (sports) and the other topics, and the hardest time distinguishing between category three (business) and category four (science/technology). This makes sense, as the words used to describe sports are very distinct and unlikely to be used in other contexts (things like football), whereas there is likely to be overlapping vocabulary between business and technology (especially company names).</p>



<p>As we saw above, there is a lot we can do to improve the signal-to-noise ratio in BoW modeling. Let’s apply four commonly used techniques to our data and see whether this improves our predictions: lemmatization, stop word removal, limiting our vocabulary to the top N terms, and TF-IDF weighting. As you’ll see, all of these can be done relatively simply using inbuilt functions in packages such as spaCy and scikit-learn.</p>



<h3 class="wp-block-heading">Lemmatization</h3>



<p>As we discussed earlier, lemmatization collapses inflected word forms into a single vocabulary entry by mapping each word to its dictionary base form, which both shrinks the vocabulary and concentrates the signal for each concept into a single feature. We&#8217;ll use spaCy for this, which first requires downloading its small English language model:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">!python -m spacy download en_core_web_sm

nlp = spacy.load("en_core_web_sm")</pre>



<p>Our <code>lemmatise_text</code> function passes each text through spaCy&#8217;s NLP pipeline using <code>nlp.pipe()</code>, which processes them in batches of 1,000 for efficiency. For each document, it extracts the <code>.lemma_</code> attribute of every token and joins them back into a single string. One small detail worth noting: we preserve the original DataFrame index when constructing the output Series, so that rows stay correctly aligned when we assign the results back.</p>



<p>We apply lemmatization before string cleaning, since spaCy needs the original casing and punctuation to correctly identify grammatical structure. For example, &#8220;running&#8221; and &#8220;Running&#8221; lemmatize to the same thing, but removing punctuation first can confuse the parser. Once lemmatized, we pass the output through <code>apply_string_cleaning</code> as before:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">ag_news_train["title_clean"] = apply_string_cleaning(lemmatise_text(ag_news_train["title"]))
ag_news_train["description_clean"] = apply_string_cleaning(lemmatise_text(ag_news_train["description"]))

ag_news_val["title_clean"] = apply_string_cleaning(lemmatise_text(ag_news_val["title"]))
ag_news_val["description_clean"] = apply_string_cleaning(lemmatise_text(ag_news_val["description"]))

ag_news_train["text_clean"] = ag_news_train["title_clean"] + " " + ag_news_train["description_clean"]

ag_news_val["text_clean"] = ag_news_val["title_clean"] + " " + ag_news_val["description_clean"]</pre>



<p>We apply this separately to the title and description columns before concatenating them into a single <code>text_clean</code> field. As you can see, we do this for both the training and validation sets using the same function, so that lemmatization is applied consistently across both splits.</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/04/screenshot-10-lemmatisation.png" alt="" class="wp-image-703698"/></figure>



<h3 class="wp-block-heading">Removing stop words</h3>



<p>As with lemmatization, we covered the motivation for stop word removal earlier: Words like &#8220;the&#8221;, &#8220;is&#8221;, and &#8220;of&#8221; appear so frequently across all texts that they add noise rather than signal to our feature matrix. Here we&#8217;ll actually apply it to our data.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">def remove_stopwords(texts: pd.Series) -> pd.Series:
   texts = texts.fillna("").astype(str)

   filtered_texts = []
   for doc in nlp.pipe(texts, batch_size=1000):
       filtered_texts.append(
           " ".join(token.text for token in doc if not token.is_stop)
       )

   return pd.Series(filtered_texts, index=texts.index)</pre>



<p>Our <code>remove_stopwords</code> function again uses <code>nlp.pipe()</code> to process texts in batches. For each document, it filters out any token where spaCy&#8217;s <code>is_stop</code> attribute is True, and joins the remaining tokens back into a string. Conveniently, spaCy handles stop word detection using the same pipeline we already loaded for lemmatization, so no additional setup is needed.</p>



<p>We apply this to the already-cleaned and lemmatized <code>text_clean</code> column for both the training and validation sets, so the stop word removal builds directly on our previous preprocessing steps and is applied consistently across both splits.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">ag_news_train["text_no_stopwords"] = remove_stopwords(ag_news_train["text_clean"])
ag_news_val["text_no_stopwords"] = remove_stopwords(ag_news_val["text_clean"])</pre>



<h3 class="wp-block-heading">Top N terms and TF-IDF vectorization</h3>



<p>The final two improvements we&#8217;ll apply are limiting the vocabulary size and switching from raw count vectorization to TF-IDF weighting. Conveniently, scikit-learn&#8217;s <code>TfidfVectorizer</code> handles both in a single step.</p>



<p>Recall from earlier that TF-IDF downweights words that appear frequently across many documents while upweighting words that are distinctive to particular documents. This cleans up uninformative words that don’t quite qualify as stopwords, but add little useful information to our dataset. The <code>max_features=20000</code> argument caps the vocabulary at the 20,000 most frequent terms after TF-IDF scoring, which discards the long tail of rare words that are unlikely to generalize well and brings our feature matrix down to a much more manageable size. (The choice of 20,000 words is arbitrary. We could have easily used a smaller or larger number, depending on our dataset and use case.)</p>



<p>As with <code>CountVectorizer</code>, we fit only on the training data and then use that fixed vocabulary to transform both the training and validation sets:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">TfidfVectorizerNews = TfidfVectorizer(max_features=20000)
TfidfVectorizerNews.fit(ag_news_train["text_no_stopwords"])

ag_news_train_tfidf = TfidfVectorizerNews.transform(ag_news_train["text_no_stopwords"]).toarray()
ag_news_val_tfidf = TfidfVectorizerNews.transform(ag_news_val["text_no_stopwords"]).toarray()</pre>



<p>We can inspect the resulting vocabulary and feature matrix exactly as we did before:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">TfidfVectorizerNews.vocabulary_</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{'fed': np.int64(6243),
 'pension': np.int64(13134),
 'default': np.int64(4469),
 'cite': np.int64(3200),
 'failure': np.int64(6109),
 'big': np.int64(1787),
 'airline': np.int64(401),
 'payment': np.int64(13051),
 'plan': np.int64(13424),
 'government': np.int64(7306),
 'official': np.int64(12453),
 'tuesday': np.int64(18437),
 'congress': np.int64(3691),
 'hard': np.int64(7689),
 'corporation': np.int64(3901),
...}</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">pd.DataFrame(ag_news_train_tfidf, columns=TfidfVectorizerNews.get_feature_names_out())</pre>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/04/screenshot-12-tf-idf-matrix.png" alt="" class="wp-image-703905"/></figure>



<p>Compared to our baseline feature matrix of 59,544 columns filled almost entirely with zeros, this is considerably leaner. We now have 20,000 columns of weighted scores that better reflect each word&#8217;s actual importance to the document it appears in. It is still relatively sparse, but we can see from both the feature matrix and the vocabulary list that it is much more focused on semantically rich words.</p>



<h3 class="wp-block-heading">Fitting the revised model</h3>



<p>With our improved features in hand, we can now retrain the model. The call is identical to before, except we pass in the TF-IDF feature matrices instead of the raw count vectors, and the input size is now 20,000 rather than 59,544:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">baseline_model = train_text_classification_model(
    ag_news_train_tfidf,
    ag_news_train["label"].to_numpy(),
    ag_news_val_tfidf,
    ag_news_val["label"].to_numpy(),
    ag_news_train_tfidf.shape[1],
    2,
    5000
)

predictions = generate_predictions(
    baseline_model,
    ag_news_val_tfidf,
    ag_news_val["label"].to_numpy()
)</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Epoch [1/2], Train Loss: 0.3183, Train Acc: 0.8932, Val Loss: 0.2301, Val Acc: 0.9225
Epoch [2/2], Train Loss: 0.1512, Train Acc: 0.9475, Val Loss: 0.2332, Val Acc: 0.9243
Confusion Matrix - Raw Counts:
Predicted     1     2     3     4
Actual                           
1          2703    71   121   105
2            20  2955    13    12
3            68    19  2691   222
4            77    17   163  2743</pre>



<p>The results are actually very encouraging! Our overall validation accuracy is essentially unchanged at around 92%, but we&#8217;ve achieved this with a feature matrix that is less than a third of the size. This suggests that the extra vocabulary in the baseline (including the stop words) was contributing to noise rather than signal. Reducing the size of the feature matrix makes our model more stable, less prone to overfitting, and much more manageable to deploy.</p>



<p>Looking at the confusion matrix, the pattern of errors is similar to before: Sports (category two) is the easiest category to classify, with 98.5% accuracy, while Business (category three) and Science/Technology (category four) remain the hardest to separate, with around 7% of articles in each category being misclassified as the other. This is consistent with what we saw in the baseline, so it seems that the preprocessing improvements have tightened things up at the margins, but the fundamental difficulty of the Business/Technology boundary is a property of the data rather than the feature representation.</p>



<h3 class="wp-block-heading">Applying our model to the test set</h3>



<p>Finally, we need to validate that our model performs as well on the test set as it does on the validation set. Up to this point, we&#8217;ve deliberately kept the test set locked away. As mentioned earlier, if we had been making modeling decisions based on test set performance, we&#8217;d risk inadvertently overfitting our choices to it, and our final accuracy estimate would be optimistic.</p>



<p>The preprocessing steps must be applied in exactly the same order as for the training and validation data: lemmatization, string cleaning, concatenation of title and description, and stop-word removal. Crucially, we also call <code>.transform()</code> rather than <code>.fit_transform()</code> on the test text, using the vocabulary learned from the training data:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">ag_news_test["title_clean"] = apply_string_cleaning(lemmatise_text(ag_news_test["title"]))
ag_news_test["description_clean"] = apply_string_cleaning(lemmatise_text(ag_news_test["description"]))
ag_news_test["text_clean"] = ag_news_test["title_clean"] + " " + ag_news_test["description_clean"]
ag_news_test["text_no_stopwords"] = remove_stopwords(ag_news_test["text_clean"])

ag_news_test_tfidf = TfidfVectorizerNews.transform(ag_news_test["text_no_stopwords"]).toarray()</pre>



<p>We can then generate predictions and evaluate accuracy on the test set:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">test_predictions = generate_predictions(
    baseline_model,
    ag_news_test_tfidf,
    ag_news_test["label"].to_numpy()
)

test_accuracy = accuracy_score(ag_news_test["label"].to_numpy(), test_predictions)
print(f"Test Accuracy: {test_accuracy:.4f}")</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Test Accuracy: 0.9183

Confusion Matrix - Raw Counts:
Predicted     1     2     3     4
Actual                           
1          1710    54    78    58
2            13  1870    10     7
3            51    12  1676   161
4            53     9   115  1723</pre>



<p>The test accuracy of 91.8% is very close to the 92.4% we saw on the validation set, which is a reassuring sign that our model has generalized well rather than overfitting to the validation data. The confusion matrix tells the same story as before: Sports (category two) remains the easiest category to classify, with only 30 misclassified articles out of 1,900, while the Business/Technology boundary continues to be the main source of errors, with around 8% of articles in each category being misclassified as the other. The consistency between validation and test results gives us confidence that these error patterns reflect genuine properties of the data rather than artifacts of any particular split.</p>



<h2 class="wp-block-heading">Limitations and alternatives</h2>



<h3 class="wp-block-heading">Loses word order information</h3>



<p>The most fundamental limitation of the bag-of-words model is right there in the name: it treats text as an unordered collection of words, discarding all sequence information. This means &#8220;the dog bit the man&#8221; and &#8220;the man bit the dog&#8221; produce identical vectors, even though they describe very different events. For many classification tasks, this doesn&#8217;t matter much, but for tasks that require understanding the relationship between words, such as question answering or natural language inference, the loss of word order is a serious handicap.</p>



<h3 class="wp-block-heading">Ignores semantics and context</h3>



<p>BoW has no notion of word meaning or context. Each word is simply a column in a matrix, entirely independent of every other word. This creates two related problems. First, synonyms are treated as completely distinct features: &#8220;cheap&#8221; and &#8220;inexpensive&#8221; contribute nothing to each other&#8217;s signal, even though they mean the same thing. Second, words with multiple meanings are treated as a single feature regardless of context: &#8220;bank&#8221; means the same thing whether it appears in a sentence about rivers or finance. Both of these issues limit how well BoW representations can capture the actual semantics of a text.</p>



<h3 class="wp-block-heading">Can result in large, sparse vectors</h3>



<p>As we saw in our own example, even a moderately sized corpus of news headlines can produce a vocabulary of nearly 60,000 unique terms. The resulting feature matrix has one column per vocabulary word, but any individual document only uses a tiny fraction of them, leaving the vast majority of values at zero. This sparsity creates two practical problems: The matrices can consume a large amount of memory if stored densely, and the high dimensionality can make it harder for models to find meaningful patterns, a phenomenon sometimes called the curse of dimensionality.</p>



<h3 class="wp-block-heading">Alternatives</h3>



<p>If BoW&#8217;s limitations are a bottleneck for your task, there are several well-established alternatives worth considering.</p>



<ul>
<li><strong>Word embeddings (Word2Vec and GloVe)</strong> address the semantics problem by representing each word as a dense vector in a continuous space, where similar words are geometrically close to each other. They capture distributional meaning far more richly than BoW, and are a natural next step when synonym handling or word similarity matters. Doc2Vec extends this idea to produce embeddings for entire documents rather than individual words.</li>



<li><strong>Transformer-based models (BERT and GPT)</strong> go further still, generating contextual representations where the same word receives a different vector depending on the surrounding text. This handles polysemy directly and captures complex long-range dependencies between words. The trade-off is substantially higher computational cost and complexity compared to BoW.</li>



<li><strong>Topic models like latent Dirichlet allocation (LDA)</strong> take a different angle entirely. Rather than encoding documents for downstream classification, they are generative models that discover latent thematic structure in a corpus. This is useful when your goal is exploration and interpretation rather than prediction.</li>
</ul>



<p>For tasks where BoW already performs well, as we saw here with AG News, the added complexity of these approaches may not be worth the cost. BoW remains a strong baseline, and it&#8217;s always worth establishing how far it can take you before reaching for heavier machinery.</p>



<h2 class="wp-block-heading">Get started with PyCharm today</h2>



<p>In this post, we&#8217;ve covered a lot of ground: from the fundamentals of the bag-of-words model and how it converts text into numerical vectors, through to building and iteratively improving a real text classification pipeline on the AG News dataset. Along the way, we&#8217;ve seen how preprocessing steps like lemmatization, stop word removal, vocabulary capping, and TF-IDF weighting can meaningfully improve the efficiency of your feature representation, and how PyCharm&#8217;s DataFrame viewer, column statistics, chart view, and AI Assistant make each of these steps faster and easier to inspect and debug.</p>



<p>If you&#8217;d like to try this yourself, <a href="https://www.jetbrains.com/pycharm/download/?section=windows" target="_blank" rel="noopener">PyCharm Pro</a> comes with a 30-day trial. As we saw in this tutorial, its built-in support for Jupyter notebooks, virtual environments, and scientific libraries means you can go from a blank project to a working NLP pipeline with minimal setup friction, leaving you free to focus on the fun parts.&nbsp;</p>



<p>You can find the <a href="https://github.com/t-redactyl/ag-news-bag-of-words-classification" target="_blank" rel="noopener">full code</a> for this project on GitHub. If you&#8217;re interested in exploring more NLP topics, check out our recent blogs <a href="https://blog.jetbrains.com/pycharm/">here</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>PyCharm for Django Fundraiser: Why Django Matters in the AI Era – And Why We’re Supporting It</title>
		<link>https://blog.jetbrains.com/pycharm/2026/04/pycharm-for-django-fundraiser-why-django-matters-in-the-ai-era-and-why-we-re-supporting-it/</link>
		
		<dc:creator><![CDATA[Valeria Letusheva]]></dc:creator>
		<pubDate>Wed, 22 Apr 2026 12:15:34 +0000</pubDate>
		<featuredImage>https://blog.jetbrains.com/wp-content/uploads/2026/04/Blog_1280x720-4.png</featuredImage>		<category><![CDATA[pycharm]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[oss]]></category>
		<guid isPermaLink="false">https://blog.jetbrains.com/?post_type=pycharm&#038;p=702538</guid>

					<description><![CDATA[Spend a few minutes around developer content, and it’s easy to come away with the impression that web apps now appear to almost write themselves. Everything that follows – review, verification, refactoring, debugging, and the open-source frameworks that make those apps dependable – gets less attention. AI can speed up code generation, but it does [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>Spend a few minutes around developer content, and it’s easy to come away with the impression that web apps now appear to almost write themselves.</p>



<p>Everything that follows – review, verification, refactoring, debugging, and the open-source frameworks that make those apps dependable – gets less attention. AI can speed up code generation, but it does not remove the need for stable foundations. A lot of AI-generated code works because it’s built on top of mature open-source frameworks, libraries, and documentation.&nbsp;</p>



<blockquote class="wp-block-quote">
<p>AI can scaffold a web app in thirty seconds. Django is what keeps it running for ten years. That gap is only getting more valuable.</p>
<cite>Will Vincent, former Django Board Member, co-host of the Django Chat podcast and co-writer of the weekly Django News newsletter</cite></blockquote>



<p>As AI makes OSS easier to consume, it can also make the work behind it easier to overlook. But OSS still needs support – perhaps more than ever.</p>



<h2 class="wp-block-heading">PyCharm for Django Fundraiser</h2>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/04/Blog_1280x720-4.png" alt="" class="wp-image-702548"/></figure>



<p>PyCharm has supported Django through fundraising campaigns and ongoing collaboration with the Django Software Foundation (DSF). This year, we’re doing it again.</p>



<p>Together with the Django community, this campaign raised $350,000 for Django from 2016 to 2025. That support helps keep Django secure, stable, relevant, and sustainable, while also supporting community programs such as Django Girls and official events. Previous PyCharm fundraisers accounted for approximately 25% of the DSF budget, according to Django’s official blog.</p>



<blockquote class="wp-block-quote">
<p>Django is the rare framework that rewards you the longer you use it: mature, dependable, and still innovating. Best-in-class software, matched by one of the most welcoming communities in open source.</p>
<cite>Will Vincent, former Django Board Member, co-host of the Django Chat podcast and co-writer of the weekly Django News newsletter</cite></blockquote>



<p>If Django has helped you learn, ship, or maintain real web products, this is a direct way to give back.</p>



<p>You can donate to the Django Software Foundation <a href="https://www.djangoproject.com/fundraising/" target="_blank" rel="noopener">directly</a>, or you can support Django through this fundraiser and get a tool you&#8217;ll rely on every day.</p>



<blockquote class="wp-block-quote">
<p>Django&#8217;s ‘batteries included’ philosophy was built for humans who wanted to ship fast. Turns out it&#8217;s perfect for AI agents too — fewer decisions, fewer dependencies, and fewer ways to go wrong. </p>
<cite>Will Vincent, former Django Board Member, co-host of the Django Chat podcast and co-writer of the weekly Django News newsletter</cite></blockquote>



<h2 class="wp-block-heading">The offer</h2>



<p>During this campaign, get 30% off PyCharm Pro, with 100% of the proceeds going to the DSF. Or you can bundle PyCharm Pro with the JetBrains AI Pro plan and get 40% off PyCharm Pro.</p>



<p>This campaign ends in less than two weeks, so act now!</p>


    <div class="buttons">
        <div class="buttons__row">
                                                <a href="https://www.jetbrains.com/pycharm/promo/support-django/" class="btn " target="_blank" rel="noopener">Get the offer</a>
                                    </div>
    </div>







<h2 class="wp-block-heading">Why PyCharm Pro</h2>



<h3 class="wp-block-heading">Perfect for your workflow</h3>



<p>The hard part of modern development is often not writing code from scratch – it’s understanding the whole project well enough to change it safely.</p>



<p>That’s where PyCharm Pro proves its value:</p>



<ul>
<li>Navigate and refactor across your entire Django project, from templates to databases.</li>



<li>Work with databases without leaving the IDE.</li>



<li><a href="https://www.jetbrains.com/pycharm/web-development/django/" target="_blank" rel="noopener">Build and debug Django templates</a> with full awareness of your context.&nbsp;</li>



<li>Develop frontend code with built-in support for JavaScript, TypeScript, and major frameworks.</li>



<li>Run and debug remote and Docker-based environments with ease</li>
</ul>



<blockquote class="wp-block-quote">
<p>No editor understands Django like PyCharm does — from template tags to ORM queries to migrations, it sees the whole stack the way you do. </p>
<cite>Will Vincent, former Django Board Member, co-host of the Django Chat podcast and co-writer of the weekly Django News newsletter</cite></blockquote>



<blockquote class="wp-block-quote">
<p>For Django work, I think PyCharm is one of the best tools available. I use it every day. If you haven’t given it a try, this campaign is a great opportunity – AND it supports the Django Software Foundation! </p>
<cite>Sarah Boyce, Django Fellow and Djangonaut Space co-organizer</cite></blockquote>



<h3 class="wp-block-heading">AI on your terms</h3>



<p>If you want AI in PyCharm, you can start with <a href="https://www.jetbrains.com/ai-ides/" target="_blank" rel="noopener">JetBrains AI</a> directly in the IDE.<strong> </strong>You can also shape it to fit your workflow. Bring your own key, sign in with a supported provider, use third-party or local models, or connect compatible agents such as Claude Code and Codex via ACP.</p>



<p>That gives you more control over how you work with AI, instead of locking you into a single workflow, model, or provider. And if AI isn’t what you need, you can simply turn it off.</p>



<h3 class="wp-block-heading">Support the framework you use every day</h3>



<p>If Django is part of how you build, this purchase can improve your workflow while also investing in the framework behind it.</p>


    <div class="buttons">
        <div class="buttons__row">
                                                <a href="https://www.jetbrains.com/pycharm/promo/support-django/" class="btn " target="_blank" rel="noopener">Get the offer</a>
                                    </div>
    </div>







<p>Happy coding!</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>How (Not) to Learn Python</title>
		<link>https://blog.jetbrains.com/pycharm/2026/04/how-not-to-learn-python/</link>
		
		<dc:creator><![CDATA[Cheuk Ting Ho]]></dc:creator>
		<pubDate>Fri, 10 Apr 2026 14:21:21 +0000</pubDate>
		<featuredImage>https://blog.jetbrains.com/wp-content/uploads/2026/04/PC-social-BlogFeatured-1280x720-1.png</featuredImage>		<guid isPermaLink="false">https://blog.jetbrains.com/?post_type=pycharm&#038;p=696301</guid>

					<description><![CDATA[While listening to Mark Smith’s inspirational talk for Python Unplugged on PyTV about How to Learn Python, what caught my attention was that Mark suggested turning off some of PyCharm’s AI features to help you learn Python more effectively. As a PyCharm user myself, I’ve found the AI-powered features beneficial in my day-to-day work; however, [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>While listening to <a href="https://www.youtube.com/watch?v=i6SdsSj96ys" target="_blank" rel="noopener">Mark Smith’s inspirational talk</a> for <em>Python Unplugged on PyTV </em>about <em>How to Learn Python</em>, what caught my attention was that Mark suggested turning off some of PyCharm’s AI features to help you learn Python more effectively.</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/04/image-2.png" alt="" class="wp-image-696367"/></figure>



<p>As a PyCharm user myself, I’ve found the AI-powered features beneficial in my day-to-day work; however, I never considered that I could turn certain features on or off to customize my experience. This can be done from the settings menu under <em>Editor</em> | <em>General</em> | <em>Code Completion</em> | <em>Inline</em>.</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/04/image1-1.png" alt="" class="wp-image-700369"/></figure>



<p>While we are at it, let’s have a look at these features and investigate in more detail why they are great for professional developers but may not be ideal for learners.</p>



<h2 class="wp-block-heading">Local full line code completion suggestions</h2>



<p>JetBrains AI credits are not consumed when you use local line completion. The completion prediction is performed using a built-in local deep learning model. To use this feature, make sure the box for <em>Enable inline completion using language models</em> is checked, and choose either <em>Local</em> or <em>Cloud and local</em> in the options. To show the complete results using the local model alone, we will look at the predictions when only <em>Local</em> is selected.</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/04/image2-1.png" alt="" class="wp-image-700380"/></figure>



<p>When it’s selected, you see that the only code completion available out of the box in PyCharm is for Python. To make suggestions available for CSS or HTML, you need to download additional models.</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/04/image3-1.png" alt="" class="wp-image-700391"/></figure>



<p>When you are writing code, you will see suggestions pop up in grey with a hint for you to use <em>Tab</em> to complete the line.&nbsp;</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/04/image4.png" alt="" class="wp-image-700402"/></figure>



<p>After completing that line, you can press <em>Enter</em> to go to the next one, where there may be a new suggestion that you can again use <em>Tab</em> to complete. As you see, this can be very convenient for developers in their daily coding, as it saves time that would otherwise be spent typing obvious lines of code that follow the flow naturally.&nbsp;</p>



<p>However, for beginners, mindlessly hitting <em>Tab</em> and letting the model complete lines may discourage them from learning how to use the functions correctly. An alternative is to use the hint provided by PyCharm to help you choose an appropriate method from the available list, determine which parameters are needed, check the documentation if necessary, and write the code yourself. Here is what the hint looks like when code completion is turned off:</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/04/image5.png" alt="" class="wp-image-700413"/></figure>



<h2 class="wp-block-heading">Cloud-based completion suggestions</h2>



<p>Let’s have a look at cloud-based completion in contrast to local completion. When using cloud-based completion, next-edit suggestions are also available (which we will look at in more detail in the next section).</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/04/image6.png" alt="" class="wp-image-700424"/></figure>



<p> Cloud-based completion comes with support for multiple languages by default, and you can switch it on or off for each language individually.</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" src="https://blog.jetbrains.com/wp-content/uploads/2026/04/image-1.png" alt="" class="wp-image-696348"/></figure>



<p>Cloud-based completion provides more functionality than local model completion, but you need a JetBrains AI subscription to use it.</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/04/image8.png" alt="" class="wp-image-700446"/></figure>



<p>You may also connect to a third-party AI provider for your cloud-based completion. Since this support is still in Beta in PyCharm 2026.1, it is highly recommended to keep your JetBrains AI subscription active as a backup to ensure all features are available.</p>



<p>After switching to cloud-based completion, one of the differences I noticed was that it is better at multiple-line completion, which can be more convenient. However, I have also encountered situations where the completion provided too much for me, and I had to jump in to make my own modifications after accepting the suggestions.</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/04/image9.png" alt="" class="wp-image-700457"/></figure>



<p>For learners of Python, again, you may want to disable this functionality or have to audit all the suggestions in detail yourself. In addition to the danger of relying too heavily on code completion, which removes opportunities to learn, cloud code completion poses another risk for learners. Because larger suggestions require active review from the developer, learners may not be equipped to fully audit the wholesale suggestions they are accepting. Disabling this feature for learners not only encourages learning, but it can also help prevent mistakes.</p>



<h2 class="wp-block-heading">Next edit suggestions</h2>



<p>In addition to cloud-based completion, JetBrains AI Pro, Ultimate, and Enterprise users are able to take advantage of next edit suggestions.</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/04/image10.png" alt="" class="wp-image-700468"/></figure>



<p>When they are enabled, every time you make changes to your code, for example, renaming a variable, you will be given suggestions about other places that need to be changed.</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/04/nes.gif" alt="" class="wp-image-700347"/></figure>



<p>And when you press <em>Tab</em>, the changes will be made automatically. You can also customize this behavior so you can see previews of the changes and jump continuously to the next edit until no more are suggested.</p>



<p>This is, no doubt, a very handy feature. It can help you avoid some careless mistakes, like forgetting to refactor your code when you make changes. However, for learners, thinking about what needs to be done is a valuable thought exercise, and using this feature can deprive them of some good learning opportunities.</p>



<h2 class="wp-block-heading">Conclusion</h2>



<p>PyCharm offers a lot of useful features to smooth out your day-to-day development workflow. However, these features may be too powerful, and even too convenient, for those who have just started working with Python and need to learn by making mistakes. It is good to use AI features to improve our work, but we also need to double-check the results and make sure that we want what the AI suggests.</p>



<p>To learn more about how to level up your Python skills, I highly recommend watching <a href="https://www.youtube.com/watch?v=i6SdsSj96ys" target="_blank" rel="noopener">Mark’s talk on PyTV</a> and checking out all the <a href="https://www.jetbrains.com/help/ai-assistant/getting-started-with-ai-assistant.html" target="_blank" rel="noopener">AI features</a> that JetBrains AI has to offer. I hope you will find the perfect way to integrate them into your work while remaining ready to turn them off when you plan to learn something new.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>How to Train Your First TensorFlow Model in PyCharm</title>
		<link>https://blog.jetbrains.com/pycharm/2026/04/how-to-train-your-first-tensorflow-model/</link>
		
		<dc:creator><![CDATA[Evgenia Verbina]]></dc:creator>
		<pubDate>Tue, 07 Apr 2026 10:36:35 +0000</pubDate>
		<featuredImage>https://blog.jetbrains.com/wp-content/uploads/2026/04/PC-social-BlogFeatured-1280x720-1-1.png</featuredImage>		<category><![CDATA[data-science]]></category>
		<category><![CDATA[tutorials]]></category>
		<category><![CDATA[tensorflow]]></category>
		<category><![CDATA[tensors]]></category>
		<guid isPermaLink="false">https://blog.jetbrains.com/?post_type=pycharm&#038;p=697464</guid>

					<description><![CDATA[This is a guest post from Iulia Feroli, founder of the Back To Engineering community on YouTube. TensorFlow is a powerful open-source framework for building machine learning and deep learning systems. At its core, it works with tensors (a.k.a multi‑dimensional arrays) and provides high‑level libraries (like Keras) that make it easy to transform raw data [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p><em>This is a guest post from </em><strong><em><a href="https://blog.jetbrains.com/pycharm/2026/04/how-to-train-your-first-tensorflow-model/#author" data-type="link" data-id="https://blog.jetbrains.com/pycharm/2026/04/how-to-train-your-first-tensorflow-model/#author">Iulia Feroli</a></em></strong><em>, founder of the Back To Engineering community on YouTube.</em></p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/04/PC-social-BlogFeatured-1280x720-1-1.png" alt="How to Train Your First TensorFlow Model in PyCharm" class="wp-image-697465"/></figure>



<p><a href="https://www.tensorflow.org/" target="_blank" rel="noopener">TensorFlow</a> is a powerful open-source framework for building machine learning and deep learning systems. At its core, it works with tensors (a.k.a multi‑dimensional arrays) and provides high‑level libraries (like Keras) that make it easy to transform raw data into models you can train, evaluate, and deploy.</p>



<p>TensorFlow helps you handle the full pipeline: loading and preprocessing data, assembling models from layers and activations, training with optimizers and loss functions, and exporting for serving or even running on edge devices (including lightweight TensorFlow Lite models on Raspberry Pi and other microcontrollers).&nbsp;</p>



<p>If you want to make data-driven applications, prototyping neural networks, or ship models to production or devices, learning TensorFlow gives you a consistent, well-supported toolkit to go from idea to deployment.</p>



<p>If you’re brand new to TensorFlow, start by watching the <strong><a href="https://www.youtube.com/watch?v=hm07b8ETaso" data-type="link" data-id="https://www.youtube.com/watch?v=hm07b8ETaso" target="_blank" rel="noopener">short overview video</a></strong> where I explain tensors, neural networks, layers, and why TensorFlow is great for taking data → model → deployment, and how all of this can be explained with a LEGO-style pieces sorting example.&nbsp;</p>



<p>In this blog post, I’ll walk you through a first, stripped-down TensorFlow implementation notebook so we can get started with some practical experience. You can also watch the walkthrough video to follow along.</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="Build Your First TensorFlow Model in Python (A Step-by-Step Tutorial)" src="https://www.youtube.com/embed/nswGrvOhaOY?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<p>We&#8217;ll be exploring a very simple use case today: load the Fashion MNIST dataset, build two very simple Keras models, train and compare them, then dig into visualizations (predictions, confidence bars, confusion matrix). I kept the code minimal and readable so you can focus on the ideas – and you’ll see how <a href="https://www.jetbrains.com/pycharm/data-science/" target="_blank" rel="noopener">PyCharm</a> helps along the way.</p>



<h2 class="wp-block-heading">Training TensorFlow models step by step</h2>



<h3 class="wp-block-heading">Getting started in PyCharm</h3>



<p>We&#8217;ll be leveraging PyCharm&#8217;s native Notebook integration to build out <a href="https://github.com/iuliaferoli/TensorFlow_with_pycharm" target="_blank" rel="noopener">our project</a>. This way, we can inspect each step of the pipeline and use some supporting visualization along the way. We&#8217;ll <a href="https://www.jetbrains.com/help/pycharm/creating-empty-project.html" target="_blank" rel="noopener">create a new project</a> and <a href="https://www.jetbrains.com/help/pycharm/creating-virtual-environment.html" target="_blank" rel="noopener">generate a virtual environment</a> to manage our dependencies.&nbsp;</p>



<p>If you&#8217;re running the code from the attached repo, you can install directly from the requirements file. If you wish to expand this example with additional visualizations for further models, you can easily add more packages to your requirements as you go by using the PyCharm package manager helpers for <a href="https://www.jetbrains.com/guide/python/tips/install-and-import/)%20and" target="_blank" rel="noopener">installing</a> and <a href="https://www.jetbrains.com/help/pycharm/installing-uninstalling-and-upgrading-packages.html" target="_blank" rel="noopener">upgrading</a>.</p>



<h3 class="wp-block-heading">Load <code>Fashion MNIST</code> and inspect the data</h3>



<p><code>Fashion MNIST</code> is a great starter because the images are small (28×28 pixels), visually meaningful, and easy to interpret. They represent various garment types as pixelated black-and-white images, and provide the relevant labels for a well-contained classification task. We can first take a look at our data sample by printing some of these images with various matplotlib functions:</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/04/image1.png" alt="" class="wp-image-699830"/></figure>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">```
fig, axes = plt.subplots(2, 5, figsize=(10, 4))
for i, ax in enumerate(axes.flat):
    ax.imshow(x_train[i], cmap='gray')
    ax.set_title(class_names[y_train[i]])
    ax.axis('off')
plt.show()
```
# Two simple models (a quick experiment)
```
model1 = models.Sequential([
    layers.Flatten(input_shape=(28, 28)),
    layers.Dense(128, activation='relu'),
    layers.Dense(10, activation='softmax')
])
model2 = models.Sequential([
    layers.Flatten(input_shape=(28, 28)),
    layers.Dense(128, activation='relu'),
    layers.Dense(128, activation='relu'),
    layers.Dense(10, activation='softmax')
])
```</pre>



<h3 class="wp-block-heading">Compile and train your first model</h3>



<p>From here, we can compile and train our first TensorFlow model(s). With PyCharm’s code completion features and documentation access, you can get instant suggestions for building out these simple code blocks.</p>



<p>For a first try at TensorFlow, this allows us to spin up a working model with just a few presses of <em>Tab</em> in our IDE. We&#8217;re using the recommended standard optimizer and loss function, and we&#8217;re tracking for accuracy. We can choose to build multiple models by playing around with the number or type of layers, along with the other parameters.&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">```
model1.compile(
    optimizer='adam',
    loss='sparse_categorical_crossentropy',
    metrics=['accuracy']
)
model1.fit(x_train, y_train, epochs=10)
model2.compile(
    optimizer='adam',
    loss='sparse_categorical_crossentropy',
    metrics=['accuracy']
)
model2.fit(x_train, y_train, epochs=15)
```</pre>



<h3 class="wp-block-heading">Evaluate and compare your TensorFlow model performance</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">```
loss1, accuracy1 = model1.evaluate(x_test, y_test)
print(f'Accuracy of model1: {accuracy1:.2f}')
loss2, accuracy2 = model2.evaluate(x_test, y_test)
print(f'Accuracy of model2: {accuracy2:.2f}')
```</pre>



<p>Once the models are trained (and you can see the epochs progressing visually as each cell is run), we can immediately evaluate the performance of the models.</p>



<p>In my experiment, <code>model1</code> sits around ~0.88 accuracy, and while <code>model2</code> is a little higher than that, it took 50% longer to train. That’s the kind of trade‑off you should be thinking about: Is a tiny accuracy gain worth the additional compute and complexity?&nbsp;</p>



<p>We can dive further into the results of the model run by generating a DataFrame instance of our new prediction dataset. Here we can also leverage built-in functions like `describe` to quickly get some initial statistical impressions:</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/04/image2.png" alt="" class="wp-image-699841"/></figure>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">```
predictions = model1.predict(x_test)
import pandas as pd
df_pred = pd.DataFrame(predictions, columns=class_names)
df_pred.describe()
```</pre>



<p>However, the most useful statistics will compare our model&#8217;s prediction with the ground truth &#8220;real&#8221; labels of our dataset. We can also break this down by item category:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">```
y_pred = model1.predict(x_test).argmax(axis=1)
cm = confusion_matrix(y_test, y_pred)
plt.figure(figsize=(8,6))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', xticklabels=class_names, yticklabels=class_names)
plt.xlabel('Predicted')
plt.ylabel('True')
plt.title('Confusion Matrix')
plt.show()
print('Classification report:')
print(classification_report(y_test, y_pred, target_names=class_names))
```</pre>



<p>From here, we can notice that the accuracy differs quite a bit by type of garment. A possible interpretation of this is that trousers are quite a distinct type of clothing from, say, t-shirts and shirts, which can be more commonly confused.&nbsp;</p>



<p>This is, of course, the type of nuance that, as humans, we can pick up by looking at the images, but the model only has access to a matrix of pixel values. The data does seem, however, to confirm our intuition. We can further build a more comprehensive visualization to test this hypothesis.&nbsp;</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/04/image-4.png" alt="" class="wp-image-697493"/></figure>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">```
import numpy as np
import matplotlib.pyplot as plt
# pick 8 wrong examples
y_pred = predictions.argmax(axis=1)
wrong_idx = np.where(y_pred != y_test)[0][:8]  # first 8 mistakes
n = len(wrong_idx)
fig, axes = plt.subplots(n, 2, figsize=(10, 2.2 * n), constrained_layout=True)
for row, idx in enumerate(wrong_idx):
    p = predictions[idx]
    pred = int(np.argmax(p))
    true = int(y_test[idx])
    axes[row, 0].imshow(x_test[idx], cmap="gray")
    axes[row, 0].axis("off")
    axes[row, 0].set_title(
        f"WRONG  P:{class_names[pred]} ({p[pred]:.2f})  T:{class_names[true]}",
        color="red",
        fontsize=10
    )
    bars = axes[row, 1].bar(range(len(class_names)), p, color="lightgray")
    bars[pred].set_color("red")
    axes[row, 1].set_ylim(0, 1)
    axes[row, 1].set_xticks(range(len(class_names)))
    axes[row, 1].set_xticklabels(class_names, rotation=90, fontsize=8)
    axes[row, 1].set_ylabel("conf", fontsize=9)
plt.show()
```</pre>



<p>This table generates a view where we can explore the confidence our model had in a prediction: By exploring which weight each class was given, we can see where there was doubt (i.e. multiple classes with a higher weight) versus when the model was certain (only one guess). These examples further confirm our intuition: top-types appear to be more commonly confused by the model.&nbsp;</p>



<h2 class="wp-block-heading">Conclusion</h2>



<p>And there we have it! We were able to set up and train our first model and already drive some data science insights from our data and model results. Using some of the PyCharm functionalities at this point can speed up the experimentation process by providing access to our documentation and applying code completion directly in the cells. We can even use AI Assistant to help generate some of the graphs we&#8217;ll need to further evaluate the TensorFlow model performance and investigate our results.</p>



<p>You can <a href="https://github.com/iuliaferoli/TensorFlow_with_pycharm" target="_blank" rel="noopener">try out this notebook yourself</a>, or better yet, try to generate it with these same tools for a more hands-on learning experience.</p>



<h2 class="wp-block-heading">Where to go next</h2>



<p><a href="https://github.com/iuliaferoli/TensorFlow_with_pycharm" target="_blank" rel="noopener">This notebook</a> is a minimal, teachable starting point. Here are some practical next steps to try afterwards:</p>



<ul>
<li>Replace the dense baseline with a small CNN (Conv2D → MaxPooling → Dense).</li>



<li>Add dropout or batch normalization to reduce overfitting.</li>



<li>Apply data augmentation (random shifts/rotations) to improve generalization.</li>



<li>Use callbacks like <code>EarlyStopping</code> and <code>ModelCheckpoint</code> so training is efficient, and you keep the best weights.</li>



<li>Export a <code>SavedModel</code> for server use or convert to TensorFlow Lite for edge devices (Raspberry Pi, microcontrollers).</li>
</ul>



<h2 class="wp-block-heading">Frequently asked questions</h2>



<h3 class="wp-block-heading">When should I use TensorFlow?</h3>



<p>TensorFlow is best used when building machine learning or deep learning models that need to scale, go into production, or run across different environments (cloud, mobile, edge devices).&nbsp;</p>



<p>TensorFlow is particularly well-suited for large-scale models and neural networks, including scenarios where you need strong deployment support (TensorFlow Serving, TensorFlow Lite). For research prototypes, TensorFlow is viable, but it’s more commonplace to use lightweight frameworks for easier experimentation.</p>



<h3 class="wp-block-heading">Can TensorFlow run on a GPU?</h3>



<p>Yes, TensorFlow can run GPUs and TPUs. Additionally, using a GPU can significantly speed up training, especially for deep learning models with large datasets. The best part is, TensorFlow will automatically use an available GPU if it’s properly configured.</p>



<h3 class="wp-block-heading">What is loss in TensorFlow?</h3>



<p>Loss (otherwise known as loss function) measures how far a model’s predictions are from the actual target values. Loss in TensorFlow is a numerical value representing the distance between predictions and actual target values. A few examples include:&nbsp;</p>



<ul>
<li>MSE (mean squared error), used in regression tasks.</li>



<li>Cross-entropy loss, often used in classification tasks.</li>
</ul>



<h3 class="wp-block-heading">How many epochs should I use?</h3>



<p>There’s no set number of epochs to use, as it depends on your dataset and model. Typical approaches cover:&nbsp;</p>



<ul>
<li>Starting with a conservative number (10–50 epochs).</li>



<li>Monitoring validation loss/accuracy and adjusting based on the results you see.</li>



<li>Using early stopping to halt training when improvements decrease.</li>
</ul>



<p>An epoch is one full pass through your training data. Not enough passes through leads to underfitting, and too many can cause overfitting. The sweet spot is where your model generalizes best to unseen data.&nbsp;</p>



<h2 class="wp-block-heading" id="author">About the author</h2>


    <div class="about-author ">
        <div class="about-author__box">
            <div class="row">
                                                            <div class="about-author__box-img">
                            <img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" src="https://blog.jetbrains.com/wp-content/uploads/2026/04/Iulia-Feroli-e1775558363746.png" alt="" loading="lazy">
                        </div>
                                        <div class="about-author__box-text">
                                                    <h4>Iulia Feroli</h4>
                                                <p><span style="font-weight: 400;">Iulia’s mission is to make tech exciting, understandable, and accessible to the new generation.</span></p>
<p><span style="font-weight: 400;">With a background spanning data science, AI, cloud architecture, and open source, she brings a unique perspective on bridging technical depth with approachability.</span></p>
<p><span style="font-weight: 400;">She’s building her own brand, Back To Engineering, through which she creates a community for tech enthusiasts, engineers, and makers. From YouTube videos on building robots from scratch, to conference talks or keynotes about real, grounded AI, and technical blogs and tutorials </span><span style="font-weight: 400;">–</span><span style="font-weight: 400;"> Iulia shares her message worldwide on how to turn complex concepts into tools developers can use every day.</span></p>
                    </div>
                            </div>
        </div>
    </div>



<p></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>What’s New in PyCharm 2026.1</title>
		<link>https://blog.jetbrains.com/pycharm/2026/03/what-s-new-in-pycharm-2026-1/</link>
		
		<dc:creator><![CDATA[Ilia Afanasiev]]></dc:creator>
		<pubDate>Mon, 30 Mar 2026 15:31:08 +0000</pubDate>
		<featuredImage>https://blog.jetbrains.com/wp-content/uploads/2026/03/PC-releases-BlogFeatured-1280x720-1.png</featuredImage>		<category><![CDATA[releases]]></category>
		<guid isPermaLink="false">https://blog.jetbrains.com/?post_type=pycharm&#038;p=687025</guid>

					<description><![CDATA[Welcome to PyCharm 2026.1. This release doesn’t just add features – it rethinks how you build, debug, and scale Python projects. From a brand-new debugging engine powered by debugpy to first-class uv support on remote targets and expanded JavaScript support in the free tier, this version is all about removing friction and letting you focus [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>Welcome to PyCharm 2026.1. This release doesn’t just add features – it rethinks how you build, debug, and scale Python projects. From a brand-new debugging engine powered by debugpy to first-class uv support on remote targets and expanded JavaScript support in the free tier, this version is all about removing friction and letting you focus on your code. Whether you’re working locally, over SSH, or inside Docker, PyCharm now adapts to your setup instead of the other way around.</p>



<p>In this post, we’ll explore the highlights of this update and show you how these improvements can streamline your daily workflow.</p>



<h2 class="wp-block-heading">Standardizing the future of debugging with debugpy</h2>



<p>PyCharm now offers the option to use debugpy as the default debugger backend, providing the industry-standard Debug Adapter Protocol (DAP) that aligns the IDE with the broader Python ecosystem. By replacing complex, legacy socket-waiting logic with a more stable connection model, race conditions and timing edge cases will no longer interfere with your debugging experience.</p>



<h3 class="wp-block-heading">A modern foundation for Python development</h3>



<p>The new engine provides full native support for <a href="https://peps.python.org/pep-0669/" target="_blank" rel="noopener">PEP 669</a>, utilizing Python 3.12’s low-impact monitoring API to significantly reduce debugger overhead compared to the legacy <code>sys.settrace()</code> approach. This ensures that your debugging sessions are faster and less intrusive. Furthermore, the migration introduces comprehensive <code>asyncio</code> support. You can now use the full suite of debugger tools, such as the debug console and expression evaluation, directly within async contexts for modern frameworks like FastAPI and aiohttp.&nbsp;</p>



<h3 class="wp-block-heading">Reliability across environments</h3>



<p>Beyond performance improvements, debugpy simplifies the <em>Attach to Process</em> experience by providing a standardized approach for Docker containers, remote servers on AWS, Azure, or GCP, and local running processes. For specialized workflows, we have introduced a new <em>Attach to DAP</em> run configuration. This allows you to connect to targets using the <code>debugpy.listen()</code> command, eliminating the friction of manual connection management and allowing you to focus on your code instead of debugging infrastructure.</p>



<figure class="wp-block-video"><video controls src="https://blog.jetbrains.com/wp-content/uploads/2026/03/debugpy.webm"></video></figure>



<h2 class="wp-block-heading">Support for uv as a remote interpreter</h2>



<p>Many developers work on projects where the code and dependencies live on a remote server – whether via SSH, in WSL, or inside Docker. By connecting PyCharm to a remote machine and using uv as the interpreter, you can keep the environment fully synchronized, ensure package management works as expected, and run projects smoothly – just as if everything were local.</p>



<figure class="wp-block-video"><video controls src="https://blog.jetbrains.com/wp-content/uploads/2026/03/uv_on_wsl.webm"></video></figure>



<h2 class="wp-block-heading">Free professional web development for everyone</h2>



<p>With PyCharm 2026.1, the core IDE experience continues to evolve as we bring a broader set of professional-grade web tools to all users for free. Everyone, from beginners to backend-first developers, now has access to a substantial set of JavaScript, TypeScript,<strong> </strong>and CSS features, as well as advanced navigation and code intelligence previously available only with a Pro subscription.</p>



<figure class="wp-block-video"><video controls src="https://blog.jetbrains.com/wp-content/uploads/2026/03/Webstorm_Free_JS.webm"></video></figure>



<p>For a complete breakdown of all new features, check out this <a href="https://blog.jetbrains.com/pycharm/2026/03/expanding-our-core-web-development-support-in-pycharm-2026-1/">blog post</a>. </p>



<h2 class="wp-block-heading">Advancements in AI integration</h2>



<p>PyCharm is evolving into an open platform that gives you the freedom to bring the AI tools of your choice directly into your professional development workflow. This release focuses on providing a flexible ecosystem where you can orchestrate the best models and agents available today.</p>



<h3 class="wp-block-heading">The ACP Registry: Your gateway to new agents</h3>



<p>Keeping up with the rapid pace of AI development can be a challenge, with new coding agents appearing almost daily. To help you navigate this dynamic landscape, we’ve launched the <a href="https://blog.jetbrains.com/ai/2026/01/acp-agent-registry/">ACP Registry</a> – a built-in directory of AI coding agents integrated directly into your IDE via the Agent Client Protocol.</p>



<p>Whether you want to experiment with open-source agents like OpenCode or specialized tools like Gemini CLI, you can now discover and install them in just a few clicks. If you have a custom setup or an agent that isn’t listed yet, you can easily add it via the <code>acp.json</code> configuration, giving you the flexibility to use your favorite tools, with no strings attached.</p>



<figure class="wp-block-video"><video controls src="https://blog.jetbrains.com/wp-content/uploads/2026/03/ACP.webm"></video></figure>



<h3 class="wp-block-heading">Native OpenAI Codex integration and BYOK</h3>



<p>OpenAI Codex is now natively integrated into the JetBrains AI chat. This means you can tackle complex development tasks without switching to a browser or copy-pasting code between windows.</p>



<p>We’ve also introduced Bring Your Own Key (BYOK) support. You can now connect your own API keys from OpenAI, Anthropic, or other compatible providers – including local models – directly in the IDE settings. This allows you to choose the setup that fits your workflow and budget best, while keeping all your AI-powered development inside PyCharm.</p>



<h3 class="wp-block-heading">Stay in the flow with next edit suggestions</h3>



<p>Small changes in your code often trigger a cascade of mechanical follow-up edits. Adding a parameter to a function or renaming a symbol can lead to errors popping up across your entire file.</p>



<p>Next edit suggestions (NES) offer a smarter, lightweight alternative to asking an AI agent for a full rewrite. As you modify your code, PyCharm proactively predicts the most likely next changes and suggests them inline.</p>



<ul>
<li><strong>Effortless consistency:</strong> Update all call sites across a file with a simple <em>Tab Tab</em> experience.</li>



<li><strong>Stay in control:</strong> Move step by step through changes rather than reviewing large, automated diffs.</li>



<li><strong>No quota required:</strong> Use NES without consuming AI credits – available without consuming the AI quota of your JetBrains AI Pro subscription.</li>
</ul>



<p>This natural evolution of code completion keeps you in the flow, making those small cascading fixes feel almost effortless.</p>



<figure class="wp-block-video"><video controls src="https://blog.jetbrains.com/wp-content/uploads/2026/03/NES.webm"></video></figure>



<p>All of the updates mentioned above are just a glimpse of what’s new in PyCharm 2026.1.</p>



<p>There is even more under the hood, including performance improvements, stability upgrades, and thoughtful refinements across the IDE that make everyday development smoother and faster.</p>



<p>To explore the full list of updates, check out our <a href="https://www.jetbrains.com/pycharm/whatsnew/" target="_blank" rel="noopener">What’s New</a> page.&nbsp;</p>



<p>As always, we would love to hear your feedback. Your insights help us shape the future of PyCharm – and we cannot wait to see what you build next.</p>
]]></content:encoded>
					
		
		
		                    <language>
                        <code><![CDATA[zh-hans]]></code>
                        <url>https://blog.jetbrains.com/zh-hans/pycharm/2026/03/what-s-new-in-pycharm-2026-1/</url>
                    </language>
                                    <language>
                        <code><![CDATA[pt-br]]></code>
                        <url>https://blog.jetbrains.com/pt-br/pycharm/2026/03/what-s-new-in-pycharm-2026-1/</url>
                    </language>
                                    <language>
                        <code><![CDATA[ko]]></code>
                        <url>https://blog.jetbrains.com/ko/pycharm/2026/03/what-s-new-in-pycharm-2026-1/</url>
                    </language>
                                    <language>
                        <code><![CDATA[ja]]></code>
                        <url>https://blog.jetbrains.com/ja/pycharm/2026/03/what-s-new-in-pycharm-2026-1/</url>
                    </language>
                                    <language>
                        <code><![CDATA[fr]]></code>
                        <url>https://blog.jetbrains.com/fr/pycharm/2026/03/what-s-new-in-pycharm-2026-1/</url>
                    </language>
                                    <language>
                        <code><![CDATA[es]]></code>
                        <url>https://blog.jetbrains.com/es/pycharm/2026/03/what-s-new-in-pycharm-2026-1/</url>
                    </language>
                                    <language>
                        <code><![CDATA[de]]></code>
                        <url>https://blog.jetbrains.com/de/pycharm/2026/03/what-s-new-in-pycharm-2026-1/</url>
                    </language>
                	</item>
		<item>
		<title>Expanding Our Core Web Development Support in PyCharm 2026.1</title>
		<link>https://blog.jetbrains.com/pycharm/2026/03/expanding-our-core-web-development-support-in-pycharm-2026-1/</link>
		
		<dc:creator><![CDATA[Ilia Afanasiev]]></dc:creator>
		<pubDate>Wed, 25 Mar 2026 15:01:54 +0000</pubDate>
		<featuredImage>https://blog.jetbrains.com/wp-content/uploads/2026/03/PC-social-BlogFeatured-1280x720-1.png</featuredImage>		<category><![CDATA[web-development]]></category>
		<guid isPermaLink="false">https://blog.jetbrains.com/?post_type=pycharm&#038;p=687028</guid>

					<description><![CDATA[With PyCharm 2026.1, our core IDE experience continues to evolve as we’re bringing a broader set of professional-grade web tools to all users for free. Everyone, from beginners to backend-first developers, is getting access to a substantial set of JavaScript, TypeScript, and CSS features that were previously only available with a Pro subscription. React, JavaScript, [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>With PyCharm 2026.1, our core IDE experience continues to evolve as we’re bringing a broader set of professional-grade web tools to all users for free. Everyone, from beginners to backend-first developers, is getting access to a substantial set of JavaScript, TypeScript,<strong> </strong>and CSS features that were previously only available with a Pro subscription.</p>



<h3 class="wp-block-heading">React, JavaScript, TypeScript, and CSS support</h3>



<p>Leverage a comprehensive set of editing and formatting tools for modern web languages within PyCharm, including:</p>



<ul>
<li><strong>Basic React support </strong>with code completion, component and attribute navigation, and React component and prop rename refactorings.</li>



<li><strong>Advanced import management</strong>:
<ul>
<li>Enjoy automatic JavaScript and TypeScript imports as you work.</li>



<li>Merge or remove unnecessary references via the <em>Optimize imports</em> feature.</li>



<li>Get required imports automatically when you paste code into the editor.</li>
</ul>
</li>
</ul>



<ul>
<li><strong>Enhanced styling</strong>: Access CSS-tailored code completion, inspections, and quick-fixes, and view any changes in real time via the built-in web preview.</li>



<li><strong>Smart editor behavior:</strong> Utilize smart keys, code vision inlay hints, and postfix code completions designed for web development.</li>
</ul>



<h3 class="wp-block-heading">Navigation and code intelligence</h3>



<p>Finding your way around web projects is now even more efficient with tools that allow for:</p>



<ul>
<li><strong>Pro-grade navigation:</strong> Use dedicated gutter icons for <em>Jump to&#8230;</em> actions, recursive calls, and TypeScript source mapping.</li>



<li><strong>Core web refactorings:</strong> Perform essential code changes with reliable <em>Rename</em> refactorings and actions (<em>Introduce variable</em>, <em>Change signature</em>, <em>Move members</em>, and more<em>)</em>.</li>



<li><strong>Quality control</strong>: Maintain high code standards with professional-grade inspections, intentions, and quick-fixes.</li>



<li><strong>Code cleanup</strong>: Identify redundant code blocks through JavaScript and TypeScript duplicate detection.</li>
</ul>



<h3 class="wp-block-heading">Frameworks and integrated tools</h3>



<p>With the added essential support for some of the most popular frontend frameworks and tools, you will have access to:</p>



<ul>
<li><strong>Project initialization</strong>: Create new web projects quickly using the built-in Vite generator.</li>



<li><strong>Standard tooling</strong>: Standardize code quality with integrated support for Prettier, ESLint, TSLint, and StyleLint.</li>



<li><strong>Script management</strong>: Discover and execute NPM scripts directly from your <code>package.json</code>.</li>



<li><strong>Security</strong>: Check project dependencies for security vulnerabilities.</li>
</ul>



<p>We’re excited to bring these tried and true features to the core PyCharm experience for free! We’re certain these tools will help beginners, students, and hobbyists tackle real-world tasks within a single, powerful IDE. Best of all, core PyCharm can be used for both commercial and non-commercial projects, so it will grow with you as you move from learning to professional development.</p>
]]></content:encoded>
					
		
		
		                    <language>
                        <code><![CDATA[zh-hans]]></code>
                        <url>https://blog.jetbrains.com/zh-hans/pycharm/2026/03/expanding-our-core-web-development-support-in-pycharm-2026-1/</url>
                    </language>
                                    <language>
                        <code><![CDATA[pt-br]]></code>
                        <url>https://blog.jetbrains.com/pt-br/pycharm/2026/03/expanding-our-core-web-development-support-in-pycharm-2026-1/</url>
                    </language>
                                    <language>
                        <code><![CDATA[ko]]></code>
                        <url>https://blog.jetbrains.com/ko/pycharm/2026/03/expanding-our-core-web-development-support-in-pycharm-2026-1/</url>
                    </language>
                                    <language>
                        <code><![CDATA[ja]]></code>
                        <url>https://blog.jetbrains.com/ja/pycharm/2026/03/expanding-our-core-web-development-support-in-pycharm-2026-1/</url>
                    </language>
                                    <language>
                        <code><![CDATA[fr]]></code>
                        <url>https://blog.jetbrains.com/fr/pycharm/2026/03/expanding-our-core-web-development-support-in-pycharm-2026-1/</url>
                    </language>
                                    <language>
                        <code><![CDATA[es]]></code>
                        <url>https://blog.jetbrains.com/es/pycharm/2026/03/expanding-our-core-web-development-support-in-pycharm-2026-1/</url>
                    </language>
                	</item>
	</channel>
</rss>
